2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtkwindow.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkscrolledwindow.h>
33 #include <gtk/gtkhpaned.h>
34 #include <gtk/gtkhbox.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtkentry.h>
37 #include <gtk/gtkctree.h>
38 #include <gtk/gtkclist.h>
39 #include <gtk/gtktable.h>
40 #include <gtk/gtkhbbox.h>
41 #include <gtk/gtkbutton.h>
42 #include <gtk/gtkmenu.h>
43 #include <gtk/gtkmenuitem.h>
44 #include <gtk/gtkitemfactory.h>
49 #include "addressbook.h"
50 #include "manage_window.h"
51 #include "prefs_common.h"
52 #include "alertpanel.h"
53 #include "inputdialog.h"
55 #include "stock_pixmap.h"
57 #include "prefs_gtk.h"
63 #include "addr_compl.h"
66 #include "addressitem.h"
68 #include "addrcache.h"
70 #include "addrindex.h"
71 #include "addressadd.h"
72 #include "addressbook_foldersel.h"
74 #include "editvcard.h"
75 #include "editgroup.h"
76 #include "editaddress.h"
78 #include "importldif.h"
79 #include "importmutt.h"
80 #include "importpine.h"
85 #include "editjpilot.h"
90 #include "ldapserver.h"
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->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->type == ADDR_IF_JPILOT ) {
1825 aot = ADDR_CATEGORY;
1827 else if( 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->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->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->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->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 );
3055 if (prefs_common.addressbook_use_editaddress_dialog)
3056 addressbook_new_address_from_book_post_cb( person );
3059 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3061 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3064 if (abf->type == ADDR_IF_LDAP) {
3065 GtkCTreeNode *parentNode;
3066 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3067 if( ds == NULL ) return;
3069 /* We must have a datasource that is an external interface */
3070 if( ! ds->interface->haveLibrary ) return;
3071 if( ! ds->interface->externalQuery ) return;
3073 if( pobj->type == ADDR_ITEM_FOLDER ) {
3074 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3077 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3079 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3082 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3083 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3084 abf = ds->rawDataSource;
3087 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3088 addrbook.editaddress_vbox,
3089 addressbook_new_address_from_folder_post_cb,
3092 if (abf->type == ADDR_IF_LDAP) {
3093 LdapServer *server = ds->rawDataSource;
3094 ldapsvr_set_modified(server, TRUE);
3095 ldapsvr_update_book(server, NULL);
3096 if (server->retVal != LDAPRC_SUCCESS) {
3097 alertpanel( _("Add address(es)"),
3098 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3099 GTK_STOCK_CLOSE, NULL, NULL );
3104 if (prefs_common.addressbook_use_editaddress_dialog)
3105 addressbook_new_address_from_folder_post_cb( person );
3107 else if( pobj->type == ADDR_ITEM_GROUP ) {
3108 /* New address in group */
3109 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3110 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3111 if (addrbook.treeSelected == addrbook.opened) {
3112 /* Change node name in tree. */
3113 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3114 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3115 addressbook_set_clist(
3116 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3124 * Search for specified child group node in address index tree.
3125 * \param parent Parent node.
3126 * \param group Group to find.
3128 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
3129 GtkCTreeNode *node = NULL;
3130 GtkCTreeRow *currRow;
3132 currRow = GTK_CTREE_ROW( parent );
3134 node = currRow->children;
3138 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3139 if( obj->type == ADDR_ITEM_GROUP ) {
3140 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3141 if( g == group ) return node;
3143 currRow = GTK_CTREE_ROW(node);
3144 node = currRow->sibling;
3150 static AddressBookFile *addressbook_get_book_file() {
3151 AddressBookFile *abf = NULL;
3152 AddressDataSource *ds = NULL;
3154 ds = addressbook_find_datasource( addrbook.treeSelected );
3155 if( ds == NULL ) return NULL;
3156 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3160 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
3164 /* Remove existing folders and groups */
3165 row = GTK_CTREE_ROW( parent );
3167 while( (node = row->children) ) {
3168 gtk_ctree_remove_node( ctree, node );
3173 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
3174 GtkCTreeNode *parent, *child;
3175 GtkCTreeRow *currRow;
3176 currRow = GTK_CTREE_ROW( node );
3178 parent = currRow->parent;
3179 while( (child = currRow->children) ) {
3180 gtk_ctree_move( ctree, child, parent, node );
3182 gtk_sctree_sort_node( ctree, parent );
3186 static void addressbook_edit_address_post_cb( ItemPerson *person )
3190 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
3191 invalidate_address_completion();
3193 addressbook_address_list_set_focus();
3196 void addressbook_address_list_set_focus( void )
3198 if (!prefs_common.addressbook_use_editaddress_dialog) {
3199 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3200 addressbook_list_menu_setup();
3204 void addressbook_address_list_disable_some_actions(void)
3206 /* disable address copy/pasting when editing contact's detail (embedded form) */
3207 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3208 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3209 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3211 /* we're already editing contact's detail here */
3212 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", FALSE );
3213 gtk_widget_set_sensitive( addrbook.edit_btn, FALSE );
3216 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3217 addressbook_edit_address(data, action, widget, TRUE);
3220 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3221 gboolean force_focus ) {
3222 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3224 AddressObject *obj = NULL, *pobj = NULL;
3225 AddressDataSource *ds = NULL;
3226 GtkCTreeNode *node = NULL, *parentNode = NULL;
3228 AddressBookFile *abf = NULL;
3230 if( addrbook.listSelected == NULL ) return;
3231 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3232 g_return_if_fail(obj != NULL);
3234 ctree = GTK_CTREE( addrbook.ctree );
3235 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3236 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3238 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3239 if( ds == NULL ) return;
3241 abf = addressbook_get_book_file();
3243 if( obj->type == ADDR_ITEM_EMAIL ) {
3244 ItemEMail *email = ( ItemEMail * ) obj;
3245 if( email == NULL ) return;
3246 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3247 /* Edit parent group */
3248 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3249 ItemGroup *itemGrp = adapter->itemGroup;
3250 if( abf == NULL ) return;
3251 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3252 name = ADDRITEM_NAME(itemGrp);
3253 node = addrbook.treeSelected;
3254 parentNode = GTK_CTREE_ROW(node)->parent;
3257 /* Edit person - email page */
3259 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3260 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3261 addressbook_edit_address_post_cb,
3262 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3265 if (abf->type == ADDR_IF_LDAP) {
3266 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3267 person->status = UPDATE_ENTRY;
3270 if (prefs_common.addressbook_use_editaddress_dialog)
3271 addressbook_edit_address_post_cb( person );
3276 else if( obj->type == ADDR_ITEM_PERSON ) {
3277 /* Edit person - basic page */
3278 ItemPerson *person = ( ItemPerson * ) obj;
3279 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3280 addressbook_edit_address_post_cb,
3281 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3284 if (abf->type == ADDR_IF_LDAP) {
3285 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3286 person->status = UPDATE_ENTRY;
3289 if (prefs_common.addressbook_use_editaddress_dialog)
3290 addressbook_edit_address_post_cb( person );
3294 else if( obj->type == ADDR_ITEM_GROUP ) {
3295 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3296 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3297 parentNode = addrbook.treeSelected;
3298 node = addressbook_find_group_node( parentNode, itemGrp );
3299 name = ADDRITEM_NAME(itemGrp);
3300 invalidate_address_completion();
3306 /* Update tree node with node name */
3307 if( node == NULL ) return;
3308 addressbook_change_node_name( node, name );
3309 gtk_sctree_sort_node( ctree, parentNode );
3310 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3311 addressbook_set_clist(
3312 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3317 static void addressbook_delete_address_cb(gpointer data, guint action,
3320 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
3321 addressbook_del_clicked(NULL, NULL);
3322 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
3325 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3327 addressbook_close();
3330 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3331 addressbook_export_to_file();
3334 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3336 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3337 if( person ) addritem_person_set_opened( person, TRUE );
3341 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3343 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3344 if( person ) addritem_person_set_opened( person, FALSE );
3348 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3350 gchar *eMailAlias = ADDRITEM_NAME(email);
3351 if( eMailAlias && *eMailAlias != '\0' ) {
3353 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3356 str = g_strdup( eMailAlias );
3362 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3363 GList *items = itemGroup->listEMail;
3364 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3365 for( ; items != NULL; items = g_list_next( items ) ) {
3366 GtkCTreeNode *nodeEMail = NULL;
3367 gchar *text[N_LIST_COLS];
3368 ItemEMail *email = items->data;
3372 if( ! email ) continue;
3374 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3375 str = addressbook_format_item_clist( person, email );
3377 text[COL_NAME] = str;
3380 text[COL_NAME] = ADDRITEM_NAME(person);
3382 text[COL_ADDRESS] = email->address;
3383 text[COL_REMARKS] = email->remarks;
3384 nodeEMail = gtk_sctree_insert_node(
3386 text, FOLDER_SPACING,
3387 atci->iconXpm, atci->maskXpm,
3388 atci->iconXpmOpen, atci->maskXpmOpen,
3390 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3396 static void addressbook_folder_load_one_person(
3397 GtkCTree *clist, ItemPerson *person,
3398 AddressTypeControlItem *atci,
3399 AddressTypeControlItem *atciMail )
3401 GtkCTreeNode *nodePerson = NULL;
3402 GtkCTreeNode *nodeEMail = NULL;
3403 gchar *text[N_LIST_COLS];
3404 gboolean flgFirst = TRUE, haveAddr = FALSE;
3406 AddressBookFile *abf = addressbook_get_book_file();
3408 if( person == NULL ) return;
3410 text[COL_NAME] = "";
3411 node = person->listEMail;
3413 ItemEMail *email = node->data;
3414 gchar *eMailAddr = NULL;
3415 node = g_list_next( node );
3417 text[COL_ADDRESS] = email->address;
3418 text[COL_REMARKS] = email->remarks;
3419 eMailAddr = ADDRITEM_NAME(email);
3420 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3422 /* First email belongs with person */
3423 gchar *str = addressbook_format_item_clist( person, email );
3425 text[COL_NAME] = str;
3428 else if( abf->type == ADDR_IF_LDAP && person->nickName ) {
3429 text[COL_NAME] = person->nickName;
3433 text[COL_NAME] = ADDRITEM_NAME(person);
3435 nodePerson = gtk_sctree_insert_node(
3437 text, FOLDER_SPACING,
3438 atci->iconXpm, atci->maskXpm,
3439 atci->iconXpmOpen, atci->maskXpmOpen,
3440 FALSE, person->isOpened );
3443 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3446 /* Subsequent email is a child node of person */
3447 text[COL_NAME] = ADDRITEM_NAME(email);
3448 nodeEMail = gtk_sctree_insert_node(
3449 clist, nodePerson, NULL,
3450 text, FOLDER_SPACING,
3451 atciMail->iconXpm, atciMail->maskXpm,
3452 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3454 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3460 /* Have name without EMail */
3461 text[COL_NAME] = ADDRITEM_NAME(person);
3462 text[COL_ADDRESS] = "";
3463 text[COL_REMARKS] = "";
3464 nodePerson = gtk_sctree_insert_node(
3466 text, FOLDER_SPACING,
3467 atci->iconXpm, atci->maskXpm,
3468 atci->iconXpmOpen, atci->maskXpmOpen,
3469 FALSE, person->isOpened );
3470 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3475 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3477 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3478 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3480 if( atci == NULL ) return;
3481 if( atciMail == NULL ) return;
3483 /* Load email addresses */
3484 items = addritem_folder_get_person_list( itemFolder );
3485 for( ; items != NULL; items = g_list_next( items ) ) {
3486 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3488 /* Free up the list */
3489 mgu_clear_list( items );
3490 g_list_free( items );
3493 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3494 addrbook.listSelected = NULL;
3495 gtk_ctree_remove_node( clist, node );
3496 addressbook_menubar_set_sensitive( FALSE );
3497 addressbook_menuitem_set_sensitive(
3498 gtk_ctree_node_get_row_data(
3499 GTK_CTREE(clist), addrbook.treeSelected ),
3500 addrbook.treeSelected );
3503 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3504 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3505 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3507 if( atci == NULL ) return;
3508 if( atciMail == NULL ) return;
3509 if( person == NULL ) return;
3510 /* unload the person */
3512 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3514 addressbook_folder_remove_node( clist, node );
3515 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3516 gtk_sctree_sort_node( clist, NULL );
3517 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3519 gtk_sctree_select( GTK_SCTREE(clist), node );
3520 if (!gtk_ctree_node_is_visible( clist, node ) )
3521 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3525 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3529 if( person == NULL ) return;
3530 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3531 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3533 addressbook_folder_remove_node( clist, node );
3537 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3539 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3541 /* Load any groups */
3542 if( ! atci ) return;
3543 items = addritem_folder_get_group_list( itemFolder );
3544 for( ; items != NULL; items = g_list_next( items ) ) {
3545 GtkCTreeNode *nodeGroup = NULL;
3546 gchar *text[N_LIST_COLS];
3547 ItemGroup *group = items->data;
3548 if( group == NULL ) continue;
3549 text[COL_NAME] = ADDRITEM_NAME(group);
3550 text[COL_ADDRESS] = "";
3551 text[COL_REMARKS] = "";
3552 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3553 text, FOLDER_SPACING,
3554 atci->iconXpm, atci->maskXpm,
3555 atci->iconXpmOpen, atci->maskXpmOpen,
3557 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3558 gtk_sctree_sort_node(clist, NULL);
3560 /* Free up the list */
3561 mgu_clear_list( items );
3562 g_list_free( items );
3566 * Search ctree widget callback function.
3567 * \param pA Pointer to node.
3568 * \param pB Pointer to data item being sought.
3569 * \return Zero (0) if group found.
3571 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3574 aoA = ( AddressObject * ) pA;
3575 if( aoA->type == ADDR_ITEM_GROUP ) {
3576 ItemGroup *group, *grp;
3578 grp = ADAPTER_GROUP(aoA)->itemGroup;
3579 group = ( ItemGroup * ) pB;
3580 if( grp == group ) return 0; /* Found group */
3586 * Remove folder and group nodes from tree widget for items contained ("cut")
3589 static void addressbook_treenode_remove_item( void ) {
3591 AddrSelectItem *cutItem;
3592 AddressCache *cache;
3593 AddrItemObject *aio;
3594 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3597 node = _clipBoard_->objectList;
3599 cutItem = node->data;
3600 node = g_list_next( node );
3601 cache = addrindex_get_cache(
3602 _clipBoard_->addressIndex, cutItem->cacheID );
3603 if( cache == NULL ) continue;
3604 aio = addrcache_get_object( cache, cutItem->uid );
3607 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3610 folder = ( ItemFolder * ) aio;
3611 tn = gtk_ctree_find_by_row_data_custom(
3612 ctree, NULL, folder,
3613 addressbook_treenode_find_folder_cb );
3615 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3618 group = ( ItemGroup * ) aio;
3619 tn = gtk_ctree_find_by_row_data_custom(
3621 addressbook_treenode_find_group_cb );
3625 /* Free up adapter and remove node. */
3626 gtk_ctree_remove_node( ctree, tn );
3633 * Find parent datasource for specified tree node.
3634 * \param node Node to test.
3635 * \return Data source, or NULL if not found.
3637 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3638 AddressDataSource *ds = NULL;
3641 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3644 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3645 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3647 /* printf( "ao->type = %d\n", ao->type ); */
3648 if( ao->type == ADDR_DATASOURCE ) {
3649 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3650 /* printf( "found it\n" ); */
3651 ds = ads->dataSource;
3655 node = GTK_CTREE_ROW(node)->parent;
3661 * Load address list widget with children of specified object.
3662 * \param obj Parent object to be loaded.
3664 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3665 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3666 GtkCList *clist = GTK_CLIST(addrbook.clist);
3667 AddressDataSource *ds = NULL;
3668 AdapterDSource *ads = NULL;
3669 static AddressObject *last_obj = NULL;
3671 if (addrbook.clist == NULL) {
3674 if (obj == last_obj && !refresh)
3679 gtk_clist_clear(clist);
3683 if( obj->type == ADDR_INTERFACE ) {
3684 /* printf( "set_clist: loading datasource...\n" ); */
3685 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3689 gtk_clist_freeze(clist);
3690 gtk_clist_clear(clist);
3692 if( obj->type == ADDR_DATASOURCE ) {
3693 ads = ADAPTER_DSOURCE(obj);
3694 ds = ADAPTER_DSOURCE(obj)->dataSource;
3696 /* Load root folder */
3697 ItemFolder *rootFolder = NULL;
3698 rootFolder = addrindex_ds_get_root_folder( ds );
3699 addressbook_folder_load_person(
3700 ctreelist, addrindex_ds_get_root_folder( ds ) );
3701 addressbook_folder_load_group(
3702 ctreelist, addrindex_ds_get_root_folder( ds ) );
3706 if( obj->type == ADDR_ITEM_GROUP ) {
3708 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3709 addressbook_load_group( ctreelist, itemGroup );
3711 else if( obj->type == ADDR_ITEM_FOLDER ) {
3713 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3714 addressbook_folder_load_person( ctreelist, itemFolder );
3715 addressbook_folder_load_group( ctreelist, itemFolder );
3718 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3719 clist->focus_row = -1;
3720 gtk_clist_thaw(clist);
3724 * Call back function to free adaptor. Call back is setup by function
3725 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3726 * called when the address book tree widget node is removed by calling
3727 * function gtk_ctree_remove_node().
3729 * \param data Tree node's row data.
3731 static void addressbook_free_treenode( gpointer data ) {
3734 ao = ( AddressObject * ) data;
3735 if( ao == NULL ) return;
3736 if( ao->type == ADDR_INTERFACE ) {
3737 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3738 addrbookctl_free_interface( ai );
3740 else if( ao->type == ADDR_DATASOURCE ) {
3741 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3742 addrbookctl_free_datasource( ads );
3744 else if( ao->type == ADDR_ITEM_FOLDER ) {
3745 AdapterFolder *af = ADAPTER_FOLDER(ao);
3746 addrbookctl_free_folder( af );
3748 else if( ao->type == ADDR_ITEM_GROUP ) {
3749 AdapterGroup *ag = ADAPTER_GROUP(ao);
3750 addrbookctl_free_group( ag );
3755 * Create new adaptor for specified data source.
3757 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3758 AddressObjectType otype, gchar *name )
3760 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3761 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3762 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3763 adapter->dataSource = ds;
3764 adapter->subType = otype;
3768 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3769 ADDRESS_OBJECT_NAME(adapter) =
3770 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3774 * Load tree from address index with the initial data.
3776 static void addressbook_load_tree( void ) {
3777 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3778 GList *nodeIf, *nodeDS;
3779 AdapterInterface *adapter;
3780 AddressInterface *iface;
3781 AddressTypeControlItem *atci;
3782 AddressDataSource *ds;
3783 AdapterDSource *ads;
3784 GtkCTreeNode *node, *newNode;
3787 nodeIf = _addressInterfaceList_;
3789 adapter = nodeIf->data;
3790 node = adapter->treeNode;
3791 iface = adapter->interface;
3792 atci = adapter->atci;
3794 if( iface->useInterface ) {
3795 /* Load data sources below interface node */
3796 nodeDS = iface->listSource;
3800 name = addrindex_ds_get_name( ds );
3801 ads = addressbook_create_ds_adapter(
3802 ds, atci->objectType, name );
3803 newNode = addressbook_add_object(
3804 node, ADDRESS_OBJECT(ads) );
3805 nodeDS = g_list_next( nodeDS );
3807 gtk_ctree_expand( ctree, node );
3810 nodeIf = g_list_next( nodeIf );
3815 * Convert the old address book to new format.
3817 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3818 gboolean retVal = FALSE;
3819 gboolean errFlag = TRUE;
3822 /* Read old address book, performing conversion */
3823 debug_print( "Reading and converting old address book...\n" );
3824 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3825 addrindex_read_data( addrIndex );
3826 if( addrIndex->retVal == MGU_NO_FILE ) {
3827 /* We do not have a file - new user */
3828 debug_print( "New user... create new books...\n" );
3829 addrindex_create_new_books( addrIndex );
3830 if( addrIndex->retVal == MGU_SUCCESS ) {
3831 /* Save index file */
3832 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3833 addrindex_save_data( addrIndex );
3834 if( addrIndex->retVal == MGU_SUCCESS ) {
3839 msg = _( "New user, could not save index file." );
3843 msg = _( "New user, could not save address book files." );
3847 /* We have an old file */
3848 if( addrIndex->wasConverted ) {
3849 /* Converted successfully - save address index */
3850 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3851 addrindex_save_data( addrIndex );
3852 if( addrIndex->retVal == MGU_SUCCESS ) {
3853 msg = _( "Old address book converted successfully." );
3858 msg = _("Old address book converted,\n"
3859 "could not save new address index file." );
3863 /* File conversion failed - just create new books */
3864 debug_print( "File conversion failed... just create new books...\n" );
3865 addrindex_create_new_books( addrIndex );
3866 if( addrIndex->retVal == MGU_SUCCESS ) {
3868 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3869 addrindex_save_data( addrIndex );
3870 if( addrIndex->retVal == MGU_SUCCESS ) {
3871 msg = _("Could not convert address book,\n"
3872 "but created empty new address book files." );
3877 msg = _("Could not convert address book,\n"
3878 "could not save new address index file." );
3882 msg = _("Could not convert address book\n"
3883 "and could not create new address book files." );
3888 debug_print( "Error\n%s\n", msg );
3889 alertpanel_full(_("Addressbook conversion error"), msg,
3890 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3891 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3894 debug_print( "Warning\n%s\n", msg );
3895 alertpanel_full(_("Addressbook conversion error"), msg,
3896 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3897 NULL, ALERT_WARNING, G_ALERTDEFAULT);
3903 void addressbook_read_file( void ) {
3904 AddressIndex *addrIndex = NULL;
3906 debug_print( "Reading address index...\n" );
3907 if( _addressIndex_ ) {
3908 debug_print( "address book already read!!!\n" );
3912 addrIndex = addrindex_create_index();
3913 addrindex_initialize();
3915 /* Use new address book index. */
3916 addrindex_set_file_path( addrIndex, get_rc_dir() );
3917 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3918 addrindex_read_data( addrIndex );
3919 if( addrIndex->retVal == MGU_NO_FILE ) {
3920 /* Conversion required */
3921 debug_print( "Converting...\n" );
3922 if( addressbook_convert( addrIndex ) ) {
3923 _addressIndex_ = addrIndex;
3926 else if( addrIndex->retVal == MGU_SUCCESS ) {
3927 _addressIndex_ = addrIndex;
3930 /* Error reading address book */
3931 debug_print( "Could not read address index.\n" );
3932 addrindex_print_index( addrIndex, stdout );
3933 alertpanel_full(_("Addressbook Error"),
3934 _("Could not read address index"),
3935 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3936 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3938 debug_print( "done.\n" );
3942 * Add object into the address index tree widget.
3943 * Enter: node Parent node.
3944 * obj Object to add.
3945 * Return: Node that was added, or NULL if object not added.
3947 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
3950 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3951 GtkCTreeNode *added;
3952 AddressObject *pobj;
3953 AddressObjectType otype;
3954 AddressTypeControlItem *atci = NULL;
3956 g_return_val_if_fail(node != NULL, NULL);
3957 g_return_val_if_fail(obj != NULL, NULL);
3959 pobj = gtk_ctree_node_get_row_data(ctree, node);
3960 g_return_val_if_fail(pobj != NULL, NULL);
3962 /* Determine object type to be displayed */
3963 if( obj->type == ADDR_DATASOURCE ) {
3964 otype = ADAPTER_DSOURCE(obj)->subType;
3970 /* Handle any special conditions. */
3972 atci = addrbookctl_lookup( otype );
3974 if( atci->showInTree ) {
3975 /* Add object to tree */
3978 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
3979 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
3980 atci->treeLeaf, atci->treeExpand );
3981 gtk_ctree_node_set_row_data_full( ctree, added, obj,
3982 addressbook_free_treenode );
3986 gtk_sctree_sort_node(ctree, node);
3992 * Add group into the address index tree.
3993 * \param node Parent node.
3994 * \param ds Data source.
3995 * \param itemGroup Group to add.
3996 * \return Inserted node.
3998 static GtkCTreeNode *addressbook_node_add_group(
3999 GtkCTreeNode *node, AddressDataSource *ds,
4000 ItemGroup *itemGroup )
4002 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4003 GtkCTreeNode *newNode;
4004 AdapterGroup *adapter;
4005 AddressTypeControlItem *atci = NULL;
4008 if( ds == NULL ) return NULL;
4009 if( node == NULL || itemGroup == NULL ) return NULL;
4011 name = &itemGroup->obj.name;
4013 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4015 adapter = g_new0( AdapterGroup, 1 );
4016 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4017 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4018 adapter->itemGroup = itemGroup;
4020 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4021 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4022 atci->treeLeaf, atci->treeExpand );
4023 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4024 addressbook_free_treenode );
4025 gtk_sctree_sort_node( ctree, node );
4030 * Add folder into the address index tree. Only visible folders are loaded into
4031 * the address index tree. Note that the root folder is not inserted into the
4034 * \param node Parent node.
4035 * \param ds Data source.
4036 * \param itemFolder Folder to add.
4037 * \param otype Object type to display.
4038 * \return Inserted node for the folder.
4040 static GtkCTreeNode *addressbook_node_add_folder(
4041 GtkCTreeNode *node, AddressDataSource *ds,
4042 ItemFolder *itemFolder, AddressObjectType otype )
4044 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4045 GtkCTreeNode *newNode = NULL;
4046 AdapterFolder *adapter;
4047 AddressTypeControlItem *atci = NULL;
4048 GList *listItems = NULL;
4050 ItemFolder *rootFolder;
4052 /* Only visible folders */
4053 if( itemFolder->isHidden ) return NULL;
4055 if( ds == NULL ) return NULL;
4056 if( node == NULL || itemFolder == NULL ) return NULL;
4058 /* Determine object type */
4059 atci = addrbookctl_lookup( otype );
4060 if( atci == NULL ) return NULL;
4062 rootFolder = addrindex_ds_get_root_folder( ds );
4063 if( itemFolder == rootFolder ) {
4067 adapter = g_new0( AdapterFolder, 1 );
4068 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4069 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4070 adapter->itemFolder = itemFolder;
4072 name = ADDRITEM_NAME(itemFolder);
4073 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4074 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4075 atci->treeLeaf, atci->treeExpand );
4077 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4078 addressbook_free_treenode );
4082 listItems = itemFolder->listFolder;
4083 while( listItems ) {
4084 ItemFolder *item = listItems->data;
4085 addressbook_node_add_folder( newNode, ds, item, otype );
4086 listItems = g_list_next( listItems );
4088 listItems = itemFolder->listGroup;
4089 while( listItems ) {
4090 ItemGroup *item = listItems->data;
4091 addressbook_node_add_group( newNode, ds, item );
4092 listItems = g_list_next( listItems );
4094 gtk_sctree_sort_node( ctree, node );
4098 void addressbook_export_to_file( void ) {
4099 if( _addressIndex_ ) {
4100 /* Save all new address book data */
4101 debug_print( "Saving address books...\n" );
4102 addrindex_save_all_books( _addressIndex_ );
4104 debug_print( "Exporting addressbook to file...\n" );
4105 addrindex_save_data( _addressIndex_ );
4106 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4107 addrindex_print_index( _addressIndex_, stdout );
4110 /* Notify address completion of new data */
4111 invalidate_address_completion();
4115 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4117 if (event && event->keyval == GDK_Return)
4118 addressbook_lup_clicked(NULL, NULL);
4123 * Comparison using cell contents (text in first column). Used for sort
4124 * address index widget.
4126 static gint addressbook_treenode_compare_func(
4127 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4129 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
4130 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
4131 gchar *name1 = NULL, *name2 = NULL;
4132 if( cell1 ) name1 = cell1->u.text;
4133 if( cell2 ) name2 = cell2->u.text;
4134 if( ! name1 ) return ( name2 != NULL );
4135 if( ! name2 ) return -1;
4136 return g_utf8_collate( name1, name2 );
4139 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
4140 AdapterDSource *ads;
4141 AdapterInterface *adapter;
4142 GtkCTreeNode *newNode;
4144 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4145 if( adapter == NULL ) return;
4146 ads = addressbook_edit_book( _addressIndex_, NULL );
4148 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4150 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4151 addrbook.treeSelected = newNode;
4156 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
4157 AdapterDSource *ads;
4158 AdapterInterface *adapter;
4159 GtkCTreeNode *newNode;
4161 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4162 if( adapter == NULL ) return;
4163 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4165 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4167 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4168 addrbook.treeSelected = newNode;
4174 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
4175 AdapterDSource *ads;
4176 AdapterInterface *adapter;
4177 AddressInterface *iface;
4178 GtkCTreeNode *newNode;
4180 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4181 if( adapter == NULL ) return;
4182 iface = adapter->interface;
4183 if( ! iface->haveLibrary ) return;
4184 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4186 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4188 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4189 addrbook.treeSelected = newNode;
4196 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
4197 AdapterDSource *ads;
4198 AdapterInterface *adapter;
4199 AddressInterface *iface;
4200 GtkCTreeNode *newNode;
4202 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4203 if( adapter == NULL ) return;
4204 iface = adapter->interface;
4205 if( ! iface->haveLibrary ) return;
4206 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4208 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4210 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4211 addrbook.treeSelected = newNode;
4218 * Display address search status message.
4219 * \param queryType Query type.
4220 * \param status Status/Error code.
4222 static void addressbook_search_message( gint queryType, gint sts ) {
4224 *addressbook_msgbuf = '\0';
4226 if( sts != MGU_SUCCESS ) {
4227 if( queryType == ADDRQUERY_LDAP ) {
4229 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4234 g_snprintf( addressbook_msgbuf,
4235 sizeof(addressbook_msgbuf), "%s", desc );
4236 addressbook_status_show( addressbook_msgbuf );
4239 addressbook_status_show( "" );
4244 * Refresh addressbook by forcing refresh of current selected object in
4247 static void addressbook_refresh_current( void ) {
4251 ctree = GTK_CTREE(addrbook.ctree);
4252 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4253 if( obj == NULL ) return;
4254 addressbook_set_clist( obj, TRUE );
4258 * Message that is displayed whilst a query is executing in a background
4261 static gchar *_tempMessage_ = N_( "Busy searching..." );
4264 * Address search idle function. This function is called during UI idle time
4265 * while a search is in progress.
4267 * \param data Idler data.
4269 static void addressbook_search_idle( gpointer data ) {
4273 queryID = GPOINTER_TO_INT( data );
4274 printf( "addressbook_ldap_idle... queryID=%d\n", queryID );
4279 * Search completion callback function. This removes the query from the idle
4282 * \param sender Sender of query.
4283 * \param queryID Query ID of search request.
4284 * \param status Search status.
4285 * \param data Query data.
4287 static void addressbook_search_callback_end(
4288 gpointer sender, gint queryID, gint status, gpointer data )
4292 AddrQueryObject *aqo;
4294 /* Remove idler function */
4295 ptrQID = GINT_TO_POINTER( queryID );
4297 g_idle_remove_by_data( ptrQID );
4300 /* Refresh addressbook contents */
4301 addressbook_refresh_current();
4302 req = qrymgr_find_request( queryID );
4304 aqo = ( AddrQueryObject * ) req->queryList->data;
4305 addressbook_search_message( aqo->queryType, status );
4308 /* Stop the search */
4309 addrindex_stop_search( queryID );
4315 * \param ds Data source to search.
4316 * \param searchTerm String to lookup.
4317 * \param pNode Parent data source node.
4319 static void addressbook_perform_search(
4320 AddressDataSource *ds, gchar *searchTerm,
4321 GtkCTreeNode *pNode )
4323 AddrBookBase *adbase;
4324 AddressCache *cache;
4330 AddressObjectType aoType = ADDR_NONE;
4334 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4336 if( ds->type == ADDR_IF_LDAP ) {
4338 aoType = ADDR_LDAP_QUERY;
4344 /* Get reference to address cache */
4345 adbase = ( AddrBookBase * ) ds->rawDataSource;
4346 cache = adbase->addressCache;
4348 /* Create a folder for the search results */
4349 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4350 folder = addressbook_setup_subf(ds, name, pNode);
4353 /* Setup the search */
4354 queryID = addrindex_setup_explicit_search(
4355 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4356 if( queryID == 0 ) return;
4358 /* Set up idler function */
4359 idleID = g_idle_add(
4360 ( GtkFunction ) addressbook_search_idle,
4361 GINT_TO_POINTER( queryID ) );
4363 /* Start search, sit back and wait for something to happen */
4364 addrindex_start_search( queryID );
4366 addressbook_status_show( _tempMessage_ );
4370 * Lookup button handler. Address search is only performed against
4371 * address interfaces for external queries.
4373 * \param button Lookup button widget.
4374 * \param data Data object.
4376 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4379 AddressDataSource *ds;
4380 AddressInterface *iface;
4382 GtkCTreeNode *node, *parentNode;
4384 node = addrbook.treeSelected;
4385 if( ! node ) return;
4386 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4388 ctree = GTK_CTREE(addrbook.ctree);
4389 obj = gtk_ctree_node_get_row_data( ctree, node );
4390 if( obj == NULL ) return;
4392 ds = addressbook_find_datasource( node );
4393 if( ds == NULL ) return;
4395 /* We must have a datasource that is an external interface */
4396 iface = ds->interface;
4397 if( ! iface->haveLibrary ) return;
4398 if( ! iface->externalQuery ) return;
4401 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4402 g_strchomp( searchTerm );
4404 if( obj->type == ADDR_ITEM_FOLDER ) {
4405 parentNode = GTK_CTREE_ROW(node)->parent;
4410 addressbook_perform_search( ds, searchTerm, parentNode );
4412 gtk_widget_grab_focus( addrbook.entry );
4414 g_free( searchTerm );
4417 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4418 addressbook_close();
4423 * Browse address entry for highlighted entry.
4425 static void addressbook_browse_entry_cb(void)
4427 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4429 AddressDataSource *ds;
4430 AddressInterface *iface;
4434 if(addrbook.listSelected == NULL)
4437 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4441 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4445 iface = ds->interface;
4446 if(! iface->haveLibrary )
4450 if (obj->type == ADDR_ITEM_EMAIL) {
4451 email = ( ItemEMail * ) obj;
4455 person = (ItemPerson *) ADDRITEM_PARENT(email);
4457 else if (obj->type == ADDR_ITEM_PERSON) {
4458 person = (ItemPerson *) obj;
4465 if( iface->type == ADDR_IF_LDAP ) {
4466 browseldap_entry(ds, person->externalID);
4471 /* **********************************************************************
4472 * Build lookup tables.
4473 * ***********************************************************************
4477 * Remap object types.
4478 * Enter: abType AddressObjectType (used in tree node).
4479 * Return: ItemObjectType (used in address cache data).
4481 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4482 ItemObjectType ioType;
4485 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4486 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4487 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4488 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4489 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4490 default: ioType = ITEMTYPE_NONE; break;
4496 * Build table that controls the rendering of object types.
4498 static void addrbookctl_build_map( GtkWidget *window ) {
4499 AddressTypeControlItem *atci;
4502 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4503 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4504 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4505 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4506 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4507 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4508 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4509 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4510 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4511 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4513 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4514 _addressBookTypeList_ = NULL;
4517 atci = g_new0( AddressTypeControlItem, 1 );
4518 atci->objectType = ADDR_INTERFACE;
4519 atci->interfaceType = ADDR_IF_NONE;
4520 atci->showInTree = TRUE;
4521 atci->treeExpand = TRUE;
4522 atci->treeLeaf = FALSE;
4523 atci->displayName = _( "Interface" );
4524 atci->iconXpm = folderxpm;
4525 atci->maskXpm = folderxpmmask;
4526 atci->iconXpmOpen = folderopenxpm;
4527 atci->maskXpmOpen = folderopenxpmmask;
4528 atci->menuCommand = NULL;
4529 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4530 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4533 atci = g_new0( AddressTypeControlItem, 1 );
4534 atci->objectType = ADDR_BOOK;
4535 atci->interfaceType = ADDR_IF_BOOK;
4536 atci->showInTree = TRUE;
4537 atci->treeExpand = TRUE;
4538 atci->treeLeaf = FALSE;
4539 atci->displayName = _( "Address Book" );
4540 atci->iconXpm = bookxpm;
4541 atci->maskXpm = bookxpmmask;
4542 atci->iconXpmOpen = bookxpm;
4543 atci->maskXpmOpen = bookxpmmask;
4544 atci->menuCommand = "/Book/New Book";
4545 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4546 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4549 atci = g_new0( AddressTypeControlItem, 1 );
4550 atci->objectType = ADDR_ITEM_PERSON;
4551 atci->interfaceType = ADDR_IF_NONE;
4552 atci->showInTree = FALSE;
4553 atci->treeExpand = FALSE;
4554 atci->treeLeaf = FALSE;
4555 atci->displayName = _( "Person" );
4556 atci->iconXpm = NULL;
4557 atci->maskXpm = NULL;
4558 atci->iconXpmOpen = NULL;
4559 atci->maskXpmOpen = NULL;
4560 atci->menuCommand = NULL;
4561 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4562 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4565 atci = g_new0( AddressTypeControlItem, 1 );
4566 atci->objectType = ADDR_ITEM_EMAIL;
4567 atci->interfaceType = ADDR_IF_NONE;
4568 atci->showInTree = FALSE;
4569 atci->treeExpand = FALSE;
4570 atci->treeLeaf = TRUE;
4571 atci->displayName = _( "EMail Address" );
4572 atci->iconXpm = addressxpm;
4573 atci->maskXpm = addressxpmmask;
4574 atci->iconXpmOpen = addressxpm;
4575 atci->maskXpmOpen = addressxpmmask;
4576 atci->menuCommand = NULL;
4577 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4578 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4581 atci = g_new0( AddressTypeControlItem, 1 );
4582 atci->objectType = ADDR_ITEM_GROUP;
4583 atci->interfaceType = ADDR_IF_BOOK;
4584 atci->showInTree = TRUE;
4585 atci->treeExpand = FALSE;
4586 atci->treeLeaf = FALSE;
4587 atci->displayName = _( "Group" );
4588 atci->iconXpm = groupxpm;
4589 atci->maskXpm = groupxpmmask;
4590 atci->iconXpmOpen = groupxpm;
4591 atci->maskXpmOpen = groupxpmmask;
4592 atci->menuCommand = NULL;
4593 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4594 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4597 atci = g_new0( AddressTypeControlItem, 1 );
4598 atci->objectType = ADDR_ITEM_FOLDER;
4599 atci->interfaceType = ADDR_IF_BOOK;
4600 atci->showInTree = TRUE;
4601 atci->treeExpand = FALSE;
4602 atci->treeLeaf = FALSE;
4603 atci->displayName = _( "Folder" );
4604 atci->iconXpm = folderxpm;
4605 atci->maskXpm = folderxpmmask;
4606 atci->iconXpmOpen = folderopenxpm;
4607 atci->maskXpmOpen = folderopenxpmmask;
4608 atci->menuCommand = NULL;
4609 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4610 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4613 atci = g_new0( AddressTypeControlItem, 1 );
4614 atci->objectType = ADDR_VCARD;
4615 atci->interfaceType = ADDR_IF_VCARD;
4616 atci->showInTree = TRUE;
4617 atci->treeExpand = TRUE;
4618 atci->treeLeaf = TRUE;
4619 atci->displayName = _( "vCard" );
4620 atci->iconXpm = vcardxpm;
4621 atci->maskXpm = vcardxpmmask;
4622 atci->iconXpmOpen = vcardxpm;
4623 atci->maskXpmOpen = vcardxpmmask;
4624 atci->menuCommand = "/Book/New vCard";
4625 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4626 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4629 atci = g_new0( AddressTypeControlItem, 1 );
4630 atci->objectType = ADDR_JPILOT;
4631 atci->interfaceType = ADDR_IF_JPILOT;
4632 atci->showInTree = TRUE;
4633 atci->treeExpand = TRUE;
4634 atci->treeLeaf = FALSE;
4635 atci->displayName = _( "JPilot" );
4636 atci->iconXpm = jpilotxpm;
4637 atci->maskXpm = jpilotxpmmask;
4638 atci->iconXpmOpen = jpilotxpm;
4639 atci->maskXpmOpen = jpilotxpmmask;
4640 atci->menuCommand = "/Book/New JPilot";
4641 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4642 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4645 atci = g_new0( AddressTypeControlItem, 1 );
4646 atci->objectType = ADDR_CATEGORY;
4647 atci->interfaceType = ADDR_IF_JPILOT;
4648 atci->showInTree = TRUE;
4649 atci->treeExpand = TRUE;
4650 atci->treeLeaf = TRUE;
4651 atci->displayName = _( "JPilot" );
4652 atci->iconXpm = categoryxpm;
4653 atci->maskXpm = categoryxpmmask;
4654 atci->iconXpmOpen = categoryxpm;
4655 atci->maskXpmOpen = categoryxpmmask;
4656 atci->menuCommand = NULL;
4657 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4658 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4661 atci = g_new0( AddressTypeControlItem, 1 );
4662 atci->objectType = ADDR_LDAP;
4663 atci->interfaceType = ADDR_IF_LDAP;
4664 atci->showInTree = TRUE;
4665 atci->treeExpand = TRUE;
4666 atci->treeLeaf = FALSE;
4667 atci->displayName = _( "LDAP servers" );
4668 atci->iconXpm = ldapxpm;
4669 atci->maskXpm = ldapxpmmask;
4670 atci->iconXpmOpen = ldapxpm;
4671 atci->maskXpmOpen = ldapxpmmask;
4672 atci->menuCommand = "/Book/New LDAP Server";
4673 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4674 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4677 atci = g_new0( AddressTypeControlItem, 1 );
4678 atci->objectType = ADDR_LDAP_QUERY;
4679 atci->interfaceType = ADDR_IF_LDAP;
4680 atci->showInTree = TRUE;
4681 atci->treeExpand = FALSE;
4682 atci->treeLeaf = TRUE;
4683 atci->displayName = _( "LDAP Query" );
4684 atci->iconXpm = addrsearchxpm;
4685 atci->maskXpm = addrsearchxpmmask;
4686 atci->iconXpmOpen = addrsearchxpm;
4687 atci->maskXpmOpen = addrsearchxpmmask;
4688 atci->menuCommand = NULL;
4689 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4690 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4695 * Search for specified object type.
4697 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4699 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4703 * Search for specified interface type.
4705 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4706 GList *node = _addressBookTypeList_;
4708 AddressTypeControlItem *atci = node->data;
4709 if( atci->interfaceType == ifType ) return atci;
4710 node = g_list_next( node );
4715 static void addrbookctl_free_address( AddressObject *obj ) {
4716 g_free( obj->name );
4717 obj->type = ADDR_NONE;
4721 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4722 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4723 adapter->interface = NULL;
4724 adapter->interfaceType = ADDR_IF_NONE;
4725 adapter->atci = NULL;
4726 adapter->enabled = FALSE;
4727 adapter->haveLibrary = FALSE;
4728 adapter->treeNode = NULL;
4732 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4733 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4734 adapter->dataSource = NULL;
4735 adapter->subType = ADDR_NONE;
4739 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4740 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4741 adapter->itemFolder = NULL;
4745 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4746 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4747 adapter->itemGroup = NULL;
4752 * Build GUI interface list.
4754 static void addrbookctl_build_iflist( void ) {
4755 AddressTypeControlItem *atci;
4756 AdapterInterface *adapter;
4759 if( _addressIndex_ == NULL ) {
4760 _addressIndex_ = addrindex_create_index();
4761 if( _clipBoard_ == NULL ) {
4762 _clipBoard_ = addrclip_create();
4764 addrclip_set_index( _clipBoard_, _addressIndex_ );
4766 _addressInterfaceList_ = NULL;
4767 list = addrindex_get_interface_list( _addressIndex_ );
4769 AddressInterface *interface = list->data;
4770 atci = addrbookctl_lookup_iface( interface->type );
4772 adapter = g_new0( AdapterInterface, 1 );
4773 adapter->interfaceType = interface->type;
4774 adapter->atci = atci;
4775 adapter->interface = interface;
4776 adapter->treeNode = NULL;
4777 adapter->enabled = TRUE;
4778 adapter->haveLibrary = interface->haveLibrary;
4779 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4780 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4781 _addressInterfaceList_ =
4782 g_list_append( _addressInterfaceList_, adapter );
4784 list = g_list_next( list );
4789 * Find GUI interface type specified interface type.
4790 * \param ifType Interface type.
4791 * \return Interface item, or NULL if not found.
4793 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4794 GList *node = _addressInterfaceList_;
4796 AdapterInterface *adapter = node->data;
4797 if( adapter->interfaceType == ifType ) return adapter;
4798 node = g_list_next( node );
4804 * Build interface list selection.
4806 static void addrbookctl_build_ifselect( void ) {
4807 GList *newList = NULL;
4812 gchar *endptr = NULL;
4814 AdapterInterface *adapter;
4816 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4819 splitStr = g_strsplit( selectStr, ",", -1 );
4820 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4822 /* printf( "%d : %s\n", i, splitStr[i] ); */
4823 ifType = strtol( splitStr[i], &endptr, 10 );
4826 if( strcmp( endptr, "/n" ) == 0 ) {
4830 /* printf( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4831 adapter = addrbookctl_find_interface( ifType );
4833 newList = g_list_append( newList, adapter );
4840 /* printf( "i=%d\n", i ); */
4841 g_strfreev( splitStr );
4842 g_free( selectStr );
4844 /* Replace existing list */
4845 mgu_clear_list( _addressIFaceSelection_ );
4846 g_list_free( _addressIFaceSelection_ );
4847 _addressIFaceSelection_ = newList;
4851 /* ***********************************************************************
4852 * Add sender to address book.
4853 * ***********************************************************************
4857 * This function is used by the Add sender to address book function.
4859 gboolean addressbook_add_contact(
4860 const gchar *name, const gchar *address, const gchar *remarks )
4862 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
4863 if( addressadd_selection( _addressIndex_, name, address, remarks ) ) {
4864 debug_print( "addressbook_add_contact - added\n" );
4865 addressbook_refresh();
4870 /* ***********************************************************************
4871 * Book/folder selection.
4872 * ***********************************************************************
4876 * This function is used by the matcher dialog to select a book/folder.
4878 gboolean addressbook_folder_selection( gchar **folderpath )
4880 AddressBookFile *book = NULL;
4881 ItemFolder *folder = NULL;
4884 g_return_val_if_fail( folderpath != NULL, FALSE);
4888 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, path )
4890 if ( folder != NULL) {
4892 gchar *oldtmp = NULL;
4893 AddrItemObject *obj = NULL;
4895 /* walk thru folder->parent to build the full folder path */
4896 /* TODO: wwp: optimize this */
4898 tmp = g_strdup(obj->uid);
4899 while ( obj->parent ) {
4901 if ( obj->name != NULL ) {
4902 oldtmp = g_strdup(tmp);
4904 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
4908 *folderpath = g_strdup_printf("%s/%s", book->fileName, tmp);
4911 *folderpath = g_strdup_printf("%s", book->fileName);
4913 debug_print( "addressbook_foldersel: %s\n", *folderpath);
4914 return (*folderpath != NULL);
4919 /* ***********************************************************************
4920 * Book/folder checking.
4921 * ***********************************************************************
4924 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
4926 FolderInfo *fi = g_new0( FolderInfo, 1 );
4928 fi->folder = folder;
4932 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
4933 FolderInfo *fiParent, FolderPathMatch *match )
4939 FolderPathMatch *nextmatch = NULL;
4944 list = parentFolder->listFolder;
4946 folder = list->data;
4947 fName = g_strdup( ADDRITEM_NAME(folder) );
4949 /* match folder name, match pointer will be set to NULL if next recursive call
4950 doesn't need to match subfolder name */
4951 if ( match != NULL &&
4952 match->matched == FALSE ) {
4953 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
4954 /* folder name matches, prepare next subfolder match */
4955 debug_print("matched folder name '%s'\n", fName);
4957 if ( match->folder_path[match->index] == NULL ) {
4958 /* we've matched all elements */
4959 match->matched = TRUE;
4960 match->folder = folder;
4961 debug_print("book/folder path matched!\n");
4963 /* keep on matching */
4971 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
4972 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
4974 list = g_list_next( list );
4979 * This function is used by to check if a matcher book/folder path corresponds to an
4980 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
4981 Caution: returned book and folder pointers can be NULL even when returning TRUE:
4982 if book AND folder are NULL this means that folderpath was empty or Any.
4983 If folderpath is a simple book name (without folder), book will not be NULL and folder
4984 will be NULL. It's not expected to return book as NULL and folder as non NULL.
4987 gboolean addressbook_peek_folder_exists( gchar *folderpath,
4988 AddressDataSource **book,
4989 ItemFolder **folder )
4991 AddressDataSource *ds;
4992 GList *list, *nodeDS;
4993 ItemFolder *rootFolder;
4994 AddressBookFile *abf;
4996 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5003 if ( folderpath == NULL )
5006 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
5009 /* split the folder path we've received, we'll try to match this path, subpath by
5010 subpath against the book/folder structure in order */
5011 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5012 if (!folder_path_match.folder_path)
5015 list = addrindex_get_interface_list( _addressIndex_ );
5016 while ( list && !folder_path_match.matched ) {
5017 AddressInterface *interface = list->data;
5018 if ( interface && interface->type == ADDR_IF_BOOK ) {
5019 nodeDS = interface->listSource;
5020 while ( nodeDS && !folder_path_match.matched ) {
5023 /* Read address book */
5024 if( ! addrindex_ds_get_read_flag( ds ) ) {
5025 addrindex_ds_read_data( ds );
5028 /* Add node for address book */
5029 abf = ds->rawDataSource;
5031 /* match book name */
5032 if ( abf && abf->fileName &&
5033 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5035 debug_print("matched book name '%s'\n", abf->fileName);
5036 folder_path_match.book = ds;
5038 if ( folder_path_match.folder_path[1] == NULL ) {
5039 /* no folder part to match */
5041 folder_path_match.matched = TRUE;
5042 folder_path_match.folder = NULL;
5043 debug_print("book path matched!\n");
5046 /* match folder part */
5048 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5049 rootFolder = addrindex_ds_get_root_folder( ds );
5051 /* prepare for recursive call */
5052 folder_path_match.index = 1;
5053 /* this call will set folder_path_match.matched and folder_path_match.folder */
5054 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5059 nodeDS = g_list_next( nodeDS );
5062 list = g_list_next( list );
5065 g_strfreev( folder_path_match.folder_path );
5068 *book = folder_path_match.book;
5070 *folder = folder_path_match.folder;
5071 return folder_path_match.matched;
5075 /* **********************************************************************
5077 * ***********************************************************************
5083 static void addressbook_import_ldif_cb( void ) {
5084 AddressDataSource *ds = NULL;
5085 AdapterDSource *ads = NULL;
5086 AddressBookFile *abf = NULL;
5087 AdapterInterface *adapter;
5088 GtkCTreeNode *newNode;
5090 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5092 if( adapter->treeNode ) {
5093 abf = addressbook_imp_ldif( _addressIndex_ );
5095 ds = addrindex_index_add_datasource(
5096 _addressIndex_, ADDR_IF_BOOK, abf );
5097 ads = addressbook_create_ds_adapter(
5098 ds, ADDR_BOOK, NULL );
5099 addressbook_ads_set_name(
5100 ads, addrbook_get_name( abf ) );
5101 newNode = addressbook_add_object(
5103 ADDRESS_OBJECT(ads) );
5105 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5107 addrbook.treeSelected = newNode;
5110 /* Notify address completion */
5111 invalidate_address_completion();
5120 static void addressbook_import_mutt_cb( void ) {
5121 AddressDataSource *ds = NULL;
5122 AdapterDSource *ads = NULL;
5123 AddressBookFile *abf = NULL;
5124 AdapterInterface *adapter;
5125 GtkCTreeNode *newNode;
5127 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5129 if( adapter->treeNode ) {
5130 abf = addressbook_imp_mutt( _addressIndex_ );
5132 ds = addrindex_index_add_datasource(
5133 _addressIndex_, ADDR_IF_BOOK, abf );
5134 ads = addressbook_create_ds_adapter(
5135 ds, ADDR_BOOK, NULL );
5136 addressbook_ads_set_name(
5137 ads, addrbook_get_name( abf ) );
5138 newNode = addressbook_add_object(
5140 ADDRESS_OBJECT(ads) );
5142 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5144 addrbook.treeSelected = newNode;
5147 /* Notify address completion */
5148 invalidate_address_completion();
5157 static void addressbook_import_pine_cb( void ) {
5158 AddressDataSource *ds = NULL;
5159 AdapterDSource *ads = NULL;
5160 AddressBookFile *abf = NULL;
5161 AdapterInterface *adapter;
5162 GtkCTreeNode *newNode;
5164 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5166 if( adapter->treeNode ) {
5167 abf = addressbook_imp_pine( _addressIndex_ );
5169 ds = addrindex_index_add_datasource(
5170 _addressIndex_, ADDR_IF_BOOK, abf );
5171 ads = addressbook_create_ds_adapter(
5172 ds, ADDR_BOOK, NULL );
5173 addressbook_ads_set_name(
5174 ads, addrbook_get_name( abf ) );
5175 newNode = addressbook_add_object(
5177 ADDRESS_OBJECT(ads) );
5179 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5181 addrbook.treeSelected = newNode;
5184 /* Notify address completion */
5185 invalidate_address_completion();
5192 * Harvest addresses.
5193 * \param folderItem Folder to import.
5194 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5195 * \param msgList List of message numbers, or NULL to process folder.
5197 void addressbook_harvest(
5198 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5200 AddressDataSource *ds = NULL;
5201 AdapterDSource *ads = NULL;
5202 AddressBookFile *abf = NULL;
5203 AdapterInterface *adapter;
5204 GtkCTreeNode *newNode;
5206 abf = addrgather_dlg_execute(
5207 folderItem, _addressIndex_, sourceInd, msgList );
5209 ds = addrindex_index_add_datasource(
5210 _addressIndex_, ADDR_IF_BOOK, abf );
5212 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5214 if( adapter->treeNode ) {
5215 ads = addressbook_create_ds_adapter(
5216 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5217 newNode = addressbook_add_object(
5219 ADDRESS_OBJECT(ads) );
5223 /* Notify address completion */
5224 invalidate_address_completion();
5231 static void addressbook_export_html_cb( void ) {
5232 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5234 AddressDataSource *ds = NULL;
5235 AddrBookBase *adbase;
5236 AddressCache *cache;
5237 GtkCTreeNode *node = NULL;
5239 if( ! addrbook.treeSelected ) return;
5240 node = addrbook.treeSelected;
5241 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5242 obj = gtk_ctree_node_get_row_data( ctree, node );
5243 if( obj == NULL ) return;
5245 ds = addressbook_find_datasource( node );
5246 if( ds == NULL ) return;
5247 adbase = ( AddrBookBase * ) ds->rawDataSource;
5248 cache = adbase->addressCache;
5249 addressbook_exp_html( cache );
5255 static void addressbook_export_ldif_cb( void ) {
5256 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5258 AddressDataSource *ds = NULL;
5259 AddrBookBase *adbase;
5260 AddressCache *cache;
5261 GtkCTreeNode *node = NULL;
5263 if( ! addrbook.treeSelected ) return;
5264 node = addrbook.treeSelected;
5265 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5266 obj = gtk_ctree_node_get_row_data( ctree, node );
5267 if( obj == NULL ) return;
5269 ds = addressbook_find_datasource( node );
5270 if( ds == NULL ) return;
5271 adbase = ( AddrBookBase * ) ds->rawDataSource;
5272 cache = adbase->addressCache;
5273 addressbook_exp_ldif( cache );
5276 static void addressbook_start_drag(GtkWidget *widget, gint button,
5280 GdkDragContext *context;
5281 if (addressbook_target_list == NULL)
5282 addressbook_target_list = gtk_target_list_new(
5283 addressbook_drag_types, 1);
5284 context = gtk_drag_begin(widget, addressbook_target_list,
5285 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5286 gtk_drag_set_icon_default(context);
5289 static void addressbook_drag_data_get(GtkWidget *widget,
5290 GdkDragContext *drag_context,
5291 GtkSelectionData *selection_data,
5296 AddrItemObject *aio = NULL;
5297 AddressObject *pobj = NULL;
5298 AdapterDSource *ads = NULL;
5299 AddressDataSource *ds = NULL;
5302 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5304 if( pobj == NULL ) return;
5306 if( pobj->type == ADDR_DATASOURCE ) {
5307 ads = ADAPTER_DSOURCE(pobj);
5308 ds = ads->dataSource;
5309 } else if (pobj->type == ADDR_ITEM_GROUP) {
5314 else if( pobj->type != ADDR_INTERFACE ) {
5315 ds = addressbook_find_datasource( addrbook.treeSelected );
5321 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5322 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5323 GTK_CTREE_NODE(cur->data));
5324 while (aio && aio->type != ADDR_ITEM_PERSON) {
5329 if (aio && aio->type == ADDR_ITEM_PERSON) {
5330 if( ds && ds->interface && ds->interface->readOnly)
5331 gtk_selection_data_set(selection_data,
5332 selection_data->target, 8,
5333 "Dummy_addr_copy", 15);
5335 gtk_selection_data_set(selection_data,
5336 selection_data->target, 8,
5337 "Dummy_addr_move", 15);
5341 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5342 GdkDragContext *context,
5349 GtkCTreeNode *node = NULL;
5350 gboolean acceptable = FALSE;
5351 gint height = addrbook.ctree->allocation.height;
5352 gint total_height = addrbook.ctree->requisition.height;
5353 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5354 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5355 gfloat vpos = pos->value;
5357 if (gtk_clist_get_selection_info
5358 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5360 if (y > height - 24 && height + vpos < total_height)
5361 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5363 if (y < 24 && y > 0)
5364 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5366 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5369 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5370 if( obj->type == ADDR_ITEM_FOLDER
5371 || obj->type == ADDR_ITEM_GROUP)
5374 AdapterDSource *ads = NULL;
5375 AddressDataSource *ds = NULL;
5376 ads = ADAPTER_DSOURCE(obj);
5377 if (ads == NULL ){ return FALSE;}
5378 ds = ads->dataSource;
5379 if (ds == NULL ) { return FALSE;}
5387 g_signal_handlers_block_by_func
5389 G_CALLBACK(addressbook_tree_selected), NULL);
5390 gtk_sctree_select( GTK_SCTREE(widget), node);
5391 g_signal_handlers_unblock_by_func
5393 G_CALLBACK(addressbook_tree_selected), NULL);
5394 gdk_drag_status(context,
5395 (context->actions == GDK_ACTION_COPY ?
5396 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5398 gdk_drag_status(context, 0, time);
5404 static void addressbook_drag_leave_cb(GtkWidget *widget,
5405 GdkDragContext *context,
5409 if (addrbook.treeSelected) {
5410 g_signal_handlers_block_by_func
5412 G_CALLBACK(addressbook_tree_selected), NULL);
5413 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5414 g_signal_handlers_unblock_by_func
5416 G_CALLBACK(addressbook_tree_selected), NULL);
5421 static void addressbook_drag_received_cb(GtkWidget *widget,
5422 GdkDragContext *drag_context,
5425 GtkSelectionData *data,
5432 GtkCTreeNode *lastopened = addrbook.opened;
5434 if (!strncmp(data->data, "Dummy_addr", 10)) {
5435 if (gtk_clist_get_selection_info
5436 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5440 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5441 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5444 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5445 if (drag_context->action == GDK_ACTION_COPY ||
5446 !strcmp(data->data, "Dummy_addr_copy"))
5447 addressbook_clip_copy_cb();
5449 addressbook_clip_cut_cb();
5450 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5451 addressbook_clip_paste_cb();
5452 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5453 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5454 gtk_drag_finish(drag_context, TRUE, TRUE, time);