2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtkwindow.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkscrolledwindow.h>
33 #include <gtk/gtkhpaned.h>
34 #include <gtk/gtkhbox.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtkentry.h>
37 #include <gtk/gtkctree.h>
38 #include <gtk/gtkclist.h>
39 #include <gtk/gtktable.h>
40 #include <gtk/gtkhbbox.h>
41 #include <gtk/gtkbutton.h>
42 #include <gtk/gtkmenu.h>
43 #include <gtk/gtkmenuitem.h>
44 #include <gtk/gtkitemfactory.h>
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"
92 #include "ldapupdate.h"
94 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
97 #include "addrquery.h"
98 #include "addrselect.h"
100 #include "addrgather.h"
101 #include "adbookbase.h"
102 #include "exphtmldlg.h"
103 #include "expldifdlg.h"
104 #include "browseldap.h"
110 } AddressIndexColumns;
118 } AddressListColumns;
121 AddressBookFile *book;
129 AddressDataSource *book;
133 static gchar *list_titles[] = { N_("Name"),
137 #define COL_NAME_WIDTH 164
138 #define COL_ADDRESS_WIDTH 156
140 #define COL_FOLDER_WIDTH 170
141 #define ADDRESSBOOK_WIDTH 640
142 #define ADDRESSBOOK_HEIGHT 360
144 #define ADDRESSBOOK_MSGBUF_SIZE 2048
146 static GdkPixmap *folderxpm;
147 static GdkBitmap *folderxpmmask;
148 static GdkPixmap *folderopenxpm;
149 static GdkBitmap *folderopenxpmmask;
150 static GdkPixmap *groupxpm;
151 static GdkBitmap *groupxpmmask;
152 static GdkPixmap *interfacexpm;
153 static GdkBitmap *interfacexpmmask;
154 static GdkPixmap *bookxpm;
155 static GdkBitmap *bookxpmmask;
156 static GdkPixmap *addressxpm;
157 static GdkBitmap *addressxpmmask;
158 static GdkPixmap *vcardxpm;
159 static GdkBitmap *vcardxpmmask;
160 static GdkPixmap *jpilotxpm;
161 static GdkBitmap *jpilotxpmmask;
162 static GdkPixmap *categoryxpm;
163 static GdkBitmap *categoryxpmmask;
164 static GdkPixmap *ldapxpm;
165 static GdkBitmap *ldapxpmmask;
166 static GdkPixmap *addrsearchxpm;
167 static GdkPixmap *addrsearchxpmmask;
170 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
172 /* Address list selection */
173 static AddrSelectList *_addressSelect_ = NULL;
174 static AddressClipboard *_clipBoard_ = NULL;
176 /* Address index file and interfaces */
177 static AddressIndex *_addressIndex_ = NULL;
178 static GList *_addressInterfaceList_ = NULL;
179 static GList *_addressIFaceSelection_ = NULL;
180 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
182 static AddressBook_win addrbook;
184 static GHashTable *_addressBookTypeHash_ = NULL;
185 static GList *_addressBookTypeList_ = NULL;
187 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
188 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
189 static void addressbook_edit_address_post_cb( ItemPerson *person );
191 static void addressbook_create (void);
192 static gint addressbook_close (void);
193 static void addressbook_button_set_sensitive (void);
195 static gboolean address_index_has_focus = FALSE;
196 static gboolean address_list_has_focus = FALSE;
198 /* callback functions */
199 static void addressbook_del_clicked (GtkButton *button,
201 static void addressbook_reg_clicked (GtkButton *button,
203 static void addressbook_to_clicked (GtkButton *button,
205 static void addressbook_lup_clicked (GtkButton *button,
207 static void addressbook_close_clicked (GtkButton *button,
210 static void addressbook_tree_selected (GtkCTree *ctree,
214 static void addressbook_select_row_tree (GtkCTree *ctree,
218 static void addressbook_list_row_selected (GtkCTree *clist,
222 static void addressbook_list_row_unselected (GtkCTree *clist,
226 static void addressbook_person_expand_node (GtkCTree *ctree,
229 static void addressbook_person_collapse_node (GtkCTree *ctree,
233 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
234 GdkEventButton *event,
236 static gboolean addressbook_list_button_released(GtkWidget *widget,
237 GdkEventButton *event,
239 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
240 GdkEventButton *event,
242 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
243 GdkEventButton *event,
246 static void addressbook_new_folder_cb (gpointer data,
249 static void addressbook_new_group_cb (gpointer data,
252 static void addressbook_treenode_edit_cb (gpointer data,
255 static void addressbook_treenode_delete_cb (gpointer data,
259 static void addressbook_change_node_name (GtkCTreeNode *node,
262 static void addressbook_new_address_cb (gpointer data,
265 static void addressbook_edit_address_cb (gpointer data,
268 static void addressbook_delete_address_cb (gpointer data,
272 static void close_cb (gpointer data,
275 static void addressbook_file_save_cb (gpointer data,
279 /* Data source edit stuff */
280 static void addressbook_new_book_cb (gpointer data,
283 static void addressbook_new_vcard_cb (gpointer data,
288 static void addressbook_new_jpilot_cb (gpointer data,
294 static void addressbook_new_ldap_cb (gpointer data,
299 static void addressbook_set_clist (AddressObject *obj,
302 static void addressbook_load_tree (void);
303 void addressbook_read_file (void);
305 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
307 static void addressbook_treenode_remove_item ( void );
309 static AddressDataSource *addressbook_find_datasource
310 (GtkCTreeNode *node );
312 static AddressBookFile *addressbook_get_book_file(void);
314 static GtkCTreeNode *addressbook_node_add_folder
316 AddressDataSource *ds,
317 ItemFolder *itemFolder,
318 AddressObjectType otype);
319 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
320 AddressDataSource *ds,
321 ItemGroup *itemGroup);
322 static void addressbook_tree_remove_children (GtkCTree *ctree,
323 GtkCTreeNode *parent);
324 static void addressbook_move_nodes_up (GtkCTree *ctree,
326 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
328 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
331 static gint addressbook_treenode_compare_func (GtkCList *clist,
334 static void addressbook_folder_load_one_person (GtkCTree *clist,
336 AddressTypeControlItem *atci,
337 AddressTypeControlItem *atciMail);
338 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
340 static void addressbook_folder_remove_one_person(GtkCTree *clist,
342 static void addressbook_folder_remove_node (GtkCTree *clist,
345 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
346 gboolean force_focus );
348 /* LUT's and IF stuff */
349 static void addressbook_free_treenode ( gpointer data );
350 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
351 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
353 static void addrbookctl_build_map (GtkWidget *window);
354 static void addrbookctl_build_iflist (void);
355 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
356 static void addrbookctl_build_ifselect (void);
358 static void addrbookctl_free_interface (AdapterInterface *adapter);
359 static void addrbookctl_free_datasource (AdapterDSource *adapter);
360 static void addrbookctl_free_folder (AdapterFolder *adapter);
361 static void addrbookctl_free_group (AdapterGroup *adapter);
363 static void addressbook_list_select_clear ( void );
364 static void addressbook_list_select_add ( AddrItemObject *aio,
365 AddressDataSource *ds );
366 static void addressbook_list_select_remove ( AddrItemObject *aio );
368 static void addressbook_import_ldif_cb ( void );
369 static void addressbook_import_mutt_cb ( void );
370 static void addressbook_import_pine_cb ( void );
371 static void addressbook_export_html_cb ( void );
372 static void addressbook_export_ldif_cb ( void );
373 static void addressbook_select_all_cb ( void );
374 static void addressbook_clip_cut_cb ( void );
375 static void addressbook_clip_copy_cb ( void );
376 static void addressbook_clip_paste_cb ( void );
377 static void addressbook_treenode_cut_cb ( void );
378 static void addressbook_treenode_copy_cb ( void );
379 static void addressbook_treenode_paste_cb ( void );
381 static void addressbook_mail_to_cb ( void );
384 static void addressbook_browse_entry_cb ( void );
386 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
388 static void addressbook_start_drag(GtkWidget *widget, gint button,
391 static void addressbook_drag_data_get(GtkWidget *widget,
392 GdkDragContext *drag_context,
393 GtkSelectionData *selection_data,
397 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
398 GdkDragContext *context,
403 static void addressbook_drag_leave_cb(GtkWidget *widget,
404 GdkDragContext *context,
407 static void addressbook_drag_received_cb(GtkWidget *widget,
408 GdkDragContext *drag_context,
411 GtkSelectionData *data,
415 static void addressbook_list_menu_setup( void );
417 static GtkTargetEntry addressbook_drag_types[] =
419 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
422 static GtkTargetList *addressbook_target_list = NULL;
425 static GtkItemFactoryEntry addressbook_entries[] =
427 {N_("/_Book"), NULL, NULL, 0, "<Branch>"},
428 {N_("/_Book/New _Book"), "<control>B", addressbook_new_book_cb, 0, NULL},
429 {N_("/_Book/New _Folder"), "<control>R", addressbook_new_folder_cb, 0, NULL},
430 {N_("/_Book/New _vCard"), "<control><shift>D", addressbook_new_vcard_cb, 0, NULL},
432 {N_("/_Book/New _JPilot"), "<control>J", addressbook_new_jpilot_cb, 0, NULL},
435 {N_("/_Book/New LDAP _Server"), "<control><shift>S", addressbook_new_ldap_cb, 0, NULL},
437 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
438 {N_("/_Book/_Edit book"), NULL, addressbook_treenode_edit_cb, 0, NULL},
439 {N_("/_Book/_Delete book"), NULL, addressbook_treenode_delete_cb, 0, NULL},
440 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>"},
441 {N_("/_Book/_Save"), "<control>S", addressbook_file_save_cb, 0, NULL},
442 {N_("/_Book/_Close"), "<control>W", close_cb, 0, NULL},
443 {N_("/_Address"), NULL, NULL, 0, "<Branch>"},
444 {N_("/_Address/_Select all"), "<control>A", addressbook_select_all_cb, 0, NULL},
445 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
446 {N_("/_Address/C_ut"), "<control>X", addressbook_clip_cut_cb, 0, NULL},
447 {N_("/_Address/_Copy"), "<control>C", addressbook_clip_copy_cb, 0, NULL},
448 {N_("/_Address/_Paste"), "<control>V", addressbook_clip_paste_cb, 0, NULL},
449 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
450 {N_("/_Address/_Edit"), "<control>Return",addressbook_edit_address_cb, 0, NULL},
451 {N_("/_Address/_Delete"), "<control>D", addressbook_delete_address_cb, 0, NULL},
452 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
453 {N_("/_Address/New _Address"), "<control>N", addressbook_new_address_cb, 0, NULL},
454 {N_("/_Address/New _Group"), "<control>G", addressbook_new_group_cb, 0, NULL},
455 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>"},
456 {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
457 {N_("/_Tools"), NULL, NULL, 0, "<Branch>"},
458 {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL},
459 {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL},
460 {N_("/_Tools/Import _Pine file..."), NULL, addressbook_import_pine_cb, 0, NULL},
461 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>"},
462 {N_("/_Tools/Export _HTML..."), NULL, addressbook_export_html_cb, 0, NULL},
463 {N_("/_Tools/Export LDI_F..."), NULL, addressbook_export_ldif_cb, 0, NULL},
464 {N_("/_Help"), NULL, NULL, 0, "<Branch>"},
465 {N_("/_Help/_About"), NULL, about_show, 0, NULL}
468 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
470 {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL},
471 {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL},
472 {"/---", NULL, NULL, 0, "<Separator>"},
473 {N_("/New _Book"), NULL, addressbook_new_book_cb, 0, NULL},
474 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL},
475 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
476 {"/---", NULL, NULL, 0, "<Separator>"},
477 {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL},
478 {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL},
479 {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL}
482 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
484 {N_("/_Select all"), NULL, addressbook_select_all_cb, 0, NULL},
485 {"/---", NULL, NULL, 0, "<Separator>"},
486 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL},
487 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL},
488 {"/---", NULL, NULL, 0, "<Separator>"},
489 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL},
490 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
491 {"/---", NULL, NULL, 0, "<Separator>"},
492 {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL},
493 {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL},
494 {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL},
495 {"/---", NULL, NULL, 0, "<Separator>"},
496 /* {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL},*/
497 {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL},
499 {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL},
504 * Structure of error message table.
506 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
507 struct _ErrMsgTableEntry {
512 static gchar *_errMsgUnknown_ = N_( "Unknown" );
515 * Lookup table of error messages for general errors. Note that a NULL
516 * description signifies the end of the table.
518 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
519 { MGU_SUCCESS, N_("Success") },
520 { MGU_BAD_ARGS, N_("Bad arguments") },
521 { MGU_NO_FILE, N_("File not specified") },
522 { MGU_OPEN_FILE, N_("Error opening file") },
523 { MGU_ERROR_READ, N_("Error reading file") },
524 { MGU_EOF, N_("End of file encountered") },
525 { MGU_OO_MEMORY, N_("Error allocating memory") },
526 { MGU_BAD_FORMAT, N_("Bad file format") },
527 { MGU_ERROR_WRITE, N_("Error writing to file") },
528 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
529 { MGU_NO_PATH, N_("No path specified") },
535 * Lookup table of error messages for LDAP errors.
537 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
538 { LDAPRC_SUCCESS, N_("Success") },
539 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
540 { LDAPRC_INIT, N_("Error initializing LDAP") },
541 { LDAPRC_BIND, N_("Error binding to LDAP server") },
542 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
543 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
544 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
545 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
546 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
547 { LDAPRC_TLS, N_("Error starting TLS connection") },
548 { LDAPRC_NODN, N_("Distinguised Name (dn) is missing") },
549 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
550 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
551 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
557 * Lookup message for specified error code.
558 * \param lut Lookup table.
559 * \param code Code to lookup.
560 * \return Description associated to code.
562 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
564 ErrMsgTableEntry entry;
567 for( i = 0; ; i++ ) {
569 if( entry.description == NULL ) break;
570 if( entry.code == code ) {
571 desc = entry.description;
576 desc = _errMsgUnknown_;
581 static gboolean lastCanLookup = FALSE;
583 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
585 if (add_and_delete) {
586 gtk_widget_show(addrbook.edit_btn);
587 gtk_widget_show(addrbook.del_btn);
588 gtk_widget_show(addrbook.reg_btn);
590 gtk_widget_hide(addrbook.edit_btn);
591 gtk_widget_hide(addrbook.del_btn);
592 gtk_widget_hide(addrbook.reg_btn);
596 gtk_widget_show(addrbook.lup_btn);
597 gtk_widget_show(addrbook.entry);
598 gtk_widget_show(addrbook.label);
600 gtk_widget_hide(addrbook.lup_btn);
601 gtk_widget_hide(addrbook.entry);
602 gtk_widget_hide(addrbook.label);
605 lastCanLookup = lookup;
608 gtk_widget_show(addrbook.to_btn);
609 gtk_widget_show(addrbook.cc_btn);
610 gtk_widget_show(addrbook.bcc_btn);
612 gtk_widget_hide(addrbook.to_btn);
613 gtk_widget_hide(addrbook.cc_btn);
614 gtk_widget_hide(addrbook.bcc_btn);
618 void addressbook_open(Compose *target)
620 /* Initialize all static members */
621 if( _clipBoard_ == NULL ) {
622 _clipBoard_ = addrclip_create();
624 if( _addressIndex_ != NULL ) {
625 addrclip_set_index( _clipBoard_, _addressIndex_ );
627 if( _addressSelect_ == NULL ) {
628 _addressSelect_ = addrselect_list_create();
630 if (!addrbook.window) {
631 addressbook_read_file();
632 addressbook_create();
633 addressbook_load_tree();
634 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
635 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
638 gtk_widget_hide(addrbook.window);
641 gtk_widget_show_all(addrbook.window);
643 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
644 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
646 if (!prefs_common.addressbook_use_editaddress_dialog)
647 addressbook_edit_person_widgetset_hide();
649 address_completion_start(addrbook.window);
651 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
652 addressbook_set_target_compose(target);
656 * Destroy addressbook.
658 void addressbook_destroy( void ) {
659 /* Free up address stuff */
660 if( _addressSelect_ != NULL ) {
661 addrselect_list_free( _addressSelect_ );
663 if( _clipBoard_ != NULL ) {
664 addrclip_free( _clipBoard_ );
666 if( _addressIndex_ != NULL ) {
667 addrindex_free_index( _addressIndex_ );
668 addrindex_teardown();
670 _addressSelect_ = NULL;
672 _addressIndex_ = NULL;
675 void addressbook_set_target_compose(Compose *target)
677 addrbook.target_compose = target;
678 addressbook_button_set_sensitive();
681 Compose *addressbook_get_target_compose(void)
683 return addrbook.target_compose;
687 * Refresh addressbook and save to file(s).
689 static void addressbook_refresh( void )
691 if (addrbook.window) {
692 if (addrbook.treeSelected) {
693 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
694 addrbook.treeSelected);
695 addressbook_set_clist(
696 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
697 addrbook.treeSelected),
702 addressbook_export_to_file();
705 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
707 if (event && event->keyval == GDK_Escape)
709 else if (event && event->keyval == GDK_Delete) {
710 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
711 if ( /* address_index_has_focus || */ address_list_has_focus )
712 addressbook_del_clicked(NULL, NULL);
718 *\brief Save Gtk object size to prefs dataset
720 static void addressbook_size_allocate_cb(GtkWidget *widget,
721 GtkAllocation *allocation)
723 g_return_if_fail(allocation != NULL);
725 prefs_common.addressbookwin_width = allocation->width;
726 prefs_common.addressbookwin_height = allocation->height;
729 static gint sort_column_number = 0;
730 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
732 static gint list_case_sort(
733 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
735 GtkCListRow *row1 = (GtkCListRow *) ptr1;
736 GtkCListRow *row2 = (GtkCListRow *) ptr2;
737 gchar *name1 = NULL, *name2 = NULL;
738 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
739 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
741 if( aio1->type == aio2->type ) {
743 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
745 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
746 if( ! name1 ) return ( name2 != NULL );
747 if( ! name2 ) return -1;
748 return strcasecmp( name1, name2 );
750 /* Order groups before person */
751 if( aio1->type == ITEMTYPE_GROUP ) {
752 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
753 } else if( aio2->type == ITEMTYPE_GROUP ) {
754 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
760 static void addressbook_sort_list(GtkCList *clist, const gint col,
761 const GtkSortType sort_type)
764 GtkWidget *hbox, *label, *arrow;
766 sort_column_number = col;
767 sort_column_type = sort_type;
768 gtk_clist_set_compare_func(clist, list_case_sort);
769 gtk_clist_set_sort_type(clist, sort_type);
770 gtk_clist_set_sort_column(clist, col);
772 gtk_clist_freeze(clist);
773 gtk_clist_sort(clist);
775 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
776 hbox = gtk_hbox_new(FALSE, 4);
777 label = gtk_label_new(gettext(list_titles[pos]));
778 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
781 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
782 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
783 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
786 gtk_widget_show_all(hbox);
787 gtk_clist_set_column_widget(clist, pos, hbox);
790 gtk_clist_thaw(clist);
793 static void addressbook_name_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_NAME, sort_type);
802 static void addressbook_address_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_ADDRESS, sort_type);
811 static void addressbook_remarks_clicked(GtkWidget *button, GtkCList *clist)
813 static GtkSortType sort_type = GTK_SORT_ASCENDING;
815 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
817 addressbook_sort_list(clist, COL_REMARKS, sort_type);
820 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
823 address_index_has_focus = TRUE;
827 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
830 address_index_has_focus = FALSE;
831 if (!prefs_common.addressbook_use_editaddress_dialog
832 && !address_list_has_focus)
833 addressbook_address_list_disable_some_actions();
837 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
840 address_list_has_focus = TRUE;
844 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
847 address_list_has_focus = FALSE;
848 if (!prefs_common.addressbook_use_editaddress_dialog
849 && !address_index_has_focus)
850 addressbook_address_list_disable_some_actions();
854 /* save hpane and vpane's handle position when it moves */
855 static void addressbook_pane_save_position(void)
858 prefs_common.addressbook_hpaned_pos =
859 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
861 prefs_common.addressbook_vpaned_pos =
862 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
866 * Create the address book widgets. The address book contains two CTree widgets: the
867 * address index tree on the left and the address list on the right.
869 * The address index tree displays a hierarchy of interfaces and groups. Each node in
870 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
871 * data sources and folder objects.
873 * The address list displays group, person and email objects. These items are linked
874 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
877 * In the tradition of MVC architecture, the data stores have been separated from the
878 * GUI components. The addrindex.c file provides the interface to all data stores.
880 static void addressbook_create(void)
886 GtkWidget *ctree_swin;
888 GtkWidget *editaddress_vbox;
889 GtkWidget *clist_vbox;
890 GtkWidget *clist_swin;
897 GtkWidget *statusbar;
908 GtkWidget *close_btn;
909 GtkWidget *tree_popup;
910 GtkWidget *list_popup;
911 GtkItemFactory *tree_factory;
912 GtkItemFactory *list_factory;
913 GtkItemFactory *menu_factory;
917 gchar *index_titles[N_INDEX_COLS];
921 static GdkGeometry geometry;
923 debug_print("Creating addressbook window...\n");
925 index_titles[COL_SOURCES] = _("Sources");
927 /* Address book window */
928 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
929 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
930 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
931 gtk_widget_realize(window);
933 g_signal_connect(G_OBJECT(window), "delete_event",
934 G_CALLBACK(addressbook_close), NULL);
935 g_signal_connect(G_OBJECT(window), "size_allocate",
936 G_CALLBACK(addressbook_size_allocate_cb), NULL);
937 g_signal_connect(G_OBJECT(window), "key_press_event",
938 G_CALLBACK(key_pressed), NULL);
939 MANAGE_WINDOW_SIGNALS_CONNECT(window);
941 vbox = gtk_vbox_new(FALSE, 0);
942 gtk_container_add(GTK_CONTAINER(window), vbox);
945 n_entries = sizeof(addressbook_entries) /
946 sizeof(addressbook_entries[0]);
947 menubar = menubar_create(window, addressbook_entries, n_entries,
948 "<AddressBook>", NULL);
949 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
950 menu_factory = gtk_item_factory_from_widget(menubar);
952 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
953 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
954 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
956 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
957 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
958 GTK_POLICY_AUTOMATIC,
959 GTK_POLICY_AUTOMATIC);
960 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
963 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
964 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
965 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
966 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
967 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
968 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
969 GTK_CTREE_EXPANDER_SQUARE);
970 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
971 gtk_clist_set_compare_func(GTK_CLIST(ctree),
972 addressbook_treenode_compare_func);
974 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
975 G_CALLBACK(addressbook_tree_selected), NULL);
976 g_signal_connect(G_OBJECT(ctree), "button_press_event",
977 G_CALLBACK(addressbook_tree_button_pressed),
979 g_signal_connect(G_OBJECT(ctree), "button_release_event",
980 G_CALLBACK(addressbook_tree_button_released),
983 g_signal_connect(G_OBJECT(ctree), "select_row",
984 G_CALLBACK(addressbook_select_row_tree), NULL);
986 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
987 addressbook_drag_types, 1,
988 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
989 g_signal_connect(G_OBJECT(ctree), "drag_motion",
990 G_CALLBACK(addressbook_drag_motion_cb),
992 g_signal_connect(G_OBJECT(ctree), "drag_leave",
993 G_CALLBACK(addressbook_drag_leave_cb),
995 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
996 G_CALLBACK(addressbook_drag_received_cb),
998 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
999 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1000 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1001 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1003 clist_vbox = gtk_vbox_new(FALSE, 4);
1005 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1006 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1007 GTK_POLICY_AUTOMATIC,
1008 GTK_POLICY_AUTOMATIC);
1009 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1012 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1013 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1014 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
1015 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
1016 gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE);
1017 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
1018 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
1020 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
1022 gtk_widget_set_size_request(clist, -1, 80);
1024 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1025 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
1026 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1027 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
1028 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1029 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
1030 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1031 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1032 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1033 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1034 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1036 for (i = 0; i < N_LIST_COLS; i++)
1037 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
1040 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1041 G_CALLBACK(addressbook_list_row_selected), NULL);
1042 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1043 G_CALLBACK(addressbook_list_row_unselected), NULL);
1044 g_signal_connect(G_OBJECT(clist), "button_press_event",
1045 G_CALLBACK(addressbook_list_button_pressed),
1047 g_signal_connect(G_OBJECT(clist), "button_release_event",
1048 G_CALLBACK(addressbook_list_button_released),
1050 g_signal_connect(G_OBJECT(clist), "tree_expand",
1051 G_CALLBACK(addressbook_person_expand_node), NULL );
1052 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1053 G_CALLBACK(addressbook_person_collapse_node), NULL );
1054 g_signal_connect(G_OBJECT(clist), "start_drag",
1055 G_CALLBACK(addressbook_start_drag), NULL);
1056 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1057 G_CALLBACK(addressbook_drag_data_get), NULL);
1058 hbox = gtk_hbox_new(FALSE, 4);
1059 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1061 label = gtk_label_new(_("Lookup name:"));
1062 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1064 entry = gtk_entry_new();
1065 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1067 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1069 g_signal_connect(G_OBJECT(entry), "key_press_event",
1070 G_CALLBACK(addressbook_entry_key_pressed),
1073 if (!prefs_common.addressbook_use_editaddress_dialog) {
1074 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1075 vpaned = gtk_vpaned_new();
1076 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1077 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1080 editaddress_vbox = NULL;
1082 hpaned = gtk_hpaned_new();
1083 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1084 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1085 if (prefs_common.addressbook_use_editaddress_dialog)
1086 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1088 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1091 hsbox = gtk_hbox_new(FALSE, 0);
1092 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1093 statusbar = gtk_statusbar_new();
1094 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1097 hbbox = gtk_hbutton_box_new();
1098 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1099 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1100 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1101 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1103 gtkut_stock_button_add_help(hbbox, &help_btn);
1105 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1106 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1107 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1108 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1109 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1110 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1111 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1112 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1113 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1116 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1117 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1118 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1120 g_signal_connect(G_OBJECT(help_btn), "clicked",
1121 G_CALLBACK(manual_open_with_anchor_cb),
1122 MANUAL_ANCHOR_ADDRBOOK);
1124 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1125 G_CALLBACK(addressbook_edit_clicked), NULL);
1126 g_signal_connect(G_OBJECT(del_btn), "clicked",
1127 G_CALLBACK(addressbook_del_clicked), NULL);
1128 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1129 G_CALLBACK(addressbook_reg_clicked), NULL);
1130 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1131 G_CALLBACK(addressbook_lup_clicked), NULL);
1133 to_btn = gtk_button_new_with_label
1134 (prefs_common_translated_header_name("To:"));
1135 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1136 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1137 cc_btn = gtk_button_new_with_label
1138 (prefs_common_translated_header_name("Cc:"));
1139 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1140 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1141 bcc_btn = gtk_button_new_with_label
1142 (prefs_common_translated_header_name("Bcc:"));
1143 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1144 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1146 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1147 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1148 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1150 g_signal_connect(G_OBJECT(to_btn), "clicked",
1151 G_CALLBACK(addressbook_to_clicked),
1152 GINT_TO_POINTER(COMPOSE_TO));
1153 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1154 G_CALLBACK(addressbook_to_clicked),
1155 GINT_TO_POINTER(COMPOSE_CC));
1156 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1157 G_CALLBACK(addressbook_to_clicked),
1158 GINT_TO_POINTER(COMPOSE_BCC));
1159 g_signal_connect(G_OBJECT(close_btn), "clicked",
1160 G_CALLBACK(addressbook_close_clicked), NULL);
1162 /* Build icons for interface */
1163 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1164 &interfacexpm, &interfacexpmmask );
1166 /* Build control tables */
1167 addrbookctl_build_map(window);
1168 addrbookctl_build_iflist();
1169 addrbookctl_build_ifselect();
1171 addrbook.clist = NULL;
1173 /* Add each interface into the tree as a root level folder */
1174 nodeIf = _addressInterfaceList_;
1176 AdapterInterface *adapter = nodeIf->data;
1177 AddressInterface *iface = adapter->interface;
1178 nodeIf = g_list_next(nodeIf);
1180 if(iface->useInterface) {
1181 AddressTypeControlItem *atci = adapter->atci;
1182 text = atci->displayName;
1184 gtk_sctree_insert_node( GTK_CTREE(ctree),
1185 NULL, NULL, &text, FOLDER_SPACING,
1186 interfacexpm, interfacexpmmask,
1187 interfacexpm, interfacexpmmask,
1189 menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
1190 gtk_ctree_node_set_row_data_full(
1191 GTK_CTREE(ctree), adapter->treeNode, adapter,
1192 addressbook_free_treenode );
1197 n_entries = sizeof(addressbook_tree_popup_entries) /
1198 sizeof(addressbook_tree_popup_entries[0]);
1199 tree_popup = menu_create_items(addressbook_tree_popup_entries,
1201 "<AddressBookTree>", &tree_factory,
1203 n_entries = sizeof(addressbook_list_popup_entries) /
1204 sizeof(addressbook_list_popup_entries[0]);
1205 list_popup = menu_create_items(addressbook_list_popup_entries,
1207 "<AddressBookList>", &list_factory,
1210 addrbook.window = window;
1211 addrbook.hpaned = hpaned;
1212 addrbook.vpaned = vpaned;
1213 addrbook.menubar = menubar;
1214 addrbook.ctree = ctree;
1217 addrbook.editaddress_vbox = editaddress_vbox;
1218 addrbook.clist = clist;
1219 addrbook.label = label;
1220 addrbook.entry = entry;
1221 addrbook.statusbar = statusbar;
1222 addrbook.status_cid = gtk_statusbar_get_context_id(
1223 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1225 addrbook.help_btn = help_btn;
1226 addrbook.edit_btn = edit_btn;
1227 addrbook.del_btn = del_btn;
1228 addrbook.reg_btn = reg_btn;
1229 addrbook.lup_btn = lup_btn;
1230 addrbook.to_btn = to_btn;
1231 addrbook.cc_btn = cc_btn;
1232 addrbook.bcc_btn = bcc_btn;
1234 addrbook.tree_popup = tree_popup;
1235 addrbook.list_popup = list_popup;
1236 addrbook.tree_factory = tree_factory;
1237 addrbook.list_factory = list_factory;
1238 addrbook.menu_factory = menu_factory;
1240 addrbook.listSelected = NULL;
1242 if (!geometry.min_height) {
1243 geometry.min_width = ADDRESSBOOK_WIDTH;
1244 geometry.min_height = ADDRESSBOOK_HEIGHT;
1247 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1249 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1250 prefs_common.addressbookwin_height);
1252 if (!prefs_common.addressbook_use_editaddress_dialog) {
1253 if (prefs_common.addressbook_vpaned_pos > 0)
1254 gtk_paned_set_position(GTK_PANED(vpaned),
1255 prefs_common.addressbook_vpaned_pos);
1257 if (prefs_common.addressbook_hpaned_pos > 0)
1258 gtk_paned_set_position(GTK_PANED(hpaned),
1259 prefs_common.addressbook_hpaned_pos);
1262 gtk_widget_show_all(window);
1266 * Close address book window and save to file(s).
1268 static gint addressbook_close( void ) {
1269 address_completion_end(addrbook.window);
1270 if (!prefs_common.addressbook_use_editaddress_dialog)
1271 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1273 addressbook_pane_save_position();
1275 gtk_widget_hide(addrbook.window);
1276 addressbook_export_to_file();
1281 * Display message in status line.
1282 * \param msg Message to display.
1284 static void addressbook_status_show( gchar *msg ) {
1285 if( addrbook.statusbar != NULL ) {
1287 GTK_STATUSBAR(addrbook.statusbar),
1288 addrbook.status_cid );
1291 GTK_STATUSBAR(addrbook.statusbar),
1292 addrbook.status_cid, msg );
1297 static void addressbook_ds_status_message( AddressDataSource *ds, gchar *msg ) {
1298 *addressbook_msgbuf = '\0';
1302 name = addrindex_ds_get_name( ds );
1303 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1304 "%s: %s", name, msg );
1307 g_snprintf( addressbook_msgbuf, sizeof(addressbook_msgbuf),
1310 addressbook_status_show( addressbook_msgbuf );
1313 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1317 *addressbook_msgbuf = '\0';
1319 name = addrindex_ds_get_name( ds );
1320 retVal = addrindex_ds_get_status_code( ds );
1321 if( retVal == MGU_SUCCESS ) {
1322 g_snprintf( addressbook_msgbuf,
1323 sizeof(addressbook_msgbuf), "%s", name );
1326 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1327 g_snprintf( addressbook_msgbuf,
1328 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1331 addressbook_status_show( addressbook_msgbuf );
1334 static void addressbook_button_set_sensitive(void)
1336 gboolean to_sens = FALSE;
1337 gboolean cc_sens = FALSE;
1338 gboolean bcc_sens = FALSE;
1340 if (!addrbook.window) return;
1342 if (addrbook.target_compose) {
1348 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1349 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1350 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1353 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1355 addressbook_edit_address_cb(NULL, 0, NULL);
1359 * Delete one or more objects from address list.
1361 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1363 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1364 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1365 AddressObject *pobj;
1366 AdapterDSource *ads = NULL;
1367 GtkCTreeNode *nodeList;
1370 AddressBookFile *abf = NULL;
1371 AddressDataSource *ds = NULL;
1372 AddressInterface *iface;
1373 AddrItemObject *aio;
1374 AddrSelectItem *item;
1376 gboolean refreshList = FALSE;
1378 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1379 g_return_if_fail(pobj != NULL);
1381 /* Test whether anything selected for deletion */
1382 nodeList = addrbook.listSelected;
1384 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1385 if( aio == NULL) return;
1386 ds = addressbook_find_datasource( addrbook.treeSelected );
1387 if( ds == NULL ) return;
1389 /* Test for read only */
1390 iface = ds->interface;
1391 if( iface->readOnly ) {
1392 alertpanel( _("Delete address(es)"),
1393 _("This address data is readonly and cannot be deleted."),
1394 GTK_STOCK_CLOSE, NULL, NULL );
1398 /* Test whether Ok to proceed */
1400 if( pobj->type == ADDR_DATASOURCE ) {
1401 ads = ADAPTER_DSOURCE(pobj);
1402 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1404 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1407 else if( pobj->type == ADDR_ITEM_GROUP ) {
1410 if( ! procFlag ) return;
1411 abf = ds->rawDataSource;
1412 if( abf == NULL ) return;
1415 /* Process deletions */
1416 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1417 gboolean group_delete = TRUE;
1418 /* Items inside folders */
1419 list = addrselect_get_list( _addressSelect_ );
1420 /* Confirm deletion */
1424 node = g_list_next( node );
1425 aio = ( AddrItemObject * ) item->addressItem;
1426 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1427 group_delete = FALSE;
1432 aval = alertpanel( _("Delete group"),
1433 _("Really delete the group(s)?\n"
1434 "The addresses it contains will not be lost."),
1435 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1436 if( aval != G_ALERTALTERNATE ) return;
1438 aval = alertpanel( _("Delete address(es)"),
1439 _("Really delete the address(es)?"),
1440 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1441 if( aval != G_ALERTALTERNATE ) return;
1447 node = g_list_next( node );
1448 aio = ( AddrItemObject * ) item->addressItem;
1449 if( aio->type == ADDR_ITEM_GROUP ) {
1450 ItemGroup *item = ( ItemGroup * ) aio;
1451 GtkCTreeNode *nd = NULL;
1453 nd = addressbook_find_group_node( addrbook.opened, item );
1454 item = addrbook_remove_group( abf, item );
1456 addritem_free_item_group( item );
1458 /* Remove group from parent node */
1459 gtk_ctree_remove_node( ctree, nd );
1462 else if( aio->type == ADDR_ITEM_PERSON ) {
1463 ItemPerson *item = ( ItemPerson * ) aio;
1464 item->status = DELETE_ENTRY;
1465 addressbook_folder_remove_one_person( clist, item );
1466 if (pobj->type == ADDR_ITEM_FOLDER)
1467 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1468 item = addrbook_remove_person( abf, item );
1470 if (ds && ds->type == ADDR_IF_LDAP) {
1471 LdapServer *server = ds->rawDataSource;
1472 ldapsvr_set_modified(server, TRUE);
1473 ldapsvr_update_book(server, item);
1477 addritem_free_item_person( item );
1480 else if( aio->type == ADDR_ITEM_EMAIL ) {
1481 ItemEMail *item = ( ItemEMail * ) aio;
1482 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1483 item = addrbook_person_remove_email( abf, person, item );
1485 addrcache_remove_email(abf->addressCache, item);
1486 addritem_free_item_email( item );
1488 addressbook_folder_refresh_one_person( clist, person );
1491 g_list_free( list );
1492 addressbook_list_select_clear();
1494 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1495 addressbook_set_clist(
1496 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1500 addrbook_set_dirty(abf, TRUE);
1501 addressbook_export_to_file();
1502 addressbook_list_menu_setup();
1505 else if( pobj->type == ADDR_ITEM_GROUP ) {
1506 /* Items inside groups */
1507 list = addrselect_get_list( _addressSelect_ );
1511 node = g_list_next( node );
1512 aio = ( AddrItemObject * ) item->addressItem;
1513 if( aio->type == ADDR_ITEM_EMAIL ) {
1514 ItemEMail *item = ( ItemEMail * ) aio;
1515 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1516 item = addrbook_person_remove_email( abf, person, item );
1518 addritem_free_item_email( item );
1522 g_list_free( list );
1523 addressbook_list_select_clear();
1524 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1525 addressbook_set_clist(
1526 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1530 addrbook_set_dirty(abf, TRUE);
1531 addressbook_export_to_file();
1532 addressbook_list_menu_setup();
1536 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1537 gtk_ctree_remove_node( clist, nodeList );
1541 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1543 addressbook_new_address_cb( NULL, 0, NULL );
1546 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1549 gchar *address = NULL;
1551 if( aio->type == ADDR_ITEM_EMAIL ) {
1552 ItemPerson *person = NULL;
1553 ItemEMail *email = ( ItemEMail * ) aio;
1555 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1556 if( email->address ) {
1557 if( ADDRITEM_NAME(email) ) {
1558 name = ADDRITEM_NAME(email);
1559 if( *name == '\0' ) {
1560 name = ADDRITEM_NAME(person);
1563 else if( ADDRITEM_NAME(person) ) {
1564 name = ADDRITEM_NAME(person);
1567 buf = g_strdup( email->address );
1569 address = email->address;
1572 else if( aio->type == ADDR_ITEM_PERSON ) {
1573 ItemPerson *person = ( ItemPerson * ) aio;
1574 GList *node = person->listEMail;
1576 name = ADDRITEM_NAME(person);
1578 ItemEMail *email = ( ItemEMail * ) node->data;
1579 address = email->address;
1583 if( name && name[0] != '\0' ) {
1584 if( strchr_with_skip_quote( name, '"', ',' ) )
1585 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1587 buf = g_strdup_printf( "%s <%s>", name, address );
1590 buf = g_strdup( address );
1597 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1601 AddrSelectItem *item;
1602 AddrItemObject *aio;
1605 compose = addrbook.target_compose;
1606 if( ! compose ) return;
1608 /* Nothing selected, but maybe there is something in text entry */
1609 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1611 compose_entry_append(
1612 compose, addr, (ComposeEntryType)data );
1615 /* Select from address list */
1616 list = addrselect_get_list( _addressSelect_ );
1621 node = g_list_next( node );
1622 aio = item->addressItem;
1623 if( aio->type == ADDR_ITEM_PERSON ||
1624 aio->type == ADDR_ITEM_EMAIL ) {
1625 addr = addressbook_format_address( aio );
1626 compose_entry_append(
1627 compose, addr, (ComposeEntryType) data );
1630 else if( aio->type == ADDR_ITEM_GROUP ) {
1631 ItemGroup *group = ( ItemGroup * ) aio;
1632 GList *nodeMail = group->listEMail;
1634 ItemEMail *email = nodeMail->data;
1636 addr = addressbook_format_address(
1637 ( AddrItemObject * ) email );
1638 compose_entry_append(
1639 compose, addr, (ComposeEntryType) data );
1641 nodeMail = g_list_next( nodeMail );
1646 AddressObject *obj = NULL;
1648 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1650 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1651 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1652 GList *nodeMail = itemGroup->listEMail;
1654 ItemEMail *email = nodeMail->data;
1656 addr = addressbook_format_address(
1657 ( AddrItemObject * ) email );
1658 compose_entry_append(
1659 compose, addr, (ComposeEntryType) data );
1661 nodeMail = g_list_next( nodeMail );
1665 g_list_free( list );
1668 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1669 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1670 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1671 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1673 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1674 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1675 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1676 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1678 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1679 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1680 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1681 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1682 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1683 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1686 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1687 gboolean canEdit = FALSE;
1688 gboolean canDelete = TRUE;
1689 gboolean canAdd = FALSE;
1690 gboolean canEditTr = TRUE;
1691 gboolean editAddress = FALSE;
1692 gboolean canExport = TRUE;
1693 AddressTypeControlItem *atci = NULL;
1694 AddressDataSource *ds = NULL;
1695 AddressInterface *iface = NULL;
1697 if( obj == NULL ) return;
1698 if( obj->type == ADDR_INTERFACE ) {
1699 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1700 iface = adapter->interface;
1702 if( iface->haveLibrary ) {
1703 /* Enable appropriate File / New command */
1704 atci = adapter->atci;
1705 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1708 canEditTr = canExport = FALSE;
1710 else if( obj->type == ADDR_DATASOURCE ) {
1711 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1712 ds = ads->dataSource;
1713 iface = ds->interface;
1714 if( ! iface->readOnly ) {
1715 canAdd = canEdit = editAddress = canDelete = TRUE;
1717 if( ! iface->haveLibrary ) {
1718 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1721 else if( obj->type == ADDR_ITEM_FOLDER ) {
1722 ds = addressbook_find_datasource( addrbook.treeSelected );
1724 iface = ds->interface;
1725 if( iface->readOnly ) {
1730 canAdd = editAddress = TRUE;
1734 else if( obj->type == ADDR_ITEM_GROUP ) {
1735 ds = addressbook_find_datasource( addrbook.treeSelected );
1737 iface = ds->interface;
1738 if( ! iface->readOnly ) {
1744 if( addrbook.listSelected == NULL ) canEdit = FALSE;
1747 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1748 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1749 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1750 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1753 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1754 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1755 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1756 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1758 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1759 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1762 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1763 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1766 static void addressbook_list_menu_setup( void );
1769 * Address book tree callback function that responds to selection of tree
1772 * \param ctree Tree widget.
1773 * \param node Node that was selected.
1774 * \param column Column number where selected occurred.
1775 * \param data Pointer to user data.
1777 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1778 gint column, gpointer data)
1780 AddressObject *obj = NULL;
1781 AdapterDSource *ads = NULL;
1782 AddressDataSource *ds = NULL;
1783 ItemFolder *rootFolder = NULL;
1784 AddressObjectType aot;
1786 addrbook.treeSelected = node;
1787 addrbook.listSelected = NULL;
1788 addressbook_status_show( "" );
1789 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1791 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1793 addressbook_set_clist(NULL, TRUE);
1796 addrbook.opened = node;
1798 if( obj->type == ADDR_DATASOURCE ) {
1799 /* Read from file */
1800 static gboolean tVal = TRUE;
1802 ads = ADAPTER_DSOURCE(obj);
1803 if( ads == NULL ) return;
1804 ds = ads->dataSource;
1805 if( ds == NULL ) return;
1807 if( addrindex_ds_get_modify_flag( ds ) ) {
1808 addrindex_ds_read_data( ds );
1811 if( ! addrindex_ds_get_read_flag( ds ) ) {
1812 addrindex_ds_read_data( ds );
1814 addressbook_ds_show_message( ds );
1816 if( ! addrindex_ds_get_access_flag( ds ) ) {
1817 /* Remove existing folders and groups */
1818 gtk_clist_freeze( GTK_CLIST(ctree) );
1819 addressbook_tree_remove_children( ctree, node );
1820 gtk_clist_thaw( GTK_CLIST(ctree) );
1822 /* Load folders into the tree */
1823 rootFolder = addrindex_ds_get_root_folder( ds );
1824 if( ds && ds->type == ADDR_IF_JPILOT ) {
1825 aot = ADDR_CATEGORY;
1827 else if( ds && ds->type == ADDR_IF_LDAP ) {
1828 aot = ADDR_LDAP_QUERY;
1831 aot = ADDR_ITEM_FOLDER;
1833 addressbook_node_add_folder( node, ds, rootFolder, aot );
1834 addrindex_ds_set_access_flag( ds, &tVal );
1835 gtk_ctree_expand( ctree, node );
1838 addressbook_set_clist(NULL, TRUE);
1841 /* Update address list */
1842 g_signal_handlers_block_by_func
1844 G_CALLBACK(addressbook_tree_selected), NULL);
1845 addressbook_set_clist( obj, FALSE );
1846 g_signal_handlers_unblock_by_func
1848 G_CALLBACK(addressbook_tree_selected), NULL);
1849 if (!prefs_common.addressbook_use_editaddress_dialog)
1850 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1852 /* Setup main menu selections */
1853 addressbook_menubar_set_sensitive( FALSE );
1854 addressbook_list_menu_setup();
1855 addressbook_menuitem_set_sensitive( obj, node );
1857 addressbook_list_select_clear();
1858 addressbook_list_menu_setup();
1863 * Setup address list popup menu items. Items are enabled or disabled as
1866 static void addressbook_list_menu_setup( void ) {
1867 GtkCTree *clist = NULL;
1868 AddressObject *pobj = NULL;
1869 AddressObject *obj = NULL;
1870 AdapterDSource *ads = NULL;
1871 AddressInterface *iface = NULL;
1872 AddressDataSource *ds = NULL;
1873 gboolean canEdit = FALSE;
1874 gboolean canDelete = FALSE;
1875 gboolean canCut = FALSE;
1876 gboolean canCopy = FALSE;
1877 gboolean canPaste = FALSE;
1878 gboolean canBrowse = FALSE;
1880 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1881 if( pobj == NULL ) return;
1883 clist = GTK_CTREE(addrbook.clist);
1884 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1885 if( obj == NULL ) canEdit = FALSE;
1887 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1888 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1890 if( pobj->type == ADDR_DATASOURCE ) {
1891 /* Parent object is a data source */
1892 ads = ADAPTER_DSOURCE(pobj);
1893 ds = ads->dataSource;
1894 iface = ds->interface;
1895 if( ! iface->readOnly ) {
1896 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1897 if (iface->type != ADDR_IF_LDAP)
1898 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1899 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1900 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1901 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1902 if( obj ) canEdit = TRUE;
1904 canDelete = canEdit;
1906 else if( pobj->type != ADDR_INTERFACE ) {
1907 /* Parent object is not an interface */
1908 ds = addressbook_find_datasource( addrbook.treeSelected );
1911 iface = ds->interface;
1912 if( ! iface->readOnly ) {
1913 /* Folder or group */
1914 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1915 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1916 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1917 if( obj ) canEdit = TRUE;
1920 if( pobj->type == ADDR_ITEM_FOLDER ) {
1921 if (iface->type != ADDR_IF_LDAP)
1922 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1923 if( obj ) canEdit = TRUE;
1925 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
1926 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
1927 canDelete = canEdit;
1929 if( iface && iface->type == ADDR_IF_LDAP ) {
1930 if( obj ) canBrowse = TRUE;
1935 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
1937 /* Disable edit or browse if more than one row selected */
1938 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
1943 /* Now go finalize menu items */
1944 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
1945 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1947 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
1948 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
1949 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
1950 /* menu_set_sensitive( addrbook.list_factory, "/Paste Address", canPaste );*/
1952 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
1954 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
1955 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
1956 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
1957 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
1959 menu_set_sensitive( addrbook.tree_factory, "/Cut", canCut );
1960 menu_set_sensitive( addrbook.tree_factory, "/Copy", canCopy );
1961 menu_set_sensitive( addrbook.tree_factory, "/Paste", canPaste );
1963 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1964 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1965 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
1967 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1968 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1971 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
1975 static void addressbook_select_row_tree (GtkCTree *ctree,
1983 * Add list of items into tree node below specified tree node.
1984 * \param treeNode Tree node.
1985 * \param ds Data source.
1986 * \param listItems List of items.
1988 static void addressbook_treenode_add_list(
1989 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
1995 AddrItemObject *aio;
1999 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2002 group = ( ItemGroup * ) aio;
2003 nn = addressbook_node_add_group( treeNode, ds, group );
2005 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2008 folder = ( ItemFolder * ) aio;
2009 nn = addressbook_node_add_folder(
2010 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2012 node = g_list_next( node );
2016 static void addressbook_select_all_cb( void ) {
2017 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2021 * Cut from address list widget.
2023 static void addressbook_clip_cut_cb( void ) {
2024 _clipBoard_->cutFlag = TRUE;
2025 addrclip_clear( _clipBoard_ );
2026 addrclip_add( _clipBoard_, _addressSelect_ );
2027 /* addrclip_list_show( _clipBoard_, stdout ); */
2031 * Copy from address list widget.
2033 static void addressbook_clip_copy_cb( void ) {
2034 _clipBoard_->cutFlag = FALSE;
2035 addrclip_clear( _clipBoard_ );
2036 addrclip_add( _clipBoard_, _addressSelect_ );
2037 /* addrclip_list_show( _clipBoard_, stdout ); */
2041 * Paste clipboard into address list widget.
2043 static void addressbook_clip_paste_cb( void ) {
2044 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2045 AddressObject *pobj = NULL;
2046 AddressDataSource *ds = NULL;
2047 AddressBookFile *abf = NULL;
2048 ItemFolder *folder = NULL;
2049 GList *folderGroup = NULL;
2051 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2052 if( ds == NULL ) return;
2053 if( addrindex_ds_get_readonly( ds ) ) {
2054 addressbook_ds_status_message(
2055 ds, _( "Cannot paste. Target address book is readonly." ) );
2059 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2061 if( pobj->type == ADDR_ITEM_FOLDER ) {
2062 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2064 else if( pobj->type == ADDR_ITEM_GROUP ) {
2065 addressbook_ds_status_message(
2066 ds, _( "Cannot paste into an address group." ) );
2071 /* Get an address book */
2072 abf = addressbook_get_book_file();
2073 if( abf == NULL ) return;
2075 if( _clipBoard_->cutFlag ) {
2077 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2079 /* Remove all groups and folders in clipboard from tree node */
2080 addressbook_treenode_remove_item();
2082 /* Remove all "cut" items */
2083 addrclip_delete_item( _clipBoard_ );
2085 /* Clear clipboard - cut items??? */
2086 addrclip_clear( _clipBoard_ );
2090 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2093 /* addrclip_list_show( _clipBoard_, stdout ); */
2095 /* Update tree by inserting node for each folder or group */
2096 addressbook_treenode_add_list(
2097 addrbook.treeSelected, ds, folderGroup );
2098 gtk_ctree_expand( ctree, addrbook.treeSelected );
2099 g_list_free( folderGroup );
2103 /* Display items pasted */
2104 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2105 addressbook_set_clist(
2106 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2114 * Add current treenode object to clipboard. Note that widget only allows
2115 * one entry from the tree list to be selected.
2117 static void addressbook_treenode_to_clipboard( void ) {
2118 AddressObject *obj = NULL;
2119 AddressDataSource *ds = NULL;
2120 AddrSelectItem *item;
2121 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2124 node = addrbook.treeSelected;
2125 if( node == NULL ) return;
2126 obj = gtk_ctree_node_get_row_data( ctree, node );
2127 if( obj == NULL ) return;
2129 ds = addressbook_find_datasource( node );
2130 if( ds == NULL ) return;
2133 if( obj->type == ADDR_ITEM_FOLDER ) {
2134 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2135 ItemFolder *folder = adapter->itemFolder;
2137 item = addrselect_create_node( obj );
2138 item->uid = g_strdup( ADDRITEM_ID(folder) );
2140 else if( obj->type == ADDR_ITEM_GROUP ) {
2141 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2142 ItemGroup *group = adapter->itemGroup;
2144 item = addrselect_create_node( obj );
2145 item->uid = g_strdup( ADDRITEM_ID(group) );
2147 else if( obj->type == ADDR_DATASOURCE ) {
2149 item = addrselect_create_node( obj );
2154 /* Clear existing list and add item into list */
2157 addressbook_list_select_clear();
2158 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2159 addrselect_list_add( _addressSelect_, item, cacheID );
2165 * Cut from tree widget.
2167 static void addressbook_treenode_cut_cb( void ) {
2168 _clipBoard_->cutFlag = TRUE;
2169 addressbook_treenode_to_clipboard();
2170 addrclip_clear( _clipBoard_ );
2171 addrclip_add( _clipBoard_, _addressSelect_ );
2172 /* addrclip_list_show( _clipBoard_, stdout ); */
2176 * Copy from tree widget.
2178 static void addressbook_treenode_copy_cb( void ) {
2179 _clipBoard_->cutFlag = FALSE;
2180 addressbook_treenode_to_clipboard();
2181 addrclip_clear( _clipBoard_ );
2182 addrclip_add( _clipBoard_, _addressSelect_ );
2183 /* addrclip_list_show( _clipBoard_, stdout ); */
2187 * Paste clipboard into address tree widget.
2189 static void addressbook_treenode_paste_cb( void ) {
2190 addressbook_clip_paste_cb();
2194 * Clear selected entries in clipboard.
2196 static void addressbook_list_select_clear( void ) {
2197 addrselect_list_clear( _addressSelect_ );
2201 * Add specified address item to selected address list.
2202 * \param aio Address item object.
2203 * \param ds Datasource.
2205 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2208 if( ds == NULL ) return;
2209 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2210 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2215 * Remove specified address item from selected address list.
2216 * \param aio Address item object.
2218 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2219 addrselect_list_remove( _addressSelect_, aio );
2223 * Invoke EMail compose window with addresses in selected address list.
2225 static void addressbook_mail_to_cb( void ) {
2228 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2229 listAddress = addrselect_build_list( _addressSelect_ );
2230 compose_new_with_list( NULL, listAddress );
2231 mgu_free_dlist( listAddress );
2236 static void addressbook_list_row_selected( GtkCTree *clist,
2241 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2242 AddrItemObject *aio = NULL;
2243 AddressObject *pobj = NULL;
2244 AdapterDSource *ads = NULL;
2245 AddressDataSource *ds = NULL;
2247 gtk_entry_set_text( entry, "" );
2248 addrbook.listSelected = node;
2250 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2251 if( pobj == NULL ) return;
2253 if( pobj->type == ADDR_DATASOURCE ) {
2254 ads = ADAPTER_DSOURCE(pobj);
2255 ds = ads->dataSource;
2257 else if( pobj->type != ADDR_INTERFACE ) {
2258 ds = addressbook_find_datasource( addrbook.treeSelected );
2261 aio = gtk_ctree_node_get_row_data( clist, node );
2263 /* printf( "list select: %d : '%s'\n", aio->type, aio->name ); */
2264 addressbook_list_select_add( aio, ds );
2267 addressbook_list_menu_setup();
2269 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog)
2270 addressbook_edit_address(NULL, 0, NULL, FALSE);
2273 static void addressbook_list_row_unselected( GtkCTree *ctree,
2278 AddrItemObject *aio;
2280 aio = gtk_ctree_node_get_row_data( ctree, node );
2282 /* printf( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2283 addressbook_list_select_remove( aio );
2286 if (!prefs_common.addressbook_use_editaddress_dialog)
2287 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2290 /* from gdkevents.c */
2291 #define DOUBLE_CLICK_TIME 250
2293 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2294 GdkEventButton *event,
2297 static guint32 lasttime = 0;
2298 if( ! event ) return FALSE;
2300 addressbook_list_menu_setup();
2302 if( event->button == 3 ) {
2303 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2304 event->button, event->time );
2305 } else if (event->button == 1) {
2306 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2307 if (prefs_common.add_address_by_click &&
2308 addrbook.target_compose)
2309 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2311 if (prefs_common.addressbook_use_editaddress_dialog)
2312 addressbook_edit_address_cb(NULL, 0, NULL);
2316 lasttime = event->time;
2322 static gboolean addressbook_list_button_released(GtkWidget *widget,
2323 GdkEventButton *event,
2329 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2330 GdkEventButton *event,
2333 GtkCList *clist = GTK_CLIST(ctree);
2335 AddressObject *obj = NULL;
2336 AdapterDSource *ads = NULL;
2337 AddressInterface *iface = NULL;
2338 AddressDataSource *ds = NULL;
2339 gboolean canEdit = FALSE;
2340 gboolean canDelete = FALSE;
2341 gboolean canCut = FALSE;
2342 gboolean canCopy = FALSE;
2343 gboolean canPaste = FALSE;
2344 gboolean canTreeCut = FALSE;
2345 gboolean canTreeCopy = FALSE;
2346 gboolean canTreePaste = FALSE;
2347 gboolean canLookup = FALSE;
2348 GtkCTreeNode *node = NULL;
2350 if( ! event ) return FALSE;
2351 addressbook_menubar_set_sensitive( FALSE );
2353 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2354 gtkut_clist_set_focus_row(clist, row);
2355 obj = gtk_clist_get_row_data( clist, row );
2358 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2360 if( obj == NULL ) return FALSE;
2361 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2363 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2364 canTreePaste = TRUE;
2367 if (obj->type == ADDR_INTERFACE) {
2368 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2369 iface = adapter->interface;
2372 canTreeCopy = FALSE;
2373 if( iface->readOnly ) {
2374 canTreePaste = FALSE;
2377 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2378 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2380 if( iface->externalQuery ) canLookup = TRUE;
2382 if (obj->type == ADDR_DATASOURCE) {
2383 ads = ADAPTER_DSOURCE(obj);
2384 ds = ads->dataSource;
2387 iface = ds->interface;
2392 if( iface->readOnly ) {
2393 canTreePaste = FALSE;
2396 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2397 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2398 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2401 if( iface->externalQuery ) canLookup = TRUE;
2403 else if (obj->type == ADDR_ITEM_FOLDER) {
2404 ds = addressbook_find_datasource( node );
2408 iface = ds->interface;
2411 if( iface->readOnly ) {
2412 canTreePaste = FALSE;
2418 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2419 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2420 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2424 if( iface->externalQuery ) {
2425 /* Enable deletion of LDAP folder */
2430 else if (obj->type == ADDR_ITEM_GROUP) {
2431 ds = addressbook_find_datasource( node );
2434 iface = ds->interface;
2437 if( ! iface->readOnly ) {
2440 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2441 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2444 else if (obj->type == ADDR_INTERFACE) {
2445 canTreePaste = FALSE;
2449 if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
2451 if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
2452 if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
2456 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2457 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2458 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2459 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2460 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2462 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2463 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2464 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2465 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2466 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2467 /* menu_set_sensitive( addrbook.menu_factory, "/Edit/Paste Address", canPaste );*/
2469 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup, addrbook.target_compose != NULL);
2470 if( event->button == 3 ) {
2471 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2472 event->button, event->time);
2478 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2479 GdkEventButton *event,
2482 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2486 static void addressbook_new_folder_cb(gpointer data, guint action,
2489 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2490 AddressObject *obj = NULL;
2491 AddressDataSource *ds = NULL;
2492 AddressBookFile *abf = NULL;
2493 ItemFolder *parentFolder = NULL;
2494 ItemFolder *folder = NULL;
2496 if( ! addrbook.treeSelected ) return;
2497 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2498 if( obj == NULL ) return;
2499 ds = addressbook_find_datasource( addrbook.treeSelected );
2500 if( ds == NULL ) return;
2502 if( obj->type == ADDR_DATASOURCE ) {
2503 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2505 else if( obj->type == ADDR_ITEM_FOLDER ) {
2506 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2512 abf = ds->rawDataSource;
2513 if( abf == NULL ) return;
2514 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2517 nn = addressbook_node_add_folder(
2518 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2519 gtk_ctree_expand( ctree, addrbook.treeSelected );
2520 if( addrbook.treeSelected == addrbook.opened )
2521 addressbook_set_clist(obj, TRUE);
2526 static void addressbook_new_group_cb(gpointer data, guint action,
2529 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2530 AddressObject *obj = NULL;
2531 AddressDataSource *ds = NULL;
2532 AddressBookFile *abf = NULL;
2533 ItemFolder *parentFolder = NULL;
2534 ItemGroup *group = NULL;
2536 if( ! addrbook.treeSelected ) return;
2537 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2538 if( obj == NULL ) return;
2539 ds = addressbook_find_datasource( addrbook.treeSelected );
2540 if( ds == NULL ) return;
2542 if( obj->type == ADDR_DATASOURCE ) {
2543 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2545 else if( obj->type == ADDR_ITEM_FOLDER ) {
2546 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2552 abf = ds->rawDataSource;
2553 if( abf == NULL ) return;
2554 group = addressbook_edit_group( abf, parentFolder, NULL );
2557 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2558 gtk_ctree_expand( ctree, addrbook.treeSelected );
2559 if( addrbook.treeSelected == addrbook.opened )
2560 addressbook_set_clist(obj, TRUE);
2565 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2567 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2570 GdkPixmap *pix_cl, *pix_op;
2571 GdkBitmap *mask_cl, *mask_op;
2572 gboolean is_leaf, expanded;
2574 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2575 &pix_cl, &mask_cl, &pix_op, &mask_op,
2576 &is_leaf, &expanded);
2577 gtk_sctree_set_node_info(ctree, node, name, spacing,
2578 pix_cl, mask_cl, pix_op, mask_op,
2584 * \param obj Address object to edit.
2585 * \param node Node in tree.
2586 * \return New name of data source.
2588 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2589 gchar *newName = NULL;
2590 AddressDataSource *ds = NULL;
2591 AddressInterface *iface = NULL;
2592 AdapterDSource *ads = NULL;
2594 ds = addressbook_find_datasource( node );
2595 if( ds == NULL ) return NULL;
2596 iface = ds->interface;
2597 if( ! iface->haveLibrary ) return NULL;
2599 /* Read data from data source */
2600 if( addrindex_ds_get_modify_flag( ds ) ) {
2601 addrindex_ds_read_data( ds );
2604 if( ! addrindex_ds_get_read_flag( ds ) ) {
2605 addrindex_ds_read_data( ds );
2609 ads = ADAPTER_DSOURCE(obj);
2610 if( ads->subType == ADDR_BOOK ) {
2611 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2613 else if( ads->subType == ADDR_VCARD ) {
2614 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2617 else if( ads->subType == ADDR_JPILOT ) {
2618 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2622 else if( ads->subType == ADDR_LDAP ) {
2623 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2629 newName = obj->name;
2634 * Edit an object that is in the address tree area.
2636 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2639 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2641 AddressDataSource *ds = NULL;
2642 AddressBookFile *abf = NULL;
2643 GtkCTreeNode *node = NULL, *parentNode = NULL;
2646 if( ! addrbook.treeSelected ) return;
2647 node = addrbook.treeSelected;
2648 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2649 obj = gtk_ctree_node_get_row_data( ctree, node );
2650 if( obj == NULL ) return;
2651 parentNode = GTK_CTREE_ROW(node)->parent;
2653 ds = addressbook_find_datasource( node );
2654 if( ds == NULL ) return;
2656 if( obj->type == ADDR_DATASOURCE ) {
2657 name = addressbook_edit_datasource( obj, node );
2658 if( name == NULL ) return;
2661 abf = ds->rawDataSource;
2662 if( abf == NULL ) return;
2663 if( obj->type == ADDR_ITEM_FOLDER ) {
2664 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2665 ItemFolder *item = adapter->itemFolder;
2666 ItemFolder *parentFolder = NULL;
2667 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2668 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2669 name = ADDRITEM_NAME(item);
2671 else if( obj->type == ADDR_ITEM_GROUP ) {
2672 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2673 ItemGroup *item = adapter->itemGroup;
2674 ItemFolder *parentFolder = NULL;
2675 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2676 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2677 name = ADDRITEM_NAME(item);
2680 if( name && parentNode ) {
2681 /* Update node in tree view */
2682 addressbook_change_node_name( node, name );
2683 gtk_sctree_sort_node(ctree, parentNode);
2684 gtk_ctree_expand( ctree, node );
2685 gtk_sctree_select( GTK_SCTREE( ctree), node );
2692 ADDRTREE_DEL_FOLDER_ONLY,
2693 ADDRTREE_DEL_FOLDER_ADDR
2697 * Delete an item from the tree widget.
2698 * \param data Data passed in.
2699 * \param action Action.
2700 * \param widget Widget issuing callback.
2702 static void addressbook_treenode_delete_cb(
2703 gpointer data, guint action, GtkWidget *widget )
2705 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2706 GtkCTreeNode *node = NULL;
2710 AddrBookBase *adbase;
2711 AddressCache *cache;
2712 AdapterDSource *ads = NULL;
2713 AddressInterface *iface = NULL;
2714 AddressDataSource *ds = NULL;
2715 gboolean remFlag = FALSE;
2716 TreeItemDelType delType;
2718 if( ! addrbook.treeSelected ) return;
2719 node = addrbook.treeSelected;
2720 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2722 obj = gtk_ctree_node_get_row_data( ctree, node );
2723 g_return_if_fail(obj != NULL);
2725 if( obj->type == ADDR_DATASOURCE ) {
2726 ads = ADAPTER_DSOURCE(obj);
2727 if( ads == NULL ) return;
2728 ds = ads->dataSource;
2729 if( ds == NULL ) return;
2732 /* Must be folder or something else */
2733 ds = addressbook_find_datasource( node );
2734 if( ds == NULL ) return;
2736 /* Only allow deletion from non-readOnly */
2737 iface = ds->interface;
2738 if( iface->readOnly ) {
2739 /* Allow deletion of query results */
2740 if( ! iface->externalQuery ) return;
2744 /* Confirm deletion */
2745 delType = ADDRTREE_DEL_NONE;
2746 if( obj->type == ADDR_ITEM_FOLDER ) {
2747 if( iface->externalQuery ) {
2748 message = g_strdup_printf( _(
2749 "Do you want to delete the query " \
2750 "results and addresses in '%s' ?" ),
2752 aval = alertpanel( _("Delete"), message,
2753 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2755 if( aval == G_ALERTALTERNATE ) {
2756 delType = ADDRTREE_DEL_FOLDER_ADDR;
2760 message = g_strdup_printf
2761 ( _( "Do you want to delete '%s' ?"
2762 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2764 aval = alertpanel( _("Delete folder"), message,
2765 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2767 if( aval == G_ALERTALTERNATE ) {
2768 delType = ADDRTREE_DEL_FOLDER_ONLY;
2770 else if( aval == G_ALERTOTHER ) {
2771 delType = ADDRTREE_DEL_FOLDER_ADDR;
2775 else if( obj->type == ADDR_ITEM_GROUP ) {
2776 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2777 "The addresses it contains will not be lost."), obj->name);
2778 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2779 "+" GTK_STOCK_DELETE, NULL);
2781 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2783 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2784 "The addresses it contains will be lost."), obj->name);
2785 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2786 "+" GTK_STOCK_DELETE, NULL);
2788 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2790 if( delType == ADDRTREE_DEL_NONE ) return;
2792 /* Proceed with deletion */
2793 if( obj->type == ADDR_DATASOURCE ) {
2794 /* Remove node from tree */
2795 gtk_ctree_remove_node( ctree, node );
2797 /* Remove data source. */
2798 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2799 addrindex_free_datasource( ds );
2804 /* Get reference to cache */
2805 adbase = ( AddrBookBase * ) ds->rawDataSource;
2806 if( adbase == NULL ) return;
2807 cache = adbase->addressCache;
2809 /* Remove query results folder */
2810 if( iface->externalQuery ) {
2811 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2812 ItemFolder *folder = adapter->itemFolder;
2814 adapter->itemFolder = NULL;
2816 printf( "remove folder for ::%s::\n", obj->name );
2817 printf( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2818 printf( "-------------- remove results\n" );
2820 addrindex_remove_results( ds, folder );
2821 /* printf( "-------------- remove node\n" ); */
2822 gtk_ctree_remove_node( ctree, node );
2826 /* Code below is valid for regular address book deletion */
2827 if( obj->type == ADDR_ITEM_FOLDER ) {
2828 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2829 ItemFolder *item = adapter->itemFolder;
2831 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2832 /* Remove folder only */
2833 item = addrcache_remove_folder( cache, item );
2835 addritem_free_item_folder( item );
2836 addressbook_move_nodes_up( ctree, node );
2840 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2841 /* Remove folder and addresses */
2842 item = addrcache_remove_folder_delete( cache, item );
2844 addritem_free_item_folder( item );
2849 else if( obj->type == ADDR_ITEM_GROUP ) {
2850 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2851 ItemGroup *item = adapter->itemGroup;
2853 item = addrcache_remove_group( cache, item );
2855 addritem_free_item_group( item );
2862 gtk_ctree_remove_node(ctree, node );
2866 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2868 if( person && addrbook.treeSelected == addrbook.opened ) {
2869 person->status = ADD_ENTRY;
2870 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2871 addressbook_folder_refresh_one_person(
2872 GTK_CTREE(addrbook.clist), person );
2874 addressbook_address_list_set_focus();
2877 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2879 if( person && addrbook.treeSelected == addrbook.opened) {
2880 person->status = ADD_ENTRY;
2881 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2882 addressbook_set_clist(
2883 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2887 addressbook_address_list_set_focus();
2891 * Label (a format string) that is used to name each folder.
2893 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
2896 * Search ctree widget callback function.
2897 * \param pA Pointer to node.
2898 * \param pB Pointer to data item being sought.
2899 * \return Zero (0) if folder found.
2901 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
2904 aoA = ( AddressObject * ) pA;
2905 if( aoA->type == ADDR_ITEM_FOLDER ) {
2906 ItemFolder *folder, *fld;
2908 fld = ADAPTER_FOLDER(aoA)->itemFolder;
2909 folder = ( ItemFolder * ) pB;
2910 if( fld == folder ) return 0; /* Found folder */
2915 static ItemFolder * addressbook_setup_subf(
2916 AddressDataSource *ds, gchar *title,
2917 GtkCTreeNode *pNode )
2919 AddrBookBase *adbase;
2920 AddressCache *cache;
2923 GtkCTreeNode *nNode;
2925 AddressObjectType aoType = ADDR_NONE;
2928 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
2930 if( ds && ds->type == ADDR_IF_LDAP ) {
2932 aoType = ADDR_LDAP_QUERY;
2939 ctree = GTK_CTREE(addrbook.ctree);
2940 /* Get reference to address cache */
2941 adbase = ( AddrBookBase * ) ds->rawDataSource;
2942 cache = adbase->addressCache;
2944 if ((children = addrcache_get_list_folder(cache)) != NULL) {
2945 GList *cur = children;
2946 for (; cur; cur = cur->next) {
2947 ItemFolder *child = (ItemFolder *) cur->data;
2948 if (!strcmp2(ADDRITEM_NAME(child), title)) {
2949 nNode = gtk_ctree_find_by_row_data_custom(
2951 addressbook_treenode_find_folder_cb );
2953 addrindex_remove_results( ds, child );
2954 while( child->listPerson ) {
2955 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
2956 item = addrcache_remove_person( cache, item );
2958 addritem_free_item_person( item );
2962 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
2963 addrbook.treeSelected = nNode;
2970 /* Create a folder */
2971 folder = addrcache_add_new_folder( cache, NULL );
2972 name = g_strdup_printf( "%s", title );
2973 addritem_folder_set_name( folder, name );
2974 addritem_folder_set_remarks( folder, "" );
2977 /* Now let's see the folder */
2978 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
2979 gtk_ctree_expand( ctree, pNode );
2981 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
2982 addrbook.treeSelected = nNode;
2988 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
2989 AddressObject *pobj = NULL;
2990 AddressDataSource *ds = NULL;
2991 AddressBookFile *abf = NULL;
2992 debug_print("adding address\n");
2993 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
2994 if( pobj == NULL ) {
2995 debug_print("no row data\n");
2998 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3000 debug_print("no datasource\n");
3004 abf = ds->rawDataSource;
3006 printf("no addressbook file\n");
3010 if( pobj->type == ADDR_DATASOURCE ) {
3011 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3012 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3014 ItemFolder *folder = NULL;
3016 if (abf && abf->type == ADDR_IF_LDAP) {
3017 GtkCTreeNode *parentNode;
3018 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3019 if( ds == NULL ) return;
3021 /* We must have a datasource that is an external interface */
3022 if( ! ds->interface->haveLibrary ) return;
3023 if( ! ds->interface->externalQuery ) return;
3025 if( pobj->type == ADDR_ITEM_FOLDER ) {
3026 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3029 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3031 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3033 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3034 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3035 abf = ds->rawDataSource;
3038 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3039 addrbook.editaddress_vbox,
3040 addressbook_new_address_from_book_post_cb,
3043 if (abf && abf->type == ADDR_IF_LDAP) {
3044 LdapServer *server = ds->rawDataSource;
3045 ldapsvr_set_modified(server, TRUE);
3046 ldapsvr_update_book(server, NULL);
3047 if (server->retVal != LDAPRC_SUCCESS) {
3048 alertpanel( _("Add address(es)"),
3049 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3050 GTK_STOCK_CLOSE, NULL, NULL );
3051 server->retVal = LDAPRC_SUCCESS;
3056 if (prefs_common.addressbook_use_editaddress_dialog)
3057 addressbook_new_address_from_book_post_cb( person );
3060 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3062 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3065 if (abf && abf->type == ADDR_IF_LDAP) {
3066 GtkCTreeNode *parentNode;
3067 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3068 if( ds == NULL ) return;
3070 /* We must have a datasource that is an external interface */
3071 if( ! ds->interface->haveLibrary ) return;
3072 if( ! ds->interface->externalQuery ) return;
3074 if( pobj->type == ADDR_ITEM_FOLDER ) {
3075 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3078 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3080 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3083 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3084 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3085 abf = ds->rawDataSource;
3088 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3089 addrbook.editaddress_vbox,
3090 addressbook_new_address_from_folder_post_cb,
3093 if (abf && abf->type == ADDR_IF_LDAP) {
3094 LdapServer *server = ds->rawDataSource;
3095 ldapsvr_set_modified(server, TRUE);
3096 ldapsvr_update_book(server, NULL);
3097 if (server->retVal != LDAPRC_SUCCESS) {
3098 alertpanel( _("Add address(es)"),
3099 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3100 GTK_STOCK_CLOSE, NULL, NULL );
3105 if (prefs_common.addressbook_use_editaddress_dialog)
3106 addressbook_new_address_from_folder_post_cb( person );
3108 else if( pobj->type == ADDR_ITEM_GROUP ) {
3109 /* New address in group */
3110 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3111 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3112 if (addrbook.treeSelected == addrbook.opened) {
3113 /* Change node name in tree. */
3114 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3115 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3116 addressbook_set_clist(
3117 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3125 * Search for specified child group node in address index tree.
3126 * \param parent Parent node.
3127 * \param group Group to find.
3129 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
3130 GtkCTreeNode *node = NULL;
3131 GtkCTreeRow *currRow;
3133 currRow = GTK_CTREE_ROW( parent );
3135 node = currRow->children;
3139 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3140 if( obj->type == ADDR_ITEM_GROUP ) {
3141 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3142 if( g == group ) return node;
3144 currRow = GTK_CTREE_ROW(node);
3145 node = currRow->sibling;
3151 static AddressBookFile *addressbook_get_book_file() {
3152 AddressBookFile *abf = NULL;
3153 AddressDataSource *ds = NULL;
3155 ds = addressbook_find_datasource( addrbook.treeSelected );
3156 if( ds == NULL ) return NULL;
3157 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3161 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
3165 /* Remove existing folders and groups */
3166 row = GTK_CTREE_ROW( parent );
3168 while( (node = row->children) ) {
3169 gtk_ctree_remove_node( ctree, node );
3174 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
3175 GtkCTreeNode *parent, *child;
3176 GtkCTreeRow *currRow;
3177 currRow = GTK_CTREE_ROW( node );
3179 parent = currRow->parent;
3180 while( (child = currRow->children) ) {
3181 gtk_ctree_move( ctree, child, parent, node );
3183 gtk_sctree_sort_node( ctree, parent );
3187 static void addressbook_edit_address_post_cb( ItemPerson *person )
3191 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
3192 invalidate_address_completion();
3194 addressbook_address_list_set_focus();
3197 void addressbook_address_list_set_focus( void )
3199 if (!prefs_common.addressbook_use_editaddress_dialog) {
3200 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3201 addressbook_list_menu_setup();
3205 void addressbook_address_list_disable_some_actions(void)
3207 /* disable address copy/pasting when editing contact's detail (embedded form) */
3208 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3209 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3210 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3212 /* we're already editing contact's detail here */
3213 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", FALSE );
3214 gtk_widget_set_sensitive( addrbook.edit_btn, FALSE );
3217 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3218 addressbook_edit_address(data, action, widget, TRUE);
3221 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3222 gboolean force_focus ) {
3223 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3225 AddressObject *obj = NULL, *pobj = NULL;
3226 AddressDataSource *ds = NULL;
3227 GtkCTreeNode *node = NULL, *parentNode = NULL;
3229 AddressBookFile *abf = NULL;
3231 if( addrbook.listSelected == NULL ) return;
3232 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3233 g_return_if_fail(obj != NULL);
3235 ctree = GTK_CTREE( addrbook.ctree );
3236 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3237 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3239 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3240 if( ds == NULL ) return;
3242 abf = addressbook_get_book_file();
3244 if( obj->type == ADDR_ITEM_EMAIL ) {
3245 ItemEMail *email = ( ItemEMail * ) obj;
3246 if( email == NULL ) return;
3247 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3248 /* Edit parent group */
3249 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3250 ItemGroup *itemGrp = adapter->itemGroup;
3251 if( abf == NULL ) return;
3252 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3253 name = ADDRITEM_NAME(itemGrp);
3254 node = addrbook.treeSelected;
3255 parentNode = GTK_CTREE_ROW(node)->parent;
3258 /* Edit person - email page */
3260 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3261 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3262 addressbook_edit_address_post_cb,
3263 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3266 if (abf && abf->type == ADDR_IF_LDAP) {
3267 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3268 person->status = UPDATE_ENTRY;
3271 if (prefs_common.addressbook_use_editaddress_dialog)
3272 addressbook_edit_address_post_cb( person );
3277 else if( obj->type == ADDR_ITEM_PERSON ) {
3278 /* Edit person - basic page */
3279 ItemPerson *person = ( ItemPerson * ) obj;
3280 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3281 addressbook_edit_address_post_cb,
3282 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3285 if (abf && abf->type == ADDR_IF_LDAP) {
3286 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3287 person->status = UPDATE_ENTRY;
3290 if (prefs_common.addressbook_use_editaddress_dialog)
3291 addressbook_edit_address_post_cb( person );
3295 else if( obj->type == ADDR_ITEM_GROUP ) {
3296 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3297 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3298 parentNode = addrbook.treeSelected;
3299 node = addressbook_find_group_node( parentNode, itemGrp );
3300 name = ADDRITEM_NAME(itemGrp);
3301 invalidate_address_completion();
3307 /* Update tree node with node name */
3308 if( node == NULL ) return;
3309 addressbook_change_node_name( node, name );
3310 gtk_sctree_sort_node( ctree, parentNode );
3311 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3312 addressbook_set_clist(
3313 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3318 static void addressbook_delete_address_cb(gpointer data, guint action,
3321 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
3322 addressbook_del_clicked(NULL, NULL);
3323 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
3326 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3328 addressbook_close();
3331 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3332 addressbook_export_to_file();
3335 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3337 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3338 if( person ) addritem_person_set_opened( person, TRUE );
3342 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3344 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3345 if( person ) addritem_person_set_opened( person, FALSE );
3349 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3351 gchar *eMailAlias = ADDRITEM_NAME(email);
3352 if( eMailAlias && *eMailAlias != '\0' ) {
3354 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3357 str = g_strdup( eMailAlias );
3363 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3364 GList *items = itemGroup->listEMail;
3365 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3366 for( ; items != NULL; items = g_list_next( items ) ) {
3367 GtkCTreeNode *nodeEMail = NULL;
3368 gchar *text[N_LIST_COLS];
3369 ItemEMail *email = items->data;
3373 if( ! email ) continue;
3375 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3376 str = addressbook_format_item_clist( person, email );
3378 text[COL_NAME] = str;
3381 text[COL_NAME] = ADDRITEM_NAME(person);
3383 text[COL_ADDRESS] = email->address;
3384 text[COL_REMARKS] = email->remarks;
3385 nodeEMail = gtk_sctree_insert_node(
3387 text, FOLDER_SPACING,
3388 atci->iconXpm, atci->maskXpm,
3389 atci->iconXpmOpen, atci->maskXpmOpen,
3391 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3397 static void addressbook_folder_load_one_person(
3398 GtkCTree *clist, ItemPerson *person,
3399 AddressTypeControlItem *atci,
3400 AddressTypeControlItem *atciMail )
3402 GtkCTreeNode *nodePerson = NULL;
3403 GtkCTreeNode *nodeEMail = NULL;
3404 gchar *text[N_LIST_COLS];
3405 gboolean flgFirst = TRUE, haveAddr = FALSE;
3407 AddressBookFile *abf = addressbook_get_book_file();
3409 if( person == NULL ) return;
3411 text[COL_NAME] = "";
3412 node = person->listEMail;
3414 ItemEMail *email = node->data;
3415 gchar *eMailAddr = NULL;
3416 node = g_list_next( node );
3418 text[COL_ADDRESS] = email->address;
3419 text[COL_REMARKS] = email->remarks;
3420 eMailAddr = ADDRITEM_NAME(email);
3421 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3423 /* First email belongs with person */
3424 gchar *str = addressbook_format_item_clist( person, email );
3426 text[COL_NAME] = str;
3429 else if( abf && abf->type == ADDR_IF_LDAP &&
3430 person && person->nickName ) {
3431 if (person->nickName) {
3432 if (strcmp(person->nickName, "") != 0) {
3433 text[COL_NAME] = person->nickName;
3436 text[COL_NAME] = ADDRITEM_NAME(person);
3442 text[COL_NAME] = ADDRITEM_NAME(person);
3444 nodePerson = gtk_sctree_insert_node(
3446 text, FOLDER_SPACING,
3447 atci->iconXpm, atci->maskXpm,
3448 atci->iconXpmOpen, atci->maskXpmOpen,
3449 FALSE, person->isOpened );
3452 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3455 /* Subsequent email is a child node of person */
3456 text[COL_NAME] = ADDRITEM_NAME(email);
3457 nodeEMail = gtk_sctree_insert_node(
3458 clist, nodePerson, NULL,
3459 text, FOLDER_SPACING,
3460 atciMail->iconXpm, atciMail->maskXpm,
3461 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3463 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3469 /* Have name without EMail */
3470 text[COL_NAME] = ADDRITEM_NAME(person);
3471 text[COL_ADDRESS] = "";
3472 text[COL_REMARKS] = "";
3473 nodePerson = gtk_sctree_insert_node(
3475 text, FOLDER_SPACING,
3476 atci->iconXpm, atci->maskXpm,
3477 atci->iconXpmOpen, atci->maskXpmOpen,
3478 FALSE, person->isOpened );
3479 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3484 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3486 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3487 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3489 if( atci == NULL ) return;
3490 if( atciMail == NULL ) return;
3492 /* Load email addresses */
3493 items = addritem_folder_get_person_list( itemFolder );
3494 for( ; items != NULL; items = g_list_next( items ) ) {
3495 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3497 /* Free up the list */
3498 mgu_clear_list( items );
3499 g_list_free( items );
3502 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3503 addrbook.listSelected = NULL;
3504 gtk_ctree_remove_node( clist, node );
3505 addressbook_menubar_set_sensitive( FALSE );
3506 addressbook_menuitem_set_sensitive(
3507 gtk_ctree_node_get_row_data(
3508 GTK_CTREE(clist), addrbook.treeSelected ),
3509 addrbook.treeSelected );
3512 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3513 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3514 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3516 if( atci == NULL ) return;
3517 if( atciMail == NULL ) return;
3518 if( person == NULL ) return;
3519 /* unload the person */
3521 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3523 addressbook_folder_remove_node( clist, node );
3524 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3525 gtk_sctree_sort_node( clist, NULL );
3526 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3528 gtk_sctree_select( GTK_SCTREE(clist), node );
3529 if (!gtk_ctree_node_is_visible( clist, node ) )
3530 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3534 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3538 if( person == NULL ) return;
3539 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3540 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3542 addressbook_folder_remove_node( clist, node );
3546 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3548 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3550 /* Load any groups */
3551 if( ! atci ) return;
3552 items = addritem_folder_get_group_list( itemFolder );
3553 for( ; items != NULL; items = g_list_next( items ) ) {
3554 GtkCTreeNode *nodeGroup = NULL;
3555 gchar *text[N_LIST_COLS];
3556 ItemGroup *group = items->data;
3557 if( group == NULL ) continue;
3558 text[COL_NAME] = ADDRITEM_NAME(group);
3559 text[COL_ADDRESS] = "";
3560 text[COL_REMARKS] = "";
3561 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3562 text, FOLDER_SPACING,
3563 atci->iconXpm, atci->maskXpm,
3564 atci->iconXpmOpen, atci->maskXpmOpen,
3566 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3567 gtk_sctree_sort_node(clist, NULL);
3569 /* Free up the list */
3570 mgu_clear_list( items );
3571 g_list_free( items );
3575 * Search ctree widget callback function.
3576 * \param pA Pointer to node.
3577 * \param pB Pointer to data item being sought.
3578 * \return Zero (0) if group found.
3580 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3583 aoA = ( AddressObject * ) pA;
3584 if( aoA->type == ADDR_ITEM_GROUP ) {
3585 ItemGroup *group, *grp;
3587 grp = ADAPTER_GROUP(aoA)->itemGroup;
3588 group = ( ItemGroup * ) pB;
3589 if( grp == group ) return 0; /* Found group */
3595 * Remove folder and group nodes from tree widget for items contained ("cut")
3598 static void addressbook_treenode_remove_item( void ) {
3600 AddrSelectItem *cutItem;
3601 AddressCache *cache;
3602 AddrItemObject *aio;
3603 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3606 node = _clipBoard_->objectList;
3608 cutItem = node->data;
3609 node = g_list_next( node );
3610 cache = addrindex_get_cache(
3611 _clipBoard_->addressIndex, cutItem->cacheID );
3612 if( cache == NULL ) continue;
3613 aio = addrcache_get_object( cache, cutItem->uid );
3616 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3619 folder = ( ItemFolder * ) aio;
3620 tn = gtk_ctree_find_by_row_data_custom(
3621 ctree, NULL, folder,
3622 addressbook_treenode_find_folder_cb );
3624 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3627 group = ( ItemGroup * ) aio;
3628 tn = gtk_ctree_find_by_row_data_custom(
3630 addressbook_treenode_find_group_cb );
3634 /* Free up adapter and remove node. */
3635 gtk_ctree_remove_node( ctree, tn );
3642 * Find parent datasource for specified tree node.
3643 * \param node Node to test.
3644 * \return Data source, or NULL if not found.
3646 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3647 AddressDataSource *ds = NULL;
3650 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3653 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3654 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3656 /* printf( "ao->type = %d\n", ao->type ); */
3657 if( ao->type == ADDR_DATASOURCE ) {
3658 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3659 /* printf( "found it\n" ); */
3660 ds = ads->dataSource;
3664 node = GTK_CTREE_ROW(node)->parent;
3670 * Load address list widget with children of specified object.
3671 * \param obj Parent object to be loaded.
3673 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3674 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3675 GtkCList *clist = GTK_CLIST(addrbook.clist);
3676 AddressDataSource *ds = NULL;
3677 AdapterDSource *ads = NULL;
3678 static AddressObject *last_obj = NULL;
3680 if (addrbook.clist == NULL) {
3683 if (obj == last_obj && !refresh)
3688 gtk_clist_clear(clist);
3692 if( obj->type == ADDR_INTERFACE ) {
3693 /* printf( "set_clist: loading datasource...\n" ); */
3694 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3698 gtk_clist_freeze(clist);
3699 gtk_clist_clear(clist);
3701 if( obj->type == ADDR_DATASOURCE ) {
3702 ads = ADAPTER_DSOURCE(obj);
3703 ds = ADAPTER_DSOURCE(obj)->dataSource;
3705 /* Load root folder */
3706 ItemFolder *rootFolder = NULL;
3707 rootFolder = addrindex_ds_get_root_folder( ds );
3708 addressbook_folder_load_person(
3709 ctreelist, addrindex_ds_get_root_folder( ds ) );
3710 addressbook_folder_load_group(
3711 ctreelist, addrindex_ds_get_root_folder( ds ) );
3715 if( obj->type == ADDR_ITEM_GROUP ) {
3717 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3718 addressbook_load_group( ctreelist, itemGroup );
3720 else if( obj->type == ADDR_ITEM_FOLDER ) {
3722 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3723 addressbook_folder_load_person( ctreelist, itemFolder );
3724 addressbook_folder_load_group( ctreelist, itemFolder );
3727 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3728 clist->focus_row = -1;
3729 gtk_clist_thaw(clist);
3733 * Call back function to free adaptor. Call back is setup by function
3734 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3735 * called when the address book tree widget node is removed by calling
3736 * function gtk_ctree_remove_node().
3738 * \param data Tree node's row data.
3740 static void addressbook_free_treenode( gpointer data ) {
3743 ao = ( AddressObject * ) data;
3744 if( ao == NULL ) return;
3745 if( ao->type == ADDR_INTERFACE ) {
3746 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3747 addrbookctl_free_interface( ai );
3749 else if( ao->type == ADDR_DATASOURCE ) {
3750 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3751 addrbookctl_free_datasource( ads );
3753 else if( ao->type == ADDR_ITEM_FOLDER ) {
3754 AdapterFolder *af = ADAPTER_FOLDER(ao);
3755 addrbookctl_free_folder( af );
3757 else if( ao->type == ADDR_ITEM_GROUP ) {
3758 AdapterGroup *ag = ADAPTER_GROUP(ao);
3759 addrbookctl_free_group( ag );
3764 * Create new adaptor for specified data source.
3766 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3767 AddressObjectType otype, gchar *name )
3769 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3770 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3771 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3772 adapter->dataSource = ds;
3773 adapter->subType = otype;
3777 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3778 ADDRESS_OBJECT_NAME(adapter) =
3779 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3783 * Load tree from address index with the initial data.
3785 static void addressbook_load_tree( void ) {
3786 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3787 GList *nodeIf, *nodeDS;
3788 AdapterInterface *adapter;
3789 AddressInterface *iface;
3790 AddressTypeControlItem *atci;
3791 AddressDataSource *ds;
3792 AdapterDSource *ads;
3793 GtkCTreeNode *node, *newNode;
3796 nodeIf = _addressInterfaceList_;
3798 adapter = nodeIf->data;
3799 node = adapter->treeNode;
3800 iface = adapter->interface;
3801 atci = adapter->atci;
3803 if( iface->useInterface ) {
3804 /* Load data sources below interface node */
3805 nodeDS = iface->listSource;
3809 name = addrindex_ds_get_name( ds );
3810 ads = addressbook_create_ds_adapter(
3811 ds, atci->objectType, name );
3812 newNode = addressbook_add_object(
3813 node, ADDRESS_OBJECT(ads) );
3814 nodeDS = g_list_next( nodeDS );
3816 gtk_ctree_expand( ctree, node );
3819 nodeIf = g_list_next( nodeIf );
3824 * Convert the old address book to new format.
3826 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3827 gboolean retVal = FALSE;
3828 gboolean errFlag = TRUE;
3831 /* Read old address book, performing conversion */
3832 debug_print( "Reading and converting old address book...\n" );
3833 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3834 addrindex_read_data( addrIndex );
3835 if( addrIndex->retVal == MGU_NO_FILE ) {
3836 /* We do not have a file - new user */
3837 debug_print( "New user... create new books...\n" );
3838 addrindex_create_new_books( addrIndex );
3839 if( addrIndex->retVal == MGU_SUCCESS ) {
3840 /* Save index file */
3841 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3842 addrindex_save_data( addrIndex );
3843 if( addrIndex->retVal == MGU_SUCCESS ) {
3848 msg = _( "New user, could not save index file." );
3852 msg = _( "New user, could not save address book files." );
3856 /* We have an old file */
3857 if( addrIndex->wasConverted ) {
3858 /* Converted successfully - save address index */
3859 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3860 addrindex_save_data( addrIndex );
3861 if( addrIndex->retVal == MGU_SUCCESS ) {
3862 msg = _( "Old address book converted successfully." );
3867 msg = _("Old address book converted,\n"
3868 "could not save new address index file." );
3872 /* File conversion failed - just create new books */
3873 debug_print( "File conversion failed... just create new books...\n" );
3874 addrindex_create_new_books( addrIndex );
3875 if( addrIndex->retVal == MGU_SUCCESS ) {
3877 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3878 addrindex_save_data( addrIndex );
3879 if( addrIndex->retVal == MGU_SUCCESS ) {
3880 msg = _("Could not convert address book,\n"
3881 "but created empty new address book files." );
3886 msg = _("Could not convert address book,\n"
3887 "could not save new address index file." );
3891 msg = _("Could not convert address book\n"
3892 "and could not create new address book files." );
3897 debug_print( "Error\n%s\n", msg );
3898 alertpanel_full(_("Addressbook conversion error"), msg,
3899 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3900 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3903 debug_print( "Warning\n%s\n", msg );
3904 alertpanel_full(_("Addressbook conversion error"), msg,
3905 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3906 NULL, ALERT_WARNING, G_ALERTDEFAULT);
3912 void addressbook_read_file( void ) {
3913 AddressIndex *addrIndex = NULL;
3915 debug_print( "Reading address index...\n" );
3916 if( _addressIndex_ ) {
3917 debug_print( "address book already read!!!\n" );
3921 addrIndex = addrindex_create_index();
3922 addrindex_initialize();
3924 /* Use new address book index. */
3925 addrindex_set_file_path( addrIndex, get_rc_dir() );
3926 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3927 addrindex_read_data( addrIndex );
3928 if( addrIndex->retVal == MGU_NO_FILE ) {
3929 /* Conversion required */
3930 debug_print( "Converting...\n" );
3931 if( addressbook_convert( addrIndex ) ) {
3932 _addressIndex_ = addrIndex;
3935 else if( addrIndex->retVal == MGU_SUCCESS ) {
3936 _addressIndex_ = addrIndex;
3939 /* Error reading address book */
3940 debug_print( "Could not read address index.\n" );
3941 addrindex_print_index( addrIndex, stdout );
3942 alertpanel_full(_("Addressbook Error"),
3943 _("Could not read address index"),
3944 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3945 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3947 debug_print( "done.\n" );
3951 * Add object into the address index tree widget.
3952 * Enter: node Parent node.
3953 * obj Object to add.
3954 * Return: Node that was added, or NULL if object not added.
3956 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
3959 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3960 GtkCTreeNode *added;
3961 AddressObject *pobj;
3962 AddressObjectType otype;
3963 AddressTypeControlItem *atci = NULL;
3965 g_return_val_if_fail(node != NULL, NULL);
3966 g_return_val_if_fail(obj != NULL, NULL);
3968 pobj = gtk_ctree_node_get_row_data(ctree, node);
3969 g_return_val_if_fail(pobj != NULL, NULL);
3971 /* Determine object type to be displayed */
3972 if( obj->type == ADDR_DATASOURCE ) {
3973 otype = ADAPTER_DSOURCE(obj)->subType;
3979 /* Handle any special conditions. */
3981 atci = addrbookctl_lookup( otype );
3983 if( atci->showInTree ) {
3984 /* Add object to tree */
3987 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
3988 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
3989 atci->treeLeaf, atci->treeExpand );
3990 gtk_ctree_node_set_row_data_full( ctree, added, obj,
3991 addressbook_free_treenode );
3995 gtk_sctree_sort_node(ctree, node);
4001 * Add group into the address index tree.
4002 * \param node Parent node.
4003 * \param ds Data source.
4004 * \param itemGroup Group to add.
4005 * \return Inserted node.
4007 static GtkCTreeNode *addressbook_node_add_group(
4008 GtkCTreeNode *node, AddressDataSource *ds,
4009 ItemGroup *itemGroup )
4011 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4012 GtkCTreeNode *newNode;
4013 AdapterGroup *adapter;
4014 AddressTypeControlItem *atci = NULL;
4017 if( ds == NULL ) return NULL;
4018 if( node == NULL || itemGroup == NULL ) return NULL;
4020 name = &itemGroup->obj.name;
4022 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4024 adapter = g_new0( AdapterGroup, 1 );
4025 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4026 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4027 adapter->itemGroup = itemGroup;
4029 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4030 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4031 atci->treeLeaf, atci->treeExpand );
4032 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4033 addressbook_free_treenode );
4034 gtk_sctree_sort_node( ctree, node );
4039 * Add folder into the address index tree. Only visible folders are loaded into
4040 * the address index tree. Note that the root folder is not inserted into the
4043 * \param node Parent node.
4044 * \param ds Data source.
4045 * \param itemFolder Folder to add.
4046 * \param otype Object type to display.
4047 * \return Inserted node for the folder.
4049 static GtkCTreeNode *addressbook_node_add_folder(
4050 GtkCTreeNode *node, AddressDataSource *ds,
4051 ItemFolder *itemFolder, AddressObjectType otype )
4053 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4054 GtkCTreeNode *newNode = NULL;
4055 AdapterFolder *adapter;
4056 AddressTypeControlItem *atci = NULL;
4057 GList *listItems = NULL;
4059 ItemFolder *rootFolder;
4061 /* Only visible folders */
4062 if( itemFolder->isHidden ) return NULL;
4064 if( ds == NULL ) return NULL;
4065 if( node == NULL || itemFolder == NULL ) return NULL;
4067 /* Determine object type */
4068 atci = addrbookctl_lookup( otype );
4069 if( atci == NULL ) return NULL;
4071 rootFolder = addrindex_ds_get_root_folder( ds );
4072 if( itemFolder == rootFolder ) {
4076 adapter = g_new0( AdapterFolder, 1 );
4077 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4078 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4079 adapter->itemFolder = itemFolder;
4081 name = ADDRITEM_NAME(itemFolder);
4082 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4083 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4084 atci->treeLeaf, atci->treeExpand );
4086 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4087 addressbook_free_treenode );
4091 listItems = itemFolder->listFolder;
4092 while( listItems ) {
4093 ItemFolder *item = listItems->data;
4094 addressbook_node_add_folder( newNode, ds, item, otype );
4095 listItems = g_list_next( listItems );
4097 listItems = itemFolder->listGroup;
4098 while( listItems ) {
4099 ItemGroup *item = listItems->data;
4100 addressbook_node_add_group( newNode, ds, item );
4101 listItems = g_list_next( listItems );
4103 gtk_sctree_sort_node( ctree, node );
4107 void addressbook_export_to_file( void ) {
4108 if( _addressIndex_ ) {
4109 /* Save all new address book data */
4110 debug_print( "Saving address books...\n" );
4111 addrindex_save_all_books( _addressIndex_ );
4113 debug_print( "Exporting addressbook to file...\n" );
4114 addrindex_save_data( _addressIndex_ );
4115 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4116 addrindex_print_index( _addressIndex_, stdout );
4119 /* Notify address completion of new data */
4120 invalidate_address_completion();
4124 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4126 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4127 addressbook_lup_clicked(NULL, NULL);
4132 * Comparison using cell contents (text in first column). Used for sort
4133 * address index widget.
4135 static gint addressbook_treenode_compare_func(
4136 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4138 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
4139 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
4140 gchar *name1 = NULL, *name2 = NULL;
4141 if( cell1 ) name1 = cell1->u.text;
4142 if( cell2 ) name2 = cell2->u.text;
4143 if( ! name1 ) return ( name2 != NULL );
4144 if( ! name2 ) return -1;
4145 return g_utf8_collate( name1, name2 );
4148 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
4149 AdapterDSource *ads;
4150 AdapterInterface *adapter;
4151 GtkCTreeNode *newNode;
4153 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4154 if( adapter == NULL ) return;
4155 ads = addressbook_edit_book( _addressIndex_, NULL );
4157 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4159 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4160 addrbook.treeSelected = newNode;
4165 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
4166 AdapterDSource *ads;
4167 AdapterInterface *adapter;
4168 GtkCTreeNode *newNode;
4170 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4171 if( adapter == NULL ) return;
4172 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4174 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4176 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4177 addrbook.treeSelected = newNode;
4183 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
4184 AdapterDSource *ads;
4185 AdapterInterface *adapter;
4186 AddressInterface *iface;
4187 GtkCTreeNode *newNode;
4189 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4190 if( adapter == NULL ) return;
4191 iface = adapter->interface;
4192 if( ! iface->haveLibrary ) return;
4193 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4195 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4197 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4198 addrbook.treeSelected = newNode;
4205 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
4206 AdapterDSource *ads;
4207 AdapterInterface *adapter;
4208 AddressInterface *iface;
4209 GtkCTreeNode *newNode;
4211 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4212 if( adapter == NULL ) return;
4213 iface = adapter->interface;
4214 if( ! iface->haveLibrary ) return;
4215 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4217 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4219 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4220 addrbook.treeSelected = newNode;
4227 * Display address search status message.
4228 * \param queryType Query type.
4229 * \param status Status/Error code.
4231 static void addressbook_search_message( gint queryType, gint sts ) {
4233 *addressbook_msgbuf = '\0';
4235 if( sts != MGU_SUCCESS ) {
4236 if( queryType == ADDRQUERY_LDAP ) {
4238 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4243 g_snprintf( addressbook_msgbuf,
4244 sizeof(addressbook_msgbuf), "%s", desc );
4245 addressbook_status_show( addressbook_msgbuf );
4248 addressbook_status_show( "" );
4253 * Refresh addressbook by forcing refresh of current selected object in
4256 static void addressbook_refresh_current( void ) {
4260 ctree = GTK_CTREE(addrbook.ctree);
4261 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4262 if( obj == NULL ) return;
4263 addressbook_set_clist( obj, TRUE );
4267 * Message that is displayed whilst a query is executing in a background
4270 static gchar *_tempMessage_ = N_( "Busy searching..." );
4273 * Address search idle function. This function is called during UI idle time
4274 * while a search is in progress.
4276 * \param data Idler data.
4278 static void addressbook_search_idle( gpointer data ) {
4282 queryID = GPOINTER_TO_INT( data );
4283 printf( "addressbook_ldap_idle... queryID=%d\n", queryID );
4288 * Search completion callback function. This removes the query from the idle
4291 * \param sender Sender of query.
4292 * \param queryID Query ID of search request.
4293 * \param status Search status.
4294 * \param data Query data.
4296 static void addressbook_search_callback_end(
4297 gpointer sender, gint queryID, gint status, gpointer data )
4301 AddrQueryObject *aqo;
4303 /* Remove idler function */
4304 ptrQID = GINT_TO_POINTER( queryID );
4306 g_idle_remove_by_data( ptrQID );
4309 /* Refresh addressbook contents */
4310 addressbook_refresh_current();
4311 req = qrymgr_find_request( queryID );
4313 aqo = ( AddrQueryObject * ) req->queryList->data;
4314 addressbook_search_message( aqo->queryType, status );
4317 /* Stop the search */
4318 addrindex_stop_search( queryID );
4324 * \param ds Data source to search.
4325 * \param searchTerm String to lookup.
4326 * \param pNode Parent data source node.
4328 static void addressbook_perform_search(
4329 AddressDataSource *ds, gchar *searchTerm,
4330 GtkCTreeNode *pNode )
4332 AddrBookBase *adbase;
4333 AddressCache *cache;
4339 AddressObjectType aoType = ADDR_NONE;
4343 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4345 if( ds && ds->type == ADDR_IF_LDAP ) {
4347 aoType = ADDR_LDAP_QUERY;
4353 /* Get reference to address cache */
4354 adbase = ( AddrBookBase * ) ds->rawDataSource;
4355 cache = adbase->addressCache;
4357 /* Create a folder for the search results */
4358 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4359 folder = addressbook_setup_subf(ds, name, pNode);
4362 /* Setup the search */
4363 queryID = addrindex_setup_explicit_search(
4364 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4365 if( queryID == 0 ) return;
4367 /* Set up idler function */
4368 idleID = g_idle_add(
4369 ( GtkFunction ) addressbook_search_idle,
4370 GINT_TO_POINTER( queryID ) );
4372 /* Start search, sit back and wait for something to happen */
4373 addrindex_start_search( queryID );
4375 addressbook_status_show( _tempMessage_ );
4379 * Lookup button handler. Address search is only performed against
4380 * address interfaces for external queries.
4382 * \param button Lookup button widget.
4383 * \param data Data object.
4385 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4388 AddressDataSource *ds;
4389 AddressInterface *iface;
4391 GtkCTreeNode *node, *parentNode;
4393 node = addrbook.treeSelected;
4394 if( ! node ) return;
4395 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4397 ctree = GTK_CTREE(addrbook.ctree);
4398 obj = gtk_ctree_node_get_row_data( ctree, node );
4399 if( obj == NULL ) return;
4401 ds = addressbook_find_datasource( node );
4402 if( ds == NULL ) return;
4404 /* We must have a datasource that is an external interface */
4405 iface = ds->interface;
4406 if( ! iface->haveLibrary ) return;
4407 if( ! iface->externalQuery ) return;
4410 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4411 g_strchomp( searchTerm );
4413 if( obj->type == ADDR_ITEM_FOLDER ) {
4414 parentNode = GTK_CTREE_ROW(node)->parent;
4419 addressbook_perform_search( ds, searchTerm, parentNode );
4421 gtk_widget_grab_focus( addrbook.entry );
4423 g_free( searchTerm );
4426 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4427 addressbook_close();
4432 * Browse address entry for highlighted entry.
4434 static void addressbook_browse_entry_cb(void)
4436 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4438 AddressDataSource *ds;
4439 AddressInterface *iface;
4443 if(addrbook.listSelected == NULL)
4446 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4450 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4454 iface = ds->interface;
4455 if(! iface->haveLibrary )
4459 if (obj->type == ADDR_ITEM_EMAIL) {
4460 email = ( ItemEMail * ) obj;
4464 person = (ItemPerson *) ADDRITEM_PARENT(email);
4466 else if (obj->type == ADDR_ITEM_PERSON) {
4467 person = (ItemPerson *) obj;
4474 if( iface && iface->type == ADDR_IF_LDAP ) {
4475 browseldap_entry(ds, person->externalID);
4480 /* **********************************************************************
4481 * Build lookup tables.
4482 * ***********************************************************************
4486 * Remap object types.
4487 * Enter: abType AddressObjectType (used in tree node).
4488 * Return: ItemObjectType (used in address cache data).
4490 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4491 ItemObjectType ioType;
4494 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4495 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4496 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4497 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4498 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4499 default: ioType = ITEMTYPE_NONE; break;
4505 * Build table that controls the rendering of object types.
4507 static void addrbookctl_build_map( GtkWidget *window ) {
4508 AddressTypeControlItem *atci;
4511 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4512 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4513 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4514 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4515 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4516 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4517 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4518 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4519 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4520 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4522 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4523 _addressBookTypeList_ = NULL;
4526 atci = g_new0( AddressTypeControlItem, 1 );
4527 atci->objectType = ADDR_INTERFACE;
4528 atci->interfaceType = ADDR_IF_NONE;
4529 atci->showInTree = TRUE;
4530 atci->treeExpand = TRUE;
4531 atci->treeLeaf = FALSE;
4532 atci->displayName = _( "Interface" );
4533 atci->iconXpm = folderxpm;
4534 atci->maskXpm = folderxpmmask;
4535 atci->iconXpmOpen = folderopenxpm;
4536 atci->maskXpmOpen = folderopenxpmmask;
4537 atci->menuCommand = NULL;
4538 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4539 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4542 atci = g_new0( AddressTypeControlItem, 1 );
4543 atci->objectType = ADDR_BOOK;
4544 atci->interfaceType = ADDR_IF_BOOK;
4545 atci->showInTree = TRUE;
4546 atci->treeExpand = TRUE;
4547 atci->treeLeaf = FALSE;
4548 atci->displayName = _( "Address Book" );
4549 atci->iconXpm = bookxpm;
4550 atci->maskXpm = bookxpmmask;
4551 atci->iconXpmOpen = bookxpm;
4552 atci->maskXpmOpen = bookxpmmask;
4553 atci->menuCommand = "/Book/New Book";
4554 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4555 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4558 atci = g_new0( AddressTypeControlItem, 1 );
4559 atci->objectType = ADDR_ITEM_PERSON;
4560 atci->interfaceType = ADDR_IF_NONE;
4561 atci->showInTree = FALSE;
4562 atci->treeExpand = FALSE;
4563 atci->treeLeaf = FALSE;
4564 atci->displayName = _( "Person" );
4565 atci->iconXpm = NULL;
4566 atci->maskXpm = NULL;
4567 atci->iconXpmOpen = NULL;
4568 atci->maskXpmOpen = NULL;
4569 atci->menuCommand = NULL;
4570 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4571 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4574 atci = g_new0( AddressTypeControlItem, 1 );
4575 atci->objectType = ADDR_ITEM_EMAIL;
4576 atci->interfaceType = ADDR_IF_NONE;
4577 atci->showInTree = FALSE;
4578 atci->treeExpand = FALSE;
4579 atci->treeLeaf = TRUE;
4580 atci->displayName = _( "EMail Address" );
4581 atci->iconXpm = addressxpm;
4582 atci->maskXpm = addressxpmmask;
4583 atci->iconXpmOpen = addressxpm;
4584 atci->maskXpmOpen = addressxpmmask;
4585 atci->menuCommand = NULL;
4586 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4587 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4590 atci = g_new0( AddressTypeControlItem, 1 );
4591 atci->objectType = ADDR_ITEM_GROUP;
4592 atci->interfaceType = ADDR_IF_BOOK;
4593 atci->showInTree = TRUE;
4594 atci->treeExpand = FALSE;
4595 atci->treeLeaf = FALSE;
4596 atci->displayName = _( "Group" );
4597 atci->iconXpm = groupxpm;
4598 atci->maskXpm = groupxpmmask;
4599 atci->iconXpmOpen = groupxpm;
4600 atci->maskXpmOpen = groupxpmmask;
4601 atci->menuCommand = NULL;
4602 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4603 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4606 atci = g_new0( AddressTypeControlItem, 1 );
4607 atci->objectType = ADDR_ITEM_FOLDER;
4608 atci->interfaceType = ADDR_IF_BOOK;
4609 atci->showInTree = TRUE;
4610 atci->treeExpand = FALSE;
4611 atci->treeLeaf = FALSE;
4612 atci->displayName = _( "Folder" );
4613 atci->iconXpm = folderxpm;
4614 atci->maskXpm = folderxpmmask;
4615 atci->iconXpmOpen = folderopenxpm;
4616 atci->maskXpmOpen = folderopenxpmmask;
4617 atci->menuCommand = NULL;
4618 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4619 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4622 atci = g_new0( AddressTypeControlItem, 1 );
4623 atci->objectType = ADDR_VCARD;
4624 atci->interfaceType = ADDR_IF_VCARD;
4625 atci->showInTree = TRUE;
4626 atci->treeExpand = TRUE;
4627 atci->treeLeaf = TRUE;
4628 atci->displayName = _( "vCard" );
4629 atci->iconXpm = vcardxpm;
4630 atci->maskXpm = vcardxpmmask;
4631 atci->iconXpmOpen = vcardxpm;
4632 atci->maskXpmOpen = vcardxpmmask;
4633 atci->menuCommand = "/Book/New vCard";
4634 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4635 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4638 atci = g_new0( AddressTypeControlItem, 1 );
4639 atci->objectType = ADDR_JPILOT;
4640 atci->interfaceType = ADDR_IF_JPILOT;
4641 atci->showInTree = TRUE;
4642 atci->treeExpand = TRUE;
4643 atci->treeLeaf = FALSE;
4644 atci->displayName = _( "JPilot" );
4645 atci->iconXpm = jpilotxpm;
4646 atci->maskXpm = jpilotxpmmask;
4647 atci->iconXpmOpen = jpilotxpm;
4648 atci->maskXpmOpen = jpilotxpmmask;
4649 atci->menuCommand = "/Book/New JPilot";
4650 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4651 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4654 atci = g_new0( AddressTypeControlItem, 1 );
4655 atci->objectType = ADDR_CATEGORY;
4656 atci->interfaceType = ADDR_IF_JPILOT;
4657 atci->showInTree = TRUE;
4658 atci->treeExpand = TRUE;
4659 atci->treeLeaf = TRUE;
4660 atci->displayName = _( "JPilot" );
4661 atci->iconXpm = categoryxpm;
4662 atci->maskXpm = categoryxpmmask;
4663 atci->iconXpmOpen = categoryxpm;
4664 atci->maskXpmOpen = categoryxpmmask;
4665 atci->menuCommand = NULL;
4666 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4667 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4670 atci = g_new0( AddressTypeControlItem, 1 );
4671 atci->objectType = ADDR_LDAP;
4672 atci->interfaceType = ADDR_IF_LDAP;
4673 atci->showInTree = TRUE;
4674 atci->treeExpand = TRUE;
4675 atci->treeLeaf = FALSE;
4676 atci->displayName = _( "LDAP servers" );
4677 atci->iconXpm = ldapxpm;
4678 atci->maskXpm = ldapxpmmask;
4679 atci->iconXpmOpen = ldapxpm;
4680 atci->maskXpmOpen = ldapxpmmask;
4681 atci->menuCommand = "/Book/New LDAP Server";
4682 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4683 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4686 atci = g_new0( AddressTypeControlItem, 1 );
4687 atci->objectType = ADDR_LDAP_QUERY;
4688 atci->interfaceType = ADDR_IF_LDAP;
4689 atci->showInTree = TRUE;
4690 atci->treeExpand = FALSE;
4691 atci->treeLeaf = TRUE;
4692 atci->displayName = _( "LDAP Query" );
4693 atci->iconXpm = addrsearchxpm;
4694 atci->maskXpm = addrsearchxpmmask;
4695 atci->iconXpmOpen = addrsearchxpm;
4696 atci->maskXpmOpen = addrsearchxpmmask;
4697 atci->menuCommand = NULL;
4698 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4699 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4704 * Search for specified object type.
4706 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4708 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4712 * Search for specified interface type.
4714 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4715 GList *node = _addressBookTypeList_;
4717 AddressTypeControlItem *atci = node->data;
4718 if( atci->interfaceType == ifType ) return atci;
4719 node = g_list_next( node );
4724 static void addrbookctl_free_address( AddressObject *obj ) {
4725 g_free( obj->name );
4726 obj->type = ADDR_NONE;
4730 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4731 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4732 adapter->interface = NULL;
4733 adapter->interfaceType = ADDR_IF_NONE;
4734 adapter->atci = NULL;
4735 adapter->enabled = FALSE;
4736 adapter->haveLibrary = FALSE;
4737 adapter->treeNode = NULL;
4741 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4742 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4743 adapter->dataSource = NULL;
4744 adapter->subType = ADDR_NONE;
4748 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4749 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4750 adapter->itemFolder = NULL;
4754 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4755 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4756 adapter->itemGroup = NULL;
4761 * Build GUI interface list.
4763 static void addrbookctl_build_iflist( void ) {
4764 AddressTypeControlItem *atci;
4765 AdapterInterface *adapter;
4768 if( _addressIndex_ == NULL ) {
4769 _addressIndex_ = addrindex_create_index();
4770 if( _clipBoard_ == NULL ) {
4771 _clipBoard_ = addrclip_create();
4773 addrclip_set_index( _clipBoard_, _addressIndex_ );
4775 _addressInterfaceList_ = NULL;
4776 list = addrindex_get_interface_list( _addressIndex_ );
4778 AddressInterface *interface = list->data;
4779 atci = addrbookctl_lookup_iface( interface->type );
4781 adapter = g_new0( AdapterInterface, 1 );
4782 adapter->interfaceType = interface->type;
4783 adapter->atci = atci;
4784 adapter->interface = interface;
4785 adapter->treeNode = NULL;
4786 adapter->enabled = TRUE;
4787 adapter->haveLibrary = interface->haveLibrary;
4788 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4789 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4790 _addressInterfaceList_ =
4791 g_list_append( _addressInterfaceList_, adapter );
4793 list = g_list_next( list );
4798 * Find GUI interface type specified interface type.
4799 * \param ifType Interface type.
4800 * \return Interface item, or NULL if not found.
4802 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4803 GList *node = _addressInterfaceList_;
4805 AdapterInterface *adapter = node->data;
4806 if( adapter->interfaceType == ifType ) return adapter;
4807 node = g_list_next( node );
4813 * Build interface list selection.
4815 static void addrbookctl_build_ifselect( void ) {
4816 GList *newList = NULL;
4821 gchar *endptr = NULL;
4823 AdapterInterface *adapter;
4825 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4828 splitStr = g_strsplit( selectStr, ",", -1 );
4829 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4831 /* printf( "%d : %s\n", i, splitStr[i] ); */
4832 ifType = strtol( splitStr[i], &endptr, 10 );
4835 if( strcmp( endptr, "/n" ) == 0 ) {
4839 /* printf( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4840 adapter = addrbookctl_find_interface( ifType );
4842 newList = g_list_append( newList, adapter );
4849 /* printf( "i=%d\n", i ); */
4850 g_strfreev( splitStr );
4851 g_free( selectStr );
4853 /* Replace existing list */
4854 mgu_clear_list( _addressIFaceSelection_ );
4855 g_list_free( _addressIFaceSelection_ );
4856 _addressIFaceSelection_ = newList;
4860 /* ***********************************************************************
4861 * Add sender to address book.
4862 * ***********************************************************************
4866 * This function is used by the Add sender to address book function.
4868 gboolean addressbook_add_contact(
4869 const gchar *name, const gchar *address, const gchar *remarks )
4871 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
4872 if( addressadd_selection( _addressIndex_, name, address, remarks ) ) {
4873 debug_print( "addressbook_add_contact - added\n" );
4874 addressbook_refresh();
4879 /* ***********************************************************************
4880 * Book/folder selection.
4881 * ***********************************************************************
4885 * This function is used by the matcher dialog to select a book/folder.
4887 gboolean addressbook_folder_selection( gchar **folderpath )
4889 AddressBookFile *book = NULL;
4890 ItemFolder *folder = NULL;
4893 g_return_val_if_fail( folderpath != NULL, FALSE);
4897 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, path )
4899 if ( folder != NULL) {
4901 gchar *oldtmp = NULL;
4902 AddrItemObject *obj = NULL;
4904 /* walk thru folder->parent to build the full folder path */
4905 /* TODO: wwp: optimize this */
4907 tmp = g_strdup(obj->uid);
4908 while ( obj->parent ) {
4910 if ( obj->name != NULL ) {
4911 oldtmp = g_strdup(tmp);
4913 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
4917 *folderpath = g_strdup_printf("%s/%s", book->fileName, tmp);
4920 *folderpath = g_strdup_printf("%s", book->fileName);
4922 debug_print( "addressbook_foldersel: %s\n", *folderpath?*folderpath:"(null)");
4923 return (*folderpath != NULL);
4928 /* ***********************************************************************
4929 * Book/folder checking.
4930 * ***********************************************************************
4933 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
4935 FolderInfo *fi = g_new0( FolderInfo, 1 );
4937 fi->folder = folder;
4941 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
4942 FolderInfo *fiParent, FolderPathMatch *match )
4948 FolderPathMatch *nextmatch = NULL;
4953 list = parentFolder->listFolder;
4955 folder = list->data;
4956 fName = g_strdup( ADDRITEM_NAME(folder) );
4958 /* match folder name, match pointer will be set to NULL if next recursive call
4959 doesn't need to match subfolder name */
4960 if ( match != NULL &&
4961 match->matched == FALSE ) {
4962 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
4963 /* folder name matches, prepare next subfolder match */
4964 debug_print("matched folder name '%s'\n", fName);
4966 if ( match->folder_path[match->index] == NULL ) {
4967 /* we've matched all elements */
4968 match->matched = TRUE;
4969 match->folder = folder;
4970 debug_print("book/folder path matched!\n");
4972 /* keep on matching */
4980 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
4981 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
4983 list = g_list_next( list );
4988 * This function is used by to check if a matcher book/folder path corresponds to an
4989 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
4990 Caution: returned book and folder pointers can be NULL even when returning TRUE:
4991 if book AND folder are NULL this means that folderpath was empty or Any.
4992 If folderpath is a simple book name (without folder), book will not be NULL and folder
4993 will be NULL. It's not expected to return book as NULL and folder as non NULL.
4996 gboolean addressbook_peek_folder_exists( gchar *folderpath,
4997 AddressDataSource **book,
4998 ItemFolder **folder )
5000 AddressDataSource *ds;
5001 GList *list, *nodeDS;
5002 ItemFolder *rootFolder;
5003 AddressBookFile *abf;
5005 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5012 if ( folderpath == NULL )
5015 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
5018 /* split the folder path we've received, we'll try to match this path, subpath by
5019 subpath against the book/folder structure in order */
5020 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5021 if (!folder_path_match.folder_path)
5024 list = addrindex_get_interface_list( _addressIndex_ );
5025 while ( list && !folder_path_match.matched ) {
5026 AddressInterface *interface = list->data;
5027 if ( interface && interface->type == ADDR_IF_BOOK ) {
5028 nodeDS = interface->listSource;
5029 while ( nodeDS && !folder_path_match.matched ) {
5032 /* Read address book */
5033 if( ! addrindex_ds_get_read_flag( ds ) ) {
5034 addrindex_ds_read_data( ds );
5037 /* Add node for address book */
5038 abf = ds->rawDataSource;
5040 /* match book name */
5041 if ( abf && abf->fileName &&
5042 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5044 debug_print("matched book name '%s'\n", abf->fileName);
5045 folder_path_match.book = ds;
5047 if ( folder_path_match.folder_path[1] == NULL ) {
5048 /* no folder part to match */
5050 folder_path_match.matched = TRUE;
5051 folder_path_match.folder = NULL;
5052 debug_print("book path matched!\n");
5055 /* match folder part */
5057 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5058 rootFolder = addrindex_ds_get_root_folder( ds );
5060 /* prepare for recursive call */
5061 folder_path_match.index = 1;
5062 /* this call will set folder_path_match.matched and folder_path_match.folder */
5063 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5068 nodeDS = g_list_next( nodeDS );
5071 list = g_list_next( list );
5074 g_strfreev( folder_path_match.folder_path );
5077 *book = folder_path_match.book;
5079 *folder = folder_path_match.folder;
5080 return folder_path_match.matched;
5084 /* **********************************************************************
5086 * ***********************************************************************
5092 static void addressbook_import_ldif_cb( void ) {
5093 AddressDataSource *ds = NULL;
5094 AdapterDSource *ads = NULL;
5095 AddressBookFile *abf = NULL;
5096 AdapterInterface *adapter;
5097 GtkCTreeNode *newNode;
5099 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5101 if( adapter->treeNode ) {
5102 abf = addressbook_imp_ldif( _addressIndex_ );
5104 ds = addrindex_index_add_datasource(
5105 _addressIndex_, ADDR_IF_BOOK, abf );
5106 ads = addressbook_create_ds_adapter(
5107 ds, ADDR_BOOK, NULL );
5108 addressbook_ads_set_name(
5109 ads, addrbook_get_name( abf ) );
5110 newNode = addressbook_add_object(
5112 ADDRESS_OBJECT(ads) );
5114 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5116 addrbook.treeSelected = newNode;
5119 /* Notify address completion */
5120 invalidate_address_completion();
5129 static void addressbook_import_mutt_cb( void ) {
5130 AddressDataSource *ds = NULL;
5131 AdapterDSource *ads = NULL;
5132 AddressBookFile *abf = NULL;
5133 AdapterInterface *adapter;
5134 GtkCTreeNode *newNode;
5136 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5138 if( adapter->treeNode ) {
5139 abf = addressbook_imp_mutt( _addressIndex_ );
5141 ds = addrindex_index_add_datasource(
5142 _addressIndex_, ADDR_IF_BOOK, abf );
5143 ads = addressbook_create_ds_adapter(
5144 ds, ADDR_BOOK, NULL );
5145 addressbook_ads_set_name(
5146 ads, addrbook_get_name( abf ) );
5147 newNode = addressbook_add_object(
5149 ADDRESS_OBJECT(ads) );
5151 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5153 addrbook.treeSelected = newNode;
5156 /* Notify address completion */
5157 invalidate_address_completion();
5166 static void addressbook_import_pine_cb( void ) {
5167 AddressDataSource *ds = NULL;
5168 AdapterDSource *ads = NULL;
5169 AddressBookFile *abf = NULL;
5170 AdapterInterface *adapter;
5171 GtkCTreeNode *newNode;
5173 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5175 if( adapter->treeNode ) {
5176 abf = addressbook_imp_pine( _addressIndex_ );
5178 ds = addrindex_index_add_datasource(
5179 _addressIndex_, ADDR_IF_BOOK, abf );
5180 ads = addressbook_create_ds_adapter(
5181 ds, ADDR_BOOK, NULL );
5182 addressbook_ads_set_name(
5183 ads, addrbook_get_name( abf ) );
5184 newNode = addressbook_add_object(
5186 ADDRESS_OBJECT(ads) );
5188 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5190 addrbook.treeSelected = newNode;
5193 /* Notify address completion */
5194 invalidate_address_completion();
5201 * Harvest addresses.
5202 * \param folderItem Folder to import.
5203 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5204 * \param msgList List of message numbers, or NULL to process folder.
5206 void addressbook_harvest(
5207 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5209 AddressDataSource *ds = NULL;
5210 AdapterDSource *ads = NULL;
5211 AddressBookFile *abf = NULL;
5212 AdapterInterface *adapter;
5213 GtkCTreeNode *newNode;
5215 abf = addrgather_dlg_execute(
5216 folderItem, _addressIndex_, sourceInd, msgList );
5218 ds = addrindex_index_add_datasource(
5219 _addressIndex_, ADDR_IF_BOOK, abf );
5221 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5223 if( adapter->treeNode ) {
5224 ads = addressbook_create_ds_adapter(
5225 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5226 newNode = addressbook_add_object(
5228 ADDRESS_OBJECT(ads) );
5232 /* Notify address completion */
5233 invalidate_address_completion();
5240 static void addressbook_export_html_cb( void ) {
5241 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5243 AddressDataSource *ds = NULL;
5244 AddrBookBase *adbase;
5245 AddressCache *cache;
5246 GtkCTreeNode *node = NULL;
5248 if( ! addrbook.treeSelected ) return;
5249 node = addrbook.treeSelected;
5250 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5251 obj = gtk_ctree_node_get_row_data( ctree, node );
5252 if( obj == NULL ) return;
5254 ds = addressbook_find_datasource( node );
5255 if( ds == NULL ) return;
5256 adbase = ( AddrBookBase * ) ds->rawDataSource;
5257 cache = adbase->addressCache;
5258 addressbook_exp_html( cache );
5264 static void addressbook_export_ldif_cb( void ) {
5265 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5267 AddressDataSource *ds = NULL;
5268 AddrBookBase *adbase;
5269 AddressCache *cache;
5270 GtkCTreeNode *node = NULL;
5272 if( ! addrbook.treeSelected ) return;
5273 node = addrbook.treeSelected;
5274 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5275 obj = gtk_ctree_node_get_row_data( ctree, node );
5276 if( obj == NULL ) return;
5278 ds = addressbook_find_datasource( node );
5279 if( ds == NULL ) return;
5280 adbase = ( AddrBookBase * ) ds->rawDataSource;
5281 cache = adbase->addressCache;
5282 addressbook_exp_ldif( cache );
5285 static void addressbook_start_drag(GtkWidget *widget, gint button,
5289 GdkDragContext *context;
5290 if (addressbook_target_list == NULL)
5291 addressbook_target_list = gtk_target_list_new(
5292 addressbook_drag_types, 1);
5293 context = gtk_drag_begin(widget, addressbook_target_list,
5294 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5295 gtk_drag_set_icon_default(context);
5298 static void addressbook_drag_data_get(GtkWidget *widget,
5299 GdkDragContext *drag_context,
5300 GtkSelectionData *selection_data,
5305 AddrItemObject *aio = NULL;
5306 AddressObject *pobj = NULL;
5307 AdapterDSource *ads = NULL;
5308 AddressDataSource *ds = NULL;
5311 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5313 if( pobj == NULL ) return;
5315 if( pobj->type == ADDR_DATASOURCE ) {
5316 ads = ADAPTER_DSOURCE(pobj);
5317 ds = ads->dataSource;
5318 } else if (pobj->type == ADDR_ITEM_GROUP) {
5323 else if( pobj->type != ADDR_INTERFACE ) {
5324 ds = addressbook_find_datasource( addrbook.treeSelected );
5330 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5331 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5332 GTK_CTREE_NODE(cur->data));
5333 while (aio && aio->type != ADDR_ITEM_PERSON) {
5338 if (aio && aio->type == ADDR_ITEM_PERSON) {
5339 if( ds && ds->interface && ds->interface->readOnly)
5340 gtk_selection_data_set(selection_data,
5341 selection_data->target, 8,
5342 "Dummy_addr_copy", 15);
5344 gtk_selection_data_set(selection_data,
5345 selection_data->target, 8,
5346 "Dummy_addr_move", 15);
5350 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5351 GdkDragContext *context,
5358 GtkCTreeNode *node = NULL;
5359 gboolean acceptable = FALSE;
5360 gint height = addrbook.ctree->allocation.height;
5361 gint total_height = addrbook.ctree->requisition.height;
5362 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5363 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5364 gfloat vpos = pos->value;
5366 if (gtk_clist_get_selection_info
5367 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5369 if (y > height - 24 && height + vpos < total_height)
5370 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5372 if (y < 24 && y > 0)
5373 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5375 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5378 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5379 if( obj->type == ADDR_ITEM_FOLDER
5380 || obj->type == ADDR_ITEM_GROUP)
5383 AdapterDSource *ads = NULL;
5384 AddressDataSource *ds = NULL;
5385 ads = ADAPTER_DSOURCE(obj);
5386 if (ads == NULL ){ return FALSE;}
5387 ds = ads->dataSource;
5388 if (ds == NULL ) { return FALSE;}
5396 g_signal_handlers_block_by_func
5398 G_CALLBACK(addressbook_tree_selected), NULL);
5399 gtk_sctree_select( GTK_SCTREE(widget), node);
5400 g_signal_handlers_unblock_by_func
5402 G_CALLBACK(addressbook_tree_selected), NULL);
5403 gdk_drag_status(context,
5404 (context->actions == GDK_ACTION_COPY ?
5405 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5407 gdk_drag_status(context, 0, time);
5413 static void addressbook_drag_leave_cb(GtkWidget *widget,
5414 GdkDragContext *context,
5418 if (addrbook.treeSelected) {
5419 g_signal_handlers_block_by_func
5421 G_CALLBACK(addressbook_tree_selected), NULL);
5422 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5423 g_signal_handlers_unblock_by_func
5425 G_CALLBACK(addressbook_tree_selected), NULL);
5430 static void addressbook_drag_received_cb(GtkWidget *widget,
5431 GdkDragContext *drag_context,
5434 GtkSelectionData *data,
5441 GtkCTreeNode *lastopened = addrbook.opened;
5443 if (!strncmp(data->data, "Dummy_addr", 10)) {
5444 if (gtk_clist_get_selection_info
5445 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5449 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5450 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5453 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5454 if (drag_context->action == GDK_ACTION_COPY ||
5455 !strcmp(data->data, "Dummy_addr_copy"))
5456 addressbook_clip_copy_cb();
5458 addressbook_clip_cut_cb();
5459 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5460 addressbook_clip_paste_cb();
5461 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5462 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5463 gtk_drag_finish(drag_context, TRUE, TRUE, time);