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 2 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, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
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>
49 #include "addressbook.h"
50 #include "manage_window.h"
51 #include "prefs_common.h"
52 #include "alertpanel.h"
53 #include "inputdialog.h"
55 #include "stock_pixmap.h"
57 #include "prefs_gtk.h"
63 #include "addr_compl.h"
66 #include "addressitem.h"
68 #include "addrcache.h"
70 #include "addrindex.h"
71 #include "addressadd.h"
72 #include "addressbook_foldersel.h"
74 #include "editvcard.h"
75 #include "editgroup.h"
76 #include "editaddress.h"
78 #include "importldif.h"
79 #include "importmutt.h"
80 #include "importpine.h"
85 #include "editjpilot.h"
90 #include "ldapserver.h"
93 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
96 #include "addrquery.h"
97 #include "addrselect.h"
99 #include "addrgather.h"
100 #include "adbookbase.h"
101 #include "exphtmldlg.h"
102 #include "expldifdlg.h"
103 #include "browseldap.h"
109 } AddressIndexColumns;
117 } AddressListColumns;
120 AddressBookFile *book;
128 AddressDataSource *book;
132 static gchar *list_titles[] = { N_("Name"),
136 #define COL_NAME_WIDTH 164
137 #define COL_ADDRESS_WIDTH 156
139 #define COL_FOLDER_WIDTH 170
140 #define ADDRESSBOOK_WIDTH 640
141 #define ADDRESSBOOK_HEIGHT 360
143 #define ADDRESSBOOK_MSGBUF_SIZE 2048
145 static GdkPixmap *folderxpm;
146 static GdkBitmap *folderxpmmask;
147 static GdkPixmap *folderopenxpm;
148 static GdkBitmap *folderopenxpmmask;
149 static GdkPixmap *groupxpm;
150 static GdkBitmap *groupxpmmask;
151 static GdkPixmap *interfacexpm;
152 static GdkBitmap *interfacexpmmask;
153 static GdkPixmap *bookxpm;
154 static GdkBitmap *bookxpmmask;
155 static GdkPixmap *addressxpm;
156 static GdkBitmap *addressxpmmask;
157 static GdkPixmap *vcardxpm;
158 static GdkBitmap *vcardxpmmask;
159 static GdkPixmap *jpilotxpm;
160 static GdkBitmap *jpilotxpmmask;
161 static GdkPixmap *categoryxpm;
162 static GdkBitmap *categoryxpmmask;
163 static GdkPixmap *ldapxpm;
164 static GdkBitmap *ldapxpmmask;
165 static GdkPixmap *addrsearchxpm;
166 static GdkPixmap *addrsearchxpmmask;
169 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
171 /* Address list selection */
172 static AddrSelectList *_addressSelect_ = NULL;
173 static AddressClipboard *_clipBoard_ = NULL;
175 /* Address index file and interfaces */
176 static AddressIndex *_addressIndex_ = NULL;
177 static GList *_addressInterfaceList_ = NULL;
178 static GList *_addressIFaceSelection_ = NULL;
179 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
181 static AddressBook_win addrbook;
183 static GHashTable *_addressBookTypeHash_ = NULL;
184 static GList *_addressBookTypeList_ = NULL;
186 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
187 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
188 static void addressbook_edit_address_post_cb( ItemPerson *person );
190 static void addressbook_create (void);
191 static gint addressbook_close (void);
192 static void addressbook_button_set_sensitive (void);
194 static gboolean address_index_has_focus = FALSE;
195 static gboolean address_list_has_focus = FALSE;
197 /* callback functions */
198 static void addressbook_del_clicked (GtkButton *button,
200 static void addressbook_reg_clicked (GtkButton *button,
202 static void addressbook_to_clicked (GtkButton *button,
204 static void addressbook_lup_clicked (GtkButton *button,
206 static void addressbook_close_clicked (GtkButton *button,
209 static void addressbook_tree_selected (GtkCTree *ctree,
213 static void addressbook_select_row_tree (GtkCTree *ctree,
217 static void addressbook_list_row_selected (GtkCTree *clist,
221 static void addressbook_list_row_unselected (GtkCTree *clist,
225 static void addressbook_person_expand_node (GtkCTree *ctree,
228 static void addressbook_person_collapse_node (GtkCTree *ctree,
232 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
233 GdkEventButton *event,
235 static gboolean addressbook_list_button_released(GtkWidget *widget,
236 GdkEventButton *event,
238 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
239 GdkEventButton *event,
241 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
242 GdkEventButton *event,
245 static void addressbook_new_folder_cb (gpointer data,
248 static void addressbook_new_group_cb (gpointer data,
251 static void addressbook_treenode_edit_cb (gpointer data,
254 static void addressbook_treenode_delete_cb (gpointer data,
258 static void addressbook_change_node_name (GtkCTreeNode *node,
261 static void addressbook_new_address_cb (gpointer data,
264 static void addressbook_edit_address_cb (gpointer data,
267 static void addressbook_delete_address_cb (gpointer data,
271 static void close_cb (gpointer data,
274 static void addressbook_file_save_cb (gpointer data,
278 /* Data source edit stuff */
279 static void addressbook_new_book_cb (gpointer data,
282 static void addressbook_new_vcard_cb (gpointer data,
287 static void addressbook_new_jpilot_cb (gpointer data,
293 static void addressbook_new_ldap_cb (gpointer data,
298 static void addressbook_set_clist (AddressObject *obj,
301 static void addressbook_load_tree (void);
302 void addressbook_read_file (void);
304 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
306 static void addressbook_treenode_remove_item ( void );
308 static AddressDataSource *addressbook_find_datasource
309 (GtkCTreeNode *node );
311 static AddressBookFile *addressbook_get_book_file(void);
313 static GtkCTreeNode *addressbook_node_add_folder
315 AddressDataSource *ds,
316 ItemFolder *itemFolder,
317 AddressObjectType otype);
318 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
319 AddressDataSource *ds,
320 ItemGroup *itemGroup);
321 static void addressbook_tree_remove_children (GtkCTree *ctree,
322 GtkCTreeNode *parent);
323 static void addressbook_move_nodes_up (GtkCTree *ctree,
325 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
327 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
330 static gint addressbook_treenode_compare_func (GtkCList *clist,
333 static void addressbook_folder_load_one_person (GtkCTree *clist,
335 AddressTypeControlItem *atci,
336 AddressTypeControlItem *atciMail);
337 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
339 static void addressbook_folder_remove_one_person(GtkCTree *clist,
341 static void addressbook_folder_remove_node (GtkCTree *clist,
344 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
345 gboolean force_focus );
347 /* LUT's and IF stuff */
348 static void addressbook_free_treenode ( gpointer data );
349 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
350 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
352 static void addrbookctl_build_map (GtkWidget *window);
353 static void addrbookctl_build_iflist (void);
354 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
355 static void addrbookctl_build_ifselect (void);
357 static void addrbookctl_free_interface (AdapterInterface *adapter);
358 static void addrbookctl_free_datasource (AdapterDSource *adapter);
359 static void addrbookctl_free_folder (AdapterFolder *adapter);
360 static void addrbookctl_free_group (AdapterGroup *adapter);
362 static void addressbook_list_select_clear ( void );
363 static void addressbook_list_select_add ( AddrItemObject *aio,
364 AddressDataSource *ds );
365 static void addressbook_list_select_remove ( AddrItemObject *aio );
367 static void addressbook_import_ldif_cb ( void );
368 static void addressbook_import_mutt_cb ( void );
369 static void addressbook_import_pine_cb ( void );
370 static void addressbook_export_html_cb ( void );
371 static void addressbook_export_ldif_cb ( void );
372 static void addressbook_select_all_cb ( void );
373 static void addressbook_clip_cut_cb ( void );
374 static void addressbook_clip_copy_cb ( void );
375 static void addressbook_clip_paste_cb ( void );
376 static void addressbook_treenode_cut_cb ( void );
377 static void addressbook_treenode_copy_cb ( void );
378 static void addressbook_treenode_paste_cb ( void );
380 static void addressbook_mail_to_cb ( void );
383 static void addressbook_browse_entry_cb ( void );
385 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
387 static void addressbook_start_drag(GtkWidget *widget, gint button,
390 static void addressbook_drag_data_get(GtkWidget *widget,
391 GdkDragContext *drag_context,
392 GtkSelectionData *selection_data,
396 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
397 GdkDragContext *context,
402 static void addressbook_drag_leave_cb(GtkWidget *widget,
403 GdkDragContext *context,
406 static void addressbook_drag_received_cb(GtkWidget *widget,
407 GdkDragContext *drag_context,
410 GtkSelectionData *data,
414 static void addressbook_list_menu_setup( void );
416 static GtkTargetEntry addressbook_drag_types[] =
418 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
421 static GtkTargetList *addressbook_target_list = NULL;
424 static GtkItemFactoryEntry addressbook_entries[] =
426 {N_("/_Book"), NULL, NULL, 0, "<Branch>"},
427 {N_("/_Book/New _Book"), "<control>B", addressbook_new_book_cb, 0, NULL},
428 {N_("/_Book/New _Folder"), "<control>R", addressbook_new_folder_cb, 0, NULL},
429 {N_("/_Book/New _vCard"), "<control><shift>D", addressbook_new_vcard_cb, 0, NULL},
431 {N_("/_Book/New _JPilot"), "<control>J", addressbook_new_jpilot_cb, 0, NULL},
434 {N_("/_Book/New LDAP _Server"), "<control><shift>S", addressbook_new_ldap_cb, 0, NULL},
436 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
437 {N_("/_Book/_Edit book"), NULL, addressbook_treenode_edit_cb, 0, NULL},
438 {N_("/_Book/_Delete book"), NULL, addressbook_treenode_delete_cb, 0, NULL},
439 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
440 {N_("/_Book/_Save"), "<control>S", addressbook_file_save_cb, 0, NULL},
441 {N_("/_Book/_Close"), "<control>W", close_cb, 0, NULL},
442 {N_("/_Address"), NULL, NULL, 0, "<Branch>"},
443 {N_("/_Address/_Select all"), "<control>A", addressbook_select_all_cb, 0, NULL},
444 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
445 {N_("/_Address/C_ut"), "<control>X", addressbook_clip_cut_cb, 0, NULL},
446 {N_("/_Address/_Copy"), "<control>C", addressbook_clip_copy_cb, 0, NULL},
447 {N_("/_Address/_Paste"), "<control>V", addressbook_clip_paste_cb, 0, NULL},
448 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
449 {N_("/_Address/_Edit"), "<control>Return",addressbook_edit_address_cb, 0, NULL},
450 {N_("/_Address/_Delete"), "<control>D", addressbook_delete_address_cb, 0, NULL},
451 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
452 {N_("/_Address/New _Address"), "<control>N", addressbook_new_address_cb, 0, NULL},
453 {N_("/_Address/New _Group"), "<control>G", addressbook_new_group_cb, 0, NULL},
454 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
455 {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
456 {N_("/_Tools"), NULL, NULL, 0, "<Branch>"},
457 {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL},
458 {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL},
459 {N_("/_Tools/Import _Pine file..."), NULL, addressbook_import_pine_cb, 0, NULL},
460 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>"},
461 {N_("/_Tools/Export _HTML..."), NULL, addressbook_export_html_cb, 0, NULL},
462 {N_("/_Tools/Export LDI_F..."), NULL, addressbook_export_ldif_cb, 0, NULL},
463 {N_("/_Help"), NULL, NULL, 0, "<Branch>"},
464 {N_("/_Help/_About"), NULL, about_show, 0, NULL}
467 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
469 {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL},
470 {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL},
471 {"/---", NULL, NULL, 0, "<Separator>"},
472 {N_("/New _Book"), NULL, addressbook_new_book_cb, 0, NULL},
473 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL},
474 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
475 {"/---", NULL, NULL, 0, "<Separator>"},
476 {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL},
477 {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL},
478 {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL}
481 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
483 {N_("/_Select all"), NULL, addressbook_select_all_cb, 0, NULL},
484 {"/---", NULL, NULL, 0, "<Separator>"},
485 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL},
486 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL},
487 {"/---", NULL, NULL, 0, "<Separator>"},
488 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL},
489 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
490 {"/---", NULL, NULL, 0, "<Separator>"},
491 {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL},
492 {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL},
493 {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL},
494 {"/---", NULL, NULL, 0, "<Separator>"},
495 /* {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL},*/
496 {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
498 {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL},
503 * Structure of error message table.
505 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
506 struct _ErrMsgTableEntry {
511 static gchar *_errMsgUnknown_ = N_( "Unknown" );
514 * Lookup table of error messages for general errors. Note that a NULL
515 * description signifies the end of the table.
517 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
518 { MGU_SUCCESS, N_("Success") },
519 { MGU_BAD_ARGS, N_("Bad arguments") },
520 { MGU_NO_FILE, N_("File not specified") },
521 { MGU_OPEN_FILE, N_("Error opening file") },
522 { MGU_ERROR_READ, N_("Error reading file") },
523 { MGU_EOF, N_("End of file encountered") },
524 { MGU_OO_MEMORY, N_("Error allocating memory") },
525 { MGU_BAD_FORMAT, N_("Bad file format") },
526 { MGU_ERROR_WRITE, N_("Error writing to file") },
527 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
528 { MGU_NO_PATH, N_("No path specified") },
534 * Lookup table of error messages for LDAP errors.
536 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
537 { LDAPRC_SUCCESS, N_("Success") },
538 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
539 { LDAPRC_INIT, N_("Error initializing LDAP") },
540 { LDAPRC_BIND, N_("Error binding to LDAP server") },
541 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
542 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
543 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
544 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
545 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
546 { LDAPRC_TLS, N_("Error starting TLS connection") },
552 * Lookup message for specified error code.
553 * \param lut Lookup table.
554 * \param code Code to lookup.
555 * \return Description associated to code.
557 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
559 ErrMsgTableEntry entry;
562 for( i = 0; ; i++ ) {
564 if( entry.description == NULL ) break;
565 if( entry.code == code ) {
566 desc = entry.description;
571 desc = _errMsgUnknown_;
576 static gboolean lastCanLookup = FALSE;
578 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
580 if (add_and_delete) {
581 gtk_widget_show(addrbook.edit_btn);
582 gtk_widget_show(addrbook.del_btn);
583 gtk_widget_show(addrbook.reg_btn);
585 gtk_widget_hide(addrbook.edit_btn);
586 gtk_widget_hide(addrbook.del_btn);
587 gtk_widget_hide(addrbook.reg_btn);
591 gtk_widget_show(addrbook.lup_btn);
592 gtk_widget_show(addrbook.entry);
593 gtk_widget_show(addrbook.label);
595 gtk_widget_hide(addrbook.lup_btn);
596 gtk_widget_hide(addrbook.entry);
597 gtk_widget_hide(addrbook.label);
600 lastCanLookup = lookup;
603 gtk_widget_show(addrbook.to_btn);
604 gtk_widget_show(addrbook.cc_btn);
605 gtk_widget_show(addrbook.bcc_btn);
607 gtk_widget_hide(addrbook.to_btn);
608 gtk_widget_hide(addrbook.cc_btn);
609 gtk_widget_hide(addrbook.bcc_btn);
613 void addressbook_open(Compose *target)
615 /* Initialize all static members */
616 if( _clipBoard_ == NULL ) {
617 _clipBoard_ = addrclip_create();
619 if( _addressIndex_ != NULL ) {
620 addrclip_set_index( _clipBoard_, _addressIndex_ );
622 if( _addressSelect_ == NULL ) {
623 _addressSelect_ = addrselect_list_create();
625 if (!addrbook.window) {
626 addressbook_read_file();
627 addressbook_create();
628 addressbook_load_tree();
629 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
630 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
633 gtk_widget_hide(addrbook.window);
636 gtk_widget_show_all(addrbook.window);
637 if (!prefs_common.addressbook_use_editaddress_dialog)
638 addressbook_edit_person_widgetset_hide();
640 address_completion_start(addrbook.window);
642 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
643 addressbook_set_target_compose(target);
647 * Destroy addressbook.
649 void addressbook_destroy( void ) {
650 /* Free up address stuff */
651 if( _addressSelect_ != NULL ) {
652 addrselect_list_free( _addressSelect_ );
654 if( _clipBoard_ != NULL ) {
655 addrclip_free( _clipBoard_ );
657 if( _addressIndex_ != NULL ) {
658 addrindex_free_index( _addressIndex_ );
659 addrindex_teardown();
661 _addressSelect_ = NULL;
663 _addressIndex_ = NULL;
666 void addressbook_set_target_compose(Compose *target)
668 addrbook.target_compose = target;
669 addressbook_button_set_sensitive();
672 Compose *addressbook_get_target_compose(void)
674 return addrbook.target_compose;
678 * Refresh addressbook and save to file(s).
680 static void addressbook_refresh( void )
682 if (addrbook.window) {
683 if (addrbook.treeSelected) {
684 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
685 addrbook.treeSelected);
686 addressbook_set_clist(
687 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
688 addrbook.treeSelected),
693 addressbook_export_to_file();
696 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
698 if (event && event->keyval == GDK_Escape)
700 else if (event && event->keyval == GDK_Delete) {
701 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
702 if ( /* address_index_has_focus || */ address_list_has_focus )
703 addressbook_del_clicked(NULL, NULL);
709 *\brief Save Gtk object size to prefs dataset
711 static void addressbook_size_allocate_cb(GtkWidget *widget,
712 GtkAllocation *allocation)
714 g_return_if_fail(allocation != NULL);
716 prefs_common.addressbookwin_width = allocation->width;
717 prefs_common.addressbookwin_height = allocation->height;
720 static gint sort_column_number = 0;
721 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
723 static gint list_case_sort(
724 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
726 GtkCListRow *row1 = (GtkCListRow *) ptr1;
727 GtkCListRow *row2 = (GtkCListRow *) ptr2;
728 gchar *name1 = NULL, *name2 = NULL;
729 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
730 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
732 if( aio1->type == aio2->type ) {
734 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
736 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
737 if( ! name1 ) return ( name2 != NULL );
738 if( ! name2 ) return -1;
739 return strcasecmp( name1, name2 );
741 /* Order groups before person */
742 if( aio1->type == ITEMTYPE_GROUP ) {
743 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
744 } else if( aio2->type == ITEMTYPE_GROUP ) {
745 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
751 static void addressbook_sort_list(GtkCList *clist, const gint col,
752 const GtkSortType sort_type)
755 GtkWidget *hbox, *label, *arrow;
757 sort_column_number = col;
758 sort_column_type = sort_type;
759 gtk_clist_set_compare_func(clist, list_case_sort);
760 gtk_clist_set_sort_type(clist, sort_type);
761 gtk_clist_set_sort_column(clist, col);
763 gtk_clist_freeze(clist);
764 gtk_clist_sort(clist);
766 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
767 hbox = gtk_hbox_new(FALSE, 4);
768 label = gtk_label_new(gettext(list_titles[pos]));
769 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
772 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
773 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
774 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
777 gtk_widget_show_all(hbox);
778 gtk_clist_set_column_widget(clist, pos, hbox);
781 gtk_clist_thaw(clist);
784 static void addressbook_name_clicked(GtkWidget *button, GtkCList *clist)
786 static GtkSortType sort_type = GTK_SORT_ASCENDING;
788 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
790 addressbook_sort_list(clist, COL_NAME, sort_type);
793 static void addressbook_address_clicked(GtkWidget *button, GtkCList *clist)
795 static GtkSortType sort_type = GTK_SORT_ASCENDING;
797 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
799 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
802 static void addressbook_remarks_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_REMARKS, sort_type);
811 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
814 address_index_has_focus = TRUE;
818 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
821 address_index_has_focus = FALSE;
822 if (!prefs_common.addressbook_use_editaddress_dialog
823 && !address_list_has_focus)
824 addressbook_address_list_disable_some_actions();
828 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
831 address_list_has_focus = TRUE;
835 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
838 address_list_has_focus = FALSE;
839 if (!prefs_common.addressbook_use_editaddress_dialog
840 && !address_index_has_focus)
841 addressbook_address_list_disable_some_actions();
845 /* save hpane and vpane's handle position when it moves */
846 static void addressbook_pane_save_position(void)
849 prefs_common.addressbook_hpaned_pos =
850 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
852 prefs_common.addressbook_vpaned_pos =
853 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
857 * Create the address book widgets. The address book contains two CTree widgets: the
858 * address index tree on the left and the address list on the right.
860 * The address index tree displays a hierarchy of interfaces and groups. Each node in
861 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
862 * data sources and folder objects.
864 * The address list displays group, person and email objects. These items are linked
865 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
868 * In the tradition of MVC architecture, the data stores have been separated from the
869 * GUI components. The addrindex.c file provides the interface to all data stores.
871 static void addressbook_create(void)
877 GtkWidget *ctree_swin;
879 GtkWidget *editaddress_vbox;
880 GtkWidget *clist_vbox;
881 GtkWidget *clist_swin;
888 GtkWidget *statusbar;
899 GtkWidget *close_btn;
900 GtkWidget *tree_popup;
901 GtkWidget *list_popup;
902 GtkItemFactory *tree_factory;
903 GtkItemFactory *list_factory;
904 GtkItemFactory *menu_factory;
908 gchar *index_titles[N_INDEX_COLS];
912 static GdkGeometry geometry;
914 debug_print("Creating addressbook window...\n");
916 index_titles[COL_SOURCES] = _("Sources");
918 /* Address book window */
919 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
920 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
921 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
922 gtk_widget_realize(window);
924 g_signal_connect(G_OBJECT(window), "delete_event",
925 G_CALLBACK(addressbook_close), NULL);
926 g_signal_connect(G_OBJECT(window), "size_allocate",
927 G_CALLBACK(addressbook_size_allocate_cb), NULL);
928 g_signal_connect(G_OBJECT(window), "key_press_event",
929 G_CALLBACK(key_pressed), NULL);
930 MANAGE_WINDOW_SIGNALS_CONNECT(window);
932 vbox = gtk_vbox_new(FALSE, 0);
933 gtk_container_add(GTK_CONTAINER(window), vbox);
936 n_entries = sizeof(addressbook_entries) /
937 sizeof(addressbook_entries[0]);
938 menubar = menubar_create(window, addressbook_entries, n_entries,
939 "<AddressBook>", NULL);
940 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
941 menu_factory = gtk_item_factory_from_widget(menubar);
943 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
944 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
945 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
947 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
948 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
949 GTK_POLICY_AUTOMATIC,
950 GTK_POLICY_AUTOMATIC);
951 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
954 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
955 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
956 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
957 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
958 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
959 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
960 GTK_CTREE_EXPANDER_SQUARE);
961 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
962 gtk_clist_set_compare_func(GTK_CLIST(ctree),
963 addressbook_treenode_compare_func);
965 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
966 G_CALLBACK(addressbook_tree_selected), NULL);
967 g_signal_connect(G_OBJECT(ctree), "button_press_event",
968 G_CALLBACK(addressbook_tree_button_pressed),
970 g_signal_connect(G_OBJECT(ctree), "button_release_event",
971 G_CALLBACK(addressbook_tree_button_released),
974 g_signal_connect(G_OBJECT(ctree), "select_row",
975 G_CALLBACK(addressbook_select_row_tree), NULL);
977 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
978 addressbook_drag_types, 1,
979 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
980 g_signal_connect(G_OBJECT(ctree), "drag_motion",
981 G_CALLBACK(addressbook_drag_motion_cb),
983 g_signal_connect(G_OBJECT(ctree), "drag_leave",
984 G_CALLBACK(addressbook_drag_leave_cb),
986 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
987 G_CALLBACK(addressbook_drag_received_cb),
989 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
990 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
991 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
992 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
994 clist_vbox = gtk_vbox_new(FALSE, 4);
996 clist_swin = gtk_scrolled_window_new(NULL, NULL);
997 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
998 GTK_POLICY_AUTOMATIC,
999 GTK_POLICY_AUTOMATIC);
1000 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1003 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1004 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1005 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
1006 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
1007 gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE);
1008 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
1009 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
1011 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
1013 gtk_widget_set_size_request(clist, -1, 80);
1015 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1016 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
1017 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1018 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
1019 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1020 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
1021 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1022 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1023 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1024 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1025 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1027 for (i = 0; i < N_LIST_COLS; i++)
1028 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
1031 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1032 G_CALLBACK(addressbook_list_row_selected), NULL);
1033 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1034 G_CALLBACK(addressbook_list_row_unselected), NULL);
1035 g_signal_connect(G_OBJECT(clist), "button_press_event",
1036 G_CALLBACK(addressbook_list_button_pressed),
1038 g_signal_connect(G_OBJECT(clist), "button_release_event",
1039 G_CALLBACK(addressbook_list_button_released),
1041 g_signal_connect(G_OBJECT(clist), "tree_expand",
1042 G_CALLBACK(addressbook_person_expand_node), NULL );
1043 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1044 G_CALLBACK(addressbook_person_collapse_node), NULL );
1045 g_signal_connect(G_OBJECT(clist), "start_drag",
1046 G_CALLBACK(addressbook_start_drag), NULL);
1047 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1048 G_CALLBACK(addressbook_drag_data_get), NULL);
1049 hbox = gtk_hbox_new(FALSE, 4);
1050 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1052 label = gtk_label_new(_("Lookup name:"));
1053 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1055 entry = gtk_entry_new();
1056 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1058 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1060 g_signal_connect(G_OBJECT(entry), "key_press_event",
1061 G_CALLBACK(addressbook_entry_key_pressed),
1064 if (!prefs_common.addressbook_use_editaddress_dialog) {
1065 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1066 vpaned = gtk_vpaned_new();
1067 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1068 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1071 editaddress_vbox = NULL;
1073 hpaned = gtk_hpaned_new();
1074 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1075 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1076 if (prefs_common.addressbook_use_editaddress_dialog)
1077 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1079 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1082 hsbox = gtk_hbox_new(FALSE, 0);
1083 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1084 statusbar = gtk_statusbar_new();
1085 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1088 hbbox = gtk_hbutton_box_new();
1089 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1090 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1091 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1092 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1094 gtkut_stock_button_add_help(hbbox, &help_btn);
1096 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1097 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1098 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1099 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1100 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1101 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1102 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1103 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1104 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1107 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1108 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1109 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1111 g_signal_connect(G_OBJECT(help_btn), "clicked",
1112 G_CALLBACK(manual_open_with_anchor_cb),
1113 MANUAL_ANCHOR_ADDRBOOK);
1115 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1116 G_CALLBACK(addressbook_edit_clicked), NULL);
1117 g_signal_connect(G_OBJECT(del_btn), "clicked",
1118 G_CALLBACK(addressbook_del_clicked), NULL);
1119 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1120 G_CALLBACK(addressbook_reg_clicked), NULL);
1121 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1122 G_CALLBACK(addressbook_lup_clicked), NULL);
1124 to_btn = gtk_button_new_with_label
1125 (prefs_common.trans_hdr ? _("To:") : "To:");
1126 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1127 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1128 cc_btn = gtk_button_new_with_label
1129 (prefs_common.trans_hdr ? _("Cc:") : "Cc:");
1130 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1131 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1132 bcc_btn = gtk_button_new_with_label
1133 (prefs_common.trans_hdr ? _("Bcc:") : "Bcc:");
1134 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1135 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1137 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1138 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1139 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1141 g_signal_connect(G_OBJECT(to_btn), "clicked",
1142 G_CALLBACK(addressbook_to_clicked),
1143 GINT_TO_POINTER(COMPOSE_TO));
1144 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1145 G_CALLBACK(addressbook_to_clicked),
1146 GINT_TO_POINTER(COMPOSE_CC));
1147 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1148 G_CALLBACK(addressbook_to_clicked),
1149 GINT_TO_POINTER(COMPOSE_BCC));
1150 g_signal_connect(G_OBJECT(close_btn), "clicked",
1151 G_CALLBACK(addressbook_close_clicked), NULL);
1153 /* Build icons for interface */
1154 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1155 &interfacexpm, &interfacexpmmask );
1157 /* Build control tables */
1158 addrbookctl_build_map(window);
1159 addrbookctl_build_iflist();
1160 addrbookctl_build_ifselect();
1162 addrbook.clist = NULL;
1164 /* Add each interface into the tree as a root level folder */
1165 nodeIf = _addressInterfaceList_;
1167 AdapterInterface *adapter = nodeIf->data;
1168 AddressInterface *iface = adapter->interface;
1169 nodeIf = g_list_next(nodeIf);
1171 if(iface->useInterface) {
1172 AddressTypeControlItem *atci = adapter->atci;
1173 text = atci->displayName;
1175 gtk_sctree_insert_node( GTK_CTREE(ctree),
1176 NULL, NULL, &text, FOLDER_SPACING,
1177 interfacexpm, interfacexpmmask,
1178 interfacexpm, interfacexpmmask,
1180 menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
1181 gtk_ctree_node_set_row_data_full(
1182 GTK_CTREE(ctree), adapter->treeNode, adapter,
1183 addressbook_free_treenode );
1188 n_entries = sizeof(addressbook_tree_popup_entries) /
1189 sizeof(addressbook_tree_popup_entries[0]);
1190 tree_popup = menu_create_items(addressbook_tree_popup_entries,
1192 "<AddressBookTree>", &tree_factory,
1194 n_entries = sizeof(addressbook_list_popup_entries) /
1195 sizeof(addressbook_list_popup_entries[0]);
1196 list_popup = menu_create_items(addressbook_list_popup_entries,
1198 "<AddressBookList>", &list_factory,
1201 addrbook.window = window;
1202 addrbook.hpaned = hpaned;
1203 addrbook.vpaned = vpaned;
1204 addrbook.menubar = menubar;
1205 addrbook.ctree = ctree;
1208 addrbook.editaddress_vbox = editaddress_vbox;
1209 addrbook.clist = clist;
1210 addrbook.label = label;
1211 addrbook.entry = entry;
1212 addrbook.statusbar = statusbar;
1213 addrbook.status_cid = gtk_statusbar_get_context_id(
1214 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1216 addrbook.help_btn = help_btn;
1217 addrbook.edit_btn = edit_btn;
1218 addrbook.del_btn = del_btn;
1219 addrbook.reg_btn = reg_btn;
1220 addrbook.lup_btn = lup_btn;
1221 addrbook.to_btn = to_btn;
1222 addrbook.cc_btn = cc_btn;
1223 addrbook.bcc_btn = bcc_btn;
1225 addrbook.tree_popup = tree_popup;
1226 addrbook.list_popup = list_popup;
1227 addrbook.tree_factory = tree_factory;
1228 addrbook.list_factory = list_factory;
1229 addrbook.menu_factory = menu_factory;
1231 addrbook.listSelected = NULL;
1233 if (!geometry.min_height) {
1234 geometry.min_width = ADDRESSBOOK_WIDTH;
1235 geometry.min_height = ADDRESSBOOK_HEIGHT;
1238 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1240 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1241 prefs_common.addressbookwin_height);
1243 if (!prefs_common.addressbook_use_editaddress_dialog) {
1244 if (prefs_common.addressbook_vpaned_pos > 0)
1245 gtk_paned_set_position(GTK_PANED(vpaned),
1246 prefs_common.addressbook_vpaned_pos);
1248 if (prefs_common.addressbook_hpaned_pos > 0)
1249 gtk_paned_set_position(GTK_PANED(hpaned),
1250 prefs_common.addressbook_hpaned_pos);
1253 gtk_widget_show_all(window);
1257 * Close address book window and save to file(s).
1259 static gint addressbook_close( void ) {
1260 address_completion_end(addrbook.window);
1261 if (!prefs_common.addressbook_use_editaddress_dialog)
1262 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1264 addressbook_pane_save_position();
1266 gtk_widget_hide(addrbook.window);
1267 addressbook_export_to_file();
1272 * Display message in status line.
1273 * \param msg Message to display.
1275 static void addressbook_status_show( gchar *msg ) {
1276 if( addrbook.statusbar != NULL ) {
1278 GTK_STATUSBAR(addrbook.statusbar),
1279 addrbook.status_cid );
1282 GTK_STATUSBAR(addrbook.statusbar),
1283 addrbook.status_cid, msg );
1288 static void addressbook_ds_status_message( AddressDataSource *ds, gchar *msg ) {
1289 *addressbook_msgbuf = '\0';
1293 name = addrindex_ds_get_name( ds );
1294 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1295 "%s: %s", name, msg );
1298 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1301 addressbook_status_show( addressbook_msgbuf );
1304 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1308 *addressbook_msgbuf = '\0';
1310 name = addrindex_ds_get_name( ds );
1311 retVal = addrindex_ds_get_status_code( ds );
1312 if( retVal == MGU_SUCCESS ) {
1313 g_snprintf( addressbook_msgbuf,
1314 sizeof(addressbook_msgbuf), "%s", name );
1317 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1318 g_snprintf( addressbook_msgbuf,
1319 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1322 addressbook_status_show( addressbook_msgbuf );
1325 static void addressbook_button_set_sensitive(void)
1327 gboolean to_sens = FALSE;
1328 gboolean cc_sens = FALSE;
1329 gboolean bcc_sens = FALSE;
1331 if (!addrbook.window) return;
1333 if (addrbook.target_compose) {
1339 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1340 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1341 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1344 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1346 addressbook_edit_address_cb(NULL, 0, NULL);
1350 * Delete one or more objects from address list.
1352 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1354 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1355 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1356 AddressObject *pobj;
1357 AdapterDSource *ads = NULL;
1358 GtkCTreeNode *nodeList;
1361 AddressBookFile *abf = NULL;
1362 AddressDataSource *ds = NULL;
1363 AddressInterface *iface;
1364 AddrItemObject *aio;
1365 AddrSelectItem *item;
1367 gboolean refreshList = FALSE;
1369 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1370 g_return_if_fail(pobj != NULL);
1372 /* Test whether anything selected for deletion */
1373 nodeList = addrbook.listSelected;
1375 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1376 if( aio == NULL) return;
1377 ds = addressbook_find_datasource( addrbook.treeSelected );
1378 if( ds == NULL ) return;
1380 /* Test for read only */
1381 iface = ds->interface;
1382 if( iface->readOnly ) {
1383 alertpanel( _("Delete address(es)"),
1384 _("This address data is readonly and cannot be deleted."),
1385 GTK_STOCK_CLOSE, NULL, NULL );
1389 /* Test whether Ok to proceed */
1391 if( pobj->type == ADDR_DATASOURCE ) {
1392 ads = ADAPTER_DSOURCE(pobj);
1393 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1395 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1398 else if( pobj->type == ADDR_ITEM_GROUP ) {
1401 if( ! procFlag ) return;
1402 abf = ds->rawDataSource;
1403 if( abf == NULL ) return;
1406 /* Process deletions */
1407 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1408 gboolean group_delete = TRUE;
1409 /* Items inside folders */
1410 list = addrselect_get_list( _addressSelect_ );
1411 /* Confirm deletion */
1415 node = g_list_next( node );
1416 aio = ( AddrItemObject * ) item->addressItem;
1417 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1418 group_delete = FALSE;
1423 aval = alertpanel( _("Delete group"),
1424 _("Really delete the group(s)?\n"
1425 "The addresses it contains will not be lost."),
1426 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1427 if( aval != G_ALERTALTERNATE ) return;
1429 aval = alertpanel( _("Delete address(es)"),
1430 _("Really delete the address(es)?"),
1431 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1432 if( aval != G_ALERTALTERNATE ) return;
1438 node = g_list_next( node );
1439 aio = ( AddrItemObject * ) item->addressItem;
1440 if( aio->type == ADDR_ITEM_GROUP ) {
1441 ItemGroup *item = ( ItemGroup * ) aio;
1442 GtkCTreeNode *nd = NULL;
1444 nd = addressbook_find_group_node( addrbook.opened, item );
1445 item = addrbook_remove_group( abf, item );
1447 addritem_free_item_group( item );
1449 /* Remove group from parent node */
1450 gtk_ctree_remove_node( ctree, nd );
1453 else if( aio->type == ADDR_ITEM_PERSON ) {
1454 ItemPerson *item = ( ItemPerson * ) aio;
1455 addressbook_folder_remove_one_person( clist, item );
1456 if (pobj->type == ADDR_ITEM_FOLDER)
1457 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1458 item = addrbook_remove_person( abf, item );
1460 addritem_free_item_person( item );
1463 else if( aio->type == ADDR_ITEM_EMAIL ) {
1464 ItemEMail *item = ( ItemEMail * ) aio;
1465 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1466 item = addrbook_person_remove_email( abf, person, item );
1468 addrcache_remove_email(abf->addressCache, item);
1469 addritem_free_item_email( item );
1471 addressbook_folder_refresh_one_person( clist, person );
1474 g_list_free( list );
1475 addressbook_list_select_clear();
1477 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1478 addressbook_set_clist(
1479 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1483 addrbook_set_dirty(abf, TRUE);
1484 addressbook_export_to_file();
1485 addressbook_list_menu_setup();
1488 else if( pobj->type == ADDR_ITEM_GROUP ) {
1489 /* Items inside groups */
1490 list = addrselect_get_list( _addressSelect_ );
1494 node = g_list_next( node );
1495 aio = ( AddrItemObject * ) item->addressItem;
1496 if( aio->type == ADDR_ITEM_EMAIL ) {
1497 ItemEMail *item = ( ItemEMail * ) aio;
1498 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1499 item = addrbook_person_remove_email( abf, person, item );
1501 addritem_free_item_email( item );
1505 g_list_free( list );
1506 addressbook_list_select_clear();
1507 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1508 addressbook_set_clist(
1509 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1513 addrbook_set_dirty(abf, TRUE);
1514 addressbook_export_to_file();
1515 addressbook_list_menu_setup();
1519 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1520 gtk_ctree_remove_node( clist, nodeList );
1524 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1526 addressbook_new_address_cb( NULL, 0, NULL );
1529 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1532 gchar *address = NULL;
1534 if( aio->type == ADDR_ITEM_EMAIL ) {
1535 ItemPerson *person = NULL;
1536 ItemEMail *email = ( ItemEMail * ) aio;
1538 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1539 if( email->address ) {
1540 if( ADDRITEM_NAME(email) ) {
1541 name = ADDRITEM_NAME(email);
1542 if( *name == '\0' ) {
1543 name = ADDRITEM_NAME(person);
1546 else if( ADDRITEM_NAME(person) ) {
1547 name = ADDRITEM_NAME(person);
1550 buf = g_strdup( email->address );
1552 address = email->address;
1555 else if( aio->type == ADDR_ITEM_PERSON ) {
1556 ItemPerson *person = ( ItemPerson * ) aio;
1557 GList *node = person->listEMail;
1559 name = ADDRITEM_NAME(person);
1561 ItemEMail *email = ( ItemEMail * ) node->data;
1562 address = email->address;
1566 if( name && name[0] != '\0' ) {
1567 if( strchr_with_skip_quote( name, '"', ',' ) )
1568 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1570 buf = g_strdup_printf( "%s <%s>", name, address );
1573 buf = g_strdup( address );
1580 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1584 AddrSelectItem *item;
1585 AddrItemObject *aio;
1588 compose = addrbook.target_compose;
1589 if( ! compose ) return;
1591 /* Nothing selected, but maybe there is something in text entry */
1592 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1594 compose_entry_append(
1595 compose, addr, (ComposeEntryType)data );
1598 /* Select from address list */
1599 list = addrselect_get_list( _addressSelect_ );
1604 node = g_list_next( node );
1605 aio = item->addressItem;
1606 if( aio->type == ADDR_ITEM_PERSON ||
1607 aio->type == ADDR_ITEM_EMAIL ) {
1608 addr = addressbook_format_address( aio );
1609 compose_entry_append(
1610 compose, addr, (ComposeEntryType) data );
1613 else if( aio->type == ADDR_ITEM_GROUP ) {
1614 ItemGroup *group = ( ItemGroup * ) aio;
1615 GList *nodeMail = group->listEMail;
1617 ItemEMail *email = nodeMail->data;
1619 addr = addressbook_format_address(
1620 ( AddrItemObject * ) email );
1621 compose_entry_append(
1622 compose, addr, (ComposeEntryType) data );
1624 nodeMail = g_list_next( nodeMail );
1629 AddressObject *obj = NULL;
1631 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1633 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1634 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1635 GList *nodeMail = itemGroup->listEMail;
1637 ItemEMail *email = nodeMail->data;
1639 addr = addressbook_format_address(
1640 ( AddrItemObject * ) email );
1641 compose_entry_append(
1642 compose, addr, (ComposeEntryType) data );
1644 nodeMail = g_list_next( nodeMail );
1648 g_list_free( list );
1651 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1652 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1653 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1654 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1656 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1657 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1658 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1659 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1661 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1662 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1663 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1664 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1665 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1666 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1669 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1670 gboolean canEdit = FALSE;
1671 gboolean canDelete = TRUE;
1672 gboolean canAdd = FALSE;
1673 gboolean canEditTr = TRUE;
1674 gboolean editAddress = FALSE;
1675 gboolean canExport = TRUE;
1676 AddressTypeControlItem *atci = NULL;
1677 AddressDataSource *ds = NULL;
1678 AddressInterface *iface = NULL;
1680 if( obj == NULL ) return;
1681 if( obj->type == ADDR_INTERFACE ) {
1682 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1683 iface = adapter->interface;
1685 if( iface->haveLibrary ) {
1686 /* Enable appropriate File / New command */
1687 atci = adapter->atci;
1688 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1691 canEditTr = canExport = FALSE;
1693 else if( obj->type == ADDR_DATASOURCE ) {
1694 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1695 ds = ads->dataSource;
1696 iface = ds->interface;
1697 if( ! iface->readOnly ) {
1698 canAdd = canEdit = editAddress = canDelete = TRUE;
1700 if( ! iface->haveLibrary ) {
1701 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1704 else if( obj->type == ADDR_ITEM_FOLDER ) {
1705 ds = addressbook_find_datasource( addrbook.treeSelected );
1707 iface = ds->interface;
1708 if( iface->readOnly ) {
1713 canAdd = editAddress = TRUE;
1717 else if( obj->type == ADDR_ITEM_GROUP ) {
1718 ds = addressbook_find_datasource( addrbook.treeSelected );
1720 iface = ds->interface;
1721 if( ! iface->readOnly ) {
1727 if( addrbook.listSelected == NULL ) canEdit = FALSE;
1730 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1731 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1732 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1733 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1736 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1737 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1738 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1739 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1741 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1742 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1745 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1746 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1749 static void addressbook_list_menu_setup( void );
1752 * Address book tree callback function that responds to selection of tree
1755 * \param ctree Tree widget.
1756 * \param node Node that was selected.
1757 * \param column Column number where selected occurred.
1758 * \param data Pointer to user data.
1760 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1761 gint column, gpointer data)
1763 AddressObject *obj = NULL;
1764 AdapterDSource *ads = NULL;
1765 AddressDataSource *ds = NULL;
1766 ItemFolder *rootFolder = NULL;
1767 AddressObjectType aot;
1769 addrbook.treeSelected = node;
1770 addrbook.listSelected = NULL;
1771 addressbook_status_show( "" );
1772 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1774 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1776 addressbook_set_clist(NULL, TRUE);
1779 addrbook.opened = node;
1781 if( obj->type == ADDR_DATASOURCE ) {
1782 /* Read from file */
1783 static gboolean tVal = TRUE;
1785 ads = ADAPTER_DSOURCE(obj);
1786 if( ads == NULL ) return;
1787 ds = ads->dataSource;
1788 if( ds == NULL ) return;
1790 if( addrindex_ds_get_modify_flag( ds ) ) {
1791 addrindex_ds_read_data( ds );
1794 if( ! addrindex_ds_get_read_flag( ds ) ) {
1795 addrindex_ds_read_data( ds );
1797 addressbook_ds_show_message( ds );
1799 if( ! addrindex_ds_get_access_flag( ds ) ) {
1800 /* Remove existing folders and groups */
1801 gtk_clist_freeze( GTK_CLIST(ctree) );
1802 addressbook_tree_remove_children( ctree, node );
1803 gtk_clist_thaw( GTK_CLIST(ctree) );
1805 /* Load folders into the tree */
1806 rootFolder = addrindex_ds_get_root_folder( ds );
1807 if( ds->type == ADDR_IF_JPILOT ) {
1808 aot = ADDR_CATEGORY;
1810 else if( ds->type == ADDR_IF_LDAP ) {
1811 aot = ADDR_LDAP_QUERY;
1814 aot = ADDR_ITEM_FOLDER;
1816 addressbook_node_add_folder( node, ds, rootFolder, aot );
1817 addrindex_ds_set_access_flag( ds, &tVal );
1818 gtk_ctree_expand( ctree, node );
1821 addressbook_set_clist(NULL, TRUE);
1824 /* Update address list */
1825 g_signal_handlers_block_by_func
1827 G_CALLBACK(addressbook_tree_selected), NULL);
1828 addressbook_set_clist( obj, FALSE );
1829 g_signal_handlers_unblock_by_func
1831 G_CALLBACK(addressbook_tree_selected), NULL);
1832 if (!prefs_common.addressbook_use_editaddress_dialog)
1833 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1835 /* Setup main menu selections */
1836 addressbook_menubar_set_sensitive( FALSE );
1837 addressbook_list_menu_setup();
1838 addressbook_menuitem_set_sensitive( obj, node );
1840 addressbook_list_select_clear();
1841 addressbook_list_menu_setup();
1846 * Setup address list popup menu items. Items are enabled or disabled as
1849 static void addressbook_list_menu_setup( void ) {
1850 GtkCTree *clist = NULL;
1851 AddressObject *pobj = NULL;
1852 AddressObject *obj = NULL;
1853 AdapterDSource *ads = NULL;
1854 AddressInterface *iface = NULL;
1855 AddressDataSource *ds = NULL;
1856 gboolean canEdit = FALSE;
1857 gboolean canDelete = FALSE;
1858 gboolean canCut = FALSE;
1859 gboolean canCopy = FALSE;
1860 gboolean canPaste = FALSE;
1861 gboolean canBrowse = FALSE;
1863 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1864 if( pobj == NULL ) return;
1866 clist = GTK_CTREE(addrbook.clist);
1867 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1868 if( obj == NULL ) canEdit = FALSE;
1870 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1871 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1873 if( pobj->type == ADDR_DATASOURCE ) {
1874 /* Parent object is a data source */
1875 ads = ADAPTER_DSOURCE(pobj);
1876 ds = ads->dataSource;
1877 iface = ds->interface;
1878 if( ! iface->readOnly ) {
1879 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1880 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1881 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1882 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1883 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1884 if( obj ) canEdit = TRUE;
1886 canDelete = canEdit;
1888 else if( pobj->type != ADDR_INTERFACE ) {
1889 /* Parent object is not an interface */
1890 ds = addressbook_find_datasource( addrbook.treeSelected );
1891 iface = ds->interface;
1892 if( ! iface->readOnly ) {
1893 /* Folder or group */
1894 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1895 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1896 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1897 if( obj ) canEdit = TRUE;
1900 if( pobj->type == ADDR_ITEM_FOLDER ) {
1901 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1902 if( obj ) canEdit = TRUE;
1904 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1905 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1906 canDelete = canEdit;
1908 if( iface->type == ADDR_IF_LDAP ) {
1909 if( obj ) canBrowse = TRUE;
1914 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
1916 /* Disable edit or browse if more than one row selected */
1917 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
1922 /* Now go finalize menu items */
1923 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
1924 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1926 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
1927 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
1928 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
1929 /* menu_set_sensitive( addrbook.list_factory, "/Paste Address", canPaste );*/
1931 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
1933 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
1934 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
1935 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
1936 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
1938 menu_set_sensitive( addrbook.tree_factory, "/Cut", canCut );
1939 menu_set_sensitive( addrbook.tree_factory, "/Copy", canCopy );
1940 menu_set_sensitive( addrbook.tree_factory, "/Paste", canPaste );
1942 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1943 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1944 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
1946 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1947 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1950 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
1954 static void addressbook_select_row_tree (GtkCTree *ctree,
1962 * Add list of items into tree node below specified tree node.
1963 * \param treeNode Tree node.
1964 * \param ds Data source.
1965 * \param listItems List of items.
1967 static void addressbook_treenode_add_list(
1968 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
1974 AddrItemObject *aio;
1978 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
1981 group = ( ItemGroup * ) aio;
1982 nn = addressbook_node_add_group( treeNode, ds, group );
1984 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
1987 folder = ( ItemFolder * ) aio;
1988 nn = addressbook_node_add_folder(
1989 treeNode, ds, folder, ADDR_ITEM_FOLDER );
1991 node = g_list_next( node );
1995 static void addressbook_select_all_cb( void ) {
1996 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2000 * Cut from address list widget.
2002 static void addressbook_clip_cut_cb( void ) {
2003 _clipBoard_->cutFlag = TRUE;
2004 addrclip_clear( _clipBoard_ );
2005 addrclip_add( _clipBoard_, _addressSelect_ );
2006 /* addrclip_list_show( _clipBoard_, stdout ); */
2010 * Copy from address list widget.
2012 static void addressbook_clip_copy_cb( void ) {
2013 _clipBoard_->cutFlag = FALSE;
2014 addrclip_clear( _clipBoard_ );
2015 addrclip_add( _clipBoard_, _addressSelect_ );
2016 /* addrclip_list_show( _clipBoard_, stdout ); */
2020 * Paste clipboard into address list widget.
2022 static void addressbook_clip_paste_cb( void ) {
2023 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2024 AddressObject *pobj = NULL;
2025 AddressDataSource *ds = NULL;
2026 AddressBookFile *abf = NULL;
2027 ItemFolder *folder = NULL;
2028 GList *folderGroup = NULL;
2030 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2031 if( ds == NULL ) return;
2032 if( addrindex_ds_get_readonly( ds ) ) {
2033 addressbook_ds_status_message(
2034 ds, _( "Cannot paste. Target address book is readonly." ) );
2038 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2040 if( pobj->type == ADDR_ITEM_FOLDER ) {
2041 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2043 else if( pobj->type == ADDR_ITEM_GROUP ) {
2044 addressbook_ds_status_message(
2045 ds, _( "Cannot paste into an address group." ) );
2050 /* Get an address book */
2051 abf = addressbook_get_book_file();
2052 if( abf == NULL ) return;
2054 if( _clipBoard_->cutFlag ) {
2056 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2058 /* Remove all groups and folders in clipboard from tree node */
2059 addressbook_treenode_remove_item();
2061 /* Remove all "cut" items */
2062 addrclip_delete_item( _clipBoard_ );
2064 /* Clear clipboard - cut items??? */
2065 addrclip_clear( _clipBoard_ );
2069 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2072 /* addrclip_list_show( _clipBoard_, stdout ); */
2074 /* Update tree by inserting node for each folder or group */
2075 addressbook_treenode_add_list(
2076 addrbook.treeSelected, ds, folderGroup );
2077 gtk_ctree_expand( ctree, addrbook.treeSelected );
2078 g_list_free( folderGroup );
2082 /* Display items pasted */
2083 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2084 addressbook_set_clist(
2085 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2093 * Add current treenode object to clipboard. Note that widget only allows
2094 * one entry from the tree list to be selected.
2096 static void addressbook_treenode_to_clipboard( void ) {
2097 AddressObject *obj = NULL;
2098 AddressDataSource *ds = NULL;
2099 AddrSelectItem *item;
2100 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2103 node = addrbook.treeSelected;
2104 if( node == NULL ) return;
2105 obj = gtk_ctree_node_get_row_data( ctree, node );
2106 if( obj == NULL ) return;
2108 ds = addressbook_find_datasource( node );
2109 if( ds == NULL ) return;
2112 if( obj->type == ADDR_ITEM_FOLDER ) {
2113 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2114 ItemFolder *folder = adapter->itemFolder;
2116 item = addrselect_create_node( obj );
2117 item->uid = g_strdup( ADDRITEM_ID(folder) );
2119 else if( obj->type == ADDR_ITEM_GROUP ) {
2120 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2121 ItemGroup *group = adapter->itemGroup;
2123 item = addrselect_create_node( obj );
2124 item->uid = g_strdup( ADDRITEM_ID(group) );
2126 else if( obj->type == ADDR_DATASOURCE ) {
2128 item = addrselect_create_node( obj );
2133 /* Clear existing list and add item into list */
2136 addressbook_list_select_clear();
2137 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2138 addrselect_list_add( _addressSelect_, item, cacheID );
2144 * Cut from tree widget.
2146 static void addressbook_treenode_cut_cb( void ) {
2147 _clipBoard_->cutFlag = TRUE;
2148 addressbook_treenode_to_clipboard();
2149 addrclip_clear( _clipBoard_ );
2150 addrclip_add( _clipBoard_, _addressSelect_ );
2151 /* addrclip_list_show( _clipBoard_, stdout ); */
2155 * Copy from tree widget.
2157 static void addressbook_treenode_copy_cb( void ) {
2158 _clipBoard_->cutFlag = FALSE;
2159 addressbook_treenode_to_clipboard();
2160 addrclip_clear( _clipBoard_ );
2161 addrclip_add( _clipBoard_, _addressSelect_ );
2162 /* addrclip_list_show( _clipBoard_, stdout ); */
2166 * Paste clipboard into address tree widget.
2168 static void addressbook_treenode_paste_cb( void ) {
2169 addressbook_clip_paste_cb();
2173 * Clear selected entries in clipboard.
2175 static void addressbook_list_select_clear( void ) {
2176 addrselect_list_clear( _addressSelect_ );
2180 * Add specified address item to selected address list.
2181 * \param aio Address item object.
2182 * \param ds Datasource.
2184 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2187 if( ds == NULL ) return;
2188 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2189 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2194 * Remove specified address item from selected address list.
2195 * \param aio Address item object.
2197 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2198 addrselect_list_remove( _addressSelect_, aio );
2202 * Invoke EMail compose window with addresses in selected address list.
2204 static void addressbook_mail_to_cb( void ) {
2207 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2208 listAddress = addrselect_build_list( _addressSelect_ );
2209 compose_new_with_list( NULL, listAddress );
2210 mgu_free_dlist( listAddress );
2215 static void addressbook_list_row_selected( GtkCTree *clist,
2220 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2221 AddrItemObject *aio = NULL;
2222 AddressObject *pobj = NULL;
2223 AdapterDSource *ads = NULL;
2224 AddressDataSource *ds = NULL;
2226 gtk_entry_set_text( entry, "" );
2227 addrbook.listSelected = node;
2229 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2230 if( pobj == NULL ) return;
2232 if( pobj->type == ADDR_DATASOURCE ) {
2233 ads = ADAPTER_DSOURCE(pobj);
2234 ds = ads->dataSource;
2236 else if( pobj->type != ADDR_INTERFACE ) {
2237 ds = addressbook_find_datasource( addrbook.treeSelected );
2240 aio = gtk_ctree_node_get_row_data( clist, node );
2242 /* printf( "list select: %d : '%s'\n", aio->type, aio->name ); */
2243 addressbook_list_select_add( aio, ds );
2246 addressbook_list_menu_setup();
2248 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog)
2249 addressbook_edit_address(NULL, 0, NULL, FALSE);
2252 static void addressbook_list_row_unselected( GtkCTree *ctree,
2257 AddrItemObject *aio;
2259 aio = gtk_ctree_node_get_row_data( ctree, node );
2261 /* printf( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2262 addressbook_list_select_remove( aio );
2265 if (!prefs_common.addressbook_use_editaddress_dialog)
2266 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2269 /* from gdkevents.c */
2270 #define DOUBLE_CLICK_TIME 250
2272 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2273 GdkEventButton *event,
2276 static guint32 lasttime = 0;
2277 if( ! event ) return FALSE;
2279 addressbook_list_menu_setup();
2281 if( event->button == 3 ) {
2282 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2283 event->button, event->time );
2284 } else if (event->button == 1) {
2285 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2286 if (prefs_common.add_address_by_click &&
2287 addrbook.target_compose)
2288 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2290 if (prefs_common.addressbook_use_editaddress_dialog)
2291 addressbook_edit_address_cb(NULL, 0, NULL);
2295 lasttime = event->time;
2301 static gboolean addressbook_list_button_released(GtkWidget *widget,
2302 GdkEventButton *event,
2308 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2309 GdkEventButton *event,
2312 GtkCList *clist = GTK_CLIST(ctree);
2314 AddressObject *obj = NULL;
2315 AdapterDSource *ads = NULL;
2316 AddressInterface *iface = NULL;
2317 AddressDataSource *ds = NULL;
2318 gboolean canEdit = FALSE;
2319 gboolean canDelete = FALSE;
2320 gboolean canCut = FALSE;
2321 gboolean canCopy = FALSE;
2322 gboolean canPaste = FALSE;
2323 gboolean canTreeCut = FALSE;
2324 gboolean canTreeCopy = FALSE;
2325 gboolean canTreePaste = FALSE;
2326 gboolean canLookup = FALSE;
2327 GtkCTreeNode *node = NULL;
2329 if( ! event ) return FALSE;
2330 addressbook_menubar_set_sensitive( FALSE );
2332 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2333 gtkut_clist_set_focus_row(clist, row);
2334 obj = gtk_clist_get_row_data( clist, row );
2337 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2339 if( obj == NULL ) return FALSE;
2340 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2342 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2343 canTreePaste = TRUE;
2346 if (obj->type == ADDR_INTERFACE) {
2347 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2348 iface = adapter->interface;
2351 canTreeCopy = FALSE;
2352 if( iface->readOnly ) {
2353 canTreePaste = FALSE;
2356 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2357 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2359 if( iface->externalQuery ) canLookup = TRUE;
2361 if (obj->type == ADDR_DATASOURCE) {
2362 ads = ADAPTER_DSOURCE(obj);
2363 ds = ads->dataSource;
2366 iface = ds->interface;
2371 if( iface->readOnly ) {
2372 canTreePaste = FALSE;
2375 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2376 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2377 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2380 if( iface->externalQuery ) canLookup = TRUE;
2382 else if (obj->type == ADDR_ITEM_FOLDER) {
2383 ds = addressbook_find_datasource( node );
2387 iface = ds->interface;
2390 if( iface->readOnly ) {
2391 canTreePaste = FALSE;
2397 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2398 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2399 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2403 if( iface->externalQuery ) {
2404 /* Enable deletion of LDAP folder */
2409 else if (obj->type == ADDR_ITEM_GROUP) {
2410 ds = addressbook_find_datasource( node );
2413 iface = ds->interface;
2416 if( ! iface->readOnly ) {
2419 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2420 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2423 else if (obj->type == ADDR_INTERFACE) {
2424 canTreePaste = FALSE;
2428 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
2430 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
2431 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
2435 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2436 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2437 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2438 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2439 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2441 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2442 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2443 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2444 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2445 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2446 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
2448 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup, addrbook.target_compose != NULL);
2449 if( event->button == 3 ) {
2450 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2451 event->button, event->time);
2457 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2458 GdkEventButton *event,
2461 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2465 static void addressbook_new_folder_cb(gpointer data, guint action,
2468 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2469 AddressObject *obj = NULL;
2470 AddressDataSource *ds = NULL;
2471 AddressBookFile *abf = NULL;
2472 ItemFolder *parentFolder = NULL;
2473 ItemFolder *folder = NULL;
2475 if( ! addrbook.treeSelected ) return;
2476 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2477 if( obj == NULL ) return;
2478 ds = addressbook_find_datasource( addrbook.treeSelected );
2479 if( ds == NULL ) return;
2481 if( obj->type == ADDR_DATASOURCE ) {
2482 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2484 else if( obj->type == ADDR_ITEM_FOLDER ) {
2485 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2491 abf = ds->rawDataSource;
2492 if( abf == NULL ) return;
2493 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2496 nn = addressbook_node_add_folder(
2497 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2498 gtk_ctree_expand( ctree, addrbook.treeSelected );
2499 if( addrbook.treeSelected == addrbook.opened )
2500 addressbook_set_clist(obj, TRUE);
2505 static void addressbook_new_group_cb(gpointer data, guint action,
2508 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2509 AddressObject *obj = NULL;
2510 AddressDataSource *ds = NULL;
2511 AddressBookFile *abf = NULL;
2512 ItemFolder *parentFolder = NULL;
2513 ItemGroup *group = NULL;
2515 if( ! addrbook.treeSelected ) return;
2516 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2517 if( obj == NULL ) return;
2518 ds = addressbook_find_datasource( addrbook.treeSelected );
2519 if( ds == NULL ) return;
2521 if( obj->type == ADDR_DATASOURCE ) {
2522 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2524 else if( obj->type == ADDR_ITEM_FOLDER ) {
2525 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2531 abf = ds->rawDataSource;
2532 if( abf == NULL ) return;
2533 group = addressbook_edit_group( abf, parentFolder, NULL );
2536 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2537 gtk_ctree_expand( ctree, addrbook.treeSelected );
2538 if( addrbook.treeSelected == addrbook.opened )
2539 addressbook_set_clist(obj, TRUE);
2544 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2546 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2549 GdkPixmap *pix_cl, *pix_op;
2550 GdkBitmap *mask_cl, *mask_op;
2551 gboolean is_leaf, expanded;
2553 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2554 &pix_cl, &mask_cl, &pix_op, &mask_op,
2555 &is_leaf, &expanded);
2556 gtk_sctree_set_node_info(ctree, node, name, spacing,
2557 pix_cl, mask_cl, pix_op, mask_op,
2563 * \param obj Address object to edit.
2564 * \param node Node in tree.
2565 * \return New name of data source.
2567 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2568 gchar *newName = NULL;
2569 AddressDataSource *ds = NULL;
2570 AddressInterface *iface = NULL;
2571 AdapterDSource *ads = NULL;
2573 ds = addressbook_find_datasource( node );
2574 if( ds == NULL ) return NULL;
2575 iface = ds->interface;
2576 if( ! iface->haveLibrary ) return NULL;
2578 /* Read data from data source */
2579 if( addrindex_ds_get_modify_flag( ds ) ) {
2580 addrindex_ds_read_data( ds );
2583 if( ! addrindex_ds_get_read_flag( ds ) ) {
2584 addrindex_ds_read_data( ds );
2588 ads = ADAPTER_DSOURCE(obj);
2589 if( ads->subType == ADDR_BOOK ) {
2590 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2592 else if( ads->subType == ADDR_VCARD ) {
2593 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2596 else if( ads->subType == ADDR_JPILOT ) {
2597 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2601 else if( ads->subType == ADDR_LDAP ) {
2602 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2608 newName = obj->name;
2613 * Edit an object that is in the address tree area.
2615 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2618 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2620 AddressDataSource *ds = NULL;
2621 AddressBookFile *abf = NULL;
2622 GtkCTreeNode *node = NULL, *parentNode = NULL;
2625 if( ! addrbook.treeSelected ) return;
2626 node = addrbook.treeSelected;
2627 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2628 obj = gtk_ctree_node_get_row_data( ctree, node );
2629 if( obj == NULL ) return;
2630 parentNode = GTK_CTREE_ROW(node)->parent;
2632 ds = addressbook_find_datasource( node );
2633 if( ds == NULL ) return;
2635 if( obj->type == ADDR_DATASOURCE ) {
2636 name = addressbook_edit_datasource( obj, node );
2637 if( name == NULL ) return;
2640 abf = ds->rawDataSource;
2641 if( abf == NULL ) return;
2642 if( obj->type == ADDR_ITEM_FOLDER ) {
2643 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2644 ItemFolder *item = adapter->itemFolder;
2645 ItemFolder *parentFolder = NULL;
2646 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2647 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2648 name = ADDRITEM_NAME(item);
2650 else if( obj->type == ADDR_ITEM_GROUP ) {
2651 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2652 ItemGroup *item = adapter->itemGroup;
2653 ItemFolder *parentFolder = NULL;
2654 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2655 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2656 name = ADDRITEM_NAME(item);
2659 if( name && parentNode ) {
2660 /* Update node in tree view */
2661 addressbook_change_node_name( node, name );
2662 gtk_sctree_sort_node(ctree, parentNode);
2663 gtk_ctree_expand( ctree, node );
2664 gtk_sctree_select( GTK_SCTREE( ctree), node );
2671 ADDRTREE_DEL_FOLDER_ONLY,
2672 ADDRTREE_DEL_FOLDER_ADDR
2676 * Delete an item from the tree widget.
2677 * \param data Data passed in.
2678 * \param action Action.
2679 * \param widget Widget issuing callback.
2681 static void addressbook_treenode_delete_cb(
2682 gpointer data, guint action, GtkWidget *widget )
2684 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2685 GtkCTreeNode *node = NULL;
2689 AddrBookBase *adbase;
2690 AddressCache *cache;
2691 AdapterDSource *ads = NULL;
2692 AddressInterface *iface = NULL;
2693 AddressDataSource *ds = NULL;
2694 gboolean remFlag = FALSE;
2695 TreeItemDelType delType;
2697 if( ! addrbook.treeSelected ) return;
2698 node = addrbook.treeSelected;
2699 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2701 obj = gtk_ctree_node_get_row_data( ctree, node );
2702 g_return_if_fail(obj != NULL);
2704 if( obj->type == ADDR_DATASOURCE ) {
2705 ads = ADAPTER_DSOURCE(obj);
2706 if( ads == NULL ) return;
2707 ds = ads->dataSource;
2708 if( ds == NULL ) return;
2711 /* Must be folder or something else */
2712 ds = addressbook_find_datasource( node );
2713 if( ds == NULL ) return;
2715 /* Only allow deletion from non-readOnly */
2716 iface = ds->interface;
2717 if( iface->readOnly ) {
2718 /* Allow deletion of query results */
2719 if( ! iface->externalQuery ) return;
2723 /* Confirm deletion */
2724 delType = ADDRTREE_DEL_NONE;
2725 if( obj->type == ADDR_ITEM_FOLDER ) {
2726 if( iface->externalQuery ) {
2727 message = g_strdup_printf( _(
2728 "Do you want to delete the query " \
2729 "results and addresses in '%s' ?" ),
2731 aval = alertpanel( _("Delete"), message,
2732 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2734 if( aval == G_ALERTALTERNATE ) {
2735 delType = ADDRTREE_DEL_FOLDER_ADDR;
2739 message = g_strdup_printf
2740 ( _( "Do you want to delete '%s' ?"
2741 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2743 aval = alertpanel( _("Delete folder"), message,
2744 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2746 if( aval == G_ALERTALTERNATE ) {
2747 delType = ADDRTREE_DEL_FOLDER_ONLY;
2749 else if( aval == G_ALERTOTHER ) {
2750 delType = ADDRTREE_DEL_FOLDER_ADDR;
2754 else if( obj->type == ADDR_ITEM_GROUP ) {
2755 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2756 "The addresses it contains will not be lost."), obj->name);
2757 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2758 "+" GTK_STOCK_DELETE, NULL);
2760 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2762 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2763 "The addresses it contains will be lost."), obj->name);
2764 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2765 "+" GTK_STOCK_DELETE, NULL);
2767 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2769 if( delType == ADDRTREE_DEL_NONE ) return;
2771 /* Proceed with deletion */
2772 if( obj->type == ADDR_DATASOURCE ) {
2773 /* Remove node from tree */
2774 gtk_ctree_remove_node( ctree, node );
2776 /* Remove data source. */
2777 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2778 addrindex_free_datasource( ds );
2783 /* Get reference to cache */
2784 adbase = ( AddrBookBase * ) ds->rawDataSource;
2785 if( adbase == NULL ) return;
2786 cache = adbase->addressCache;
2788 /* Remove query results folder */
2789 if( iface->externalQuery ) {
2790 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2791 ItemFolder *folder = adapter->itemFolder;
2793 adapter->itemFolder = NULL;
2795 printf( "remove folder for ::%s::\n", obj->name );
2796 printf( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2797 printf( "-------------- remove results\n" );
2799 addrindex_remove_results( ds, folder );
2800 /* printf( "-------------- remove node\n" ); */
2801 gtk_ctree_remove_node( ctree, node );
2805 /* Code below is valid for regular address book deletion */
2806 if( obj->type == ADDR_ITEM_FOLDER ) {
2807 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2808 ItemFolder *item = adapter->itemFolder;
2810 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2811 /* Remove folder only */
2812 item = addrcache_remove_folder( cache, item );
2814 addritem_free_item_folder( item );
2815 addressbook_move_nodes_up( ctree, node );
2819 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2820 /* Remove folder and addresses */
2821 item = addrcache_remove_folder_delete( cache, item );
2823 addritem_free_item_folder( item );
2828 else if( obj->type == ADDR_ITEM_GROUP ) {
2829 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2830 ItemGroup *item = adapter->itemGroup;
2832 item = addrcache_remove_group( cache, item );
2834 addritem_free_item_group( item );
2841 gtk_ctree_remove_node(ctree, node );
2845 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2847 if( person && addrbook.treeSelected == addrbook.opened ) {
2848 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2849 addressbook_folder_refresh_one_person(
2850 GTK_CTREE(addrbook.clist), person );
2852 addressbook_address_list_set_focus();
2855 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2857 if( person && addrbook.treeSelected == addrbook.opened) {
2858 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2859 addressbook_set_clist(
2860 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2864 addressbook_address_list_set_focus();
2867 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
2868 AddressObject *pobj = NULL;
2869 AddressDataSource *ds = NULL;
2870 AddressBookFile *abf = NULL;
2872 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
2873 if( pobj == NULL ) return;
2874 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2875 if( ds == NULL ) return;
2877 abf = ds->rawDataSource;
2878 if( abf == NULL ) return;
2880 if( pobj->type == ADDR_DATASOURCE ) {
2881 if( ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ) {
2883 ItemPerson *person = addressbook_edit_person( abf, NULL, NULL, FALSE,
2884 addrbook.editaddress_vbox,
2885 addressbook_new_address_from_book_post_cb,
2887 if (prefs_common.addressbook_use_editaddress_dialog)
2888 addressbook_new_address_from_book_post_cb( person );
2891 else if( pobj->type == ADDR_ITEM_FOLDER ) {
2893 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
2894 ItemPerson *person = addressbook_edit_person( abf, folder, NULL, FALSE,
2895 addrbook.editaddress_vbox,
2896 addressbook_new_address_from_folder_post_cb,
2898 if (prefs_common.addressbook_use_editaddress_dialog)
2899 addressbook_new_address_from_folder_post_cb( person );
2901 else if( pobj->type == ADDR_ITEM_GROUP ) {
2902 /* New address in group */
2903 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
2904 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
2905 if (addrbook.treeSelected == addrbook.opened) {
2906 /* Change node name in tree. */
2907 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
2908 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2909 addressbook_set_clist(
2910 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2918 * Search for specified child group node in address index tree.
2919 * \param parent Parent node.
2920 * \param group Group to find.
2922 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
2923 GtkCTreeNode *node = NULL;
2924 GtkCTreeRow *currRow;
2926 currRow = GTK_CTREE_ROW( parent );
2928 node = currRow->children;
2932 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
2933 if( obj->type == ADDR_ITEM_GROUP ) {
2934 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
2935 if( g == group ) return node;
2937 currRow = GTK_CTREE_ROW(node);
2938 node = currRow->sibling;
2944 static AddressBookFile *addressbook_get_book_file() {
2945 AddressBookFile *abf = NULL;
2946 AddressDataSource *ds = NULL;
2948 ds = addressbook_find_datasource( addrbook.treeSelected );
2949 if( ds == NULL ) return NULL;
2950 if( ds->type == ADDR_IF_BOOK ) abf = ds->rawDataSource;
2954 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
2958 /* Remove existing folders and groups */
2959 row = GTK_CTREE_ROW( parent );
2961 while( (node = row->children) ) {
2962 gtk_ctree_remove_node( ctree, node );
2967 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
2968 GtkCTreeNode *parent, *child;
2969 GtkCTreeRow *currRow;
2970 currRow = GTK_CTREE_ROW( node );
2972 parent = currRow->parent;
2973 while( (child = currRow->children) ) {
2974 gtk_ctree_move( ctree, child, parent, node );
2976 gtk_sctree_sort_node( ctree, parent );
2980 static void addressbook_edit_address_post_cb( ItemPerson *person )
2983 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
2984 invalidate_address_completion();
2986 addressbook_address_list_set_focus();
2989 void addressbook_address_list_set_focus( void )
2991 if (!prefs_common.addressbook_use_editaddress_dialog) {
2992 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
2993 addressbook_list_menu_setup();
2997 void addressbook_address_list_disable_some_actions(void)
2999 /* disable address copy/pasting when editing contact's detail (embedded form) */
3000 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3001 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3002 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3004 /* we're already editing contact's detail here */
3005 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", FALSE );
3006 gtk_widget_set_sensitive( addrbook.edit_btn, FALSE );
3009 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3010 addressbook_edit_address(data, action, widget, TRUE);
3013 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3014 gboolean force_focus ) {
3015 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3017 AddressObject *obj = NULL, *pobj = NULL;
3018 AddressDataSource *ds = NULL;
3019 GtkCTreeNode *node = NULL, *parentNode = NULL;
3021 AddressBookFile *abf = NULL;
3023 if( addrbook.listSelected == NULL ) return;
3024 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3025 g_return_if_fail(obj != NULL);
3027 ctree = GTK_CTREE( addrbook.ctree );
3028 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3029 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3031 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3032 if( ds == NULL ) return;
3034 abf = addressbook_get_book_file();
3036 if( obj->type == ADDR_ITEM_EMAIL ) {
3037 ItemEMail *email = ( ItemEMail * ) obj;
3038 if( email == NULL ) return;
3039 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3040 /* Edit parent group */
3041 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3042 ItemGroup *itemGrp = adapter->itemGroup;
3043 if( abf == NULL ) return;
3044 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3045 name = ADDRITEM_NAME(itemGrp);
3046 node = addrbook.treeSelected;
3047 parentNode = GTK_CTREE_ROW(node)->parent;
3050 /* Edit person - email page */
3052 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3053 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3054 addressbook_edit_address_post_cb,
3055 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3057 if (prefs_common.addressbook_use_editaddress_dialog)
3058 addressbook_edit_address_post_cb( person );
3063 else if( obj->type == ADDR_ITEM_PERSON ) {
3064 /* Edit person - basic page */
3065 ItemPerson *person = ( ItemPerson * ) obj;
3066 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3067 addressbook_edit_address_post_cb,
3068 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3070 if (prefs_common.addressbook_use_editaddress_dialog)
3071 addressbook_edit_address_post_cb( person );
3075 else if( obj->type == ADDR_ITEM_GROUP ) {
3076 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3077 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3078 parentNode = addrbook.treeSelected;
3079 node = addressbook_find_group_node( parentNode, itemGrp );
3080 name = ADDRITEM_NAME(itemGrp);
3081 invalidate_address_completion();
3087 /* Update tree node with node name */
3088 if( node == NULL ) return;
3089 addressbook_change_node_name( node, name );
3090 gtk_sctree_sort_node( ctree, parentNode );
3091 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3092 addressbook_set_clist(
3093 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3098 static void addressbook_delete_address_cb(gpointer data, guint action,
3101 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
3102 addressbook_del_clicked(NULL, NULL);
3103 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
3106 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3108 addressbook_close();
3111 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3112 addressbook_export_to_file();
3115 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3117 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3118 if( person ) addritem_person_set_opened( person, TRUE );
3122 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3124 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3125 if( person ) addritem_person_set_opened( person, FALSE );
3129 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3131 gchar *eMailAlias = ADDRITEM_NAME(email);
3132 if( eMailAlias && *eMailAlias != '\0' ) {
3134 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3137 str = g_strdup( eMailAlias );
3143 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3144 GList *items = itemGroup->listEMail;
3145 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3146 for( ; items != NULL; items = g_list_next( items ) ) {
3147 GtkCTreeNode *nodeEMail = NULL;
3148 gchar *text[N_LIST_COLS];
3149 ItemEMail *email = items->data;
3153 if( ! email ) continue;
3155 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3156 str = addressbook_format_item_clist( person, email );
3158 text[COL_NAME] = str;
3161 text[COL_NAME] = ADDRITEM_NAME(person);
3163 text[COL_ADDRESS] = email->address;
3164 text[COL_REMARKS] = email->remarks;
3165 nodeEMail = gtk_sctree_insert_node(
3167 text, FOLDER_SPACING,
3168 atci->iconXpm, atci->maskXpm,
3169 atci->iconXpmOpen, atci->maskXpmOpen,
3171 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3177 static void addressbook_folder_load_one_person(
3178 GtkCTree *clist, ItemPerson *person,
3179 AddressTypeControlItem *atci,
3180 AddressTypeControlItem *atciMail )
3182 GtkCTreeNode *nodePerson = NULL;
3183 GtkCTreeNode *nodeEMail = NULL;
3184 gchar *text[N_LIST_COLS];
3185 gboolean flgFirst = TRUE, haveAddr = FALSE;
3188 if( person == NULL ) return;
3190 text[COL_NAME] = "";
3191 node = person->listEMail;
3193 ItemEMail *email = node->data;
3194 gchar *eMailAddr = NULL;
3195 node = g_list_next( node );
3197 text[COL_ADDRESS] = email->address;
3198 text[COL_REMARKS] = email->remarks;
3199 eMailAddr = ADDRITEM_NAME(email);
3200 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3202 /* First email belongs with person */
3203 gchar *str = addressbook_format_item_clist( person, email );
3205 text[COL_NAME] = str;
3208 text[COL_NAME] = ADDRITEM_NAME(person);
3210 nodePerson = gtk_sctree_insert_node(
3212 text, FOLDER_SPACING,
3213 atci->iconXpm, atci->maskXpm,
3214 atci->iconXpmOpen, atci->maskXpmOpen,
3215 FALSE, person->isOpened );
3218 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3221 /* Subsequent email is a child node of person */
3222 text[COL_NAME] = ADDRITEM_NAME(email);
3223 nodeEMail = gtk_sctree_insert_node(
3224 clist, nodePerson, NULL,
3225 text, FOLDER_SPACING,
3226 atciMail->iconXpm, atciMail->maskXpm,
3227 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3229 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3235 /* Have name without EMail */
3236 text[COL_NAME] = ADDRITEM_NAME(person);
3237 text[COL_ADDRESS] = "";
3238 text[COL_REMARKS] = "";
3239 nodePerson = gtk_sctree_insert_node(
3241 text, FOLDER_SPACING,
3242 atci->iconXpm, atci->maskXpm,
3243 atci->iconXpmOpen, atci->maskXpmOpen,
3244 FALSE, person->isOpened );
3245 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3250 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3252 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3253 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3255 if( atci == NULL ) return;
3256 if( atciMail == NULL ) return;
3258 /* Load email addresses */
3259 items = addritem_folder_get_person_list( itemFolder );
3260 for( ; items != NULL; items = g_list_next( items ) ) {
3261 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3263 /* Free up the list */
3264 mgu_clear_list( items );
3265 g_list_free( items );
3268 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3269 addrbook.listSelected = NULL;
3270 gtk_ctree_remove_node( clist, node );
3271 addressbook_menubar_set_sensitive( FALSE );
3272 addressbook_menuitem_set_sensitive(
3273 gtk_ctree_node_get_row_data(
3274 GTK_CTREE(clist), addrbook.treeSelected ),
3275 addrbook.treeSelected );
3278 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3279 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3280 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3282 if( atci == NULL ) return;
3283 if( atciMail == NULL ) return;
3284 if( person == NULL ) return;
3285 /* unload the person */
3287 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3289 addressbook_folder_remove_node( clist, node );
3290 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3291 gtk_sctree_sort_node( clist, NULL );
3292 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3294 gtk_sctree_select( GTK_SCTREE(clist), node );
3295 if (!gtk_ctree_node_is_visible( clist, node ) )
3296 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3300 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3304 if( person == NULL ) return;
3305 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3306 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3308 addressbook_folder_remove_node( clist, node );
3312 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3314 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3316 /* Load any groups */
3317 if( ! atci ) return;
3318 items = addritem_folder_get_group_list( itemFolder );
3319 for( ; items != NULL; items = g_list_next( items ) ) {
3320 GtkCTreeNode *nodeGroup = NULL;
3321 gchar *text[N_LIST_COLS];
3322 ItemGroup *group = items->data;
3323 if( group == NULL ) continue;
3324 text[COL_NAME] = ADDRITEM_NAME(group);
3325 text[COL_ADDRESS] = "";
3326 text[COL_REMARKS] = "";
3327 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3328 text, FOLDER_SPACING,
3329 atci->iconXpm, atci->maskXpm,
3330 atci->iconXpmOpen, atci->maskXpmOpen,
3332 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3333 gtk_sctree_sort_node(clist, NULL);
3335 /* Free up the list */
3336 mgu_clear_list( items );
3337 g_list_free( items );
3341 * Search ctree widget callback function.
3342 * \param pA Pointer to node.
3343 * \param pB Pointer to data item being sought.
3344 * \return Zero (0) if group found.
3346 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3349 aoA = ( AddressObject * ) pA;
3350 if( aoA->type == ADDR_ITEM_GROUP ) {
3351 ItemGroup *group, *grp;
3353 grp = ADAPTER_GROUP(aoA)->itemGroup;
3354 group = ( ItemGroup * ) pB;
3355 if( grp == group ) return 0; /* Found group */
3361 * Search ctree widget callback function.
3362 * \param pA Pointer to node.
3363 * \param pB Pointer to data item being sought.
3364 * \return Zero (0) if folder found.
3366 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3369 aoA = ( AddressObject * ) pA;
3370 if( aoA->type == ADDR_ITEM_FOLDER ) {
3371 ItemFolder *folder, *fld;
3373 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3374 folder = ( ItemFolder * ) pB;
3375 if( fld == folder ) return 0; /* Found folder */
3381 * Remove folder and group nodes from tree widget for items contained ("cut")
3384 static void addressbook_treenode_remove_item( void ) {
3386 AddrSelectItem *cutItem;
3387 AddressCache *cache;
3388 AddrItemObject *aio;
3389 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3392 node = _clipBoard_->objectList;
3394 cutItem = node->data;
3395 node = g_list_next( node );
3396 cache = addrindex_get_cache(
3397 _clipBoard_->addressIndex, cutItem->cacheID );
3398 if( cache == NULL ) continue;
3399 aio = addrcache_get_object( cache, cutItem->uid );
3402 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3405 folder = ( ItemFolder * ) aio;
3406 tn = gtk_ctree_find_by_row_data_custom(
3407 ctree, NULL, folder,
3408 addressbook_treenode_find_folder_cb );
3410 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3413 group = ( ItemGroup * ) aio;
3414 tn = gtk_ctree_find_by_row_data_custom(
3416 addressbook_treenode_find_group_cb );
3420 /* Free up adapter and remove node. */
3421 gtk_ctree_remove_node( ctree, tn );
3428 * Find parent datasource for specified tree node.
3429 * \param node Node to test.
3430 * \return Data source, or NULL if not found.
3432 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3433 AddressDataSource *ds = NULL;
3436 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3439 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3440 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3442 /* printf( "ao->type = %d\n", ao->type ); */
3443 if( ao->type == ADDR_DATASOURCE ) {
3444 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3445 /* printf( "found it\n" ); */
3446 ds = ads->dataSource;
3450 node = GTK_CTREE_ROW(node)->parent;
3456 * Load address list widget with children of specified object.
3457 * \param obj Parent object to be loaded.
3459 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3460 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3461 GtkCList *clist = GTK_CLIST(addrbook.clist);
3462 AddressDataSource *ds = NULL;
3463 AdapterDSource *ads = NULL;
3464 static AddressObject *last_obj = NULL;
3466 if (addrbook.clist == NULL) {
3469 if (obj == last_obj && !refresh)
3474 gtk_clist_clear(clist);
3478 if( obj->type == ADDR_INTERFACE ) {
3479 /* printf( "set_clist: loading datasource...\n" ); */
3480 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3484 gtk_clist_freeze(clist);
3485 gtk_clist_clear(clist);
3487 if( obj->type == ADDR_DATASOURCE ) {
3488 ads = ADAPTER_DSOURCE(obj);
3489 ds = ADAPTER_DSOURCE(obj)->dataSource;
3491 /* Load root folder */
3492 ItemFolder *rootFolder = NULL;
3493 rootFolder = addrindex_ds_get_root_folder( ds );
3494 addressbook_folder_load_person(
3495 ctreelist, addrindex_ds_get_root_folder( ds ) );
3496 addressbook_folder_load_group(
3497 ctreelist, addrindex_ds_get_root_folder( ds ) );
3501 if( obj->type == ADDR_ITEM_GROUP ) {
3503 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3504 addressbook_load_group( ctreelist, itemGroup );
3506 else if( obj->type == ADDR_ITEM_FOLDER ) {
3508 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3509 addressbook_folder_load_person( ctreelist, itemFolder );
3510 addressbook_folder_load_group( ctreelist, itemFolder );
3513 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3514 clist->focus_row = -1;
3515 gtk_clist_thaw(clist);
3519 * Call back function to free adaptor. Call back is setup by function
3520 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3521 * called when the address book tree widget node is removed by calling
3522 * function gtk_ctree_remove_node().
3524 * \param data Tree node's row data.
3526 static void addressbook_free_treenode( gpointer data ) {
3529 ao = ( AddressObject * ) data;
3530 if( ao == NULL ) return;
3531 if( ao->type == ADDR_INTERFACE ) {
3532 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3533 addrbookctl_free_interface( ai );
3535 else if( ao->type == ADDR_DATASOURCE ) {
3536 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3537 addrbookctl_free_datasource( ads );
3539 else if( ao->type == ADDR_ITEM_FOLDER ) {
3540 AdapterFolder *af = ADAPTER_FOLDER(ao);
3541 addrbookctl_free_folder( af );
3543 else if( ao->type == ADDR_ITEM_GROUP ) {
3544 AdapterGroup *ag = ADAPTER_GROUP(ao);
3545 addrbookctl_free_group( ag );
3550 * Create new adaptor for specified data source.
3552 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3553 AddressObjectType otype, gchar *name )
3555 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3556 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3557 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3558 adapter->dataSource = ds;
3559 adapter->subType = otype;
3563 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3564 ADDRESS_OBJECT_NAME(adapter) =
3565 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3569 * Load tree from address index with the initial data.
3571 static void addressbook_load_tree( void ) {
3572 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3573 GList *nodeIf, *nodeDS;
3574 AdapterInterface *adapter;
3575 AddressInterface *iface;
3576 AddressTypeControlItem *atci;
3577 AddressDataSource *ds;
3578 AdapterDSource *ads;
3579 GtkCTreeNode *node, *newNode;
3582 nodeIf = _addressInterfaceList_;
3584 adapter = nodeIf->data;
3585 node = adapter->treeNode;
3586 iface = adapter->interface;
3587 atci = adapter->atci;
3589 if( iface->useInterface ) {
3590 /* Load data sources below interface node */
3591 nodeDS = iface->listSource;
3595 name = addrindex_ds_get_name( ds );
3596 ads = addressbook_create_ds_adapter(
3597 ds, atci->objectType, name );
3598 newNode = addressbook_add_object(
3599 node, ADDRESS_OBJECT(ads) );
3600 nodeDS = g_list_next( nodeDS );
3602 gtk_ctree_expand( ctree, node );
3605 nodeIf = g_list_next( nodeIf );
3610 * Convert the old address book to new format.
3612 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3613 gboolean retVal = FALSE;
3614 gboolean errFlag = TRUE;
3617 /* Read old address book, performing conversion */
3618 debug_print( "Reading and converting old address book...\n" );
3619 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3620 addrindex_read_data( addrIndex );
3621 if( addrIndex->retVal == MGU_NO_FILE ) {
3622 /* We do not have a file - new user */
3623 debug_print( "New user... create new books...\n" );
3624 addrindex_create_new_books( addrIndex );
3625 if( addrIndex->retVal == MGU_SUCCESS ) {
3626 /* Save index file */
3627 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3628 addrindex_save_data( addrIndex );
3629 if( addrIndex->retVal == MGU_SUCCESS ) {
3634 msg = _( "New user, could not save index file." );
3638 msg = _( "New user, could not save address book files." );
3642 /* We have an old file */
3643 if( addrIndex->wasConverted ) {
3644 /* Converted successfully - save address index */
3645 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3646 addrindex_save_data( addrIndex );
3647 if( addrIndex->retVal == MGU_SUCCESS ) {
3648 msg = _( "Old address book converted successfully." );
3653 msg = _("Old address book converted,\n"
3654 "could not save new address index file." );
3658 /* File conversion failed - just create new books */
3659 debug_print( "File conversion failed... just create new books...\n" );
3660 addrindex_create_new_books( addrIndex );
3661 if( addrIndex->retVal == MGU_SUCCESS ) {
3663 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3664 addrindex_save_data( addrIndex );
3665 if( addrIndex->retVal == MGU_SUCCESS ) {
3666 msg = _("Could not convert address book,\n"
3667 "but created empty new address book files." );
3672 msg = _("Could not convert address book,\n"
3673 "could not save new address index file." );
3677 msg = _("Could not convert address book\n"
3678 "and could not create new address book files." );
3683 debug_print( "Error\n%s\n", msg );
3684 alertpanel_full(_("Addressbook conversion error"), msg,
3685 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3686 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3689 debug_print( "Warning\n%s\n", msg );
3690 alertpanel_full(_("Addressbook conversion error"), msg,
3691 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3692 NULL, ALERT_WARNING, G_ALERTDEFAULT);
3698 void addressbook_read_file( void ) {
3699 AddressIndex *addrIndex = NULL;
3701 debug_print( "Reading address index...\n" );
3702 if( _addressIndex_ ) {
3703 debug_print( "address book already read!!!\n" );
3707 addrIndex = addrindex_create_index();
3708 addrindex_initialize();
3710 /* Use new address book index. */
3711 addrindex_set_file_path( addrIndex, get_rc_dir() );
3712 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3713 addrindex_read_data( addrIndex );
3714 if( addrIndex->retVal == MGU_NO_FILE ) {
3715 /* Conversion required */
3716 debug_print( "Converting...\n" );
3717 if( addressbook_convert( addrIndex ) ) {
3718 _addressIndex_ = addrIndex;
3721 else if( addrIndex->retVal == MGU_SUCCESS ) {
3722 _addressIndex_ = addrIndex;
3725 /* Error reading address book */
3726 debug_print( "Could not read address index.\n" );
3727 addrindex_print_index( addrIndex, stdout );
3728 alertpanel_full(_("Addressbook Error"),
3729 _("Could not read address index"),
3730 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3731 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3733 debug_print( "done.\n" );
3737 * Add object into the address index tree widget.
3738 * Enter: node Parent node.
3739 * obj Object to add.
3740 * Return: Node that was added, or NULL if object not added.
3742 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
3745 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3746 GtkCTreeNode *added;
3747 AddressObject *pobj;
3748 AddressObjectType otype;
3749 AddressTypeControlItem *atci = NULL;
3751 g_return_val_if_fail(node != NULL, NULL);
3752 g_return_val_if_fail(obj != NULL, NULL);
3754 pobj = gtk_ctree_node_get_row_data(ctree, node);
3755 g_return_val_if_fail(pobj != NULL, NULL);
3757 /* Determine object type to be displayed */
3758 if( obj->type == ADDR_DATASOURCE ) {
3759 otype = ADAPTER_DSOURCE(obj)->subType;
3765 /* Handle any special conditions. */
3767 atci = addrbookctl_lookup( otype );
3769 if( atci->showInTree ) {
3770 /* Add object to tree */
3773 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
3774 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
3775 atci->treeLeaf, atci->treeExpand );
3776 gtk_ctree_node_set_row_data_full( ctree, added, obj,
3777 addressbook_free_treenode );
3781 gtk_sctree_sort_node(ctree, node);
3787 * Add group into the address index tree.
3788 * \param node Parent node.
3789 * \param ds Data source.
3790 * \param itemGroup Group to add.
3791 * \return Inserted node.
3793 static GtkCTreeNode *addressbook_node_add_group(
3794 GtkCTreeNode *node, AddressDataSource *ds,
3795 ItemGroup *itemGroup )
3797 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3798 GtkCTreeNode *newNode;
3799 AdapterGroup *adapter;
3800 AddressTypeControlItem *atci = NULL;
3803 if( ds == NULL ) return NULL;
3804 if( node == NULL || itemGroup == NULL ) return NULL;
3806 name = &itemGroup->obj.name;
3808 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3810 adapter = g_new0( AdapterGroup, 1 );
3811 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
3812 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
3813 adapter->itemGroup = itemGroup;
3815 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
3816 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
3817 atci->treeLeaf, atci->treeExpand );
3818 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
3819 addressbook_free_treenode );
3820 gtk_sctree_sort_node( ctree, node );
3825 * Add folder into the address index tree. Only visible folders are loaded into
3826 * the address index tree. Note that the root folder is not inserted into the
3829 * \param node Parent node.
3830 * \param ds Data source.
3831 * \param itemFolder Folder to add.
3832 * \param otype Object type to display.
3833 * \return Inserted node for the folder.
3835 static GtkCTreeNode *addressbook_node_add_folder(
3836 GtkCTreeNode *node, AddressDataSource *ds,
3837 ItemFolder *itemFolder, AddressObjectType otype )
3839 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3840 GtkCTreeNode *newNode = NULL;
3841 AdapterFolder *adapter;
3842 AddressTypeControlItem *atci = NULL;
3843 GList *listItems = NULL;
3845 ItemFolder *rootFolder;
3847 /* Only visible folders */
3848 if( itemFolder->isHidden ) return NULL;
3850 if( ds == NULL ) return NULL;
3851 if( node == NULL || itemFolder == NULL ) return NULL;
3853 /* Determine object type */
3854 atci = addrbookctl_lookup( otype );
3855 if( atci == NULL ) return NULL;
3857 rootFolder = addrindex_ds_get_root_folder( ds );
3858 if( itemFolder == rootFolder ) {
3862 adapter = g_new0( AdapterFolder, 1 );
3863 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
3864 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
3865 adapter->itemFolder = itemFolder;
3867 name = ADDRITEM_NAME(itemFolder);
3868 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
3869 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
3870 atci->treeLeaf, atci->treeExpand );
3872 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
3873 addressbook_free_treenode );
3877 listItems = itemFolder->listFolder;
3878 while( listItems ) {
3879 ItemFolder *item = listItems->data;
3880 addressbook_node_add_folder( newNode, ds, item, otype );
3881 listItems = g_list_next( listItems );
3883 listItems = itemFolder->listGroup;
3884 while( listItems ) {
3885 ItemGroup *item = listItems->data;
3886 addressbook_node_add_group( newNode, ds, item );
3887 listItems = g_list_next( listItems );
3889 gtk_sctree_sort_node( ctree, node );
3893 void addressbook_export_to_file( void ) {
3894 if( _addressIndex_ ) {
3895 /* Save all new address book data */
3896 debug_print( "Saving address books...\n" );
3897 addrindex_save_all_books( _addressIndex_ );
3899 debug_print( "Exporting addressbook to file...\n" );
3900 addrindex_save_data( _addressIndex_ );
3901 if( _addressIndex_->retVal != MGU_SUCCESS ) {
3902 addrindex_print_index( _addressIndex_, stdout );
3905 /* Notify address completion of new data */
3906 invalidate_address_completion();
3910 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
3912 if (event && event->keyval == GDK_Return)
3913 addressbook_lup_clicked(NULL, NULL);
3918 * Comparison using cell contents (text in first column). Used for sort
3919 * address index widget.
3921 static gint addressbook_treenode_compare_func(
3922 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
3924 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
3925 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
3926 gchar *name1 = NULL, *name2 = NULL;
3927 if( cell1 ) name1 = cell1->u.text;
3928 if( cell2 ) name2 = cell2->u.text;
3929 if( ! name1 ) return ( name2 != NULL );
3930 if( ! name2 ) return -1;
3931 return g_utf8_collate( name1, name2 );
3934 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
3935 AdapterDSource *ads;
3936 AdapterInterface *adapter;
3937 GtkCTreeNode *newNode;
3939 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
3940 if( adapter == NULL ) return;
3941 ads = addressbook_edit_book( _addressIndex_, NULL );
3943 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
3945 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
3946 addrbook.treeSelected = newNode;
3951 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
3952 AdapterDSource *ads;
3953 AdapterInterface *adapter;
3954 GtkCTreeNode *newNode;
3956 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
3957 if( adapter == NULL ) return;
3958 ads = addressbook_edit_vcard( _addressIndex_, NULL );
3960 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
3962 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
3963 addrbook.treeSelected = newNode;
3969 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
3970 AdapterDSource *ads;
3971 AdapterInterface *adapter;
3972 AddressInterface *iface;
3973 GtkCTreeNode *newNode;
3975 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
3976 if( adapter == NULL ) return;
3977 iface = adapter->interface;
3978 if( ! iface->haveLibrary ) return;
3979 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
3981 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
3983 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
3984 addrbook.treeSelected = newNode;
3991 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
3992 AdapterDSource *ads;
3993 AdapterInterface *adapter;
3994 AddressInterface *iface;
3995 GtkCTreeNode *newNode;
3997 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
3998 if( adapter == NULL ) return;
3999 iface = adapter->interface;
4000 if( ! iface->haveLibrary ) return;
4001 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4003 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4005 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4006 addrbook.treeSelected = newNode;
4013 * Display address search status message.
4014 * \param queryType Query type.
4015 * \param status Status/Error code.
4017 static void addressbook_search_message( gint queryType, gint sts ) {
4019 *addressbook_msgbuf = '\0';
4021 if( sts != MGU_SUCCESS ) {
4022 if( queryType == ADDRQUERY_LDAP ) {
4024 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4029 g_snprintf( addressbook_msgbuf,
4030 sizeof(addressbook_msgbuf), "%s", desc );
4031 addressbook_status_show( addressbook_msgbuf );
4034 addressbook_status_show( "" );
4039 * Refresh addressbook by forcing refresh of current selected object in
4042 static void addressbook_refresh_current( void ) {
4046 ctree = GTK_CTREE(addrbook.ctree);
4047 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4048 if( obj == NULL ) return;
4049 addressbook_set_clist( obj, TRUE );
4053 * Message that is displayed whilst a query is executing in a background
4056 static gchar *_tempMessage_ = N_( "Busy searching..." );
4059 * Address search idle function. This function is called during UI idle time
4060 * while a search is in progress.
4062 * \param data Idler data.
4064 static void addressbook_search_idle( gpointer data ) {
4068 queryID = GPOINTER_TO_INT( data );
4069 printf( "addressbook_ldap_idle... queryID=%d\n", queryID );
4074 * Search completion callback function. This removes the query from the idle
4077 * \param sender Sender of query.
4078 * \param queryID Query ID of search request.
4079 * \param status Search status.
4080 * \param data Query data.
4082 static void addressbook_search_callback_end(
4083 gpointer sender, gint queryID, gint status, gpointer data )
4087 AddrQueryObject *aqo;
4089 /* Remove idler function */
4090 ptrQID = GINT_TO_POINTER( queryID );
4092 g_idle_remove_by_data( ptrQID );
4095 /* Refresh addressbook contents */
4096 addressbook_refresh_current();
4097 req = qrymgr_find_request( queryID );
4099 aqo = ( AddrQueryObject * ) req->queryList->data;
4100 addressbook_search_message( aqo->queryType, status );
4103 /* Stop the search */
4104 addrindex_stop_search( queryID );
4108 * Label (a format string) that is used to name each folder.
4110 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
4115 * \param ds Data source to search.
4116 * \param searchTerm String to lookup.
4117 * \param pNode Parent data source node.
4119 static void addressbook_perform_search(
4120 AddressDataSource *ds, gchar *searchTerm,
4121 GtkCTreeNode *pNode )
4123 AddrBookBase *adbase;
4124 AddressCache *cache;
4127 GtkCTreeNode *nNode;
4131 AddressObjectType aoType = ADDR_NONE;
4134 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4136 if( ds->type == ADDR_IF_LDAP ) {
4138 aoType = ADDR_LDAP_QUERY;
4145 /* Get reference to address cache */
4146 adbase = ( AddrBookBase * ) ds->rawDataSource;
4147 cache = adbase->addressCache;
4149 /* Create a folder for the search results */
4150 folder = addrcache_add_new_folder( cache, NULL );
4151 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4152 addritem_folder_set_name( folder, name );
4153 addritem_folder_set_remarks( folder, "" );
4156 /* Now let's see the folder */
4157 ctree = GTK_CTREE(addrbook.ctree);
4158 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
4159 gtk_ctree_expand( ctree, pNode );
4161 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
4162 addrbook.treeSelected = nNode;
4165 /* Setup the search */
4166 queryID = addrindex_setup_explicit_search(
4167 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4168 if( queryID == 0 ) return;
4170 /* Set up idler function */
4171 idleID = g_idle_add(
4172 ( GtkFunction ) addressbook_search_idle,
4173 GINT_TO_POINTER( queryID ) );
4175 /* Start search, sit back and wait for something to happen */
4176 addrindex_start_search( queryID );
4178 addressbook_status_show( _tempMessage_ );
4182 * Lookup button handler. Address search is only performed against
4183 * address interfaces for external queries.
4185 * \param button Lookup button widget.
4186 * \param data Data object.
4188 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4191 AddressDataSource *ds;
4192 AddressInterface *iface;
4194 GtkCTreeNode *node, *parentNode;
4196 node = addrbook.treeSelected;
4197 if( ! node ) return;
4198 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4200 ctree = GTK_CTREE(addrbook.ctree);
4201 obj = gtk_ctree_node_get_row_data( ctree, node );
4202 if( obj == NULL ) return;
4204 ds = addressbook_find_datasource( node );
4205 if( ds == NULL ) return;
4207 /* We must have a datasource that is an external interface */
4208 iface = ds->interface;
4209 if( ! iface->haveLibrary ) return;
4210 if( ! iface->externalQuery ) return;
4213 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4214 g_strchomp( searchTerm );
4216 if( obj->type == ADDR_ITEM_FOLDER ) {
4217 parentNode = GTK_CTREE_ROW(node)->parent;
4222 addressbook_perform_search( ds, searchTerm, parentNode );
4224 gtk_widget_grab_focus( addrbook.entry );
4226 g_free( searchTerm );
4229 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4230 addressbook_close();
4235 * Browse address entry for highlighted entry.
4237 static void addressbook_browse_entry_cb(void)
4239 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4241 AddressDataSource *ds;
4242 AddressInterface *iface;
4246 if(addrbook.listSelected == NULL)
4249 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4253 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4257 iface = ds->interface;
4258 if(! iface->haveLibrary )
4262 if (obj->type == ADDR_ITEM_EMAIL) {
4263 email = ( ItemEMail * ) obj;
4267 person = (ItemPerson *) ADDRITEM_PARENT(email);
4269 else if (obj->type == ADDR_ITEM_PERSON) {
4270 person = (ItemPerson *) obj;
4277 if( iface->type == ADDR_IF_LDAP ) {
4278 browseldap_entry(ds, person->externalID);
4283 /* **********************************************************************
4284 * Build lookup tables.
4285 * ***********************************************************************
4289 * Remap object types.
4290 * Enter: abType AddressObjectType (used in tree node).
4291 * Return: ItemObjectType (used in address cache data).
4293 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4294 ItemObjectType ioType;
4297 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4298 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4299 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4300 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4301 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4302 default: ioType = ITEMTYPE_NONE; break;
4308 * Build table that controls the rendering of object types.
4310 static void addrbookctl_build_map( GtkWidget *window ) {
4311 AddressTypeControlItem *atci;
4314 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4315 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4316 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4317 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4318 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4319 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4320 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4321 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4322 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4323 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4325 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4326 _addressBookTypeList_ = NULL;
4329 atci = g_new0( AddressTypeControlItem, 1 );
4330 atci->objectType = ADDR_INTERFACE;
4331 atci->interfaceType = ADDR_IF_NONE;
4332 atci->showInTree = TRUE;
4333 atci->treeExpand = TRUE;
4334 atci->treeLeaf = FALSE;
4335 atci->displayName = _( "Interface" );
4336 atci->iconXpm = folderxpm;
4337 atci->maskXpm = folderxpmmask;
4338 atci->iconXpmOpen = folderopenxpm;
4339 atci->maskXpmOpen = folderopenxpmmask;
4340 atci->menuCommand = NULL;
4341 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4342 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4345 atci = g_new0( AddressTypeControlItem, 1 );
4346 atci->objectType = ADDR_BOOK;
4347 atci->interfaceType = ADDR_IF_BOOK;
4348 atci->showInTree = TRUE;
4349 atci->treeExpand = TRUE;
4350 atci->treeLeaf = FALSE;
4351 atci->displayName = _( "Address Book" );
4352 atci->iconXpm = bookxpm;
4353 atci->maskXpm = bookxpmmask;
4354 atci->iconXpmOpen = bookxpm;
4355 atci->maskXpmOpen = bookxpmmask;
4356 atci->menuCommand = "/Book/New Book";
4357 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4358 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4361 atci = g_new0( AddressTypeControlItem, 1 );
4362 atci->objectType = ADDR_ITEM_PERSON;
4363 atci->interfaceType = ADDR_IF_NONE;
4364 atci->showInTree = FALSE;
4365 atci->treeExpand = FALSE;
4366 atci->treeLeaf = FALSE;
4367 atci->displayName = _( "Person" );
4368 atci->iconXpm = NULL;
4369 atci->maskXpm = NULL;
4370 atci->iconXpmOpen = NULL;
4371 atci->maskXpmOpen = NULL;
4372 atci->menuCommand = NULL;
4373 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4374 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4377 atci = g_new0( AddressTypeControlItem, 1 );
4378 atci->objectType = ADDR_ITEM_EMAIL;
4379 atci->interfaceType = ADDR_IF_NONE;
4380 atci->showInTree = FALSE;
4381 atci->treeExpand = FALSE;
4382 atci->treeLeaf = TRUE;
4383 atci->displayName = _( "EMail Address" );
4384 atci->iconXpm = addressxpm;
4385 atci->maskXpm = addressxpmmask;
4386 atci->iconXpmOpen = addressxpm;
4387 atci->maskXpmOpen = addressxpmmask;
4388 atci->menuCommand = NULL;
4389 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4390 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4393 atci = g_new0( AddressTypeControlItem, 1 );
4394 atci->objectType = ADDR_ITEM_GROUP;
4395 atci->interfaceType = ADDR_IF_BOOK;
4396 atci->showInTree = TRUE;
4397 atci->treeExpand = FALSE;
4398 atci->treeLeaf = FALSE;
4399 atci->displayName = _( "Group" );
4400 atci->iconXpm = groupxpm;
4401 atci->maskXpm = groupxpmmask;
4402 atci->iconXpmOpen = groupxpm;
4403 atci->maskXpmOpen = groupxpmmask;
4404 atci->menuCommand = NULL;
4405 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4406 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4409 atci = g_new0( AddressTypeControlItem, 1 );
4410 atci->objectType = ADDR_ITEM_FOLDER;
4411 atci->interfaceType = ADDR_IF_BOOK;
4412 atci->showInTree = TRUE;
4413 atci->treeExpand = FALSE;
4414 atci->treeLeaf = FALSE;
4415 atci->displayName = _( "Folder" );
4416 atci->iconXpm = folderxpm;
4417 atci->maskXpm = folderxpmmask;
4418 atci->iconXpmOpen = folderopenxpm;
4419 atci->maskXpmOpen = folderopenxpmmask;
4420 atci->menuCommand = NULL;
4421 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4422 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4425 atci = g_new0( AddressTypeControlItem, 1 );
4426 atci->objectType = ADDR_VCARD;
4427 atci->interfaceType = ADDR_IF_VCARD;
4428 atci->showInTree = TRUE;
4429 atci->treeExpand = TRUE;
4430 atci->treeLeaf = TRUE;
4431 atci->displayName = _( "vCard" );
4432 atci->iconXpm = vcardxpm;
4433 atci->maskXpm = vcardxpmmask;
4434 atci->iconXpmOpen = vcardxpm;
4435 atci->maskXpmOpen = vcardxpmmask;
4436 atci->menuCommand = "/Book/New vCard";
4437 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4438 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4441 atci = g_new0( AddressTypeControlItem, 1 );
4442 atci->objectType = ADDR_JPILOT;
4443 atci->interfaceType = ADDR_IF_JPILOT;
4444 atci->showInTree = TRUE;
4445 atci->treeExpand = TRUE;
4446 atci->treeLeaf = FALSE;
4447 atci->displayName = _( "JPilot" );
4448 atci->iconXpm = jpilotxpm;
4449 atci->maskXpm = jpilotxpmmask;
4450 atci->iconXpmOpen = jpilotxpm;
4451 atci->maskXpmOpen = jpilotxpmmask;
4452 atci->menuCommand = "/Book/New JPilot";
4453 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4454 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4457 atci = g_new0( AddressTypeControlItem, 1 );
4458 atci->objectType = ADDR_CATEGORY;
4459 atci->interfaceType = ADDR_IF_JPILOT;
4460 atci->showInTree = TRUE;
4461 atci->treeExpand = TRUE;
4462 atci->treeLeaf = TRUE;
4463 atci->displayName = _( "JPilot" );
4464 atci->iconXpm = categoryxpm;
4465 atci->maskXpm = categoryxpmmask;
4466 atci->iconXpmOpen = categoryxpm;
4467 atci->maskXpmOpen = categoryxpmmask;
4468 atci->menuCommand = NULL;
4469 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4470 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4473 atci = g_new0( AddressTypeControlItem, 1 );
4474 atci->objectType = ADDR_LDAP;
4475 atci->interfaceType = ADDR_IF_LDAP;
4476 atci->showInTree = TRUE;
4477 atci->treeExpand = TRUE;
4478 atci->treeLeaf = FALSE;
4479 atci->displayName = _( "LDAP servers" );
4480 atci->iconXpm = ldapxpm;
4481 atci->maskXpm = ldapxpmmask;
4482 atci->iconXpmOpen = ldapxpm;
4483 atci->maskXpmOpen = ldapxpmmask;
4484 atci->menuCommand = "/Book/New LDAP Server";
4485 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4486 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4489 atci = g_new0( AddressTypeControlItem, 1 );
4490 atci->objectType = ADDR_LDAP_QUERY;
4491 atci->interfaceType = ADDR_IF_LDAP;
4492 atci->showInTree = TRUE;
4493 atci->treeExpand = FALSE;
4494 atci->treeLeaf = TRUE;
4495 atci->displayName = _( "LDAP Query" );
4496 atci->iconXpm = addrsearchxpm;
4497 atci->maskXpm = addrsearchxpmmask;
4498 atci->iconXpmOpen = addrsearchxpm;
4499 atci->maskXpmOpen = addrsearchxpmmask;
4500 atci->menuCommand = NULL;
4501 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4502 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4507 * Search for specified object type.
4509 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4511 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4515 * Search for specified interface type.
4517 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4518 GList *node = _addressBookTypeList_;
4520 AddressTypeControlItem *atci = node->data;
4521 if( atci->interfaceType == ifType ) return atci;
4522 node = g_list_next( node );
4527 static void addrbookctl_free_address( AddressObject *obj ) {
4528 g_free( obj->name );
4529 obj->type = ADDR_NONE;
4533 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4534 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4535 adapter->interface = NULL;
4536 adapter->interfaceType = ADDR_IF_NONE;
4537 adapter->atci = NULL;
4538 adapter->enabled = FALSE;
4539 adapter->haveLibrary = FALSE;
4540 adapter->treeNode = NULL;
4544 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4545 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4546 adapter->dataSource = NULL;
4547 adapter->subType = ADDR_NONE;
4551 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4552 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4553 adapter->itemFolder = NULL;
4557 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4558 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4559 adapter->itemGroup = NULL;
4564 * Build GUI interface list.
4566 static void addrbookctl_build_iflist( void ) {
4567 AddressTypeControlItem *atci;
4568 AdapterInterface *adapter;
4571 if( _addressIndex_ == NULL ) {
4572 _addressIndex_ = addrindex_create_index();
4573 if( _clipBoard_ == NULL ) {
4574 _clipBoard_ = addrclip_create();
4576 addrclip_set_index( _clipBoard_, _addressIndex_ );
4578 _addressInterfaceList_ = NULL;
4579 list = addrindex_get_interface_list( _addressIndex_ );
4581 AddressInterface *interface = list->data;
4582 atci = addrbookctl_lookup_iface( interface->type );
4584 adapter = g_new0( AdapterInterface, 1 );
4585 adapter->interfaceType = interface->type;
4586 adapter->atci = atci;
4587 adapter->interface = interface;
4588 adapter->treeNode = NULL;
4589 adapter->enabled = TRUE;
4590 adapter->haveLibrary = interface->haveLibrary;
4591 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4592 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4593 _addressInterfaceList_ =
4594 g_list_append( _addressInterfaceList_, adapter );
4596 list = g_list_next( list );
4601 * Find GUI interface type specified interface type.
4602 * \param ifType Interface type.
4603 * \return Interface item, or NULL if not found.
4605 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4606 GList *node = _addressInterfaceList_;
4608 AdapterInterface *adapter = node->data;
4609 if( adapter->interfaceType == ifType ) return adapter;
4610 node = g_list_next( node );
4616 * Build interface list selection.
4618 static void addrbookctl_build_ifselect( void ) {
4619 GList *newList = NULL;
4624 gchar *endptr = NULL;
4626 AdapterInterface *adapter;
4628 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4631 splitStr = g_strsplit( selectStr, ",", -1 );
4632 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4634 /* printf( "%d : %s\n", i, splitStr[i] ); */
4635 ifType = strtol( splitStr[i], &endptr, 10 );
4638 if( strcmp( endptr, "/n" ) == 0 ) {
4642 /* printf( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4643 adapter = addrbookctl_find_interface( ifType );
4645 newList = g_list_append( newList, adapter );
4652 /* printf( "i=%d\n", i ); */
4653 g_strfreev( splitStr );
4654 g_free( selectStr );
4656 /* Replace existing list */
4657 mgu_clear_list( _addressIFaceSelection_ );
4658 g_list_free( _addressIFaceSelection_ );
4659 _addressIFaceSelection_ = newList;
4663 /* ***********************************************************************
4664 * Add sender to address book.
4665 * ***********************************************************************
4669 * This function is used by the Add sender to address book function.
4671 gboolean addressbook_add_contact(
4672 const gchar *name, const gchar *address, const gchar *remarks )
4674 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
4675 if( addressadd_selection( _addressIndex_, name, address, remarks ) ) {
4676 debug_print( "addressbook_add_contact - added\n" );
4677 addressbook_refresh();
4682 /* ***********************************************************************
4683 * Book/folder selection.
4684 * ***********************************************************************
4688 * This function is used by the matcher dialog to select a book/folder.
4690 gboolean addressbook_folder_selection( gchar **folderpath )
4692 AddressBookFile *book = NULL;
4693 ItemFolder *folder = NULL;
4696 g_return_val_if_fail( folderpath != NULL, FALSE);
4700 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, path )
4702 if ( folder != NULL) {
4704 gchar *oldtmp = NULL;
4705 AddrItemObject *obj = NULL;
4707 /* walk thru folder->parent to build the full folder path */
4708 /* TODO: wwp: optimize this */
4710 tmp = g_strdup(obj->uid);
4711 while ( obj->parent ) {
4713 if ( obj->name != NULL ) {
4714 oldtmp = g_strdup(tmp);
4716 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
4720 *folderpath = g_strdup_printf("%s/%s", book->fileName, tmp);
4723 *folderpath = g_strdup_printf("%s", book->fileName);
4725 debug_print( "addressbook_foldersel: %s\n", *folderpath);
4726 return (*folderpath != NULL);
4731 /* ***********************************************************************
4732 * Book/folder checking.
4733 * ***********************************************************************
4736 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
4738 FolderInfo *fi = g_new0( FolderInfo, 1 );
4740 fi->folder = folder;
4744 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
4745 FolderInfo *fiParent, FolderPathMatch *match )
4751 FolderPathMatch *nextmatch = NULL;
4756 list = parentFolder->listFolder;
4758 folder = list->data;
4759 fName = g_strdup( ADDRITEM_NAME(folder) );
4761 /* match folder name, match pointer will be set to NULL if next recursive call
4762 doesn't need to match subfolder name */
4763 if ( match != NULL &&
4764 match->matched == FALSE ) {
4765 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
4766 /* folder name matches, prepare next subfolder match */
4767 debug_print("matched folder name '%s'\n", fName);
4769 if ( match->folder_path[match->index] == NULL ) {
4770 /* we've matched all elements */
4771 match->matched = TRUE;
4772 match->folder = folder;
4773 debug_print("book/folder path matched!\n");
4775 /* keep on matching */
4783 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
4784 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
4786 list = g_list_next( list );
4791 * This function is used by to check if a matcher book/folder path corresponds to an
4792 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
4793 Caution: returned book and folder pointers can be NULL even when returning TRUE:
4794 if book AND folder are NULL this means that folderpath was empty or Any.
4795 If folderpath is a simple book name (without folder), book will not be NULL and folder
4796 will be NULL. It's not expected to return book as NULL and folder as non NULL.
4799 gboolean addressbook_peek_folder_exists( gchar *folderpath,
4800 AddressDataSource **book,
4801 ItemFolder **folder )
4803 AddressDataSource *ds;
4804 GList *list, *nodeDS;
4805 ItemFolder *rootFolder;
4806 AddressBookFile *abf;
4808 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
4815 if ( folderpath == NULL )
4818 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
4821 /* split the folder path we've received, we'll try to match this path, subpath by
4822 subpath against the book/folder structure in order */
4823 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
4824 if (!folder_path_match.folder_path)
4827 list = addrindex_get_interface_list( _addressIndex_ );
4828 while ( list && !folder_path_match.matched ) {
4829 AddressInterface *interface = list->data;
4830 if ( interface && interface->type == ADDR_IF_BOOK ) {
4831 nodeDS = interface->listSource;
4832 while ( nodeDS && !folder_path_match.matched ) {
4835 /* Read address book */
4836 if( ! addrindex_ds_get_read_flag( ds ) ) {
4837 addrindex_ds_read_data( ds );
4840 /* Add node for address book */
4841 abf = ds->rawDataSource;
4843 /* match book name */
4844 if ( abf && abf->fileName &&
4845 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
4847 debug_print("matched book name '%s'\n", abf->fileName);
4848 folder_path_match.book = ds;
4850 if ( folder_path_match.folder_path[1] == NULL ) {
4851 /* no folder part to match */
4853 folder_path_match.matched = TRUE;
4854 folder_path_match.folder = NULL;
4855 debug_print("book path matched!\n");
4858 /* match folder part */
4860 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
4861 rootFolder = addrindex_ds_get_root_folder( ds );
4863 /* prepare for recursive call */
4864 folder_path_match.index = 1;
4865 /* this call will set folder_path_match.matched and folder_path_match.folder */
4866 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
4871 nodeDS = g_list_next( nodeDS );
4874 list = g_list_next( list );
4877 g_strfreev( folder_path_match.folder_path );
4880 *book = folder_path_match.book;
4882 *folder = folder_path_match.folder;
4883 return folder_path_match.matched;
4887 /* **********************************************************************
4889 * ***********************************************************************
4895 static void addressbook_import_ldif_cb( void ) {
4896 AddressDataSource *ds = NULL;
4897 AdapterDSource *ads = NULL;
4898 AddressBookFile *abf = NULL;
4899 AdapterInterface *adapter;
4900 GtkCTreeNode *newNode;
4902 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4904 if( adapter->treeNode ) {
4905 abf = addressbook_imp_ldif( _addressIndex_ );
4907 ds = addrindex_index_add_datasource(
4908 _addressIndex_, ADDR_IF_BOOK, abf );
4909 ads = addressbook_create_ds_adapter(
4910 ds, ADDR_BOOK, NULL );
4911 addressbook_ads_set_name(
4912 ads, addrbook_get_name( abf ) );
4913 newNode = addressbook_add_object(
4915 ADDRESS_OBJECT(ads) );
4917 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
4919 addrbook.treeSelected = newNode;
4922 /* Notify address completion */
4923 invalidate_address_completion();
4932 static void addressbook_import_mutt_cb( void ) {
4933 AddressDataSource *ds = NULL;
4934 AdapterDSource *ads = NULL;
4935 AddressBookFile *abf = NULL;
4936 AdapterInterface *adapter;
4937 GtkCTreeNode *newNode;
4939 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4941 if( adapter->treeNode ) {
4942 abf = addressbook_imp_mutt( _addressIndex_ );
4944 ds = addrindex_index_add_datasource(
4945 _addressIndex_, ADDR_IF_BOOK, abf );
4946 ads = addressbook_create_ds_adapter(
4947 ds, ADDR_BOOK, NULL );
4948 addressbook_ads_set_name(
4949 ads, addrbook_get_name( abf ) );
4950 newNode = addressbook_add_object(
4952 ADDRESS_OBJECT(ads) );
4954 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
4956 addrbook.treeSelected = newNode;
4959 /* Notify address completion */
4960 invalidate_address_completion();
4969 static void addressbook_import_pine_cb( void ) {
4970 AddressDataSource *ds = NULL;
4971 AdapterDSource *ads = NULL;
4972 AddressBookFile *abf = NULL;
4973 AdapterInterface *adapter;
4974 GtkCTreeNode *newNode;
4976 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4978 if( adapter->treeNode ) {
4979 abf = addressbook_imp_pine( _addressIndex_ );
4981 ds = addrindex_index_add_datasource(
4982 _addressIndex_, ADDR_IF_BOOK, abf );
4983 ads = addressbook_create_ds_adapter(
4984 ds, ADDR_BOOK, NULL );
4985 addressbook_ads_set_name(
4986 ads, addrbook_get_name( abf ) );
4987 newNode = addressbook_add_object(
4989 ADDRESS_OBJECT(ads) );
4991 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
4993 addrbook.treeSelected = newNode;
4996 /* Notify address completion */
4997 invalidate_address_completion();
5004 * Harvest addresses.
5005 * \param folderItem Folder to import.
5006 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5007 * \param msgList List of message numbers, or NULL to process folder.
5009 void addressbook_harvest(
5010 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5012 AddressDataSource *ds = NULL;
5013 AdapterDSource *ads = NULL;
5014 AddressBookFile *abf = NULL;
5015 AdapterInterface *adapter;
5016 GtkCTreeNode *newNode;
5018 abf = addrgather_dlg_execute(
5019 folderItem, _addressIndex_, sourceInd, msgList );
5021 ds = addrindex_index_add_datasource(
5022 _addressIndex_, ADDR_IF_BOOK, abf );
5024 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5026 if( adapter->treeNode ) {
5027 ads = addressbook_create_ds_adapter(
5028 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5029 newNode = addressbook_add_object(
5031 ADDRESS_OBJECT(ads) );
5035 /* Notify address completion */
5036 invalidate_address_completion();
5043 static void addressbook_export_html_cb( void ) {
5044 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5046 AddressDataSource *ds = NULL;
5047 AddrBookBase *adbase;
5048 AddressCache *cache;
5049 GtkCTreeNode *node = NULL;
5051 if( ! addrbook.treeSelected ) return;
5052 node = addrbook.treeSelected;
5053 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5054 obj = gtk_ctree_node_get_row_data( ctree, node );
5055 if( obj == NULL ) return;
5057 ds = addressbook_find_datasource( node );
5058 if( ds == NULL ) return;
5059 adbase = ( AddrBookBase * ) ds->rawDataSource;
5060 cache = adbase->addressCache;
5061 addressbook_exp_html( cache );
5067 static void addressbook_export_ldif_cb( void ) {
5068 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5070 AddressDataSource *ds = NULL;
5071 AddrBookBase *adbase;
5072 AddressCache *cache;
5073 GtkCTreeNode *node = NULL;
5075 if( ! addrbook.treeSelected ) return;
5076 node = addrbook.treeSelected;
5077 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5078 obj = gtk_ctree_node_get_row_data( ctree, node );
5079 if( obj == NULL ) return;
5081 ds = addressbook_find_datasource( node );
5082 if( ds == NULL ) return;
5083 adbase = ( AddrBookBase * ) ds->rawDataSource;
5084 cache = adbase->addressCache;
5085 addressbook_exp_ldif( cache );
5088 static void addressbook_start_drag(GtkWidget *widget, gint button,
5092 GdkDragContext *context;
5093 if (addressbook_target_list == NULL)
5094 addressbook_target_list = gtk_target_list_new(
5095 addressbook_drag_types, 1);
5096 context = gtk_drag_begin(widget, addressbook_target_list,
5097 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5098 gtk_drag_set_icon_default(context);
5101 static void addressbook_drag_data_get(GtkWidget *widget,
5102 GdkDragContext *drag_context,
5103 GtkSelectionData *selection_data,
5108 AddrItemObject *aio = NULL;
5109 AddressObject *pobj = NULL;
5110 AdapterDSource *ads = NULL;
5111 AddressDataSource *ds = NULL;
5114 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5116 if( pobj == NULL ) return;
5118 if( pobj->type == ADDR_DATASOURCE ) {
5119 ads = ADAPTER_DSOURCE(pobj);
5120 ds = ads->dataSource;
5121 } else if (pobj->type == ADDR_ITEM_GROUP) {
5126 else if( pobj->type != ADDR_INTERFACE ) {
5127 ds = addressbook_find_datasource( addrbook.treeSelected );
5133 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5134 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5135 GTK_CTREE_NODE(cur->data));
5136 while (aio && aio->type != ADDR_ITEM_PERSON) {
5141 if (aio && aio->type == ADDR_ITEM_PERSON) {
5142 if( ds && ds->interface && ds->interface->readOnly)
5143 gtk_selection_data_set(selection_data,
5144 selection_data->target, 8,
5145 "Dummy_addr_copy", 15);
5147 gtk_selection_data_set(selection_data,
5148 selection_data->target, 8,
5149 "Dummy_addr_move", 15);
5153 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5154 GdkDragContext *context,
5161 GtkCTreeNode *node = NULL;
5162 gboolean acceptable = FALSE;
5163 gint height = addrbook.ctree->allocation.height;
5164 gint total_height = addrbook.ctree->requisition.height;
5165 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5166 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5167 gfloat vpos = pos->value;
5169 if (gtk_clist_get_selection_info
5170 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5172 if (y > height - 24 && height + vpos < total_height)
5173 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5175 if (y < 24 && y > 0)
5176 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5178 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5181 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5182 if( obj->type == ADDR_ITEM_FOLDER
5183 || obj->type == ADDR_ITEM_GROUP)
5186 AdapterDSource *ads = NULL;
5187 AddressDataSource *ds = NULL;
5188 ads = ADAPTER_DSOURCE(obj);
5189 if (ads == NULL ){ return FALSE;}
5190 ds = ads->dataSource;
5191 if (ds == NULL ) { return FALSE;}
5199 g_signal_handlers_block_by_func
5201 G_CALLBACK(addressbook_tree_selected), NULL);
5202 gtk_sctree_select( GTK_SCTREE(widget), node);
5203 g_signal_handlers_unblock_by_func
5205 G_CALLBACK(addressbook_tree_selected), NULL);
5206 gdk_drag_status(context,
5207 (context->actions == GDK_ACTION_COPY ?
5208 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5210 gdk_drag_status(context, 0, time);
5216 static void addressbook_drag_leave_cb(GtkWidget *widget,
5217 GdkDragContext *context,
5221 if (addrbook.treeSelected) {
5222 g_signal_handlers_block_by_func
5224 G_CALLBACK(addressbook_tree_selected), NULL);
5225 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5226 g_signal_handlers_unblock_by_func
5228 G_CALLBACK(addressbook_tree_selected), NULL);
5233 static void addressbook_drag_received_cb(GtkWidget *widget,
5234 GdkDragContext *drag_context,
5237 GtkSelectionData *data,
5244 GtkCTreeNode *lastopened = addrbook.opened;
5246 if (!strncmp(data->data, "Dummy_addr", 10)) {
5247 if (gtk_clist_get_selection_info
5248 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5252 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5253 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5256 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5257 if (drag_context->action == GDK_ACTION_COPY ||
5258 !strcmp(data->data, "Dummy_addr_copy"))
5259 addressbook_clip_copy_cb();
5261 addressbook_clip_cut_cb();
5262 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5263 addressbook_clip_paste_cb();
5264 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5265 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5266 gtk_drag_finish(drag_context, TRUE, TRUE, time);