2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtkwindow.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkscrolledwindow.h>
33 #include <gtk/gtkhpaned.h>
34 #include <gtk/gtkhbox.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtkentry.h>
37 #include <gtk/gtkctree.h>
38 #include <gtk/gtkclist.h>
39 #include <gtk/gtktable.h>
40 #include <gtk/gtkhbbox.h>
41 #include <gtk/gtkbutton.h>
42 #include <gtk/gtkmenu.h>
43 #include <gtk/gtkmenuitem.h>
44 #include <gtk/gtkitemfactory.h>
47 #include <sys/types.h>
51 #include "addressbook.h"
52 #include "manage_window.h"
53 #include "prefs_common.h"
54 #include "alertpanel.h"
55 #include "inputdialog.h"
57 #include "stock_pixmap.h"
59 #include "prefs_gtk.h"
65 #include "addr_compl.h"
68 #include "addressitem.h"
70 #include "addrcache.h"
72 #include "addrindex.h"
73 #include "addressadd.h"
74 #include "addrduplicates.h"
75 #include "addressbook_foldersel.h"
77 #include "editvcard.h"
78 #include "editgroup.h"
79 #include "editaddress.h"
81 #include "importldif.h"
82 #include "importmutt.h"
83 #include "importpine.h"
88 #include "editjpilot.h"
93 #include "ldapserver.h"
95 #include "ldapupdate.h"
97 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
100 #include "addrquery.h"
101 #include "addrselect.h"
102 #include "addrclip.h"
103 #include "addrgather.h"
104 #include "adbookbase.h"
105 #include "exphtmldlg.h"
106 #include "expldifdlg.h"
107 #include "browseldap.h"
108 #include "addrcustomattr.h"
114 } AddressIndexColumns;
122 } AddressListColumns;
125 AddressBookFile *book;
133 AddressDataSource *book;
137 static gchar *list_titles[] = { N_("Name"),
141 #define COL_NAME_WIDTH 164
142 #define COL_ADDRESS_WIDTH 156
144 #define COL_FOLDER_WIDTH 170
145 #define ADDRESSBOOK_WIDTH 640
146 #define ADDRESSBOOK_HEIGHT 360
148 #define ADDRESSBOOK_MSGBUF_SIZE 2048
150 static GdkPixmap *folderxpm;
151 static GdkBitmap *folderxpmmask;
152 static GdkPixmap *folderopenxpm;
153 static GdkBitmap *folderopenxpmmask;
154 static GdkPixmap *groupxpm;
155 static GdkBitmap *groupxpmmask;
156 static GdkPixmap *interfacexpm;
157 static GdkBitmap *interfacexpmmask;
158 static GdkPixmap *bookxpm;
159 static GdkBitmap *bookxpmmask;
160 static GdkPixmap *addressxpm;
161 static GdkBitmap *addressxpmmask;
162 static GdkPixmap *vcardxpm;
163 static GdkBitmap *vcardxpmmask;
164 static GdkPixmap *jpilotxpm;
165 static GdkBitmap *jpilotxpmmask;
166 static GdkPixmap *categoryxpm;
167 static GdkBitmap *categoryxpmmask;
168 static GdkPixmap *ldapxpm;
169 static GdkBitmap *ldapxpmmask;
170 static GdkPixmap *addrsearchxpm;
171 static GdkPixmap *addrsearchxpmmask;
174 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
176 /* Address list selection */
177 static AddrSelectList *_addressSelect_ = NULL;
178 static AddressClipboard *_clipBoard_ = NULL;
180 /* Address index file and interfaces */
181 static AddressIndex *_addressIndex_ = NULL;
182 static GList *_addressInterfaceList_ = NULL;
183 static GList *_addressIFaceSelection_ = NULL;
184 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
186 static AddressBook_win addrbook;
188 static GHashTable *_addressBookTypeHash_ = NULL;
189 static GList *_addressBookTypeList_ = NULL;
191 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
192 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
193 static void addressbook_edit_address_post_cb( ItemPerson *person );
195 static void addressbook_create (void);
196 static gint addressbook_close (void);
197 static void addressbook_button_set_sensitive (void);
199 static gboolean address_index_has_focus = FALSE;
200 static gboolean address_list_has_focus = FALSE;
202 /* callback functions */
203 static void addressbook_del_clicked (GtkButton *button,
205 static void addressbook_reg_clicked (GtkButton *button,
207 static void addressbook_to_clicked (GtkButton *button,
209 static void addressbook_lup_clicked (GtkButton *button,
211 static void addressbook_close_clicked (GtkButton *button,
214 static void addressbook_tree_selected (GtkCTree *ctree,
218 static void addressbook_select_row_tree (GtkCTree *ctree,
222 static void addressbook_list_row_selected (GtkCTree *clist,
226 static void addressbook_list_row_unselected (GtkCTree *clist,
230 static void addressbook_person_expand_node (GtkCTree *ctree,
233 static void addressbook_person_collapse_node (GtkCTree *ctree,
237 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
238 GdkEventButton *event,
240 static gboolean addressbook_list_button_released(GtkWidget *widget,
241 GdkEventButton *event,
243 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
244 GdkEventButton *event,
246 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
247 GdkEventButton *event,
250 static void addressbook_new_folder_cb (gpointer data,
253 static void addressbook_new_group_cb (gpointer data,
256 static void addressbook_treenode_edit_cb (gpointer data,
259 static void addressbook_treenode_delete_cb (gpointer data,
263 static void addressbook_change_node_name (GtkCTreeNode *node,
266 static void addressbook_new_address_cb (gpointer data,
269 static void addressbook_edit_address_cb (gpointer data,
272 static void addressbook_delete_address_cb (gpointer data,
276 static void close_cb (gpointer data,
279 static void addressbook_file_save_cb (gpointer data,
283 /* Data source edit stuff */
284 static void addressbook_new_book_cb (gpointer data,
287 static void addressbook_new_vcard_cb (gpointer data,
292 static void addressbook_new_jpilot_cb (gpointer data,
298 static void addressbook_new_ldap_cb (gpointer data,
303 static void addressbook_set_clist (AddressObject *obj,
306 static void addressbook_load_tree (void);
307 void addressbook_read_file (void);
309 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
311 static void addressbook_treenode_remove_item ( void );
313 static AddressDataSource *addressbook_find_datasource
314 (GtkCTreeNode *node );
316 static AddressBookFile *addressbook_get_book_file(void);
318 static GtkCTreeNode *addressbook_node_add_folder
320 AddressDataSource *ds,
321 ItemFolder *itemFolder,
322 AddressObjectType otype);
323 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
324 AddressDataSource *ds,
325 ItemGroup *itemGroup);
326 static void addressbook_tree_remove_children (GtkCTree *ctree,
327 GtkCTreeNode *parent);
328 static void addressbook_move_nodes_up (GtkCTree *ctree,
330 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
332 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
335 static gint addressbook_treenode_compare_func (GtkCList *clist,
338 static void addressbook_folder_load_one_person (GtkCTree *clist,
340 AddressTypeControlItem *atci,
341 AddressTypeControlItem *atciMail);
342 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
344 static void addressbook_folder_remove_one_person(GtkCTree *clist,
346 static void addressbook_folder_remove_node (GtkCTree *clist,
349 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
350 gboolean force_focus );
352 /* LUT's and IF stuff */
353 static void addressbook_free_treenode ( gpointer data );
354 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
355 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
357 static void addrbookctl_build_map (GtkWidget *window);
358 static void addrbookctl_build_iflist (void);
359 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
360 static void addrbookctl_build_ifselect (void);
362 static void addrbookctl_free_interface (AdapterInterface *adapter);
363 static void addrbookctl_free_datasource (AdapterDSource *adapter);
364 static void addrbookctl_free_folder (AdapterFolder *adapter);
365 static void addrbookctl_free_group (AdapterGroup *adapter);
367 static void addressbook_list_select_clear ( void );
368 static void addressbook_list_select_add ( AddrItemObject *aio,
369 AddressDataSource *ds );
370 static void addressbook_list_select_remove ( AddrItemObject *aio );
372 static void addressbook_import_ldif_cb ( void );
373 static void addressbook_find_duplicates_cb ( void );
374 static void addressbook_edit_custom_attr_cb ( void );
375 static void addressbook_import_mutt_cb ( void );
376 static void addressbook_import_pine_cb ( void );
377 static void addressbook_export_html_cb ( void );
378 static void addressbook_export_ldif_cb ( void );
379 static void addressbook_select_all_cb ( void );
380 static void addressbook_clip_cut_cb ( void );
381 static void addressbook_clip_copy_cb ( void );
382 static void addressbook_clip_paste_cb ( void );
383 static void addressbook_treenode_cut_cb ( void );
384 static void addressbook_treenode_copy_cb ( void );
385 static void addressbook_treenode_paste_cb ( void );
387 static void addressbook_mail_to_cb ( void );
390 static void addressbook_browse_entry_cb ( void );
392 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
394 static void addressbook_start_drag(GtkWidget *widget, gint button,
397 static void addressbook_drag_data_get(GtkWidget *widget,
398 GdkDragContext *drag_context,
399 GtkSelectionData *selection_data,
403 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
404 GdkDragContext *context,
409 static void addressbook_drag_leave_cb(GtkWidget *widget,
410 GdkDragContext *context,
413 static void addressbook_drag_received_cb(GtkWidget *widget,
414 GdkDragContext *drag_context,
417 GtkSelectionData *data,
421 static void addressbook_list_menu_setup( void );
423 static GtkTargetEntry addressbook_drag_types[] =
425 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
428 static GtkTargetList *addressbook_target_list = NULL;
431 static GtkItemFactoryEntry addressbook_entries[] =
433 {N_("/_Book"), NULL, NULL, 0, "<Branch>", NULL},
434 {N_("/_Book/New _Book"), "<control>B", addressbook_new_book_cb, 0, NULL, NULL},
435 {N_("/_Book/New _Folder"), "<control>R", addressbook_new_folder_cb, 0, NULL, NULL},
436 {N_("/_Book/New _vCard"), "<control><shift>D", addressbook_new_vcard_cb, 0, NULL, NULL},
438 {N_("/_Book/New _JPilot"), "<control>J", addressbook_new_jpilot_cb, 0, NULL, NULL},
441 {N_("/_Book/New LDAP _Server"), "<control><shift>S", addressbook_new_ldap_cb, 0, NULL, NULL},
443 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>", NULL},
444 {N_("/_Book/_Edit book"), NULL, addressbook_treenode_edit_cb, 0, NULL, NULL},
445 {N_("/_Book/_Delete book"), NULL, addressbook_treenode_delete_cb, 0, NULL, NULL},
446 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>", NULL},
447 {N_("/_Book/_Save"), "<control>S", addressbook_file_save_cb, 0, NULL, NULL},
448 {N_("/_Book/_Close"), "<control>W", close_cb, 0, NULL, NULL},
449 {N_("/_Address"), NULL, NULL, 0, "<Branch>", NULL},
450 {N_("/_Address/_Select all"), "<control>A", addressbook_select_all_cb, 0, NULL, NULL},
451 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
452 {N_("/_Address/C_ut"), "<control>X", addressbook_clip_cut_cb, 0, NULL, NULL},
453 {N_("/_Address/_Copy"), "<control>C", addressbook_clip_copy_cb, 0, NULL, NULL},
454 {N_("/_Address/_Paste"), "<control>V", addressbook_clip_paste_cb, 0, NULL, NULL},
455 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
456 {N_("/_Address/_Edit"), "<control>Return",addressbook_edit_address_cb, 0, NULL, NULL},
457 {N_("/_Address/_Delete"), "<control>D", addressbook_delete_address_cb, 0, NULL, NULL},
458 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
459 {N_("/_Address/New _Address"), "<control>N", addressbook_new_address_cb, 0, NULL, NULL},
460 {N_("/_Address/New _Group"), "<control>G", addressbook_new_group_cb, 0, NULL, NULL},
461 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
462 {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL, NULL},
463 {N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL},
464 {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL, NULL},
465 {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL, NULL},
466 {N_("/_Tools/Import _Pine file..."), NULL, addressbook_import_pine_cb, 0, NULL, NULL},
467 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>", NULL},
468 {N_("/_Tools/Export _HTML..."), NULL, addressbook_export_html_cb, 0, NULL, NULL},
469 {N_("/_Tools/Export LDI_F..."), NULL, addressbook_export_ldif_cb, 0, NULL, NULL},
470 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>", NULL},
471 {N_("/_Tools/Find duplicates..."), NULL, addressbook_find_duplicates_cb, 0, NULL, NULL},
472 {N_("/_Tools/Edit custom attributes..."), NULL, addressbook_edit_custom_attr_cb, 0, NULL, NULL},
473 {N_("/_Help"), NULL, NULL, 0, "<Branch>", NULL},
474 {N_("/_Help/_About"), NULL, about_show, 0, NULL, NULL}
477 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
479 {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL, NULL},
480 {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL, NULL},
481 {"/---", NULL, NULL, 0, "<Separator>", NULL},
482 {N_("/New _Book"), NULL, addressbook_new_book_cb, 0, NULL, NULL},
483 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL, NULL},
484 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL, NULL},
485 {"/---", NULL, NULL, 0, "<Separator>", NULL},
486 {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL, NULL},
487 {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL, NULL},
488 {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL, NULL}
491 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
493 {N_("/_Select all"), NULL, addressbook_select_all_cb, 0, NULL, NULL},
494 {"/---", NULL, NULL, 0, "<Separator>", NULL},
495 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL, NULL},
496 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL, NULL},
497 {"/---", NULL, NULL, 0, "<Separator>", NULL},
498 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL, NULL},
499 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL, NULL},
500 {"/---", NULL, NULL, 0, "<Separator>", NULL},
501 {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL, NULL},
502 {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL, NULL},
503 {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL, NULL},
504 {"/---", NULL, NULL, 0, "<Separator>", NULL},
505 /* {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL, NULL},*/
506 {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL, NULL},
508 {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL, NULL},
513 * Structure of error message table.
515 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
516 struct _ErrMsgTableEntry {
521 static gchar *_errMsgUnknown_ = N_( "Unknown" );
524 * Lookup table of error messages for general errors. Note that a NULL
525 * description signifies the end of the table.
527 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
528 { MGU_SUCCESS, N_("Success") },
529 { MGU_BAD_ARGS, N_("Bad arguments") },
530 { MGU_NO_FILE, N_("File not specified") },
531 { MGU_OPEN_FILE, N_("Error opening file") },
532 { MGU_ERROR_READ, N_("Error reading file") },
533 { MGU_EOF, N_("End of file encountered") },
534 { MGU_OO_MEMORY, N_("Error allocating memory") },
535 { MGU_BAD_FORMAT, N_("Bad file format") },
536 { MGU_ERROR_WRITE, N_("Error writing to file") },
537 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
538 { MGU_NO_PATH, N_("No path specified") },
544 * Lookup table of error messages for LDAP errors.
546 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
547 { LDAPRC_SUCCESS, N_("Success") },
548 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
549 { LDAPRC_INIT, N_("Error initializing LDAP") },
550 { LDAPRC_BIND, N_("Error binding to LDAP server") },
551 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
552 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
553 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
554 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
555 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
556 { LDAPRC_TLS, N_("Error starting TLS connection") },
557 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
558 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
559 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
560 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
566 * Lookup message for specified error code.
567 * \param lut Lookup table.
568 * \param code Code to lookup.
569 * \return Description associated to code.
571 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
573 ErrMsgTableEntry entry;
576 for( i = 0; ; i++ ) {
578 if( entry.description == NULL ) break;
579 if( entry.code == code ) {
580 desc = entry.description;
585 desc = _errMsgUnknown_;
590 static gboolean lastCanLookup = FALSE;
592 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
594 if (add_and_delete) {
595 gtk_widget_show(addrbook.edit_btn);
596 gtk_widget_show(addrbook.del_btn);
597 gtk_widget_show(addrbook.reg_btn);
599 gtk_widget_hide(addrbook.edit_btn);
600 gtk_widget_hide(addrbook.del_btn);
601 gtk_widget_hide(addrbook.reg_btn);
605 gtk_widget_show(addrbook.lup_btn);
606 gtk_widget_show(addrbook.entry);
607 gtk_widget_show(addrbook.label);
609 gtk_widget_hide(addrbook.lup_btn);
610 gtk_widget_hide(addrbook.entry);
611 gtk_widget_hide(addrbook.label);
614 lastCanLookup = lookup;
617 gtk_widget_show(addrbook.to_btn);
618 gtk_widget_show(addrbook.cc_btn);
619 gtk_widget_show(addrbook.bcc_btn);
621 gtk_widget_hide(addrbook.to_btn);
622 gtk_widget_hide(addrbook.cc_btn);
623 gtk_widget_hide(addrbook.bcc_btn);
627 void addressbook_open(Compose *target)
629 /* Initialize all static members */
630 if( _clipBoard_ == NULL ) {
631 _clipBoard_ = addrclip_create();
633 if( _addressIndex_ != NULL ) {
634 addrclip_set_index( _clipBoard_, _addressIndex_ );
636 if( _addressSelect_ == NULL ) {
637 _addressSelect_ = addrselect_list_create();
639 if (!addrbook.window) {
640 addressbook_read_file();
641 addressbook_create();
642 addressbook_load_tree();
643 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
644 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
647 gtk_widget_hide(addrbook.window);
650 gtk_widget_show_all(addrbook.window);
652 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
653 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
655 if (!prefs_common.addressbook_use_editaddress_dialog)
656 addressbook_edit_person_widgetset_hide();
658 address_completion_start(addrbook.window);
660 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
661 addressbook_set_target_compose(target);
665 * Destroy addressbook.
667 void addressbook_destroy( void ) {
668 /* Free up address stuff */
669 if( _addressSelect_ != NULL ) {
670 addrselect_list_free( _addressSelect_ );
672 if( _clipBoard_ != NULL ) {
673 addrclip_free( _clipBoard_ );
675 if( _addressIndex_ != NULL ) {
676 addrindex_free_index( _addressIndex_ );
677 addrindex_teardown();
679 _addressSelect_ = NULL;
681 _addressIndex_ = NULL;
684 void addressbook_set_target_compose(Compose *target)
686 addrbook.target_compose = target;
687 addressbook_button_set_sensitive();
690 Compose *addressbook_get_target_compose(void)
692 return addrbook.target_compose;
696 * Refresh addressbook and save to file(s).
698 void addressbook_refresh( void )
700 if (addrbook.window) {
701 if (addrbook.treeSelected) {
702 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
703 addrbook.treeSelected);
704 addressbook_set_clist(
705 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
706 addrbook.treeSelected),
711 addressbook_export_to_file();
714 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
716 if (event && event->keyval == GDK_Escape)
718 else if (event && event->keyval == GDK_Delete) {
719 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
720 if ( /* address_index_has_focus || */ address_list_has_focus )
721 addressbook_del_clicked(NULL, NULL);
727 *\brief Save Gtk object size to prefs dataset
729 static void addressbook_size_allocate_cb(GtkWidget *widget,
730 GtkAllocation *allocation)
732 g_return_if_fail(allocation != NULL);
734 prefs_common.addressbookwin_width = allocation->width;
735 prefs_common.addressbookwin_height = allocation->height;
738 static gint sort_column_number = 0;
739 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
741 static gint list_case_sort(
742 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
744 GtkCListRow *row1 = (GtkCListRow *) ptr1;
745 GtkCListRow *row2 = (GtkCListRow *) ptr2;
746 gchar *name1 = NULL, *name2 = NULL;
747 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
748 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
750 if( aio1->type == aio2->type ) {
752 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
754 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
755 if( ! name1 ) return ( name2 != NULL );
756 if( ! name2 ) return -1;
757 return g_utf8_collate( name1, name2 );
759 /* Order groups before person */
760 if( aio1->type == ITEMTYPE_GROUP ) {
761 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
762 } else if( aio2->type == ITEMTYPE_GROUP ) {
763 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
769 static void addressbook_sort_list(GtkCList *clist, const gint col,
770 const GtkSortType sort_type)
773 GtkWidget *hbox, *label, *arrow;
775 sort_column_number = col;
776 sort_column_type = sort_type;
777 gtk_clist_set_compare_func(clist, list_case_sort);
778 gtk_clist_set_sort_type(clist, sort_type);
779 gtk_clist_set_sort_column(clist, col);
781 gtk_clist_freeze(clist);
782 gtk_clist_sort(clist);
784 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
785 hbox = gtk_hbox_new(FALSE, 4);
786 label = gtk_label_new(gettext(list_titles[pos]));
787 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
790 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
791 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
792 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
795 gtk_widget_show_all(hbox);
796 gtk_clist_set_column_widget(clist, pos, hbox);
799 gtk_clist_thaw(clist);
802 static void addressbook_name_clicked(GtkWidget *button, GtkCList *clist)
804 static GtkSortType sort_type = GTK_SORT_ASCENDING;
806 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
808 addressbook_sort_list(clist, COL_NAME, sort_type);
811 static void addressbook_address_clicked(GtkWidget *button, GtkCList *clist)
813 static GtkSortType sort_type = GTK_SORT_ASCENDING;
815 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
817 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
820 static void addressbook_remarks_clicked(GtkWidget *button, GtkCList *clist)
822 static GtkSortType sort_type = GTK_SORT_ASCENDING;
824 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
826 addressbook_sort_list(clist, COL_REMARKS, sort_type);
829 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
832 address_index_has_focus = TRUE;
836 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
839 address_index_has_focus = FALSE;
840 if (!prefs_common.addressbook_use_editaddress_dialog
841 && !address_list_has_focus)
842 addressbook_address_list_disable_some_actions();
846 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
849 address_list_has_focus = TRUE;
853 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
856 address_list_has_focus = FALSE;
857 if (!prefs_common.addressbook_use_editaddress_dialog
858 && !address_index_has_focus)
859 addressbook_address_list_disable_some_actions();
863 /* save hpane and vpane's handle position when it moves */
864 static void addressbook_pane_save_position(void)
867 prefs_common.addressbook_hpaned_pos =
868 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
870 prefs_common.addressbook_vpaned_pos =
871 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
875 * Create the address book widgets. The address book contains two CTree widgets: the
876 * address index tree on the left and the address list on the right.
878 * The address index tree displays a hierarchy of interfaces and groups. Each node in
879 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
880 * data sources and folder objects.
882 * The address list displays group, person and email objects. These items are linked
883 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
886 * In the tradition of MVC architecture, the data stores have been separated from the
887 * GUI components. The addrindex.c file provides the interface to all data stores.
889 static void addressbook_create(void)
895 GtkWidget *ctree_swin;
897 GtkWidget *editaddress_vbox;
898 GtkWidget *clist_vbox;
899 GtkWidget *clist_swin;
906 GtkWidget *statusbar;
917 GtkWidget *close_btn;
918 GtkWidget *tree_popup;
919 GtkWidget *list_popup;
920 GtkItemFactory *tree_factory;
921 GtkItemFactory *list_factory;
922 GtkItemFactory *menu_factory;
926 gchar *index_titles[N_INDEX_COLS];
930 static GdkGeometry geometry;
932 debug_print("Creating addressbook window...\n");
934 index_titles[COL_SOURCES] = _("Sources");
936 /* Address book window */
937 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
938 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
939 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
940 gtk_widget_realize(window);
942 g_signal_connect(G_OBJECT(window), "delete_event",
943 G_CALLBACK(addressbook_close), NULL);
944 g_signal_connect(G_OBJECT(window), "size_allocate",
945 G_CALLBACK(addressbook_size_allocate_cb), NULL);
946 g_signal_connect(G_OBJECT(window), "key_press_event",
947 G_CALLBACK(key_pressed), NULL);
948 MANAGE_WINDOW_SIGNALS_CONNECT(window);
950 vbox = gtk_vbox_new(FALSE, 0);
951 gtk_container_add(GTK_CONTAINER(window), vbox);
954 n_entries = sizeof(addressbook_entries) /
955 sizeof(addressbook_entries[0]);
956 menubar = menubar_create(window, addressbook_entries, n_entries,
957 "<AddressBook>", NULL);
958 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
959 menu_factory = gtk_item_factory_from_widget(menubar);
961 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
962 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
963 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
965 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
966 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
967 GTK_POLICY_AUTOMATIC,
968 GTK_POLICY_AUTOMATIC);
969 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
972 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
973 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
974 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
975 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
976 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
977 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
978 GTK_CTREE_EXPANDER_SQUARE);
979 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
980 gtk_clist_set_compare_func(GTK_CLIST(ctree),
981 addressbook_treenode_compare_func);
983 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
984 G_CALLBACK(addressbook_tree_selected), NULL);
985 g_signal_connect(G_OBJECT(ctree), "button_press_event",
986 G_CALLBACK(addressbook_tree_button_pressed),
988 g_signal_connect(G_OBJECT(ctree), "button_release_event",
989 G_CALLBACK(addressbook_tree_button_released),
992 g_signal_connect(G_OBJECT(ctree), "select_row",
993 G_CALLBACK(addressbook_select_row_tree), NULL);
995 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
996 addressbook_drag_types, 1,
997 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
998 g_signal_connect(G_OBJECT(ctree), "drag_motion",
999 G_CALLBACK(addressbook_drag_motion_cb),
1001 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1002 G_CALLBACK(addressbook_drag_leave_cb),
1004 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1005 G_CALLBACK(addressbook_drag_received_cb),
1007 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1008 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1009 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1010 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1012 clist_vbox = gtk_vbox_new(FALSE, 4);
1014 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1015 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1016 GTK_POLICY_AUTOMATIC,
1017 GTK_POLICY_AUTOMATIC);
1018 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1021 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1022 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1023 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
1024 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
1025 gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE);
1026 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
1027 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
1029 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
1031 gtk_widget_set_size_request(clist, -1, 80);
1033 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1034 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
1035 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1036 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
1037 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1038 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
1039 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1040 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1041 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1042 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1043 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1045 for (i = 0; i < N_LIST_COLS; i++)
1046 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
1049 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1050 G_CALLBACK(addressbook_list_row_selected), NULL);
1051 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1052 G_CALLBACK(addressbook_list_row_unselected), NULL);
1053 g_signal_connect(G_OBJECT(clist), "button_press_event",
1054 G_CALLBACK(addressbook_list_button_pressed),
1056 g_signal_connect(G_OBJECT(clist), "button_release_event",
1057 G_CALLBACK(addressbook_list_button_released),
1059 g_signal_connect(G_OBJECT(clist), "tree_expand",
1060 G_CALLBACK(addressbook_person_expand_node), NULL );
1061 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1062 G_CALLBACK(addressbook_person_collapse_node), NULL );
1063 g_signal_connect(G_OBJECT(clist), "start_drag",
1064 G_CALLBACK(addressbook_start_drag), NULL);
1065 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1066 G_CALLBACK(addressbook_drag_data_get), NULL);
1067 hbox = gtk_hbox_new(FALSE, 4);
1068 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1070 label = gtk_label_new(_("Lookup name:"));
1071 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1073 entry = gtk_entry_new();
1074 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1076 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1078 g_signal_connect(G_OBJECT(entry), "key_press_event",
1079 G_CALLBACK(addressbook_entry_key_pressed),
1082 if (!prefs_common.addressbook_use_editaddress_dialog) {
1083 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1084 vpaned = gtk_vpaned_new();
1085 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1086 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1089 editaddress_vbox = NULL;
1091 hpaned = gtk_hpaned_new();
1092 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1093 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1094 if (prefs_common.addressbook_use_editaddress_dialog)
1095 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1097 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1100 hsbox = gtk_hbox_new(FALSE, 0);
1101 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1102 statusbar = gtk_statusbar_new();
1103 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1106 hbbox = gtk_hbutton_box_new();
1107 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1108 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1109 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1110 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1112 gtkut_stock_button_add_help(hbbox, &help_btn);
1114 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1115 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1116 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1117 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1118 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1119 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1120 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1121 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1122 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1125 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1126 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1127 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1129 g_signal_connect(G_OBJECT(help_btn), "clicked",
1130 G_CALLBACK(manual_open_with_anchor_cb),
1131 MANUAL_ANCHOR_ADDRBOOK);
1133 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1134 G_CALLBACK(addressbook_edit_clicked), NULL);
1135 g_signal_connect(G_OBJECT(del_btn), "clicked",
1136 G_CALLBACK(addressbook_del_clicked), NULL);
1137 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1138 G_CALLBACK(addressbook_reg_clicked), NULL);
1139 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1140 G_CALLBACK(addressbook_lup_clicked), NULL);
1142 to_btn = gtk_button_new_with_label
1143 (prefs_common_translated_header_name("To:"));
1144 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1145 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1146 cc_btn = gtk_button_new_with_label
1147 (prefs_common_translated_header_name("Cc:"));
1148 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1149 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1150 bcc_btn = gtk_button_new_with_label
1151 (prefs_common_translated_header_name("Bcc:"));
1152 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1153 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1155 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1156 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1157 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1159 g_signal_connect(G_OBJECT(to_btn), "clicked",
1160 G_CALLBACK(addressbook_to_clicked),
1161 GINT_TO_POINTER(COMPOSE_TO));
1162 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1163 G_CALLBACK(addressbook_to_clicked),
1164 GINT_TO_POINTER(COMPOSE_CC));
1165 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1166 G_CALLBACK(addressbook_to_clicked),
1167 GINT_TO_POINTER(COMPOSE_BCC));
1168 g_signal_connect(G_OBJECT(close_btn), "clicked",
1169 G_CALLBACK(addressbook_close_clicked), NULL);
1171 /* Build icons for interface */
1172 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1173 &interfacexpm, &interfacexpmmask );
1175 /* Build control tables */
1176 addrbookctl_build_map(window);
1177 addrbookctl_build_iflist();
1178 addrbookctl_build_ifselect();
1180 addrbook.clist = NULL;
1182 /* Add each interface into the tree as a root level folder */
1183 nodeIf = _addressInterfaceList_;
1185 AdapterInterface *adapter = nodeIf->data;
1186 AddressInterface *iface = adapter->interface;
1187 nodeIf = g_list_next(nodeIf);
1189 if(iface->useInterface) {
1190 AddressTypeControlItem *atci = adapter->atci;
1191 text = atci->displayName;
1193 gtk_sctree_insert_node( GTK_CTREE(ctree),
1194 NULL, NULL, &text, FOLDER_SPACING,
1195 interfacexpm, interfacexpmmask,
1196 interfacexpm, interfacexpmmask,
1198 menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
1199 gtk_ctree_node_set_row_data_full(
1200 GTK_CTREE(ctree), adapter->treeNode, adapter,
1201 addressbook_free_treenode );
1206 n_entries = sizeof(addressbook_tree_popup_entries) /
1207 sizeof(addressbook_tree_popup_entries[0]);
1208 tree_popup = menu_create_items(addressbook_tree_popup_entries,
1210 "<AddressBookTree>", &tree_factory,
1212 n_entries = sizeof(addressbook_list_popup_entries) /
1213 sizeof(addressbook_list_popup_entries[0]);
1214 list_popup = menu_create_items(addressbook_list_popup_entries,
1216 "<AddressBookList>", &list_factory,
1219 addrbook.window = window;
1220 addrbook.hpaned = hpaned;
1221 addrbook.vpaned = vpaned;
1222 addrbook.menubar = menubar;
1223 addrbook.ctree = ctree;
1226 addrbook.editaddress_vbox = editaddress_vbox;
1227 addrbook.clist = clist;
1228 addrbook.label = label;
1229 addrbook.entry = entry;
1230 addrbook.statusbar = statusbar;
1231 addrbook.status_cid = gtk_statusbar_get_context_id(
1232 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1234 addrbook.help_btn = help_btn;
1235 addrbook.edit_btn = edit_btn;
1236 addrbook.del_btn = del_btn;
1237 addrbook.reg_btn = reg_btn;
1238 addrbook.lup_btn = lup_btn;
1239 addrbook.to_btn = to_btn;
1240 addrbook.cc_btn = cc_btn;
1241 addrbook.bcc_btn = bcc_btn;
1243 addrbook.tree_popup = tree_popup;
1244 addrbook.list_popup = list_popup;
1245 addrbook.tree_factory = tree_factory;
1246 addrbook.list_factory = list_factory;
1247 addrbook.menu_factory = menu_factory;
1249 addrbook.listSelected = NULL;
1251 if (!geometry.min_height) {
1252 geometry.min_width = ADDRESSBOOK_WIDTH;
1253 geometry.min_height = ADDRESSBOOK_HEIGHT;
1256 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1258 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1259 prefs_common.addressbookwin_height);
1261 if (!prefs_common.addressbook_use_editaddress_dialog) {
1262 if (prefs_common.addressbook_vpaned_pos > 0)
1263 gtk_paned_set_position(GTK_PANED(vpaned),
1264 prefs_common.addressbook_vpaned_pos);
1266 if (prefs_common.addressbook_hpaned_pos > 0)
1267 gtk_paned_set_position(GTK_PANED(hpaned),
1268 prefs_common.addressbook_hpaned_pos);
1271 gtk_widget_show_all(window);
1275 * Close address book window and save to file(s).
1277 static gint addressbook_close( void ) {
1278 address_completion_end(addrbook.window);
1279 if (!prefs_common.addressbook_use_editaddress_dialog)
1280 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1282 addressbook_pane_save_position();
1284 gtk_widget_hide(addrbook.window);
1285 addressbook_export_to_file();
1290 * Display message in status line.
1291 * \param msg Message to display.
1293 static void addressbook_status_show( gchar *msg ) {
1294 if( addrbook.statusbar != NULL ) {
1296 GTK_STATUSBAR(addrbook.statusbar),
1297 addrbook.status_cid );
1300 GTK_STATUSBAR(addrbook.statusbar),
1301 addrbook.status_cid, msg );
1306 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1310 *addressbook_msgbuf = '\0';
1312 name = addrindex_ds_get_name( ds );
1313 retVal = addrindex_ds_get_status_code( ds );
1314 if( retVal == MGU_SUCCESS ) {
1315 g_snprintf( addressbook_msgbuf,
1316 sizeof(addressbook_msgbuf), "%s", name );
1319 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1320 g_snprintf( addressbook_msgbuf,
1321 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1324 addressbook_status_show( addressbook_msgbuf );
1327 static void addressbook_button_set_sensitive(void)
1329 gboolean to_sens = FALSE;
1330 gboolean cc_sens = FALSE;
1331 gboolean bcc_sens = FALSE;
1333 if (!addrbook.window) return;
1335 if (addrbook.target_compose) {
1341 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1342 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1343 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1346 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1348 addressbook_edit_address_cb(NULL, 0, NULL);
1352 * Delete one or more objects from address list.
1354 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1356 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1357 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1358 AddressObject *pobj;
1359 AdapterDSource *ads = NULL;
1360 GtkCTreeNode *nodeList;
1363 AddressBookFile *abf = NULL;
1364 AddressDataSource *ds = NULL;
1365 AddressInterface *iface;
1366 AddrItemObject *aio;
1367 AddrSelectItem *item;
1369 gboolean refreshList = FALSE;
1371 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1372 g_return_if_fail(pobj != NULL);
1374 /* Test whether anything selected for deletion */
1375 nodeList = addrbook.listSelected;
1377 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1378 if( aio == NULL) return;
1379 ds = addressbook_find_datasource( addrbook.treeSelected );
1380 if( ds == NULL ) return;
1382 /* Test for read only */
1383 iface = ds->interface;
1384 if( iface->readOnly ) {
1385 alertpanel( _("Delete address(es)"),
1386 _("This address data is readonly and cannot be deleted."),
1387 GTK_STOCK_CLOSE, NULL, NULL );
1391 /* Test whether Ok to proceed */
1393 if( pobj->type == ADDR_DATASOURCE ) {
1394 ads = ADAPTER_DSOURCE(pobj);
1395 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1397 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1400 else if( pobj->type == ADDR_ITEM_GROUP ) {
1403 if( ! procFlag ) return;
1404 abf = ds->rawDataSource;
1405 if( abf == NULL ) return;
1408 /* Process deletions */
1409 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1410 gboolean group_delete = TRUE;
1411 /* Items inside folders */
1412 list = addrselect_get_list( _addressSelect_ );
1413 /* Confirm deletion */
1417 node = g_list_next( node );
1418 aio = ( AddrItemObject * ) item->addressItem;
1419 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1420 group_delete = FALSE;
1425 aval = alertpanel( _("Delete group"),
1426 _("Really delete the group(s)?\n"
1427 "The addresses it contains will not be lost."),
1428 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1429 if( aval != G_ALERTALTERNATE ) return;
1431 aval = alertpanel( _("Delete address(es)"),
1432 _("Really delete the address(es)?"),
1433 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1434 if( aval != G_ALERTALTERNATE ) return;
1440 node = g_list_next( node );
1441 aio = ( AddrItemObject * ) item->addressItem;
1444 if( aio->type == ADDR_ITEM_GROUP ) {
1445 ItemGroup *item = ( ItemGroup * ) aio;
1446 GtkCTreeNode *nd = NULL;
1448 nd = addressbook_find_group_node( addrbook.opened, item );
1449 item = addrbook_remove_group( abf, item );
1451 addritem_free_item_group( item );
1453 /* Remove group from parent node */
1454 gtk_ctree_remove_node( ctree, nd );
1457 else if( aio->type == ADDR_ITEM_PERSON ) {
1458 ItemPerson *item = ( ItemPerson * ) aio;
1459 item->status = DELETE_ENTRY;
1460 addressbook_folder_remove_one_person( clist, item );
1461 if (pobj->type == ADDR_ITEM_FOLDER)
1462 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1463 item = addrbook_remove_person( abf, item );
1465 if (ds && ds->type == ADDR_IF_LDAP) {
1466 LdapServer *server = ds->rawDataSource;
1467 ldapsvr_set_modified(server, TRUE);
1468 ldapsvr_update_book(server, item);
1472 gchar *filename = addritem_person_get_picture(item);
1473 if (filename && is_file_exist(filename))
1476 addritem_free_item_person( item );
1479 else if( aio->type == ADDR_ITEM_EMAIL ) {
1480 ItemEMail *item = ( ItemEMail * ) aio;
1481 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1482 item = addrbook_person_remove_email( abf, person, item );
1484 addrcache_remove_email(abf->addressCache, item);
1485 addritem_free_item_email( item );
1487 addressbook_folder_refresh_one_person( clist, person );
1490 g_list_free( list );
1491 addressbook_list_select_clear();
1493 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1494 addressbook_set_clist(
1495 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1499 addrbook_set_dirty(abf, TRUE);
1500 addressbook_export_to_file();
1501 addressbook_list_menu_setup();
1504 else if( pobj->type == ADDR_ITEM_GROUP ) {
1505 /* Items inside groups */
1506 list = addrselect_get_list( _addressSelect_ );
1510 node = g_list_next( node );
1511 aio = ( AddrItemObject * ) item->addressItem;
1512 if( aio->type == ADDR_ITEM_EMAIL ) {
1513 ItemEMail *item = ( ItemEMail * ) aio;
1514 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1515 item = addrbook_person_remove_email( abf, person, item );
1517 addritem_free_item_email( item );
1521 g_list_free( list );
1522 addressbook_list_select_clear();
1523 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1524 addressbook_set_clist(
1525 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1529 addrbook_set_dirty(abf, TRUE);
1530 addressbook_export_to_file();
1531 addressbook_list_menu_setup();
1535 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1536 gtk_ctree_remove_node( clist, nodeList );
1540 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1542 addressbook_new_address_cb( NULL, 0, NULL );
1545 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1548 gchar *address = NULL;
1550 if( aio->type == ADDR_ITEM_EMAIL ) {
1551 ItemPerson *person = NULL;
1552 ItemEMail *email = ( ItemEMail * ) aio;
1554 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1555 if( email->address ) {
1556 if( ADDRITEM_NAME(email) ) {
1557 name = ADDRITEM_NAME(email);
1558 if( *name == '\0' ) {
1559 name = ADDRITEM_NAME(person);
1562 else if( ADDRITEM_NAME(person) ) {
1563 name = ADDRITEM_NAME(person);
1566 buf = g_strdup( email->address );
1568 address = email->address;
1571 else if( aio->type == ADDR_ITEM_PERSON ) {
1572 ItemPerson *person = ( ItemPerson * ) aio;
1573 GList *node = person->listEMail;
1575 name = ADDRITEM_NAME(person);
1577 ItemEMail *email = ( ItemEMail * ) node->data;
1578 address = email->address;
1582 if( name && name[0] != '\0' ) {
1583 if( strchr_with_skip_quote( name, '"', ',' ) )
1584 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1586 buf = g_strdup_printf( "%s <%s>", name, address );
1589 buf = g_strdup( address );
1596 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1600 AddrSelectItem *item;
1601 AddrItemObject *aio;
1604 compose = addrbook.target_compose;
1605 if( ! compose ) return;
1607 /* Nothing selected, but maybe there is something in text entry */
1608 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1610 compose_entry_append(
1611 compose, addr, (ComposeEntryType)data );
1614 /* Select from address list */
1615 list = addrselect_get_list( _addressSelect_ );
1620 node = g_list_next( node );
1621 aio = item->addressItem;
1622 if( aio->type == ADDR_ITEM_PERSON ||
1623 aio->type == ADDR_ITEM_EMAIL ) {
1624 addr = addressbook_format_address( aio );
1625 compose_entry_append(
1626 compose, addr, (ComposeEntryType) data );
1629 else if( aio->type == ADDR_ITEM_GROUP ) {
1630 ItemGroup *group = ( ItemGroup * ) aio;
1631 GList *nodeMail = group->listEMail;
1633 ItemEMail *email = nodeMail->data;
1635 addr = addressbook_format_address(
1636 ( AddrItemObject * ) email );
1637 compose_entry_append(
1638 compose, addr, (ComposeEntryType) data );
1640 nodeMail = g_list_next( nodeMail );
1645 AddressObject *obj = NULL;
1647 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1649 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1650 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1651 GList *nodeMail = itemGroup->listEMail;
1653 ItemEMail *email = nodeMail->data;
1655 addr = addressbook_format_address(
1656 ( AddrItemObject * ) email );
1657 compose_entry_append(
1658 compose, addr, (ComposeEntryType) data );
1660 nodeMail = g_list_next( nodeMail );
1664 g_list_free( list );
1667 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1668 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1669 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1670 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1672 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1673 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1674 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1675 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1677 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1678 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1679 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1680 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1681 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1682 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1685 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1686 gboolean canEdit = FALSE;
1687 gboolean canDelete = TRUE;
1688 gboolean canAdd = FALSE;
1689 gboolean canEditTr = TRUE;
1690 gboolean editAddress = FALSE;
1691 gboolean canExport = TRUE;
1692 AddressTypeControlItem *atci = NULL;
1693 AddressDataSource *ds = NULL;
1694 AddressInterface *iface = NULL;
1696 if( obj == NULL ) return;
1697 if( obj->type == ADDR_INTERFACE ) {
1698 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1699 iface = adapter->interface;
1701 if( iface->haveLibrary ) {
1702 /* Enable appropriate File / New command */
1703 atci = adapter->atci;
1704 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1707 canEditTr = canExport = FALSE;
1709 else if( obj->type == ADDR_DATASOURCE ) {
1710 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1711 ds = ads->dataSource;
1712 iface = ds->interface;
1713 if( ! iface->readOnly ) {
1714 canAdd = canEdit = editAddress = canDelete = TRUE;
1716 if( ! iface->haveLibrary ) {
1717 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1720 else if( obj->type == ADDR_ITEM_FOLDER ) {
1721 ds = addressbook_find_datasource( addrbook.treeSelected );
1723 iface = ds->interface;
1724 if( iface->readOnly ) {
1729 canAdd = editAddress = TRUE;
1733 else if( obj->type == ADDR_ITEM_GROUP ) {
1734 ds = addressbook_find_datasource( addrbook.treeSelected );
1736 iface = ds->interface;
1737 if( ! iface->readOnly ) {
1743 if( addrbook.listSelected == NULL )
1747 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1748 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1749 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1750 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1753 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1754 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1755 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1756 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1758 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1759 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1762 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1763 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1767 * Address book tree callback function that responds to selection of tree
1770 * \param ctree Tree widget.
1771 * \param node Node that was selected.
1772 * \param column Column number where selected occurred.
1773 * \param data Pointer to user data.
1775 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1776 gint column, gpointer data)
1778 AddressObject *obj = NULL;
1779 AdapterDSource *ads = NULL;
1780 AddressDataSource *ds = NULL;
1781 ItemFolder *rootFolder = NULL;
1782 AddressObjectType aot;
1784 addrbook.treeSelected = node;
1785 addrbook.listSelected = NULL;
1786 addressbook_status_show( "" );
1787 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1789 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1791 addressbook_set_clist(NULL, TRUE);
1794 addrbook.opened = node;
1796 if( obj->type == ADDR_DATASOURCE ) {
1797 /* Read from file */
1798 static gboolean tVal = TRUE;
1800 ads = ADAPTER_DSOURCE(obj);
1801 if( ads == NULL ) return;
1802 ds = ads->dataSource;
1803 if( ds == NULL ) return;
1805 if( addrindex_ds_get_modify_flag( ds ) ) {
1806 addrindex_ds_read_data( ds );
1809 if( ! addrindex_ds_get_read_flag( ds ) ) {
1810 addrindex_ds_read_data( ds );
1812 addressbook_ds_show_message( ds );
1814 if( ! addrindex_ds_get_access_flag( ds ) ) {
1815 /* Remove existing folders and groups */
1816 gtk_clist_freeze( GTK_CLIST(ctree) );
1817 addressbook_tree_remove_children( ctree, node );
1818 gtk_clist_thaw( GTK_CLIST(ctree) );
1820 /* Load folders into the tree */
1821 rootFolder = addrindex_ds_get_root_folder( ds );
1822 if( ds && ds->type == ADDR_IF_JPILOT ) {
1823 aot = ADDR_CATEGORY;
1825 else if( ds && ds->type == ADDR_IF_LDAP ) {
1826 aot = ADDR_LDAP_QUERY;
1829 aot = ADDR_ITEM_FOLDER;
1831 addressbook_node_add_folder( node, ds, rootFolder, aot );
1832 addrindex_ds_set_access_flag( ds, &tVal );
1833 gtk_ctree_expand( ctree, node );
1836 addressbook_set_clist(NULL, TRUE);
1839 /* Update address list */
1840 g_signal_handlers_block_by_func
1842 G_CALLBACK(addressbook_tree_selected), NULL);
1843 addressbook_set_clist( obj, FALSE );
1844 g_signal_handlers_unblock_by_func
1846 G_CALLBACK(addressbook_tree_selected), NULL);
1847 if (!prefs_common.addressbook_use_editaddress_dialog)
1848 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1850 /* Setup main menu selections */
1851 addressbook_menubar_set_sensitive( FALSE );
1852 addressbook_menuitem_set_sensitive( obj, node );
1853 addressbook_list_select_clear();
1854 addressbook_list_menu_setup();
1859 * Setup address list popup menu items. Items are enabled or disabled as
1862 static void addressbook_list_menu_setup( void ) {
1863 GtkCTree *clist = NULL;
1864 AddressObject *pobj = NULL;
1865 AddressObject *obj = NULL;
1866 AdapterDSource *ads = NULL;
1867 AddressInterface *iface = NULL;
1868 AddressDataSource *ds = NULL;
1869 gboolean canEdit = FALSE;
1870 gboolean canDelete = FALSE;
1871 gboolean canCut = FALSE;
1872 gboolean canCopy = FALSE;
1873 gboolean canPaste = FALSE;
1874 gboolean canBrowse = FALSE;
1875 AddrSelectItem *item;
1876 AddrItemObject *aio;
1879 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1880 if( pobj == NULL ) return;
1882 clist = GTK_CTREE(addrbook.clist);
1883 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1884 if( obj == NULL ) canEdit = FALSE;
1886 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1887 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1889 if( pobj->type == ADDR_DATASOURCE ) {
1890 /* Parent object is a data source */
1891 ads = ADAPTER_DSOURCE(pobj);
1892 ds = ads->dataSource;
1895 iface = ds->interface;
1898 if( ! iface->readOnly ) {
1899 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1900 if (iface->type != ADDR_IF_LDAP)
1901 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1902 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1905 canDelete = canEdit;
1908 else if( pobj->type != ADDR_INTERFACE ) {
1909 /* Parent object is not an interface */
1910 ds = addressbook_find_datasource( addrbook.treeSelected );
1913 iface = ds->interface;
1916 if( ! iface->readOnly ) {
1917 /* Folder or group */
1918 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1919 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1920 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1921 if( obj ) canEdit = TRUE;
1924 if( pobj->type == ADDR_ITEM_FOLDER ) {
1925 if (iface->type != ADDR_IF_LDAP)
1926 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1927 if( obj ) canEdit = TRUE;
1929 canDelete = canEdit;
1931 if( iface->type == ADDR_IF_LDAP ) {
1932 if( obj ) canBrowse = TRUE;
1939 /* Enable cut and paste */
1940 if( ! addrclip_is_empty( _clipBoard_ ) )
1942 if( ! addrselect_test_empty( _addressSelect_ ) )
1944 /* Enable copy if something is selected */
1945 if( ! addrselect_test_empty( _addressSelect_ ) )
1949 /* Disable edit or browse if more than one row selected */
1950 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
1955 /* Forbid write changes when read-only */
1956 if( iface && iface->readOnly ) {
1962 /* Now go finalize menu items */
1963 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
1964 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1966 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
1967 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
1968 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
1970 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
1972 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
1973 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
1974 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
1976 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1977 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1978 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
1980 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1981 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1984 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
1988 static void addressbook_select_row_tree (GtkCTree *ctree,
1996 * Add list of items into tree node below specified tree node.
1997 * \param treeNode Tree node.
1998 * \param ds Data source.
1999 * \param listItems List of items.
2001 static void addressbook_treenode_add_list(
2002 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2008 AddrItemObject *aio;
2012 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2015 group = ( ItemGroup * ) aio;
2016 nn = addressbook_node_add_group( treeNode, ds, group );
2018 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2021 folder = ( ItemFolder * ) aio;
2022 nn = addressbook_node_add_folder(
2023 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2025 node = g_list_next( node );
2029 static void addressbook_select_all_cb( void ) {
2030 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2034 * Cut from address list widget.
2036 static void addressbook_clip_cut_cb( void ) {
2037 _clipBoard_->cutFlag = TRUE;
2038 addrclip_clear( _clipBoard_ );
2039 addrclip_add( _clipBoard_, _addressSelect_ );
2040 /* addrclip_list_show( _clipBoard_, stdout ); */
2044 * Copy from address list widget.
2046 static void addressbook_clip_copy_cb( void ) {
2047 _clipBoard_->cutFlag = FALSE;
2048 addrclip_clear( _clipBoard_ );
2049 addrclip_add( _clipBoard_, _addressSelect_ );
2050 /* addrclip_list_show( _clipBoard_, stdout ); */
2054 * Paste clipboard into address list widget.
2056 static void addressbook_clip_paste_cb( void ) {
2057 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2058 AddressObject *pobj = NULL;
2059 AddressDataSource *ds = NULL;
2060 AddressBookFile *abf = NULL;
2061 ItemFolder *folder = NULL;
2062 GList *folderGroup = NULL;
2064 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2065 if( ds == NULL ) return;
2066 if( addrindex_ds_get_readonly( ds ) ) {
2067 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2071 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2073 if( pobj->type == ADDR_ITEM_FOLDER ) {
2074 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2076 else if( pobj->type == ADDR_ITEM_GROUP ) {
2077 alertpanel_error( _("Cannot paste into an address group.") );
2082 /* Get an address book */
2083 abf = addressbook_get_book_file();
2084 if( abf == NULL ) return;
2086 if( _clipBoard_->cutFlag ) {
2088 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2090 /* Remove all groups and folders in clipboard from tree node */
2091 addressbook_treenode_remove_item();
2093 /* Remove all "cut" items */
2094 addrclip_delete_item( _clipBoard_ );
2096 /* Clear clipboard - cut items??? */
2097 addrclip_clear( _clipBoard_ );
2101 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2104 /* addrclip_list_show( _clipBoard_, stdout ); */
2106 /* Update tree by inserting node for each folder or group */
2107 addressbook_treenode_add_list(
2108 addrbook.treeSelected, ds, folderGroup );
2109 gtk_ctree_expand( ctree, addrbook.treeSelected );
2110 g_list_free( folderGroup );
2114 /* Display items pasted */
2115 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2116 addressbook_set_clist(
2117 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2125 * Add current treenode object to clipboard. Note that widget only allows
2126 * one entry from the tree list to be selected.
2128 static void addressbook_treenode_to_clipboard( void ) {
2129 AddressObject *obj = NULL;
2130 AddressDataSource *ds = NULL;
2131 AddrSelectItem *item;
2132 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2135 node = addrbook.treeSelected;
2136 if( node == NULL ) return;
2137 obj = gtk_ctree_node_get_row_data( ctree, node );
2138 if( obj == NULL ) return;
2140 ds = addressbook_find_datasource( node );
2141 if( ds == NULL ) return;
2144 if( obj->type == ADDR_ITEM_FOLDER ) {
2145 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2146 ItemFolder *folder = adapter->itemFolder;
2148 item = addrselect_create_node( obj );
2149 item->uid = g_strdup( ADDRITEM_ID(folder) );
2151 else if( obj->type == ADDR_ITEM_GROUP ) {
2152 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2153 ItemGroup *group = adapter->itemGroup;
2155 item = addrselect_create_node( obj );
2156 item->uid = g_strdup( ADDRITEM_ID(group) );
2158 else if( obj->type == ADDR_DATASOURCE ) {
2160 item = addrselect_create_node( obj );
2165 /* Clear existing list and add item into list */
2168 addressbook_list_select_clear();
2169 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2170 addrselect_list_add( _addressSelect_, item, cacheID );
2176 * Cut from tree widget.
2178 static void addressbook_treenode_cut_cb( void ) {
2179 _clipBoard_->cutFlag = TRUE;
2180 addressbook_treenode_to_clipboard();
2181 addrclip_clear( _clipBoard_ );
2182 addrclip_add( _clipBoard_, _addressSelect_ );
2183 /* addrclip_list_show( _clipBoard_, stdout ); */
2187 * Copy from tree widget.
2189 static void addressbook_treenode_copy_cb( void ) {
2190 _clipBoard_->cutFlag = FALSE;
2191 addressbook_treenode_to_clipboard();
2192 addrclip_clear( _clipBoard_ );
2193 addrclip_add( _clipBoard_, _addressSelect_ );
2194 /* addrclip_list_show( _clipBoard_, stdout ); */
2198 * Paste clipboard into address tree widget.
2200 static void addressbook_treenode_paste_cb( void ) {
2201 addressbook_clip_paste_cb();
2205 * Clear selected entries in clipboard.
2207 static void addressbook_list_select_clear( void ) {
2208 addrselect_list_clear( _addressSelect_ );
2212 * Add specified address item to selected address list.
2213 * \param aio Address item object.
2214 * \param ds Datasource.
2216 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2219 if( ds == NULL ) return;
2220 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2221 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2226 * Remove specified address item from selected address list.
2227 * \param aio Address item object.
2229 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2230 addrselect_list_remove( _addressSelect_, aio );
2234 * Invoke EMail compose window with addresses in selected address list.
2236 static void addressbook_mail_to_cb( void ) {
2239 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2240 listAddress = addrselect_build_list( _addressSelect_ );
2241 compose_new_with_list( NULL, listAddress );
2242 mgu_free_dlist( listAddress );
2247 static void addressbook_list_row_selected( GtkCTree *clist,
2252 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2253 AddrItemObject *aio = NULL;
2254 AddressObject *pobj = NULL;
2255 AdapterDSource *ads = NULL;
2256 AddressDataSource *ds = NULL;
2258 gtk_entry_set_text( entry, "" );
2259 addrbook.listSelected = node;
2261 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2262 if( pobj == NULL ) return;
2264 if( pobj->type == ADDR_DATASOURCE ) {
2265 ads = ADAPTER_DSOURCE(pobj);
2266 ds = ads->dataSource;
2268 else if( pobj->type != ADDR_INTERFACE ) {
2269 ds = addressbook_find_datasource( addrbook.treeSelected );
2272 aio = gtk_ctree_node_get_row_data( clist, node );
2274 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2275 addressbook_list_select_add( aio, ds );
2278 addressbook_list_menu_setup();
2280 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2281 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2283 if (obj && obj->type != ADDR_ITEM_GROUP)
2284 addressbook_edit_address(NULL, 0, NULL, FALSE);
2288 static void addressbook_list_row_unselected( GtkCTree *ctree,
2293 AddrItemObject *aio;
2295 aio = gtk_ctree_node_get_row_data( ctree, node );
2297 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2298 addressbook_list_select_remove( aio );
2301 if (!prefs_common.addressbook_use_editaddress_dialog)
2302 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2305 /* from gdkevents.c */
2306 #define DOUBLE_CLICK_TIME 250
2308 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2309 GdkEventButton *event,
2312 static guint32 lasttime = 0;
2313 if( ! event ) return FALSE;
2315 addressbook_list_menu_setup();
2317 if( event->button == 3 ) {
2318 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2319 event->button, event->time );
2320 } else if (event->button == 1) {
2321 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2322 if (prefs_common.add_address_by_click &&
2323 addrbook.target_compose)
2324 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2326 if (prefs_common.addressbook_use_editaddress_dialog)
2327 addressbook_edit_address_cb(NULL, 0, NULL);
2329 GtkCTree *clist = GTK_CTREE(addrbook.clist);
2330 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2331 if( obj && obj->type == ADDR_ITEM_GROUP )
2332 addressbook_edit_address_cb(NULL, 0, NULL);
2337 lasttime = event->time;
2343 static gboolean addressbook_list_button_released(GtkWidget *widget,
2344 GdkEventButton *event,
2350 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2351 GdkEventButton *event,
2354 GtkCList *clist = GTK_CLIST(ctree);
2356 AddressObject *obj = NULL;
2357 AdapterDSource *ads = NULL;
2358 AddressInterface *iface = NULL;
2359 AddressDataSource *ds = NULL;
2360 gboolean canEdit = FALSE;
2361 gboolean canDelete = FALSE;
2362 gboolean canCut = FALSE;
2363 gboolean canCopy = FALSE;
2364 gboolean canPaste = FALSE;
2365 gboolean canTreeCut = FALSE;
2366 gboolean canTreeCopy = FALSE;
2367 gboolean canTreePaste = FALSE;
2368 gboolean canLookup = FALSE;
2369 GtkCTreeNode *node = NULL;
2371 if( ! event ) return FALSE;
2372 addressbook_menubar_set_sensitive( FALSE );
2374 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2375 gtkut_clist_set_focus_row(clist, row);
2376 obj = gtk_clist_get_row_data( clist, row );
2379 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2381 if( obj == NULL ) return FALSE;
2382 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2384 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2385 canTreePaste = TRUE;
2387 if (obj->type == ADDR_INTERFACE) {
2388 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2391 iface = adapter->interface;
2394 if( !iface->readOnly ) {
2395 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2396 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2398 if( iface->externalQuery ) canLookup = TRUE;
2400 if (obj->type == ADDR_DATASOURCE) {
2401 ads = ADAPTER_DSOURCE(obj);
2402 ds = ads->dataSource;
2405 iface = ds->interface;
2408 if( !iface->readOnly ) {
2410 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2411 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2412 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2416 if( iface->externalQuery ) canLookup = TRUE;
2418 else if (obj->type == ADDR_ITEM_FOLDER) {
2419 ds = addressbook_find_datasource( node );
2422 iface = ds->interface;
2425 if( !iface->readOnly ) {
2429 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2430 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2431 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2435 if( iface->externalQuery ) {
2436 /* Enable deletion of LDAP folder */
2441 else if (obj->type == ADDR_ITEM_GROUP) {
2442 ds = addressbook_find_datasource( node );
2445 iface = ds->interface;
2448 if( ! iface->readOnly ) {
2451 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2452 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2457 if( ! addrselect_test_empty( _addressSelect_ ) )
2460 if( ! addrselect_test_empty( _addressSelect_ ) )
2462 if( ! addrclip_is_empty( _clipBoard_ ) )
2465 /* Forbid write changes when read-only */
2466 if( iface && iface->readOnly ) {
2468 canTreePaste = FALSE;
2476 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2477 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2478 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2479 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2480 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2482 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2483 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2484 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2485 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2486 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2488 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2489 addrbook.target_compose != NULL);
2491 if( event->button == 3 ) {
2492 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2493 event->button, event->time);
2499 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2500 GdkEventButton *event,
2503 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2507 static void addressbook_new_folder_cb(gpointer data, guint action,
2510 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2511 AddressObject *obj = NULL;
2512 AddressDataSource *ds = NULL;
2513 AddressBookFile *abf = NULL;
2514 ItemFolder *parentFolder = NULL;
2515 ItemFolder *folder = NULL;
2517 if( ! addrbook.treeSelected ) return;
2518 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2519 if( obj == NULL ) return;
2520 ds = addressbook_find_datasource( addrbook.treeSelected );
2521 if( ds == NULL ) return;
2523 if( obj->type == ADDR_DATASOURCE ) {
2524 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2526 else if( obj->type == ADDR_ITEM_FOLDER ) {
2527 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2533 abf = ds->rawDataSource;
2534 if( abf == NULL ) return;
2535 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2538 nn = addressbook_node_add_folder(
2539 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2540 gtk_ctree_expand( ctree, addrbook.treeSelected );
2541 if( addrbook.treeSelected == addrbook.opened )
2542 addressbook_set_clist(obj, TRUE);
2547 static void addressbook_new_group_cb(gpointer data, guint action,
2550 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2551 AddressObject *obj = NULL;
2552 AddressDataSource *ds = NULL;
2553 AddressBookFile *abf = NULL;
2554 ItemFolder *parentFolder = NULL;
2555 ItemGroup *group = NULL;
2557 if( ! addrbook.treeSelected ) return;
2558 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2559 if( obj == NULL ) return;
2560 ds = addressbook_find_datasource( addrbook.treeSelected );
2561 if( ds == NULL ) return;
2563 if( obj->type == ADDR_DATASOURCE ) {
2564 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2566 else if( obj->type == ADDR_ITEM_FOLDER ) {
2567 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2573 abf = ds->rawDataSource;
2574 if( abf == NULL ) return;
2575 group = addressbook_edit_group( abf, parentFolder, NULL );
2578 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2579 gtk_ctree_expand( ctree, addrbook.treeSelected );
2580 if( addrbook.treeSelected == addrbook.opened )
2581 addressbook_set_clist(obj, TRUE);
2586 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2588 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2591 GdkPixmap *pix_cl, *pix_op;
2592 GdkBitmap *mask_cl, *mask_op;
2593 gboolean is_leaf, expanded;
2595 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2596 &pix_cl, &mask_cl, &pix_op, &mask_op,
2597 &is_leaf, &expanded);
2598 gtk_sctree_set_node_info(ctree, node, name, spacing,
2599 pix_cl, mask_cl, pix_op, mask_op,
2605 * \param obj Address object to edit.
2606 * \param node Node in tree.
2607 * \return New name of data source.
2609 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2610 gchar *newName = NULL;
2611 AddressDataSource *ds = NULL;
2612 AddressInterface *iface = NULL;
2613 AdapterDSource *ads = NULL;
2615 ds = addressbook_find_datasource( node );
2616 if( ds == NULL ) return NULL;
2617 iface = ds->interface;
2618 if( ! iface->haveLibrary ) return NULL;
2620 /* Read data from data source */
2621 if( addrindex_ds_get_modify_flag( ds ) ) {
2622 addrindex_ds_read_data( ds );
2625 if( ! addrindex_ds_get_read_flag( ds ) ) {
2626 addrindex_ds_read_data( ds );
2630 ads = ADAPTER_DSOURCE(obj);
2631 if( ads->subType == ADDR_BOOK ) {
2632 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2634 else if( ads->subType == ADDR_VCARD ) {
2635 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2638 else if( ads->subType == ADDR_JPILOT ) {
2639 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2643 else if( ads->subType == ADDR_LDAP ) {
2644 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2650 newName = obj->name;
2655 * Edit an object that is in the address tree area.
2657 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2660 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2662 AddressDataSource *ds = NULL;
2663 AddressBookFile *abf = NULL;
2664 GtkCTreeNode *node = NULL, *parentNode = NULL;
2667 if( ! addrbook.treeSelected ) return;
2668 node = addrbook.treeSelected;
2669 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2670 obj = gtk_ctree_node_get_row_data( ctree, node );
2671 if( obj == NULL ) return;
2672 parentNode = GTK_CTREE_ROW(node)->parent;
2674 ds = addressbook_find_datasource( node );
2675 if( ds == NULL ) return;
2677 if( obj->type == ADDR_DATASOURCE ) {
2678 name = addressbook_edit_datasource( obj, node );
2679 if( name == NULL ) return;
2682 abf = ds->rawDataSource;
2683 if( abf == NULL ) return;
2684 if( obj->type == ADDR_ITEM_FOLDER ) {
2685 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2686 ItemFolder *item = adapter->itemFolder;
2687 ItemFolder *parentFolder = NULL;
2688 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2689 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2690 name = ADDRITEM_NAME(item);
2692 else if( obj->type == ADDR_ITEM_GROUP ) {
2693 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2694 ItemGroup *item = adapter->itemGroup;
2695 ItemFolder *parentFolder = NULL;
2696 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2697 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2698 name = ADDRITEM_NAME(item);
2701 if( name && parentNode ) {
2702 /* Update node in tree view */
2703 addressbook_change_node_name( node, name );
2704 gtk_sctree_sort_node(ctree, parentNode);
2705 gtk_ctree_expand( ctree, node );
2706 gtk_sctree_select( GTK_SCTREE( ctree), node );
2713 ADDRTREE_DEL_FOLDER_ONLY,
2714 ADDRTREE_DEL_FOLDER_ADDR
2718 * Delete an item from the tree widget.
2719 * \param data Data passed in.
2720 * \param action Action.
2721 * \param widget Widget issuing callback.
2723 static void addressbook_treenode_delete_cb(
2724 gpointer data, guint action, GtkWidget *widget )
2726 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2727 GtkCTreeNode *node = NULL;
2731 AddrBookBase *adbase;
2732 AddressCache *cache;
2733 AdapterDSource *ads = NULL;
2734 AddressInterface *iface = NULL;
2735 AddressDataSource *ds = NULL;
2736 gboolean remFlag = FALSE;
2737 TreeItemDelType delType;
2739 if( ! addrbook.treeSelected ) return;
2740 node = addrbook.treeSelected;
2741 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2743 obj = gtk_ctree_node_get_row_data( ctree, node );
2744 g_return_if_fail(obj != NULL);
2746 if( obj->type == ADDR_DATASOURCE ) {
2747 ads = ADAPTER_DSOURCE(obj);
2748 if( ads == NULL ) return;
2749 ds = ads->dataSource;
2750 if( ds == NULL ) return;
2753 /* Must be folder or something else */
2754 ds = addressbook_find_datasource( node );
2755 if( ds == NULL ) return;
2757 /* Only allow deletion from non-readOnly */
2758 iface = ds->interface;
2759 if( iface->readOnly ) {
2760 /* Allow deletion of query results */
2761 if( ! iface->externalQuery ) return;
2765 /* Confirm deletion */
2766 delType = ADDRTREE_DEL_NONE;
2767 if( obj->type == ADDR_ITEM_FOLDER ) {
2768 if( iface->externalQuery ) {
2769 message = g_strdup_printf( _(
2770 "Do you want to delete the query " \
2771 "results and addresses in '%s' ?" ),
2773 aval = alertpanel( _("Delete"), message,
2774 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2776 if( aval == G_ALERTALTERNATE ) {
2777 delType = ADDRTREE_DEL_FOLDER_ADDR;
2781 message = g_strdup_printf
2782 ( _( "Do you want to delete '%s' ?"
2783 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2785 aval = alertpanel( _("Delete folder"), message,
2786 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2788 if( aval == G_ALERTALTERNATE ) {
2789 delType = ADDRTREE_DEL_FOLDER_ONLY;
2791 else if( aval == G_ALERTOTHER ) {
2792 delType = ADDRTREE_DEL_FOLDER_ADDR;
2796 else if( obj->type == ADDR_ITEM_GROUP ) {
2797 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2798 "The addresses it contains will not be lost."), obj->name);
2799 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2800 "+" GTK_STOCK_DELETE, NULL);
2802 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2804 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2805 "The addresses it contains will be lost."), obj->name);
2806 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2807 "+" GTK_STOCK_DELETE, NULL);
2809 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2811 if( delType == ADDRTREE_DEL_NONE ) return;
2813 /* Proceed with deletion */
2814 if( obj->type == ADDR_DATASOURCE ) {
2815 /* Remove node from tree */
2816 gtk_ctree_remove_node( ctree, node );
2818 /* Remove data source. */
2819 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2820 addrindex_free_datasource( ds );
2825 /* Get reference to cache */
2826 adbase = ( AddrBookBase * ) ds->rawDataSource;
2827 if( adbase == NULL ) return;
2828 cache = adbase->addressCache;
2830 /* Remove query results folder */
2831 if( iface->externalQuery ) {
2832 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2833 ItemFolder *folder = adapter->itemFolder;
2835 adapter->itemFolder = NULL;
2837 g_print( "remove folder for ::%s::\n", obj->name );
2838 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2839 g_print( "-------------- remove results\n" );
2841 addrindex_remove_results( ds, folder );
2842 /* g_print( "-------------- remove node\n" ); */
2843 gtk_ctree_remove_node( ctree, node );
2847 /* Code below is valid for regular address book deletion */
2848 if( obj->type == ADDR_ITEM_FOLDER ) {
2849 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2850 ItemFolder *item = adapter->itemFolder;
2852 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2853 /* Remove folder only */
2854 item = addrcache_remove_folder( cache, item );
2856 addritem_free_item_folder( item );
2857 addressbook_move_nodes_up( ctree, node );
2861 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2862 /* Remove folder and addresses */
2863 item = addrcache_remove_folder_delete( cache, item );
2865 addritem_free_item_folder( item );
2870 else if( obj->type == ADDR_ITEM_GROUP ) {
2871 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2872 ItemGroup *item = adapter->itemGroup;
2874 item = addrcache_remove_group( cache, item );
2876 addritem_free_item_group( item );
2883 gtk_ctree_remove_node(ctree, node );
2887 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2889 if( person && addrbook.treeSelected == addrbook.opened ) {
2890 person->status = ADD_ENTRY;
2891 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2892 addressbook_folder_refresh_one_person(
2893 GTK_CTREE(addrbook.clist), person );
2895 addressbook_address_list_set_focus();
2898 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2900 if( person && addrbook.treeSelected == addrbook.opened) {
2901 person->status = ADD_ENTRY;
2902 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2903 addressbook_set_clist(
2904 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2908 addressbook_address_list_set_focus();
2912 * Label (a format string) that is used to name each folder.
2914 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
2917 * Search ctree widget callback function.
2918 * \param pA Pointer to node.
2919 * \param pB Pointer to data item being sought.
2920 * \return Zero (0) if folder found.
2922 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
2925 aoA = ( AddressObject * ) pA;
2926 if( aoA->type == ADDR_ITEM_FOLDER ) {
2927 ItemFolder *folder, *fld;
2929 fld = ADAPTER_FOLDER(aoA)->itemFolder;
2930 folder = ( ItemFolder * ) pB;
2931 if( fld == folder ) return 0; /* Found folder */
2936 static ItemFolder * addressbook_setup_subf(
2937 AddressDataSource *ds, gchar *title,
2938 GtkCTreeNode *pNode )
2940 AddrBookBase *adbase;
2941 AddressCache *cache;
2944 GtkCTreeNode *nNode;
2946 AddressObjectType aoType = ADDR_NONE;
2949 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
2951 if( ds && ds->type == ADDR_IF_LDAP ) {
2953 aoType = ADDR_LDAP_QUERY;
2960 ctree = GTK_CTREE(addrbook.ctree);
2961 /* Get reference to address cache */
2962 adbase = ( AddrBookBase * ) ds->rawDataSource;
2963 cache = adbase->addressCache;
2965 if ((children = addrcache_get_list_folder(cache)) != NULL) {
2966 GList *cur = children;
2967 for (; cur; cur = cur->next) {
2968 ItemFolder *child = (ItemFolder *) cur->data;
2969 if (!strcmp2(ADDRITEM_NAME(child), title)) {
2970 nNode = gtk_ctree_find_by_row_data_custom(
2972 addressbook_treenode_find_folder_cb );
2974 addrindex_remove_results( ds, child );
2975 while( child->listPerson ) {
2976 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
2977 item = addrcache_remove_person( cache, item );
2979 addritem_free_item_person( item );
2983 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
2984 addrbook.treeSelected = nNode;
2991 /* Create a folder */
2992 folder = addrcache_add_new_folder( cache, NULL );
2993 name = g_strdup_printf( "%s", title );
2994 addritem_folder_set_name( folder, name );
2995 addritem_folder_set_remarks( folder, "" );
2998 /* Now let's see the folder */
2999 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3000 gtk_ctree_expand( ctree, pNode );
3002 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3003 addrbook.treeSelected = nNode;
3009 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3010 AddressObject *pobj = NULL;
3011 AddressDataSource *ds = NULL;
3012 AddressBookFile *abf = NULL;
3013 debug_print("adding address\n");
3014 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3015 if( pobj == NULL ) {
3016 debug_print("no row data\n");
3019 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3021 debug_print("no datasource\n");
3025 abf = ds->rawDataSource;
3027 g_print("no addressbook file\n");
3031 if( pobj->type == ADDR_DATASOURCE ) {
3032 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3033 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3035 ItemFolder *folder = NULL;
3037 if (abf && abf->type == ADDR_IF_LDAP) {
3038 GtkCTreeNode *parentNode;
3039 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3040 if( ds == NULL ) return;
3042 /* We must have a datasource that is an external interface */
3043 if( ! ds->interface->haveLibrary ) return;
3044 if( ! ds->interface->externalQuery ) return;
3046 if( pobj->type == ADDR_ITEM_FOLDER ) {
3047 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3050 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3052 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3054 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3055 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3056 abf = ds->rawDataSource;
3059 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3060 addrbook.editaddress_vbox,
3061 addressbook_new_address_from_book_post_cb,
3064 if (abf && abf->type == ADDR_IF_LDAP) {
3065 LdapServer *server = ds->rawDataSource;
3066 ldapsvr_set_modified(server, TRUE);
3067 ldapsvr_update_book(server, NULL);
3068 if (server->retVal != LDAPRC_SUCCESS) {
3069 alertpanel( _("Add address(es)"),
3070 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3071 GTK_STOCK_CLOSE, NULL, NULL );
3072 server->retVal = LDAPRC_SUCCESS;
3077 if (prefs_common.addressbook_use_editaddress_dialog)
3078 addressbook_new_address_from_book_post_cb( person );
3081 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3083 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3086 if (abf && abf->type == ADDR_IF_LDAP) {
3087 GtkCTreeNode *parentNode;
3088 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3089 if( ds == NULL ) return;
3091 /* We must have a datasource that is an external interface */
3092 if( ! ds->interface->haveLibrary ) return;
3093 if( ! ds->interface->externalQuery ) return;
3095 if( pobj->type == ADDR_ITEM_FOLDER ) {
3096 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3099 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3101 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3104 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3105 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3106 abf = ds->rawDataSource;
3109 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3110 addrbook.editaddress_vbox,
3111 addressbook_new_address_from_folder_post_cb,
3114 if (abf && abf->type == ADDR_IF_LDAP) {
3115 LdapServer *server = ds->rawDataSource;
3116 ldapsvr_set_modified(server, TRUE);
3117 ldapsvr_update_book(server, NULL);
3118 if (server->retVal != LDAPRC_SUCCESS) {
3119 alertpanel( _("Add address(es)"),
3120 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3121 GTK_STOCK_CLOSE, NULL, NULL );
3126 if (prefs_common.addressbook_use_editaddress_dialog)
3127 addressbook_new_address_from_folder_post_cb( person );
3129 else if( pobj->type == ADDR_ITEM_GROUP ) {
3130 /* New address in group */
3131 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3132 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3133 if (addrbook.treeSelected == addrbook.opened) {
3134 /* Change node name in tree. */
3135 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3136 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3137 addressbook_set_clist(
3138 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3146 * Search for specified child group node in address index tree.
3147 * \param parent Parent node.
3148 * \param group Group to find.
3150 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
3151 GtkCTreeNode *node = NULL;
3152 GtkCTreeRow *currRow;
3154 currRow = GTK_CTREE_ROW( parent );
3156 node = currRow->children;
3160 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3161 if( obj->type == ADDR_ITEM_GROUP ) {
3162 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3163 if( g == group ) return node;
3165 currRow = GTK_CTREE_ROW(node);
3166 node = currRow->sibling;
3172 static AddressBookFile *addressbook_get_book_file() {
3173 AddressBookFile *abf = NULL;
3174 AddressDataSource *ds = NULL;
3176 ds = addressbook_find_datasource( addrbook.treeSelected );
3177 if( ds == NULL ) return NULL;
3178 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3182 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
3186 /* Remove existing folders and groups */
3187 row = GTK_CTREE_ROW( parent );
3189 while( (node = row->children) ) {
3190 gtk_ctree_remove_node( ctree, node );
3195 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
3196 GtkCTreeNode *parent, *child;
3197 GtkCTreeRow *currRow;
3198 currRow = GTK_CTREE_ROW( node );
3200 parent = currRow->parent;
3201 while( (child = currRow->children) ) {
3202 gtk_ctree_move( ctree, child, parent, node );
3204 gtk_sctree_sort_node( ctree, parent );
3208 static void addressbook_edit_address_post_cb( ItemPerson *person )
3212 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3213 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3215 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
3216 invalidate_address_completion();
3218 addressbook_address_list_set_focus();
3221 void addressbook_address_list_set_focus( void )
3223 if (!prefs_common.addressbook_use_editaddress_dialog) {
3224 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3225 addressbook_list_menu_setup();
3229 void addressbook_address_list_disable_some_actions(void)
3231 /* disable address copy/pasting when editing contact's detail (embedded form) */
3232 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3233 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3234 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3237 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3238 addressbook_edit_address(data, action, widget, TRUE);
3241 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3242 gboolean force_focus ) {
3243 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3245 AddressObject *obj = NULL, *pobj = NULL;
3246 AddressDataSource *ds = NULL;
3247 GtkCTreeNode *node = NULL, *parentNode = NULL;
3249 AddressBookFile *abf = NULL;
3251 if( addrbook.listSelected == NULL ) return;
3252 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3253 g_return_if_fail(obj != NULL);
3255 ctree = GTK_CTREE( addrbook.ctree );
3256 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3257 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3259 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3260 if( ds == NULL ) return;
3262 abf = addressbook_get_book_file();
3264 if( obj->type == ADDR_ITEM_EMAIL ) {
3265 ItemEMail *email = ( ItemEMail * ) obj;
3266 if( email == NULL ) return;
3267 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3268 /* Edit parent group */
3269 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3270 ItemGroup *itemGrp = adapter->itemGroup;
3271 if( abf == NULL ) return;
3272 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3273 name = ADDRITEM_NAME(itemGrp);
3274 node = addrbook.treeSelected;
3275 parentNode = GTK_CTREE_ROW(node)->parent;
3278 /* Edit person - email page */
3280 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3281 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3282 addressbook_edit_address_post_cb,
3283 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3286 if (abf && abf->type == ADDR_IF_LDAP) {
3287 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3288 person->status = UPDATE_ENTRY;
3291 if (prefs_common.addressbook_use_editaddress_dialog)
3292 addressbook_edit_address_post_cb( person );
3297 else if( obj->type == ADDR_ITEM_PERSON ) {
3298 /* Edit person - basic page */
3299 ItemPerson *person = ( ItemPerson * ) obj;
3300 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3301 addressbook_edit_address_post_cb,
3302 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3305 if (abf && abf->type == ADDR_IF_LDAP) {
3306 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3307 person->status = UPDATE_ENTRY;
3310 if (prefs_common.addressbook_use_editaddress_dialog)
3311 addressbook_edit_address_post_cb( person );
3315 else if( obj->type == ADDR_ITEM_GROUP ) {
3316 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3317 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3318 parentNode = addrbook.treeSelected;
3319 node = addressbook_find_group_node( parentNode, itemGrp );
3320 name = ADDRITEM_NAME(itemGrp);
3321 invalidate_address_completion();
3327 /* Update tree node with node name */
3328 if( node == NULL ) return;
3329 addressbook_change_node_name( node, name );
3330 gtk_sctree_sort_node( ctree, parentNode );
3331 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3332 addressbook_set_clist(
3333 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3338 static void addressbook_delete_address_cb(gpointer data, guint action,
3341 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
3342 addressbook_del_clicked(NULL, NULL);
3343 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
3346 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3348 addressbook_close();
3351 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3352 addressbook_export_to_file();
3355 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3357 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3358 if( person ) addritem_person_set_opened( person, TRUE );
3362 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3364 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3365 if( person ) addritem_person_set_opened( person, FALSE );
3369 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3371 gchar *eMailAlias = ADDRITEM_NAME(email);
3372 if( eMailAlias && *eMailAlias != '\0' ) {
3374 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3377 str = g_strdup( eMailAlias );
3383 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3384 GList *items = itemGroup->listEMail;
3385 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3386 for( ; items != NULL; items = g_list_next( items ) ) {
3387 GtkCTreeNode *nodeEMail = NULL;
3388 gchar *text[N_LIST_COLS];
3389 ItemEMail *email = items->data;
3393 if( ! email ) continue;
3395 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3396 str = addressbook_format_item_clist( person, email );
3398 text[COL_NAME] = addressbook_set_col_name_guard(str);
3401 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3403 text[COL_ADDRESS] = email->address;
3404 text[COL_REMARKS] = email->remarks;
3405 nodeEMail = gtk_sctree_insert_node(
3407 text, FOLDER_SPACING,
3408 atci->iconXpm, atci->maskXpm,
3409 atci->iconXpmOpen, atci->maskXpmOpen,
3411 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3417 gchar *addressbook_set_col_name_guard(gchar *value)
3419 gchar *ret = "<not set>";
3420 gchar *tmp = g_strdup(value);
3422 if (tmp !=NULL && *tmp != '\0')
3428 static void addressbook_folder_load_one_person(
3429 GtkCTree *clist, ItemPerson *person,
3430 AddressTypeControlItem *atci,
3431 AddressTypeControlItem *atciMail )
3433 GtkCTreeNode *nodePerson = NULL;
3434 GtkCTreeNode *nodeEMail = NULL;
3435 gchar *text[N_LIST_COLS];
3436 gboolean flgFirst = TRUE, haveAddr = FALSE;
3439 AddressBookFile *abf = addressbook_get_book_file();
3442 if( person == NULL ) return;
3444 text[COL_NAME] = "";
3445 node = person->listEMail;
3447 ItemEMail *email = node->data;
3448 gchar *eMailAddr = NULL;
3449 node = g_list_next( node );
3451 text[COL_ADDRESS] = email->address;
3452 text[COL_REMARKS] = email->remarks;
3453 eMailAddr = ADDRITEM_NAME(email);
3454 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3456 /* First email belongs with person */
3457 gchar *str = addressbook_format_item_clist( person, email );
3459 text[COL_NAME] = addressbook_set_col_name_guard(str);
3462 else if( abf && abf->type == ADDR_IF_LDAP &&
3463 person && person->nickName ) {
3464 if (person->nickName) {
3465 if (strcmp(person->nickName, "") != 0) {
3466 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3469 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3475 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3477 nodePerson = gtk_sctree_insert_node(
3479 text, FOLDER_SPACING,
3480 atci->iconXpm, atci->maskXpm,
3481 atci->iconXpmOpen, atci->maskXpmOpen,
3482 FALSE, person->isOpened );
3485 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3488 /* Subsequent email is a child node of person */
3489 text[COL_NAME] = ADDRITEM_NAME(email);
3490 nodeEMail = gtk_sctree_insert_node(
3491 clist, nodePerson, NULL,
3492 text, FOLDER_SPACING,
3493 atciMail->iconXpm, atciMail->maskXpm,
3494 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3496 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3502 /* Have name without EMail */
3503 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3504 text[COL_ADDRESS] = "";
3505 text[COL_REMARKS] = "";
3506 nodePerson = gtk_sctree_insert_node(
3508 text, FOLDER_SPACING,
3509 atci->iconXpm, atci->maskXpm,
3510 atci->iconXpmOpen, atci->maskXpmOpen,
3511 FALSE, person->isOpened );
3512 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3517 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3519 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3520 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3522 if( atci == NULL ) return;
3523 if( atciMail == NULL ) return;
3525 /* Load email addresses */
3526 items = addritem_folder_get_person_list( itemFolder );
3527 for( ; items != NULL; items = g_list_next( items ) ) {
3528 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3530 /* Free up the list */
3531 mgu_clear_list( items );
3532 g_list_free( items );
3535 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3536 addrbook.listSelected = NULL;
3537 gtk_ctree_remove_node( clist, node );
3538 addressbook_menubar_set_sensitive( FALSE );
3539 addressbook_menuitem_set_sensitive(
3540 gtk_ctree_node_get_row_data(
3541 GTK_CTREE(clist), addrbook.treeSelected ),
3542 addrbook.treeSelected );
3545 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3546 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3547 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3549 if( atci == NULL ) return;
3550 if( atciMail == NULL ) return;
3551 if( person == NULL ) return;
3552 /* unload the person */
3554 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3556 addressbook_folder_remove_node( clist, node );
3557 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3558 gtk_sctree_sort_node( clist, NULL );
3559 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3561 gtk_sctree_select( GTK_SCTREE(clist), node );
3562 if (!gtk_ctree_node_is_visible( clist, node ) )
3563 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3567 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3571 if( person == NULL ) return;
3572 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3573 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3575 addressbook_folder_remove_node( clist, node );
3579 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3581 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3583 /* Load any groups */
3584 if( ! atci ) return;
3585 items = addritem_folder_get_group_list( itemFolder );
3586 for( ; items != NULL; items = g_list_next( items ) ) {
3587 GtkCTreeNode *nodeGroup = NULL;
3588 gchar *text[N_LIST_COLS];
3589 ItemGroup *group = items->data;
3590 if( group == NULL ) continue;
3591 text[COL_NAME] = ADDRITEM_NAME(group);
3592 text[COL_ADDRESS] = "";
3593 text[COL_REMARKS] = "";
3594 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3595 text, FOLDER_SPACING,
3596 atci->iconXpm, atci->maskXpm,
3597 atci->iconXpmOpen, atci->maskXpmOpen,
3599 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3600 gtk_sctree_sort_node(clist, NULL);
3602 /* Free up the list */
3603 mgu_clear_list( items );
3604 g_list_free( items );
3608 * Search ctree widget callback function.
3609 * \param pA Pointer to node.
3610 * \param pB Pointer to data item being sought.
3611 * \return Zero (0) if group found.
3613 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3616 aoA = ( AddressObject * ) pA;
3617 if( aoA->type == ADDR_ITEM_GROUP ) {
3618 ItemGroup *group, *grp;
3620 grp = ADAPTER_GROUP(aoA)->itemGroup;
3621 group = ( ItemGroup * ) pB;
3622 if( grp == group ) return 0; /* Found group */
3628 * Remove folder and group nodes from tree widget for items contained ("cut")
3631 static void addressbook_treenode_remove_item( void ) {
3633 AddrSelectItem *cutItem;
3634 AddressCache *cache;
3635 AddrItemObject *aio;
3636 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3639 node = _clipBoard_->objectList;
3641 cutItem = node->data;
3642 node = g_list_next( node );
3643 cache = addrindex_get_cache(
3644 _clipBoard_->addressIndex, cutItem->cacheID );
3645 if( cache == NULL ) continue;
3646 aio = addrcache_get_object( cache, cutItem->uid );
3649 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3652 folder = ( ItemFolder * ) aio;
3653 tn = gtk_ctree_find_by_row_data_custom(
3654 ctree, NULL, folder,
3655 addressbook_treenode_find_folder_cb );
3657 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3660 group = ( ItemGroup * ) aio;
3661 tn = gtk_ctree_find_by_row_data_custom(
3663 addressbook_treenode_find_group_cb );
3667 /* Free up adapter and remove node. */
3668 gtk_ctree_remove_node( ctree, tn );
3675 * Find parent datasource for specified tree node.
3676 * \param node Node to test.
3677 * \return Data source, or NULL if not found.
3679 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3680 AddressDataSource *ds = NULL;
3683 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3686 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3687 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3689 /* g_print( "ao->type = %d\n", ao->type ); */
3690 if( ao->type == ADDR_DATASOURCE ) {
3691 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3692 /* g_print( "found it\n" ); */
3693 ds = ads->dataSource;
3697 node = GTK_CTREE_ROW(node)->parent;
3703 * Load address list widget with children of specified object.
3704 * \param obj Parent object to be loaded.
3706 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3707 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3708 GtkCList *clist = GTK_CLIST(addrbook.clist);
3709 AddressDataSource *ds = NULL;
3710 AdapterDSource *ads = NULL;
3711 static AddressObject *last_obj = NULL;
3713 if (addrbook.clist == NULL) {
3716 if (obj == last_obj && !refresh)
3721 gtk_clist_clear(clist);
3725 if( obj->type == ADDR_INTERFACE ) {
3726 /* g_print( "set_clist: loading datasource...\n" ); */
3727 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3731 gtk_clist_freeze(clist);
3732 gtk_clist_clear(clist);
3734 if( obj->type == ADDR_DATASOURCE ) {
3735 ads = ADAPTER_DSOURCE(obj);
3736 ds = ADAPTER_DSOURCE(obj)->dataSource;
3738 /* Load root folder */
3739 ItemFolder *rootFolder = NULL;
3740 rootFolder = addrindex_ds_get_root_folder( ds );
3741 addressbook_folder_load_person(
3742 ctreelist, addrindex_ds_get_root_folder( ds ) );
3743 addressbook_folder_load_group(
3744 ctreelist, addrindex_ds_get_root_folder( ds ) );
3748 if( obj->type == ADDR_ITEM_GROUP ) {
3750 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3751 addressbook_load_group( ctreelist, itemGroup );
3753 else if( obj->type == ADDR_ITEM_FOLDER ) {
3755 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3756 addressbook_folder_load_person( ctreelist, itemFolder );
3757 addressbook_folder_load_group( ctreelist, itemFolder );
3760 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3761 clist->focus_row = -1;
3762 gtk_clist_thaw(clist);
3766 * Call back function to free adaptor. Call back is setup by function
3767 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3768 * called when the address book tree widget node is removed by calling
3769 * function gtk_ctree_remove_node().
3771 * \param data Tree node's row data.
3773 static void addressbook_free_treenode( gpointer data ) {
3776 ao = ( AddressObject * ) data;
3777 if( ao == NULL ) return;
3778 if( ao->type == ADDR_INTERFACE ) {
3779 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3780 addrbookctl_free_interface( ai );
3782 else if( ao->type == ADDR_DATASOURCE ) {
3783 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3784 addrbookctl_free_datasource( ads );
3786 else if( ao->type == ADDR_ITEM_FOLDER ) {
3787 AdapterFolder *af = ADAPTER_FOLDER(ao);
3788 addrbookctl_free_folder( af );
3790 else if( ao->type == ADDR_ITEM_GROUP ) {
3791 AdapterGroup *ag = ADAPTER_GROUP(ao);
3792 addrbookctl_free_group( ag );
3797 * Create new adaptor for specified data source.
3799 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3800 AddressObjectType otype, gchar *name )
3802 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3803 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3804 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3805 adapter->dataSource = ds;
3806 adapter->subType = otype;
3810 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3811 ADDRESS_OBJECT_NAME(adapter) =
3812 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3816 * Load tree from address index with the initial data.
3818 static void addressbook_load_tree( void ) {
3819 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3820 GList *nodeIf, *nodeDS;
3821 AdapterInterface *adapter;
3822 AddressInterface *iface;
3823 AddressTypeControlItem *atci;
3824 AddressDataSource *ds;
3825 AdapterDSource *ads;
3826 GtkCTreeNode *node, *newNode;
3829 nodeIf = _addressInterfaceList_;
3831 adapter = nodeIf->data;
3832 node = adapter->treeNode;
3833 iface = adapter->interface;
3834 atci = adapter->atci;
3836 if( iface->useInterface ) {
3837 /* Load data sources below interface node */
3838 nodeDS = iface->listSource;
3842 name = addrindex_ds_get_name( ds );
3843 ads = addressbook_create_ds_adapter(
3844 ds, atci->objectType, name );
3845 newNode = addressbook_add_object(
3846 node, ADDRESS_OBJECT(ads) );
3847 nodeDS = g_list_next( nodeDS );
3849 gtk_ctree_expand( ctree, node );
3852 nodeIf = g_list_next( nodeIf );
3857 * Convert the old address book to new format.
3859 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3860 gboolean retVal = FALSE;
3861 gboolean errFlag = TRUE;
3864 /* Read old address book, performing conversion */
3865 debug_print( "Reading and converting old address book...\n" );
3866 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3867 addrindex_read_data( addrIndex );
3868 if( addrIndex->retVal == MGU_NO_FILE ) {
3869 /* We do not have a file - new user */
3870 debug_print( "New user... create new books...\n" );
3871 addrindex_create_new_books( addrIndex );
3872 if( addrIndex->retVal == MGU_SUCCESS ) {
3873 /* Save index file */
3874 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3875 addrindex_save_data( addrIndex );
3876 if( addrIndex->retVal == MGU_SUCCESS ) {
3881 msg = _( "New user, could not save index file." );
3885 msg = _( "New user, could not save address book files." );
3889 /* We have an old file */
3890 if( addrIndex->wasConverted ) {
3891 /* Converted successfully - save address index */
3892 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3893 addrindex_save_data( addrIndex );
3894 if( addrIndex->retVal == MGU_SUCCESS ) {
3895 msg = _( "Old address book converted successfully." );
3900 msg = _("Old address book converted,\n"
3901 "could not save new address index file." );
3905 /* File conversion failed - just create new books */
3906 debug_print( "File conversion failed... just create new books...\n" );
3907 addrindex_create_new_books( addrIndex );
3908 if( addrIndex->retVal == MGU_SUCCESS ) {
3910 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3911 addrindex_save_data( addrIndex );
3912 if( addrIndex->retVal == MGU_SUCCESS ) {
3913 msg = _("Could not convert address book,\n"
3914 "but created empty new address book files." );
3919 msg = _("Could not convert address book,\n"
3920 "could not save new address index file." );
3924 msg = _("Could not convert address book\n"
3925 "and could not create new address book files." );
3930 debug_print( "Error\n%s\n", msg );
3931 alertpanel_full(_("Addressbook conversion error"), msg,
3932 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3933 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3936 debug_print( "Warning\n%s\n", msg );
3937 alertpanel_full(_("Addressbook conversion error"), msg,
3938 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3939 NULL, ALERT_WARNING, G_ALERTDEFAULT);
3945 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
3949 gboolean failed = FALSE;
3951 if( ( dp = opendir( origdir ) ) == NULL ) {
3955 while( ( d = readdir( dp ) ) != NULL ) {
3956 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
3959 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
3961 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
3963 if (copy_file(orig_file, dest_file, FALSE) < 0) {
3976 /* all copies succeeded, we can remove source files */
3977 if( ( dp = opendir( origdir ) ) == NULL ) {
3980 while( ( d = readdir( dp ) ) != NULL ) {
3981 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
3984 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
3986 g_unlink(orig_file);
3996 void addressbook_read_file( void ) {
3997 AddressIndex *addrIndex = NULL;
3998 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4000 debug_print( "Reading address index...\n" );
4001 if( _addressIndex_ ) {
4002 debug_print( "address book already read!!!\n" );
4006 addrIndex = addrindex_create_index();
4007 addrindex_initialize();
4009 /* Use new address book index. */
4011 if ( !is_dir_exist(indexdir) ) {
4012 if ( make_dir(indexdir) < 0 ) {
4013 addrindex_set_file_path( addrIndex, get_rc_dir() );
4014 g_warning( "couldn't create dir %s\n", indexdir);
4016 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4017 remove_dir_recursive(indexdir);
4018 addrindex_set_file_path( addrIndex, get_rc_dir() );
4019 g_error("couldn't migrate dir %s", indexdir);
4021 addrindex_set_file_path( addrIndex, indexdir);
4025 addrindex_set_file_path( addrIndex, indexdir);
4028 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4029 addrindex_read_data( addrIndex );
4030 if( addrIndex->retVal == MGU_NO_FILE ) {
4031 /* Conversion required */
4032 debug_print( "Converting...\n" );
4033 if( addressbook_convert( addrIndex ) ) {
4034 _addressIndex_ = addrIndex;
4037 else if( addrIndex->retVal == MGU_SUCCESS ) {
4038 _addressIndex_ = addrIndex;
4041 /* Error reading address book */
4042 debug_print( "Could not read address index.\n" );
4043 addrindex_print_index( addrIndex, stdout );
4044 alertpanel_full(_("Addressbook Error"),
4045 _("Could not read address index"),
4046 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4047 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4049 debug_print( "done.\n" );
4053 * Add object into the address index tree widget.
4054 * Enter: node Parent node.
4055 * obj Object to add.
4056 * Return: Node that was added, or NULL if object not added.
4058 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
4061 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4062 GtkCTreeNode *added;
4063 AddressObject *pobj;
4064 AddressObjectType otype;
4065 AddressTypeControlItem *atci = NULL;
4067 g_return_val_if_fail(node != NULL, NULL);
4068 g_return_val_if_fail(obj != NULL, NULL);
4070 pobj = gtk_ctree_node_get_row_data(ctree, node);
4071 g_return_val_if_fail(pobj != NULL, NULL);
4073 /* Determine object type to be displayed */
4074 if( obj->type == ADDR_DATASOURCE ) {
4075 otype = ADAPTER_DSOURCE(obj)->subType;
4081 /* Handle any special conditions. */
4083 atci = addrbookctl_lookup( otype );
4085 if( atci->showInTree ) {
4086 /* Add object to tree */
4089 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4090 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
4091 atci->treeLeaf, atci->treeExpand );
4092 gtk_ctree_node_set_row_data_full( ctree, added, obj,
4093 addressbook_free_treenode );
4097 gtk_sctree_sort_node(ctree, node);
4103 * Add group into the address index tree.
4104 * \param node Parent node.
4105 * \param ds Data source.
4106 * \param itemGroup Group to add.
4107 * \return Inserted node.
4109 static GtkCTreeNode *addressbook_node_add_group(
4110 GtkCTreeNode *node, AddressDataSource *ds,
4111 ItemGroup *itemGroup )
4113 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4114 GtkCTreeNode *newNode;
4115 AdapterGroup *adapter;
4116 AddressTypeControlItem *atci = NULL;
4119 if( ds == NULL ) return NULL;
4120 if( node == NULL || itemGroup == NULL ) return NULL;
4122 name = &itemGroup->obj.name;
4124 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4126 adapter = g_new0( AdapterGroup, 1 );
4127 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4128 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4129 adapter->itemGroup = itemGroup;
4131 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4132 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4133 atci->treeLeaf, atci->treeExpand );
4134 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4135 addressbook_free_treenode );
4136 gtk_sctree_sort_node( ctree, node );
4141 * Add folder into the address index tree. Only visible folders are loaded into
4142 * the address index tree. Note that the root folder is not inserted into the
4145 * \param node Parent node.
4146 * \param ds Data source.
4147 * \param itemFolder Folder to add.
4148 * \param otype Object type to display.
4149 * \return Inserted node for the folder.
4151 static GtkCTreeNode *addressbook_node_add_folder(
4152 GtkCTreeNode *node, AddressDataSource *ds,
4153 ItemFolder *itemFolder, AddressObjectType otype )
4155 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4156 GtkCTreeNode *newNode = NULL;
4157 AdapterFolder *adapter;
4158 AddressTypeControlItem *atci = NULL;
4159 GList *listItems = NULL;
4161 ItemFolder *rootFolder;
4163 /* Only visible folders */
4164 if( itemFolder->isHidden ) return NULL;
4166 if( ds == NULL ) return NULL;
4167 if( node == NULL || itemFolder == NULL ) return NULL;
4169 /* Determine object type */
4170 atci = addrbookctl_lookup( otype );
4171 if( atci == NULL ) return NULL;
4173 rootFolder = addrindex_ds_get_root_folder( ds );
4174 if( itemFolder == rootFolder ) {
4178 adapter = g_new0( AdapterFolder, 1 );
4179 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4180 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4181 adapter->itemFolder = itemFolder;
4183 name = ADDRITEM_NAME(itemFolder);
4184 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4185 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4186 atci->treeLeaf, atci->treeExpand );
4188 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4189 addressbook_free_treenode );
4193 listItems = itemFolder->listFolder;
4194 while( listItems ) {
4195 ItemFolder *item = listItems->data;
4196 addressbook_node_add_folder( newNode, ds, item, otype );
4197 listItems = g_list_next( listItems );
4199 listItems = itemFolder->listGroup;
4200 while( listItems ) {
4201 ItemGroup *item = listItems->data;
4202 addressbook_node_add_group( newNode, ds, item );
4203 listItems = g_list_next( listItems );
4205 gtk_sctree_sort_node( ctree, node );
4209 void addressbook_export_to_file( void ) {
4210 if( _addressIndex_ ) {
4211 /* Save all new address book data */
4212 debug_print( "Saving address books...\n" );
4213 addrindex_save_all_books( _addressIndex_ );
4215 debug_print( "Exporting addressbook to file...\n" );
4216 addrindex_save_data( _addressIndex_ );
4217 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4218 addrindex_print_index( _addressIndex_, stdout );
4221 /* Notify address completion of new data */
4222 invalidate_address_completion();
4226 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4228 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4229 addressbook_lup_clicked(NULL, NULL);
4234 * Comparison using cell contents (text in first column). Used for sort
4235 * address index widget.
4237 static gint addressbook_treenode_compare_func(
4238 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4240 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
4241 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
4242 gchar *name1 = NULL, *name2 = NULL;
4243 if( cell1 ) name1 = cell1->u.text;
4244 if( cell2 ) name2 = cell2->u.text;
4245 if( ! name1 ) return ( name2 != NULL );
4246 if( ! name2 ) return -1;
4247 return g_utf8_collate( name1, name2 );
4250 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
4251 AdapterDSource *ads;
4252 AdapterInterface *adapter;
4253 GtkCTreeNode *newNode;
4255 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4256 if( adapter == NULL ) return;
4257 ads = addressbook_edit_book( _addressIndex_, NULL );
4259 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4261 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4262 addrbook.treeSelected = newNode;
4267 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
4268 AdapterDSource *ads;
4269 AdapterInterface *adapter;
4270 GtkCTreeNode *newNode;
4272 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4273 if( adapter == NULL ) return;
4274 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4276 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4278 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4279 addrbook.treeSelected = newNode;
4285 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
4286 AdapterDSource *ads;
4287 AdapterInterface *adapter;
4288 AddressInterface *iface;
4289 GtkCTreeNode *newNode;
4291 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4292 if( adapter == NULL ) return;
4293 iface = adapter->interface;
4294 if( ! iface->haveLibrary ) return;
4295 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4297 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4299 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4300 addrbook.treeSelected = newNode;
4307 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
4308 AdapterDSource *ads;
4309 AdapterInterface *adapter;
4310 AddressInterface *iface;
4311 GtkCTreeNode *newNode;
4313 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4314 if( adapter == NULL ) return;
4315 iface = adapter->interface;
4316 if( ! iface->haveLibrary ) return;
4317 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4319 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4321 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4322 addrbook.treeSelected = newNode;
4329 * Display address search status message.
4330 * \param queryType Query type.
4331 * \param status Status/Error code.
4333 static void addressbook_search_message( gint queryType, gint sts ) {
4335 *addressbook_msgbuf = '\0';
4337 if( sts != MGU_SUCCESS ) {
4338 if( queryType == ADDRQUERY_LDAP ) {
4340 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4345 g_snprintf( addressbook_msgbuf,
4346 sizeof(addressbook_msgbuf), "%s", desc );
4347 addressbook_status_show( addressbook_msgbuf );
4350 addressbook_status_show( "" );
4355 * Refresh addressbook by forcing refresh of current selected object in
4358 static void addressbook_refresh_current( void ) {
4362 ctree = GTK_CTREE(addrbook.ctree);
4363 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4364 if( obj == NULL ) return;
4365 addressbook_set_clist( obj, TRUE );
4369 * Message that is displayed whilst a query is executing in a background
4372 static gchar *_tempMessage_ = N_( "Busy searching..." );
4375 * Address search idle function. This function is called during UI idle time
4376 * while a search is in progress.
4378 * \param data Idler data.
4380 static void addressbook_search_idle( gpointer data ) {
4384 queryID = GPOINTER_TO_INT( data );
4385 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4390 * Search completion callback function. This removes the query from the idle
4393 * \param sender Sender of query.
4394 * \param queryID Query ID of search request.
4395 * \param status Search status.
4396 * \param data Query data.
4398 static void addressbook_search_callback_end(
4399 gpointer sender, gint queryID, gint status, gpointer data )
4403 AddrQueryObject *aqo;
4405 /* Remove idler function */
4406 ptrQID = GINT_TO_POINTER( queryID );
4408 g_idle_remove_by_data( ptrQID );
4411 /* Refresh addressbook contents */
4412 addressbook_refresh_current();
4413 req = qrymgr_find_request( queryID );
4415 aqo = ( AddrQueryObject * ) req->queryList->data;
4416 addressbook_search_message( aqo->queryType, status );
4419 /* Stop the search */
4420 addrindex_stop_search( queryID );
4426 * \param ds Data source to search.
4427 * \param searchTerm String to lookup.
4428 * \param pNode Parent data source node.
4430 static void addressbook_perform_search(
4431 AddressDataSource *ds, gchar *searchTerm,
4432 GtkCTreeNode *pNode )
4434 AddrBookBase *adbase;
4435 AddressCache *cache;
4441 AddressObjectType aoType = ADDR_NONE;
4445 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4447 if( ds && ds->type == ADDR_IF_LDAP ) {
4449 aoType = ADDR_LDAP_QUERY;
4455 /* Get reference to address cache */
4456 adbase = ( AddrBookBase * ) ds->rawDataSource;
4457 cache = adbase->addressCache;
4459 /* Create a folder for the search results */
4460 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4461 folder = addressbook_setup_subf(ds, name, pNode);
4464 /* Setup the search */
4465 queryID = addrindex_setup_explicit_search(
4466 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4467 if( queryID == 0 ) return;
4469 /* Set up idler function */
4470 idleID = g_idle_add(
4471 ( GtkFunction ) addressbook_search_idle,
4472 GINT_TO_POINTER( queryID ) );
4474 /* Start search, sit back and wait for something to happen */
4475 addrindex_start_search( queryID );
4477 addressbook_status_show( _tempMessage_ );
4481 * Lookup button handler. Address search is only performed against
4482 * address interfaces for external queries.
4484 * \param button Lookup button widget.
4485 * \param data Data object.
4487 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4490 AddressDataSource *ds;
4491 AddressInterface *iface;
4493 GtkCTreeNode *node, *parentNode;
4495 node = addrbook.treeSelected;
4496 if( ! node ) return;
4497 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4499 ctree = GTK_CTREE(addrbook.ctree);
4500 obj = gtk_ctree_node_get_row_data( ctree, node );
4501 if( obj == NULL ) return;
4503 ds = addressbook_find_datasource( node );
4504 if( ds == NULL ) return;
4506 /* We must have a datasource that is an external interface */
4507 iface = ds->interface;
4508 if( ! iface->haveLibrary ) return;
4509 if( ! iface->externalQuery ) return;
4512 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4513 g_strchomp( searchTerm );
4515 if( obj->type == ADDR_ITEM_FOLDER ) {
4516 parentNode = GTK_CTREE_ROW(node)->parent;
4521 addressbook_perform_search( ds, searchTerm, parentNode );
4523 gtk_widget_grab_focus( addrbook.entry );
4525 g_free( searchTerm );
4528 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4529 addressbook_close();
4534 * Browse address entry for highlighted entry.
4536 static void addressbook_browse_entry_cb(void)
4538 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4540 AddressDataSource *ds;
4541 AddressInterface *iface;
4545 if(addrbook.listSelected == NULL)
4548 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4552 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4556 iface = ds->interface;
4557 if(! iface->haveLibrary )
4561 if (obj->type == ADDR_ITEM_EMAIL) {
4562 email = ( ItemEMail * ) obj;
4566 person = (ItemPerson *) ADDRITEM_PARENT(email);
4568 else if (obj->type == ADDR_ITEM_PERSON) {
4569 person = (ItemPerson *) obj;
4576 if( iface && iface->type == ADDR_IF_LDAP ) {
4577 browseldap_entry(ds, person->externalID);
4582 /* **********************************************************************
4583 * Build lookup tables.
4584 * ***********************************************************************
4588 * Remap object types.
4589 * Enter: abType AddressObjectType (used in tree node).
4590 * Return: ItemObjectType (used in address cache data).
4592 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4593 ItemObjectType ioType;
4596 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4597 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4598 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4599 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4600 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4601 default: ioType = ITEMTYPE_NONE; break;
4607 * Build table that controls the rendering of object types.
4609 static void addrbookctl_build_map( GtkWidget *window ) {
4610 AddressTypeControlItem *atci;
4613 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4614 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4615 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4616 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4617 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4618 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4619 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4620 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4621 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4622 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4624 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4625 _addressBookTypeList_ = NULL;
4628 atci = g_new0( AddressTypeControlItem, 1 );
4629 atci->objectType = ADDR_INTERFACE;
4630 atci->interfaceType = ADDR_IF_NONE;
4631 atci->showInTree = TRUE;
4632 atci->treeExpand = TRUE;
4633 atci->treeLeaf = FALSE;
4634 atci->displayName = _( "Interface" );
4635 atci->iconXpm = folderxpm;
4636 atci->maskXpm = folderxpmmask;
4637 atci->iconXpmOpen = folderopenxpm;
4638 atci->maskXpmOpen = folderopenxpmmask;
4639 atci->menuCommand = NULL;
4640 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4641 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4644 atci = g_new0( AddressTypeControlItem, 1 );
4645 atci->objectType = ADDR_BOOK;
4646 atci->interfaceType = ADDR_IF_BOOK;
4647 atci->showInTree = TRUE;
4648 atci->treeExpand = TRUE;
4649 atci->treeLeaf = FALSE;
4650 atci->displayName = _( "Address Book" );
4651 atci->iconXpm = bookxpm;
4652 atci->maskXpm = bookxpmmask;
4653 atci->iconXpmOpen = bookxpm;
4654 atci->maskXpmOpen = bookxpmmask;
4655 atci->menuCommand = "/Book/New Book";
4656 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4657 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4660 atci = g_new0( AddressTypeControlItem, 1 );
4661 atci->objectType = ADDR_ITEM_PERSON;
4662 atci->interfaceType = ADDR_IF_NONE;
4663 atci->showInTree = FALSE;
4664 atci->treeExpand = FALSE;
4665 atci->treeLeaf = FALSE;
4666 atci->displayName = _( "Person" );
4667 atci->iconXpm = NULL;
4668 atci->maskXpm = NULL;
4669 atci->iconXpmOpen = NULL;
4670 atci->maskXpmOpen = NULL;
4671 atci->menuCommand = NULL;
4672 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4673 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4676 atci = g_new0( AddressTypeControlItem, 1 );
4677 atci->objectType = ADDR_ITEM_EMAIL;
4678 atci->interfaceType = ADDR_IF_NONE;
4679 atci->showInTree = FALSE;
4680 atci->treeExpand = FALSE;
4681 atci->treeLeaf = TRUE;
4682 atci->displayName = _( "Email Address" );
4683 atci->iconXpm = addressxpm;
4684 atci->maskXpm = addressxpmmask;
4685 atci->iconXpmOpen = addressxpm;
4686 atci->maskXpmOpen = addressxpmmask;
4687 atci->menuCommand = NULL;
4688 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4689 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4692 atci = g_new0( AddressTypeControlItem, 1 );
4693 atci->objectType = ADDR_ITEM_GROUP;
4694 atci->interfaceType = ADDR_IF_BOOK;
4695 atci->showInTree = TRUE;
4696 atci->treeExpand = FALSE;
4697 atci->treeLeaf = FALSE;
4698 atci->displayName = _( "Group" );
4699 atci->iconXpm = groupxpm;
4700 atci->maskXpm = groupxpmmask;
4701 atci->iconXpmOpen = groupxpm;
4702 atci->maskXpmOpen = groupxpmmask;
4703 atci->menuCommand = NULL;
4704 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4705 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4708 atci = g_new0( AddressTypeControlItem, 1 );
4709 atci->objectType = ADDR_ITEM_FOLDER;
4710 atci->interfaceType = ADDR_IF_BOOK;
4711 atci->showInTree = TRUE;
4712 atci->treeExpand = FALSE;
4713 atci->treeLeaf = FALSE;
4714 atci->displayName = _( "Folder" );
4715 atci->iconXpm = folderxpm;
4716 atci->maskXpm = folderxpmmask;
4717 atci->iconXpmOpen = folderopenxpm;
4718 atci->maskXpmOpen = folderopenxpmmask;
4719 atci->menuCommand = NULL;
4720 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4721 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4724 atci = g_new0( AddressTypeControlItem, 1 );
4725 atci->objectType = ADDR_VCARD;
4726 atci->interfaceType = ADDR_IF_VCARD;
4727 atci->showInTree = TRUE;
4728 atci->treeExpand = TRUE;
4729 atci->treeLeaf = TRUE;
4730 atci->displayName = _( "vCard" );
4731 atci->iconXpm = vcardxpm;
4732 atci->maskXpm = vcardxpmmask;
4733 atci->iconXpmOpen = vcardxpm;
4734 atci->maskXpmOpen = vcardxpmmask;
4735 atci->menuCommand = "/Book/New vCard";
4736 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4737 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4740 atci = g_new0( AddressTypeControlItem, 1 );
4741 atci->objectType = ADDR_JPILOT;
4742 atci->interfaceType = ADDR_IF_JPILOT;
4743 atci->showInTree = TRUE;
4744 atci->treeExpand = TRUE;
4745 atci->treeLeaf = FALSE;
4746 atci->displayName = _( "JPilot" );
4747 atci->iconXpm = jpilotxpm;
4748 atci->maskXpm = jpilotxpmmask;
4749 atci->iconXpmOpen = jpilotxpm;
4750 atci->maskXpmOpen = jpilotxpmmask;
4751 atci->menuCommand = "/Book/New JPilot";
4752 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4753 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4756 atci = g_new0( AddressTypeControlItem, 1 );
4757 atci->objectType = ADDR_CATEGORY;
4758 atci->interfaceType = ADDR_IF_JPILOT;
4759 atci->showInTree = TRUE;
4760 atci->treeExpand = TRUE;
4761 atci->treeLeaf = TRUE;
4762 atci->displayName = _( "JPilot" );
4763 atci->iconXpm = categoryxpm;
4764 atci->maskXpm = categoryxpmmask;
4765 atci->iconXpmOpen = categoryxpm;
4766 atci->maskXpmOpen = categoryxpmmask;
4767 atci->menuCommand = NULL;
4768 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4769 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4772 atci = g_new0( AddressTypeControlItem, 1 );
4773 atci->objectType = ADDR_LDAP;
4774 atci->interfaceType = ADDR_IF_LDAP;
4775 atci->showInTree = TRUE;
4776 atci->treeExpand = TRUE;
4777 atci->treeLeaf = FALSE;
4778 atci->displayName = _( "LDAP servers" );
4779 atci->iconXpm = ldapxpm;
4780 atci->maskXpm = ldapxpmmask;
4781 atci->iconXpmOpen = ldapxpm;
4782 atci->maskXpmOpen = ldapxpmmask;
4783 atci->menuCommand = "/Book/New LDAP Server";
4784 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4785 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4788 atci = g_new0( AddressTypeControlItem, 1 );
4789 atci->objectType = ADDR_LDAP_QUERY;
4790 atci->interfaceType = ADDR_IF_LDAP;
4791 atci->showInTree = TRUE;
4792 atci->treeExpand = FALSE;
4793 atci->treeLeaf = TRUE;
4794 atci->displayName = _( "LDAP Query" );
4795 atci->iconXpm = addrsearchxpm;
4796 atci->maskXpm = addrsearchxpmmask;
4797 atci->iconXpmOpen = addrsearchxpm;
4798 atci->maskXpmOpen = addrsearchxpmmask;
4799 atci->menuCommand = NULL;
4800 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4801 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4806 * Search for specified object type.
4808 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4810 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4814 * Search for specified interface type.
4816 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4817 GList *node = _addressBookTypeList_;
4819 AddressTypeControlItem *atci = node->data;
4820 if( atci->interfaceType == ifType ) return atci;
4821 node = g_list_next( node );
4826 static void addrbookctl_free_address( AddressObject *obj ) {
4827 g_free( obj->name );
4828 obj->type = ADDR_NONE;
4832 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4833 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4834 adapter->interface = NULL;
4835 adapter->interfaceType = ADDR_IF_NONE;
4836 adapter->atci = NULL;
4837 adapter->enabled = FALSE;
4838 adapter->haveLibrary = FALSE;
4839 adapter->treeNode = NULL;
4843 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4844 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4845 adapter->dataSource = NULL;
4846 adapter->subType = ADDR_NONE;
4850 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4851 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4852 adapter->itemFolder = NULL;
4856 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4857 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4858 adapter->itemGroup = NULL;
4863 * Build GUI interface list.
4865 static void addrbookctl_build_iflist( void ) {
4866 AddressTypeControlItem *atci;
4867 AdapterInterface *adapter;
4870 if( _addressIndex_ == NULL ) {
4871 _addressIndex_ = addrindex_create_index();
4872 if( _clipBoard_ == NULL ) {
4873 _clipBoard_ = addrclip_create();
4875 addrclip_set_index( _clipBoard_, _addressIndex_ );
4877 _addressInterfaceList_ = NULL;
4878 list = addrindex_get_interface_list( _addressIndex_ );
4880 AddressInterface *interface = list->data;
4881 atci = addrbookctl_lookup_iface( interface->type );
4883 adapter = g_new0( AdapterInterface, 1 );
4884 adapter->interfaceType = interface->type;
4885 adapter->atci = atci;
4886 adapter->interface = interface;
4887 adapter->treeNode = NULL;
4888 adapter->enabled = TRUE;
4889 adapter->haveLibrary = interface->haveLibrary;
4890 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4891 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4892 _addressInterfaceList_ =
4893 g_list_append( _addressInterfaceList_, adapter );
4895 list = g_list_next( list );
4900 * Find GUI interface type specified interface type.
4901 * \param ifType Interface type.
4902 * \return Interface item, or NULL if not found.
4904 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4905 GList *node = _addressInterfaceList_;
4907 AdapterInterface *adapter = node->data;
4908 if( adapter->interfaceType == ifType ) return adapter;
4909 node = g_list_next( node );
4915 * Build interface list selection.
4917 static void addrbookctl_build_ifselect( void ) {
4918 GList *newList = NULL;
4923 gchar *endptr = NULL;
4925 AdapterInterface *adapter;
4927 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4930 splitStr = g_strsplit( selectStr, ",", -1 );
4931 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4933 /* g_print( "%d : %s\n", i, splitStr[i] ); */
4934 ifType = strtol( splitStr[i], &endptr, 10 );
4937 if( strcmp( endptr, "/n" ) == 0 ) {
4941 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4942 adapter = addrbookctl_find_interface( ifType );
4944 newList = g_list_append( newList, adapter );
4951 /* g_print( "i=%d\n", i ); */
4952 g_strfreev( splitStr );
4953 g_free( selectStr );
4955 /* Replace existing list */
4956 mgu_clear_list( _addressIFaceSelection_ );
4957 g_list_free( _addressIFaceSelection_ );
4958 _addressIFaceSelection_ = newList;
4962 /* ***********************************************************************
4963 * Add sender to address book.
4964 * ***********************************************************************
4968 * This function is used by the Add sender to address book function.
4970 gboolean addressbook_add_contact(
4971 const gchar *name, const gchar *address, const gchar *remarks,
4972 GdkPixbuf *picture )
4974 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
4975 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
4976 debug_print( "addressbook_add_contact - added\n" );
4977 addressbook_refresh();
4982 /* ***********************************************************************
4983 * Book/folder selection.
4984 * ***********************************************************************
4988 * This function is used by the matcher dialog to select a book/folder.
4990 gboolean addressbook_folder_selection( gchar **folderpath )
4992 AddressBookFile *book = NULL;
4993 ItemFolder *folder = NULL;
4996 g_return_val_if_fail( folderpath != NULL, FALSE);
5000 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, path )
5002 if ( folder != NULL) {
5004 gchar *oldtmp = NULL;
5005 AddrItemObject *obj = NULL;
5007 /* walk thru folder->parent to build the full folder path */
5008 /* TODO: wwp: optimize this */
5010 tmp = g_strdup(obj->uid);
5011 while ( obj->parent ) {
5013 if ( obj->name != NULL ) {
5014 oldtmp = g_strdup(tmp);
5016 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5020 *folderpath = g_strdup_printf("%s/%s", book->fileName, tmp);
5023 *folderpath = g_strdup_printf("%s", book->fileName);
5025 debug_print( "addressbook_foldersel: %s\n", *folderpath?*folderpath:"(null)");
5026 return (*folderpath != NULL);
5031 /* ***********************************************************************
5032 * Book/folder checking.
5033 * ***********************************************************************
5036 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5038 FolderInfo *fi = g_new0( FolderInfo, 1 );
5040 fi->folder = folder;
5044 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5045 FolderInfo *fiParent, FolderPathMatch *match )
5051 FolderPathMatch *nextmatch = NULL;
5056 list = parentFolder->listFolder;
5058 folder = list->data;
5059 fName = g_strdup( ADDRITEM_NAME(folder) );
5061 /* match folder name, match pointer will be set to NULL if next recursive call
5062 doesn't need to match subfolder name */
5063 if ( match != NULL &&
5064 match->matched == FALSE ) {
5065 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5066 /* folder name matches, prepare next subfolder match */
5067 debug_print("matched folder name '%s'\n", fName);
5069 if ( match->folder_path[match->index] == NULL ) {
5070 /* we've matched all elements */
5071 match->matched = TRUE;
5072 match->folder = folder;
5073 debug_print("book/folder path matched!\n");
5075 /* keep on matching */
5083 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5084 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5086 list = g_list_next( list );
5091 * This function is used by to check if a matcher book/folder path corresponds to an
5092 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5093 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5094 if book AND folder are NULL this means that folderpath was empty or Any.
5095 If folderpath is a simple book name (without folder), book will not be NULL and folder
5096 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5099 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5100 AddressDataSource **book,
5101 ItemFolder **folder )
5103 AddressDataSource *ds;
5104 GList *list, *nodeDS;
5105 ItemFolder *rootFolder;
5106 AddressBookFile *abf;
5108 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5115 if ( folderpath == NULL )
5118 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
5121 /* split the folder path we've received, we'll try to match this path, subpath by
5122 subpath against the book/folder structure in order */
5123 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5124 if (!folder_path_match.folder_path)
5127 list = addrindex_get_interface_list( _addressIndex_ );
5128 while ( list && !folder_path_match.matched ) {
5129 AddressInterface *interface = list->data;
5130 if ( interface && interface->type == ADDR_IF_BOOK ) {
5131 nodeDS = interface->listSource;
5132 while ( nodeDS && !folder_path_match.matched ) {
5135 /* Read address book */
5136 if( ! addrindex_ds_get_read_flag( ds ) ) {
5137 addrindex_ds_read_data( ds );
5140 /* Add node for address book */
5141 abf = ds->rawDataSource;
5143 /* match book name */
5144 if ( abf && abf->fileName &&
5145 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5147 debug_print("matched book name '%s'\n", abf->fileName);
5148 folder_path_match.book = ds;
5150 if ( folder_path_match.folder_path[1] == NULL ) {
5151 /* no folder part to match */
5153 folder_path_match.matched = TRUE;
5154 folder_path_match.folder = NULL;
5155 debug_print("book path matched!\n");
5158 /* match folder part */
5160 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5161 rootFolder = addrindex_ds_get_root_folder( ds );
5163 /* prepare for recursive call */
5164 folder_path_match.index = 1;
5165 /* this call will set folder_path_match.matched and folder_path_match.folder */
5166 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5171 nodeDS = g_list_next( nodeDS );
5174 list = g_list_next( list );
5177 g_strfreev( folder_path_match.folder_path );
5180 *book = folder_path_match.book;
5182 *folder = folder_path_match.folder;
5183 return folder_path_match.matched;
5187 /* **********************************************************************
5189 * ***********************************************************************
5195 static void addressbook_import_ldif_cb( void ) {
5196 AddressDataSource *ds = NULL;
5197 AdapterDSource *ads = NULL;
5198 AddressBookFile *abf = NULL;
5199 AdapterInterface *adapter;
5200 GtkCTreeNode *newNode;
5202 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5204 if( adapter->treeNode ) {
5205 abf = addressbook_imp_ldif( _addressIndex_ );
5207 ds = addrindex_index_add_datasource(
5208 _addressIndex_, ADDR_IF_BOOK, abf );
5209 ads = addressbook_create_ds_adapter(
5210 ds, ADDR_BOOK, NULL );
5211 addressbook_ads_set_name(
5212 ads, addrbook_get_name( abf ) );
5213 newNode = addressbook_add_object(
5215 ADDRESS_OBJECT(ads) );
5217 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5219 addrbook.treeSelected = newNode;
5222 /* Notify address completion */
5223 invalidate_address_completion();
5232 static void addressbook_import_mutt_cb( void ) {
5233 AddressDataSource *ds = NULL;
5234 AdapterDSource *ads = NULL;
5235 AddressBookFile *abf = NULL;
5236 AdapterInterface *adapter;
5237 GtkCTreeNode *newNode;
5239 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5241 if( adapter->treeNode ) {
5242 abf = addressbook_imp_mutt( _addressIndex_ );
5244 ds = addrindex_index_add_datasource(
5245 _addressIndex_, ADDR_IF_BOOK, abf );
5246 ads = addressbook_create_ds_adapter(
5247 ds, ADDR_BOOK, NULL );
5248 addressbook_ads_set_name(
5249 ads, addrbook_get_name( abf ) );
5250 newNode = addressbook_add_object(
5252 ADDRESS_OBJECT(ads) );
5254 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5256 addrbook.treeSelected = newNode;
5259 /* Notify address completion */
5260 invalidate_address_completion();
5269 static void addressbook_import_pine_cb( void ) {
5270 AddressDataSource *ds = NULL;
5271 AdapterDSource *ads = NULL;
5272 AddressBookFile *abf = NULL;
5273 AdapterInterface *adapter;
5274 GtkCTreeNode *newNode;
5276 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5278 if( adapter->treeNode ) {
5279 abf = addressbook_imp_pine( _addressIndex_ );
5281 ds = addrindex_index_add_datasource(
5282 _addressIndex_, ADDR_IF_BOOK, abf );
5283 ads = addressbook_create_ds_adapter(
5284 ds, ADDR_BOOK, NULL );
5285 addressbook_ads_set_name(
5286 ads, addrbook_get_name( abf ) );
5287 newNode = addressbook_add_object(
5289 ADDRESS_OBJECT(ads) );
5291 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5293 addrbook.treeSelected = newNode;
5296 /* Notify address completion */
5297 invalidate_address_completion();
5304 * Harvest addresses.
5305 * \param folderItem Folder to import.
5306 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5307 * \param msgList List of message numbers, or NULL to process folder.
5309 void addressbook_harvest(
5310 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5312 AddressDataSource *ds = NULL;
5313 AdapterDSource *ads = NULL;
5314 AddressBookFile *abf = NULL;
5315 AdapterInterface *adapter;
5316 GtkCTreeNode *newNode;
5318 abf = addrgather_dlg_execute(
5319 folderItem, _addressIndex_, sourceInd, msgList );
5321 ds = addrindex_index_add_datasource(
5322 _addressIndex_, ADDR_IF_BOOK, abf );
5324 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5326 if( adapter->treeNode ) {
5327 ads = addressbook_create_ds_adapter(
5328 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5329 newNode = addressbook_add_object(
5331 ADDRESS_OBJECT(ads) );
5335 /* Notify address completion */
5336 invalidate_address_completion();
5343 static void addressbook_export_html_cb( void ) {
5344 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5346 AddressDataSource *ds = NULL;
5347 AddrBookBase *adbase;
5348 AddressCache *cache;
5349 GtkCTreeNode *node = NULL;
5351 if( ! addrbook.treeSelected ) return;
5352 node = addrbook.treeSelected;
5353 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5354 obj = gtk_ctree_node_get_row_data( ctree, node );
5355 if( obj == NULL ) return;
5357 ds = addressbook_find_datasource( node );
5358 if( ds == NULL ) return;
5359 adbase = ( AddrBookBase * ) ds->rawDataSource;
5360 cache = adbase->addressCache;
5361 addressbook_exp_html( cache );
5367 static void addressbook_export_ldif_cb( void ) {
5368 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5370 AddressDataSource *ds = NULL;
5371 AddrBookBase *adbase;
5372 AddressCache *cache;
5373 GtkCTreeNode *node = NULL;
5375 if( ! addrbook.treeSelected ) return;
5376 node = addrbook.treeSelected;
5377 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5378 obj = gtk_ctree_node_get_row_data( ctree, node );
5379 if( obj == NULL ) return;
5381 ds = addressbook_find_datasource( node );
5382 if( ds == NULL ) return;
5383 adbase = ( AddrBookBase * ) ds->rawDataSource;
5384 cache = adbase->addressCache;
5385 addressbook_exp_ldif( cache );
5388 static void addressbook_find_duplicates_cb(void)
5390 addrduplicates_find(GTK_WINDOW(addrbook.window));
5393 static void addressbook_edit_custom_attr_cb(void)
5395 addressbook_custom_attr_edit();
5398 static void addressbook_start_drag(GtkWidget *widget, gint button,
5402 GdkDragContext *context;
5403 if (addressbook_target_list == NULL)
5404 addressbook_target_list = gtk_target_list_new(
5405 addressbook_drag_types, 1);
5406 context = gtk_drag_begin(widget, addressbook_target_list,
5407 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5408 gtk_drag_set_icon_default(context);
5411 static void addressbook_drag_data_get(GtkWidget *widget,
5412 GdkDragContext *drag_context,
5413 GtkSelectionData *selection_data,
5418 AddrItemObject *aio = NULL;
5419 AddressObject *pobj = NULL;
5420 AdapterDSource *ads = NULL;
5421 AddressDataSource *ds = NULL;
5424 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5426 if( pobj == NULL ) return;
5428 if( pobj->type == ADDR_DATASOURCE ) {
5429 ads = ADAPTER_DSOURCE(pobj);
5430 ds = ads->dataSource;
5431 } else if (pobj->type == ADDR_ITEM_GROUP) {
5436 else if( pobj->type != ADDR_INTERFACE ) {
5437 ds = addressbook_find_datasource( addrbook.treeSelected );
5443 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5444 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5445 GTK_CTREE_NODE(cur->data));
5446 while (aio && aio->type != ADDR_ITEM_PERSON) {
5451 if (aio && aio->type == ADDR_ITEM_PERSON) {
5452 if( ds && ds->interface && ds->interface->readOnly)
5453 gtk_selection_data_set(selection_data,
5454 selection_data->target, 8,
5455 (const guchar *)"Dummy_addr_copy", 15);
5457 gtk_selection_data_set(selection_data,
5458 selection_data->target, 8,
5459 (const guchar *)"Dummy_addr_move", 15);
5463 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5464 GdkDragContext *context,
5471 GtkCTreeNode *node = NULL;
5472 gboolean acceptable = FALSE;
5473 gint height = addrbook.ctree->allocation.height;
5474 gint total_height = addrbook.ctree->requisition.height;
5475 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5476 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5477 gfloat vpos = pos->value;
5479 if (gtk_clist_get_selection_info
5480 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5482 if (y > height - 24 && height + vpos < total_height) {
5483 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5484 gtk_adjustment_changed(pos);
5486 if (y < 24 && y > 0) {
5487 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5488 gtk_adjustment_changed(pos);
5490 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5493 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5494 if( obj->type == ADDR_ITEM_FOLDER
5495 || obj->type == ADDR_ITEM_GROUP)
5498 AdapterDSource *ads = NULL;
5499 AddressDataSource *ds = NULL;
5500 ads = ADAPTER_DSOURCE(obj);
5501 if (ads == NULL ){ return FALSE;}
5502 ds = ads->dataSource;
5503 if (ds == NULL ) { return FALSE;}
5511 g_signal_handlers_block_by_func
5513 G_CALLBACK(addressbook_tree_selected), NULL);
5514 gtk_sctree_select( GTK_SCTREE(widget), node);
5515 g_signal_handlers_unblock_by_func
5517 G_CALLBACK(addressbook_tree_selected), NULL);
5518 gdk_drag_status(context,
5519 (context->actions == GDK_ACTION_COPY ?
5520 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5522 gdk_drag_status(context, 0, time);
5527 static void addressbook_drag_leave_cb(GtkWidget *widget,
5528 GdkDragContext *context,
5532 if (addrbook.treeSelected) {
5533 g_signal_handlers_block_by_func
5535 G_CALLBACK(addressbook_tree_selected), NULL);
5536 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5537 g_signal_handlers_unblock_by_func
5539 G_CALLBACK(addressbook_tree_selected), NULL);
5544 static void addressbook_drag_received_cb(GtkWidget *widget,
5545 GdkDragContext *drag_context,
5548 GtkSelectionData *data,
5555 GtkCTreeNode *lastopened = addrbook.opened;
5557 if (!strncmp(data->data, "Dummy_addr", 10)) {
5558 if (gtk_clist_get_selection_info
5559 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5563 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5564 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5567 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5568 if (drag_context->action == GDK_ACTION_COPY ||
5569 !strcmp(data->data, "Dummy_addr_copy"))
5570 addressbook_clip_copy_cb();
5572 addressbook_clip_cut_cb();
5573 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5574 addressbook_clip_paste_cb();
5575 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5576 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5577 gtk_drag_finish(drag_context, TRUE, TRUE, time);