New address book.
[claws.git] / src / addressbook.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999,2000 Hiroyuki Yamamoto
4  *
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.
9  *
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.
14  *
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27 #include <gdk/gdkkeysyms.h>
28 #include <gtk/gtkwindow.h>
29 #include <gtk/gtksignal.h>
30 #include <gtk/gtkvbox.h>
31 #include <gtk/gtkscrolledwindow.h>
32 #include <gtk/gtkhpaned.h>
33 #include <gtk/gtkhbox.h>
34 #include <gtk/gtklabel.h>
35 #include <gtk/gtkentry.h>
36 #include <gtk/gtkctree.h>
37 #include <gtk/gtkclist.h>
38 #include <gtk/gtktable.h>
39 #include <gtk/gtkhbbox.h>
40 #include <gtk/gtkbutton.h>
41 #include <gtk/gtkmenu.h>
42 #include <gtk/gtkmenuitem.h>
43 #include <gtk/gtkitemfactory.h>
44 #include <string.h>
45 #include <setjmp.h>
46
47 #include "intl.h"
48 #include "main.h"
49 #include "addressbook.h"
50 #include "manage_window.h"
51 #include "prefs_common.h"
52 #include "alertpanel.h"
53 #include "inputdialog.h"
54 #include "menu.h"
55 #include "xml.h"
56 #include "prefs.h"
57 #include "procmime.h"
58 #include "utils.h"
59 #include "gtkutils.h"
60 #include "codeconv.h"
61 #include "about.h"
62 #include "addr_compl.h"
63
64 #include "mgutils.h"
65 #include "addressitem.h"
66 #include "addritem.h"
67 #include "addrcache.h"
68 #include "addrbook.h"
69 #include "addrindex.h"
70 #include "vcard.h"
71 #include "editvcard.h"
72 #include "editgroup.h"
73 #include "editaddress.h"
74 #include "editbook.h"
75
76 #ifdef USE_JPILOT
77 #include "jpilot.h"
78 #include "editjpilot.h"
79 #endif
80
81 #ifdef USE_LDAP
82 #include <pthread.h>
83 #include "syldap.h"
84 #include "editldap.h"
85
86 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
87 #endif
88
89 #include "pixmaps/dir-close.xpm"
90 #include "pixmaps/dir-open.xpm"
91 #include "pixmaps/group.xpm"
92 #include "pixmaps/interface.xpm"
93 #include "pixmaps/book.xpm"
94 #include "pixmaps/address.xpm"
95 #include "pixmaps/vcard.xpm"
96 #include "pixmaps/jpilot.xpm"
97 #include "pixmaps/category.xpm"
98 #include "pixmaps/ldap.xpm"
99
100 typedef enum
101 {
102         COL_NAME        = 0,
103         COL_ADDRESS     = 1,
104         COL_REMARKS     = 2
105 } AddressBookColumnPos;
106
107 #define N_COLS  3
108 #define COL_NAME_WIDTH          164
109 #define COL_ADDRESS_WIDTH       156
110
111 #define COL_FOLDER_WIDTH        170
112 #define ADDRESSBOOK_WIDTH       640
113 #define ADDRESSBOOK_HEIGHT      360
114
115 #define ADDRESSBOOK_MSGBUF_SIZE 2048
116
117 static GdkPixmap *folderxpm;
118 static GdkBitmap *folderxpmmask;
119 static GdkPixmap *folderopenxpm;
120 static GdkBitmap *folderopenxpmmask;
121 static GdkPixmap *groupxpm;
122 static GdkBitmap *groupxpmmask;
123 static GdkPixmap *interfacexpm;
124 static GdkBitmap *interfacexpmmask;
125 static GdkPixmap *bookxpm;
126 static GdkBitmap *bookxpmmask;
127 static GdkPixmap *addressxpm;
128 static GdkBitmap *addressxpmmask;
129 static GdkPixmap *vcardxpm;
130 static GdkBitmap *vcardxpmmask;
131 static GdkPixmap *jpilotxpm;
132 static GdkBitmap *jpilotxpmmask;
133 static GdkPixmap *categoryxpm;
134 static GdkBitmap *categoryxpmmask;
135 static GdkPixmap *ldapxpm;
136 static GdkBitmap *ldapxpmmask;
137
138 // Message buffer
139 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
140
141 // Address list selection
142 static GList *_addressListSelection_ = NULL;
143
144 // Address index file and interfaces
145 static AddressIndex *_addressIndex_ = NULL;
146 static GList *_addressInterfaceList_ = NULL;
147 static GList *_addressIFaceSelection_ = NULL;
148 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
149
150 static AddressBook_win addrbook;
151
152 static GHashTable *_addressBookTypeHash_ = NULL;
153 static GList *_addressBookTypeList_ = NULL;
154
155 static void addressbook_create                  ( void );
156 static gint addressbook_close                   (void);
157 static void addressbook_button_set_sensitive    (void);
158
159 /* callback functions */
160 static void addressbook_del_clicked             (GtkButton      *button,
161                                                  gpointer        data);
162 static void addressbook_reg_clicked             (GtkButton      *button,
163                                                  gpointer        data);
164 static void addressbook_to_clicked              (GtkButton      *button,
165                                                  gpointer        data);
166 static void addressbook_lup_clicked             (GtkButton      *button,
167                                                  gpointer       data);
168
169 static void addressbook_tree_selected           (GtkCTree       *ctree,
170                                                  GtkCTreeNode   *node,
171                                                  gint            column,
172                                                  gpointer        data);
173 static void addressbook_list_selected           (GtkCList       *clist,
174                                                  gint            row,
175                                                  gint            column,
176                                                  GdkEvent       *event,
177                                                  gpointer        data);
178 static void addressbook_list_row_selected       (GtkCTree       *clist,
179                                                  GtkCTreeNode   *node,
180                                                  gint            column,
181                                                  gpointer        data);
182 static void addressbook_list_row_unselected     (GtkCTree       *clist,
183                                                  GtkCTreeNode   *node,
184                                                  gint            column,
185                                                  gpointer        data);
186 static void addressbook_person_expand_node      (GtkCTree       *ctree,
187                                                  GList          *node,
188                                                  gpointer       *data );
189 static void addressbook_person_collapse_node    (GtkCTree       *ctree,
190                                                  GList          *node,
191                                                  gpointer       *data );
192 static void addressbook_entry_gotfocus          (GtkWidget      *widget);
193
194 #if 0
195 static void addressbook_entry_changed           (GtkWidget      *widget);
196 #endif
197
198 static void addressbook_list_button_pressed     (GtkWidget      *widget,
199                                                  GdkEventButton *event,
200                                                  gpointer        data);
201 static void addressbook_list_button_released    (GtkWidget      *widget,
202                                                  GdkEventButton *event,
203                                                  gpointer        data);
204 static void addressbook_tree_button_pressed     (GtkWidget      *ctree,
205                                                  GdkEventButton *event,
206                                                  gpointer        data);
207 static void addressbook_tree_button_released    (GtkWidget      *ctree,
208                                                  GdkEventButton *event,
209                                                  gpointer        data);
210 static void addressbook_popup_close             (GtkMenuShell   *menu_shell,
211                                                  gpointer        data);
212
213 static void addressbook_new_folder_cb           (gpointer        data,
214                                                  guint           action,
215                                                  GtkWidget      *widget);
216 static void addressbook_new_group_cb            (gpointer        data,
217                                                  guint           action,
218                                                  GtkWidget      *widget);
219 static void addressbook_treenode_edit_cb        (gpointer        data,
220                                                  guint           action,
221                                                  GtkWidget      *widget);
222 static void addressbook_treenode_delete_cb      (gpointer        data,
223                                                  guint           action,
224                                                  GtkWidget      *widget);
225
226 static void addressbook_change_node_name        (GtkCTreeNode   *node,
227                                                  const gchar    *name);
228
229 static void addressbook_new_address_cb          (gpointer        data,
230                                                  guint           action,
231                                                  GtkWidget      *widget);
232 static void addressbook_edit_address_cb         (gpointer        data,
233                                                  guint           action,
234                                                  GtkWidget      *widget);
235 static void addressbook_delete_address_cb       (gpointer        data,
236                                                  guint           action,
237                                                  GtkWidget      *widget);
238
239 static void close_cb                            (gpointer        data,
240                                                  guint           action,
241                                                  GtkWidget      *widget);
242 static void addressbook_file_save_cb            (gpointer        data,
243                                                  guint           action,
244                                                  GtkWidget      *widget);
245
246 // Data source edit stuff
247 static void addressbook_new_book_cb             ( gpointer      data,
248                                                   guint         action,
249                                                   GtkWidget     *widget );
250 static void addressbook_new_vcard_cb            ( gpointer      data,
251                                                   guint         action,
252                                                   GtkWidget     *widget );
253
254 #ifdef USE_JPILOT
255 static void addressbook_new_jpilot_cb           ( gpointer      data,
256                                                   guint         action,
257                                                   GtkWidget     *widget );
258 #endif
259
260 #ifdef USE_LDAP
261 static void addressbook_new_ldap_cb             ( gpointer      data,
262                                                   guint         action,
263                                                   GtkWidget     *widget );
264 #endif
265
266 static void addressbook_set_clist               (AddressObject  *obj);
267
268 static void addressbook_load_tree               (void);
269 void addressbook_read_file                      (void);
270
271 static GtkCTreeNode *addressbook_add_object     (GtkCTreeNode   *node,
272                                                  AddressObject  *obj);
273 static AddressDataSource *addressbook_find_datasource
274                                                 (GtkCTreeNode   *node );
275
276 static AddressBookFile *addressbook_get_book_file();
277
278 static GtkCTreeNode *addressbook_node_add_folder
279                                                 (GtkCTreeNode   *node,
280                                                 AddressDataSource *ds,
281                                                 ItemFolder      *itemFolder,
282                                                 AddressObjectType otype );
283 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode   *node,
284                                                 AddressDataSource *ds,
285                                                 ItemGroup       *itemGroup );
286 static GtkCTreeNode *addressbook_node_add_category
287                                                 (GtkCTreeNode   *node,
288                                                  AddressDataSource *ds,
289                                                  ItemFolder     *itemFolder );
290 static void addressbook_tree_remove_children    (GtkCTree       *ctree,
291                                                 GtkCTreeNode    *parent );
292 static void addressbook_move_nodes_up           (GtkCTree       *ctree,
293                                                 GtkCTreeNode    *node );
294 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode  *parent,
295                                                 ItemGroup       *group );
296
297 static void addressbook_delete_object           (AddressObject  *obj);
298
299 static void key_pressed                         (GtkWidget      *widget,
300                                                  GdkEventKey    *event,
301                                                  gpointer        data);
302 static gint addressbook_list_compare_func       (GtkCList       *clist,
303                                                  gconstpointer   ptr1,
304                                                  gconstpointer   ptr2);
305 //static gint addressbook_obj_name_compare      (gconstpointer   a,
306 //                                               gconstpointer   b);
307
308 static void addressbook_book_show_message       ( AddressBookFile *book );
309 static void addressbook_vcard_show_message      ( VCardFile *vcf );
310 #ifdef USE_JPILOT
311 static void addressbook_jpilot_show_message     ( JPilotFile *jpf );
312 #endif
313 #ifdef USE_LDAP
314 static void addressbook_ldap_show_message       ( SyldapServer *server );
315 #endif
316
317 // LUT's and IF stuff
318 static void addressbook_free_adapter            ( GtkCTreeNode  *node );
319 static void addressbook_free_child_adapters     ( GtkCTreeNode  *node );
320 AddressTypeControlItem *addrbookctl_lookup      ( gint          ot );
321 AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType );
322
323 void addrbookctl_build_map                      ( GtkWidget     *window );
324 void addrbookctl_build_iflist                   ( void );
325 AdapterInterface *addrbookctl_find_interface    ( AddressIfType ifType );
326 void addrbookctl_build_ifselect();
327
328 static void addrbookctl_free_interface          ( AdapterInterface      *adapter );
329 static void addrbookctl_free_datasource         ( AdapterDSource        *adapter );
330 static void addrbookctl_free_folder             ( AdapterFolder *adapter );
331 static void addrbookctl_free_group              ( AdapterGroup  *adapter );
332
333 static void addressbook_list_select_clear       ( void );
334 static void addressbook_list_select_add         ( AddressObject *obj );
335 static void addressbook_list_select_remove      ( AddressObject *obj );
336
337 static GtkItemFactoryEntry addressbook_entries[] =
338 {
339         {N_("/_File"),                  NULL,           NULL, 0, "<Branch>"},
340         {N_("/_File/New _Book"),        "<alt>B",       addressbook_new_book_cb,        0, NULL},
341         {N_("/_File/New _V-Card"),      "<alt>D",       addressbook_new_vcard_cb,       0, NULL},
342 #ifdef USE_JPILOT
343         {N_("/_File/New _J-Pilot"),     "<alt>J",       addressbook_new_jpilot_cb,      0, NULL},
344 #endif
345 #ifdef USE_LDAP
346         {N_("/_File/New _Server"),      "<alt>S",       addressbook_new_ldap_cb,        0, NULL},
347 #endif
348         {N_("/_File/---"),              NULL,           NULL, 0, "<Separator>"},
349         {N_("/_File/_Edit"),            NULL,           addressbook_treenode_edit_cb,   0, NULL},
350         {N_("/_File/_Delete"),          NULL,           addressbook_treenode_delete_cb, 0, NULL},
351         {N_("/_File/---"),              NULL,           NULL, 0, "<Separator>"},
352         {N_("/_File/_Save"),            "<alt>V",       addressbook_file_save_cb,       0, NULL},
353         {N_("/_File/_Close"),           "<alt>W",       close_cb, 0, NULL},
354         {N_("/_Address"),               NULL,           NULL, 0, "<Branch>"},
355         {N_("/_Address/New _Address"),  "<alt>N",       addressbook_new_address_cb,     0, NULL},
356         {N_("/_Address/New _Group"),    "<alt>G",       addressbook_new_group_cb,       0, NULL},
357         {N_("/_Address/New _Folder"),   "<alt>R",       addressbook_new_folder_cb,      0, NULL},
358         {N_("/_Address/---"),           NULL,           NULL, 0, "<Separator>"},
359         {N_("/_Address/_Edit"),         "<alt>Return",  addressbook_edit_address_cb,    0, NULL},
360         {N_("/_Address/_Delete"),       NULL,           addressbook_delete_address_cb,  0, NULL},
361         {N_("/_Help"),                  NULL,           NULL, 0, "<LastBranch>"},
362         {N_("/_Help/_About"),           NULL,           about_show, 0, NULL}
363 };
364
365 // New options to be added.
366 /*
367         {N_("/_Edit"),                  NULL,           NULL, 0, "<Branch>"},
368         {N_("/_Edit/C_ut"),             "<ctl>X",       NULL,                           0, NULL},
369         {N_("/_Edit/_Copy"),            "<ctl>C",       NULL,                           0, NULL},
370         {N_("/_Edit/_Paste"),           "<ctl>V",       NULL,                           0, NULL},
371         {N_("/_Tools"),                 NULL,           NULL, 0, "<Branch>"},
372         {N_("/_Tools/Import _Mozilla"), NULL,           NULL,                           0, NULL},
373         {N_("/_Tools/Import _LDIF"),    NULL,           NULL,                           0, NULL},
374         {N_("/_Tools/Import _V-Card"),  NULL,           NULL,                           0, NULL},
375         {N_("/_Tools/---"),             NULL,           NULL, 0, "<Separator>"},
376         {N_("/_Tools/Export _LDIF"),    NULL,           NULL,                           0, NULL},
377         {N_("/_Tools/Export V-_Card"),  NULL,           NULL,                           0, NULL},
378 */
379
380 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
381 {
382         {N_("/New _Address"),   NULL, addressbook_new_address_cb, 0, NULL},
383         {N_("/New _Group"),     NULL, addressbook_new_group_cb,   0, NULL},
384         {N_("/New _Folder"),    NULL, addressbook_new_folder_cb,  0, NULL},
385         {N_("/---"),            NULL, NULL, 0, "<Separator>"},
386         {N_("/_Edit"),          NULL, addressbook_treenode_edit_cb,   0, NULL},
387         {N_("/_Delete"),        NULL, addressbook_treenode_delete_cb, 0, NULL}
388 };
389
390 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
391 {
392         {N_("/New _Address"),   NULL, addressbook_new_address_cb,  0, NULL},
393         {N_("/New _Group"),     NULL, addressbook_new_group_cb,    0, NULL},
394         {N_("/New _Folder"),    NULL, addressbook_new_folder_cb,   0, NULL},
395         {N_("/---"),            NULL, NULL, 0, "<Separator>"},
396         {N_("/_Edit"),          NULL, addressbook_edit_address_cb,   0, NULL},
397         {N_("/_Delete"),        NULL, addressbook_delete_address_cb, 0, NULL}
398 };
399
400 void addressbook_open(Compose *target)
401 {
402         if (!addrbook.window) {
403                 addressbook_read_file();
404                 addressbook_create();
405                 addressbook_load_tree();
406                 gtk_ctree_select(GTK_CTREE(addrbook.ctree),
407                                  GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
408         }
409         
410                 gtk_widget_hide(addrbook.window);
411
412         gtk_widget_show_all(addrbook.window);
413
414         addressbook_set_target_compose(target);
415 }
416
417 void addressbook_set_target_compose(Compose *target)
418 {
419         addrbook.target_compose = target;
420
421         addressbook_button_set_sensitive();
422 }
423
424 Compose *addressbook_get_target_compose(void)
425 {
426         return addrbook.target_compose;
427 }
428
429 void addressbook_refresh( void ) {
430         if( addrbook.window ) {
431                 if( addrbook.treeSelected ) {
432                         gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
433                 }
434         }
435         addressbook_export_to_file();
436 }
437
438 /*
439 * Create the address book widgets. The address book contains two CTree widgets: the
440 * address index tree on the left and the address list on the right.
441 *
442 * The address index tree displays a hierarchy of interfaces and groups. Each node in
443 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
444 * data sources and folder objects.
445 *
446 * The address list displays group, person and email objects. These items are linked
447 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
448 * sources.
449 *
450 * In the tradition of MVC architecture, the data stores have been separated from the
451 * GUI components. The addrindex.c file provides the interface to all data stores.
452 */
453 static void addressbook_create( void ) {
454         GtkWidget *window;
455         GtkWidget *vbox;
456         GtkWidget *menubar;
457         GtkWidget *vbox2;
458         GtkWidget *ctree_swin;
459         GtkWidget *ctree;
460         GtkWidget *clist_vbox;
461         GtkWidget *clist_swin;
462         GtkWidget *clist;
463         GtkWidget *paned;
464         GtkWidget *hbox;
465         GtkWidget *label;
466         GtkWidget *entry;
467         GtkWidget *statusbar;
468         GtkWidget *hmbox;
469         GtkWidget *hbbox;
470         GtkWidget *hsbox;
471         GtkWidget *del_btn;
472         GtkWidget *reg_btn;
473         GtkWidget *lup_btn;
474         GtkWidget *to_btn;
475         GtkWidget *cc_btn;
476         GtkWidget *bcc_btn;
477         GtkWidget *tree_popup;
478         GtkWidget *list_popup;
479         GtkItemFactory *tree_factory;
480         GtkItemFactory *list_factory;
481         GtkItemFactory *menu_factory;
482         gint n_entries;
483         GList *nodeIf;
484         AdapterInterface *adapter;
485         AddressTypeControlItem *atci;
486         AddressInterface *iface;
487
488         gchar *titles[N_COLS] = {_("Name"), _("E-Mail address"), _("Remarks")};
489         gchar *text;
490         gint i;
491
492         debug_print("Creating addressbook window...\n");
493
494         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
495         gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
496         gtk_widget_set_usize(window, ADDRESSBOOK_WIDTH, ADDRESSBOOK_HEIGHT);
497         gtk_container_set_border_width(GTK_CONTAINER(window), BORDER_WIDTH);
498         gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, TRUE);
499         gtk_widget_realize(window);
500
501         gtk_signal_connect(GTK_OBJECT(window), "delete_event",
502                            GTK_SIGNAL_FUNC(addressbook_close), NULL);
503         gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
504                            GTK_SIGNAL_FUNC(key_pressed), NULL);
505         gtk_signal_connect(GTK_OBJECT(window), "focus_in_event",
506                            GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
507         gtk_signal_connect(GTK_OBJECT(window), "focus_out_event",
508                            GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
509
510         vbox = gtk_vbox_new(FALSE, 0);
511         gtk_container_add(GTK_CONTAINER(window), vbox);
512
513         n_entries = sizeof(addressbook_entries) /
514                 sizeof(addressbook_entries[0]);
515         menubar = menubar_create(window, addressbook_entries, n_entries,
516                                  "<AddressBook>", NULL);
517         gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
518         menu_factory = gtk_item_factory_from_widget(menubar);
519
520         vbox2 = gtk_vbox_new(FALSE, 4);
521         gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
522         gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
523
524         ctree_swin = gtk_scrolled_window_new(NULL, NULL);
525         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
526                                        GTK_POLICY_AUTOMATIC,
527                                        GTK_POLICY_ALWAYS);
528         gtk_widget_set_usize(ctree_swin, COL_FOLDER_WIDTH + 40, -1);
529
530         // Address index
531         ctree = gtk_ctree_new(1, 0);
532         gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
533         gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
534         gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
535         gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
536         gtk_ctree_set_expander_style(GTK_CTREE(ctree),
537                                      GTK_CTREE_EXPANDER_SQUARE);
538         gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
539         gtk_clist_set_compare_func(GTK_CLIST(ctree),
540                                    addressbook_list_compare_func);
541
542         gtk_signal_connect(GTK_OBJECT(ctree), "tree_select_row",
543                            GTK_SIGNAL_FUNC(addressbook_tree_selected), NULL);
544         gtk_signal_connect(GTK_OBJECT(ctree), "button_press_event",
545                            GTK_SIGNAL_FUNC(addressbook_tree_button_pressed),
546                            NULL);
547         gtk_signal_connect(GTK_OBJECT(ctree), "button_release_event",
548                            GTK_SIGNAL_FUNC(addressbook_tree_button_released),
549                            NULL);
550
551         clist_vbox = gtk_vbox_new(FALSE, 4);
552
553         clist_swin = gtk_scrolled_window_new(NULL, NULL);
554         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
555                                        GTK_POLICY_AUTOMATIC,
556                                        GTK_POLICY_ALWAYS);
557         gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
558
559         // Address list
560         clist = gtk_ctree_new_with_titles(N_COLS, 0, titles);
561         gtk_container_add(GTK_CONTAINER(clist_swin), clist);
562         gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
563         gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_DOTTED);
564         gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE);
565         gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
566         gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
567                                    COL_NAME_WIDTH);
568         gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
569                                    COL_ADDRESS_WIDTH);
570         gtk_clist_set_compare_func(GTK_CLIST(clist),
571                                    addressbook_list_compare_func);
572
573         for (i = 0; i < N_COLS; i++)
574                 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
575                                        GTK_CAN_FOCUS);
576
577         gtk_signal_connect(GTK_OBJECT(clist), "tree_select_row",
578                            GTK_SIGNAL_FUNC(addressbook_list_row_selected), NULL);
579         gtk_signal_connect(GTK_OBJECT(clist), "tree_unselect_row",
580                            GTK_SIGNAL_FUNC(addressbook_list_row_unselected), NULL);
581         gtk_signal_connect(GTK_OBJECT(clist), "button_press_event",
582                            GTK_SIGNAL_FUNC(addressbook_list_button_pressed),
583                            NULL);
584         gtk_signal_connect(GTK_OBJECT(clist), "button_release_event",
585                            GTK_SIGNAL_FUNC(addressbook_list_button_released),
586                            NULL);
587         gtk_signal_connect(GTK_OBJECT(clist), "select_row",
588                            GTK_SIGNAL_FUNC(addressbook_list_selected), NULL);
589         gtk_signal_connect(GTK_OBJECT(clist), "tree_expand",
590                            GTK_SIGNAL_FUNC(addressbook_person_expand_node), NULL );
591         gtk_signal_connect(GTK_OBJECT(clist), "tree_collapse",
592                            GTK_SIGNAL_FUNC(addressbook_person_collapse_node), NULL );
593
594         hbox = gtk_hbox_new(FALSE, 4);
595         gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
596
597         label = gtk_label_new(_("Name:"));
598         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
599
600         entry = gtk_entry_new();
601         gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
602
603         address_completion_register_entry(GTK_ENTRY(entry));
604         gtk_signal_connect(GTK_OBJECT(entry), "focus_in_event",
605                            GTK_SIGNAL_FUNC(addressbook_entry_gotfocus), NULL);
606
607 #if 0
608         gtk_signal_connect(GTK_OBJECT(entry), "changed",
609                            GTK_SIGNAL_FUNC(addressbook_entry_changed), NULL);
610 #endif
611
612         paned = gtk_hpaned_new();
613         gtk_box_pack_start(GTK_BOX(vbox2), paned, TRUE, TRUE, 0);
614         gtk_paned_add1(GTK_PANED(paned), ctree_swin);
615         gtk_paned_add2(GTK_PANED(paned), clist_vbox);
616
617         // Status bar
618         hsbox = gtk_hbox_new(FALSE, 0);
619         gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
620         statusbar = gtk_statusbar_new();
621         gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
622
623         // Button panel
624         hbbox = gtk_hbutton_box_new();
625         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
626         gtk_button_box_set_spacing(GTK_BUTTON_BOX(hbbox), 2);
627         gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
628
629         del_btn = gtk_button_new_with_label(_("Delete"));
630         GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
631         gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
632         reg_btn = gtk_button_new_with_label(_("Add"));
633         GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
634         gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
635         lup_btn = gtk_button_new_with_label(_("Lookup"));
636         GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
637         gtk_box_pack_start(GTK_BOX(hbbox), lup_btn, TRUE, TRUE, 0);
638
639         gtk_signal_connect(GTK_OBJECT(del_btn), "clicked",
640                            GTK_SIGNAL_FUNC(addressbook_del_clicked), NULL);
641         gtk_signal_connect(GTK_OBJECT(reg_btn), "clicked",
642                            GTK_SIGNAL_FUNC(addressbook_reg_clicked), NULL);
643         gtk_signal_connect(GTK_OBJECT(lup_btn), "clicked",
644                            GTK_SIGNAL_FUNC(addressbook_lup_clicked), NULL);
645
646         to_btn = gtk_button_new_with_label
647                 (prefs_common.trans_hdr ? _("To:") : "To:");
648         GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
649         gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
650         cc_btn = gtk_button_new_with_label
651                 (prefs_common.trans_hdr ? _("Cc:") : "Cc:");
652         GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
653         gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
654         bcc_btn = gtk_button_new_with_label
655                 (prefs_common.trans_hdr ? _("Bcc:") : "Bcc:");
656         GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
657         gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
658
659         gtk_signal_connect(GTK_OBJECT(to_btn), "clicked",
660                            GTK_SIGNAL_FUNC(addressbook_to_clicked),
661                            GINT_TO_POINTER(COMPOSE_TO));
662         gtk_signal_connect(GTK_OBJECT(cc_btn), "clicked",
663                            GTK_SIGNAL_FUNC(addressbook_to_clicked),
664                            GINT_TO_POINTER(COMPOSE_CC));
665         gtk_signal_connect(GTK_OBJECT(bcc_btn), "clicked",
666                            GTK_SIGNAL_FUNC(addressbook_to_clicked),
667                            GINT_TO_POINTER(COMPOSE_BCC));
668
669         // Build icons for interface
670         PIXMAP_CREATE( window, interfacexpm, interfacexpmmask, interface_xpm );
671
672         // Build control tables
673         addrbookctl_build_map( window );
674         addrbookctl_build_iflist();
675         addrbookctl_build_ifselect();
676
677         // Add each interface into the tree as a root level folder
678         nodeIf = _addressInterfaceList_;
679         while( nodeIf ) {
680                 adapter = nodeIf->data;
681                 nodeIf = g_list_next( nodeIf );
682                 iface = adapter->interface;
683                 if( iface->useInterface ) {
684                         atci = adapter->atci;
685                         text = atci->displayName;
686                         adapter->treeNode =
687                                 gtk_ctree_insert_node( GTK_CTREE(ctree),
688                                         NULL, NULL, &text, FOLDER_SPACING,
689                                         interfacexpm, interfacexpmmask,
690                                         interfacexpm, interfacexpmmask,
691                                         FALSE, FALSE );
692                         menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
693                         gtk_ctree_node_set_row_data( GTK_CTREE(ctree), adapter->treeNode, adapter );
694                 }
695         }
696
697         // Popup menu
698         n_entries = sizeof(addressbook_tree_popup_entries) /
699                 sizeof(addressbook_tree_popup_entries[0]);
700         tree_popup = menu_create_items(addressbook_tree_popup_entries,
701                                        n_entries,
702                                        "<AddressBookTree>", &tree_factory,
703                                        NULL);
704         gtk_signal_connect(GTK_OBJECT(tree_popup), "selection_done",
705                            GTK_SIGNAL_FUNC(addressbook_popup_close), NULL);
706         n_entries = sizeof(addressbook_list_popup_entries) /
707                 sizeof(addressbook_list_popup_entries[0]);
708         list_popup = menu_create_items(addressbook_list_popup_entries,
709                                        n_entries,
710                                        "<AddressBookList>", &list_factory,
711                                        NULL);
712
713         addrbook.window  = window;
714         addrbook.menubar = menubar;
715         addrbook.ctree   = ctree;
716         addrbook.clist   = clist;
717         addrbook.entry   = entry;
718         addrbook.statusbar = statusbar;
719         addrbook.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Addressbook Window" );
720
721         addrbook.del_btn = del_btn;
722         addrbook.reg_btn = reg_btn;
723         addrbook.lup_btn = lup_btn;
724         addrbook.to_btn  = to_btn;
725         addrbook.cc_btn  = cc_btn;
726         addrbook.bcc_btn = bcc_btn;
727
728         addrbook.tree_popup   = tree_popup;
729         addrbook.list_popup   = list_popup;
730         addrbook.tree_factory = tree_factory;
731         addrbook.list_factory = list_factory;
732         addrbook.menu_factory = menu_factory;
733
734         addrbook.listSelected = NULL;
735         address_completion_start(window);
736         gtk_widget_show_all(window);
737
738 }
739
740 static gint addressbook_close(void)
741 {
742         gtk_widget_hide(addrbook.window);
743         addressbook_export_to_file();
744         return TRUE;
745 }
746
747 static void addressbook_status_show( gchar *msg ) {
748         if( addrbook.statusbar != NULL ) {
749                 gtk_statusbar_pop( GTK_STATUSBAR(addrbook.statusbar), addrbook.status_cid );
750                 if( msg ) {
751                         gtk_statusbar_push( GTK_STATUSBAR(addrbook.statusbar), addrbook.status_cid, msg );
752                 }
753         }
754 }
755
756 static void addressbook_ds_show_message( AddressDataSource *ds ) {
757         gint retVal;
758         gchar *name;
759         *addressbook_msgbuf = '\0';
760         if( ds ) {
761                 name = addrindex_ds_get_name( ds );
762                 retVal = addrindex_ds_get_status_code( ds );
763                 if( retVal == MGU_SUCCESS ) {
764                         if( ds ) {
765                                 sprintf( addressbook_msgbuf, "%s", name );
766                         }
767                 }
768                 else {
769                         if( ds == NULL ) {
770                                 sprintf( addressbook_msgbuf, "%s", mgu_error2string( retVal ) );
771                         }
772                         else {
773                                 sprintf( addressbook_msgbuf, "%s: %s", name, mgu_error2string( retVal ) );
774                         }
775                 }
776         }
777         addressbook_status_show( addressbook_msgbuf );
778 }
779
780 static void addressbook_button_set_sensitive(void)
781 {
782         gboolean to_sens  = FALSE;
783         gboolean cc_sens  = FALSE;
784         gboolean bcc_sens = FALSE;
785
786         if (!addrbook.window) return;
787
788         if (addrbook.target_compose) {
789                 to_sens = TRUE;
790                 cc_sens = TRUE;
791                 if (addrbook.target_compose->use_bcc)
792                         bcc_sens = TRUE;
793         }
794
795         gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
796         gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
797         gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
798 }
799
800 /*
801 * Delete one or more objects from address list.
802 */
803 static void addressbook_del_clicked(GtkButton *button, gpointer data)
804 {
805         GtkCTree *clist = GTK_CTREE(addrbook.clist);
806         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
807         AddressObject *pobj, *obj;
808         AdapterDSource *ads = NULL;
809         GtkCTreeNode *nodeList;
810         gboolean remFlag, procFlag;
811         AlertValue aval;
812         AddressBookFile *abf = NULL;
813         AddressDataSource *ds = NULL;
814
815         pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
816         g_return_if_fail(pobj != NULL);
817
818         nodeList = addrbook.listSelected;
819         obj = gtk_ctree_node_get_row_data( clist, nodeList );
820         if( obj == NULL) return;
821         ds = addressbook_find_datasource( addrbook.treeSelected );
822         if( ds == NULL ) return;
823
824         procFlag = FALSE;
825         if( pobj->type == ADDR_DATASOURCE ) {
826                 ads = ADAPTER_DSOURCE(pobj);
827                 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
828         }
829         else if( pobj->type == ADDR_ITEM_FOLDER ) {
830                 procFlag = TRUE;
831         }
832         else if( pobj->type == ADDR_ITEM_GROUP ) {
833                 procFlag = TRUE;
834         }
835         if( ! procFlag ) return;
836         abf = ds->rawDataSource;
837         if( abf == NULL ) return;
838
839         // Confirm deletion
840         aval = alertpanel( _("Delete address(es)"),
841                         _("Really delete the address(es)?"),
842                         _("Yes"), _("No"), NULL );
843         if( aval != G_ALERTDEFAULT ) return;
844
845         // Process deletions
846         if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
847                 // Items inside folders
848                 GList *node;
849                 node = _addressListSelection_;
850                 while( node ) {
851                         AddrItemObject *aio = node->data;
852                         node = g_list_next( node );
853                         if( aio->type == ADDR_ITEM_GROUP ) {
854                                 ItemGroup *item = ( ItemGroup * ) aio;
855                                 GtkCTreeNode *nd = NULL;
856
857                                 nd = addressbook_find_group_node( addrbook.opened, item );
858                                 item = addrbook_remove_group( abf, item );
859                                 if( item ) {
860                                         addritem_free_item_group( item );
861                                         item = NULL;
862                                 }
863                                 // Remove group from parent node
864                                 gtk_ctree_remove_node( ctree, nd );
865                         }
866                         else if( aio->type == ADDR_ITEM_PERSON ) {
867                                 ItemPerson *item = ( ItemPerson * ) aio;
868                                 item = addrbook_remove_person( abf, item );
869                                 if( item ) {
870                                         addritem_free_item_person( item );
871                                         item = NULL;
872                                 }
873                         }
874                         else if( aio->type == ADDR_ITEM_EMAIL ) {
875                                 ItemEMail *item = ( ItemEMail * ) aio;
876                                 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
877                                 item = addrbook_person_remove_email( abf, person, item );
878                                 if( item ) {
879                                         addritem_free_item_email( item );
880                                         item = NULL;
881                                 }
882                         }
883                 }
884                 addressbook_list_select_clear();
885                 gtk_ctree_select( ctree, addrbook.opened);
886                 return;
887         }
888         else if( pobj->type == ADDR_ITEM_GROUP ) {
889                 // Items inside groups
890                 GList *node;
891                 node = _addressListSelection_;
892                 while( node ) {
893                         AddrItemObject *aio = node->data;
894                         node = g_list_next( node );
895                         if( aio->type == ADDR_ITEM_EMAIL ) {
896                                 ItemEMail *item = ( ItemEMail * ) aio;
897                                 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
898                                 item = addrbook_person_remove_email( abf, person, item );
899                                 if( item ) {
900                                         addritem_print_item_email( item, stdout );
901                                         addritem_free_item_email( item );
902                                         item = NULL;
903                                 }
904                         }
905                 }
906                 addressbook_list_select_clear();
907                 gtk_ctree_select( ctree, addrbook.opened);
908                 return;
909         }
910
911         gtk_ctree_node_set_row_data( clist, nodeList, NULL );
912         gtk_ctree_remove_node( clist, nodeList );
913         addressbook_list_select_remove( obj );
914
915 }
916
917 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
918 {
919         addressbook_new_address_cb( NULL, 0, NULL );
920 }
921
922 gchar *addressbook_format_address( AddressObject * obj ) {
923         gchar *buf = NULL;
924         gchar *name = NULL;
925         gchar *address = NULL;
926
927         if( obj->type == ADDR_ITEM_EMAIL ) {
928                 ItemPerson *person = NULL;
929                 ItemEMail *email = ( ItemEMail * ) obj;
930
931                 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
932                 if( email->address ) {
933                         if( ADDRITEM_NAME(email) ) {
934                                 name = ADDRITEM_NAME(email);
935                                 if( *name == '\0' ) {
936                                         name = ADDRITEM_NAME(person);
937                                 }
938                         }
939                         else if( ADDRITEM_NAME(person) ) {
940                                 name = ADDRITEM_NAME(person);
941                         }
942                         else {
943                                 buf = g_strdup( email->address );
944                         }
945                         address = email->address;
946                 }
947         }
948         else if( obj->type == ADDR_ITEM_PERSON ) {
949                 ItemPerson *person = ( ItemPerson * ) obj;
950                 GList *node = person->listEMail;
951
952                 name = ADDRITEM_NAME(person);
953                 if( node ) {
954                         ItemEMail *email = ( ItemEMail * ) node->data;
955                         address = email->address;
956                 }
957         }
958         if( address ) {
959                 if( name ) {
960                         buf = g_strdup_printf( "%s <%s>", name, address );
961                 }
962                 else {
963                         buf = g_strdup( address );
964                 }
965         }
966
967         return buf;
968 }
969
970 static void addressbook_to_clicked(GtkButton *button, gpointer data)
971 {
972         GList *node = _addressListSelection_;
973         if (!addrbook.target_compose) return;
974         while( node ) {
975                 AddressObject *obj = node->data;
976                 Compose *compose = addrbook.target_compose;
977                 node = g_list_next( node );
978                 if( obj->type == ADDR_ITEM_PERSON || obj->type == ADDR_ITEM_EMAIL ) {
979                         gchar *addr = addressbook_format_address( obj );
980                         compose_entry_append( compose, addr, (ComposeEntryType) data );
981                         g_free( addr );
982                         addr = NULL;
983                 }
984                 else if( obj->type == ADDR_ITEM_GROUP ) {
985                         ItemGroup *group = ( ItemGroup * ) obj;
986                         GList *nodeMail = group->listEMail;
987                         while( nodeMail ) {
988                                 ItemEMail *email = nodeMail->data;
989                                 gchar *addr = addressbook_format_address( ( AddressObject * ) email );
990                                 compose_entry_append( compose, addr, (ComposeEntryType) data );
991                                 g_free( addr );
992                                 nodeMail = g_list_next( nodeMail );
993                         }
994                 }
995         }
996 }
997
998 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
999         menu_set_sensitive( addrbook.menu_factory, "/File/New Book",    sensitive );
1000         menu_set_sensitive( addrbook.menu_factory, "/File/New V-Card",  sensitive );
1001 #ifdef USE_JPILOT
1002         menu_set_sensitive( addrbook.menu_factory, "/File/New J-Pilot", sensitive );
1003 #endif
1004 #ifdef USE_LDAP
1005         menu_set_sensitive( addrbook.menu_factory, "/File/New Server",  sensitive );
1006 #endif
1007         menu_set_sensitive( addrbook.menu_factory, "/File/Edit",        sensitive );
1008         menu_set_sensitive( addrbook.menu_factory, "/File/Delete",      sensitive );
1009
1010         menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1011         menu_set_sensitive( addrbook.menu_factory, "/Address/New Group",   sensitive );
1012         menu_set_sensitive( addrbook.menu_factory, "/Address/New Folder",  sensitive );
1013         gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1014         gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1015 }
1016
1017 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1018         gboolean canEdit = FALSE;
1019         gboolean canAdd = FALSE;
1020         gboolean canEditTr = TRUE;
1021         gboolean editAddress = FALSE;
1022         AddressTypeControlItem *atci = NULL;
1023         AddressDataSource *ds = NULL;
1024         AddressInterface *iface = NULL;
1025
1026         if( obj == NULL ) return;
1027         if( obj->type == ADDR_INTERFACE ) {
1028                 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1029                 iface = adapter->interface;
1030                 if( iface ) {
1031                         if( iface->haveLibrary ) {
1032                                 // Enable appropriate File / New command
1033                                 atci = adapter->atci;
1034                                 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1035                         }
1036                 }
1037                 canEditTr = FALSE;
1038         }
1039         else if( obj->type == ADDR_DATASOURCE ) {
1040                 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1041                 ds = ads->dataSource;
1042                 iface = ds->interface;
1043                 if( ! iface->readOnly ) {
1044                         canAdd = canEdit = editAddress = TRUE;
1045                 }
1046                 if( ! iface->haveLibrary ) {
1047                         canAdd = canEdit = editAddress = FALSE;
1048                 }
1049         }
1050         else if( obj->type == ADDR_ITEM_FOLDER ) {
1051                 ds = addressbook_find_datasource( addrbook.treeSelected );
1052                 if( ds ) {
1053                         iface = ds->interface;
1054                         if( ! iface->readOnly ) {
1055                                 canAdd = editAddress = TRUE;
1056                         }
1057                 }
1058         }
1059         else if( obj->type == ADDR_ITEM_GROUP ) {
1060                 ds = addressbook_find_datasource( addrbook.treeSelected );
1061                 if( ds ) {
1062                         iface = ds->interface;
1063                         if( ! iface->readOnly ) {
1064                                 editAddress = TRUE;
1065                         }
1066                 }
1067         }
1068
1069         if( addrbook.listSelected == NULL ) canEdit = FALSE;
1070
1071         // Enable add
1072         menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1073         menu_set_sensitive( addrbook.menu_factory, "/Address/New Group",   canAdd );
1074         menu_set_sensitive( addrbook.menu_factory, "/Address/New Folder",  canAdd );
1075         gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1076
1077         // Enable edit
1078         menu_set_sensitive( addrbook.menu_factory, "/Address/Edit",   canEdit );
1079         menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canEdit );
1080         gtk_widget_set_sensitive( addrbook.del_btn, canEdit );
1081
1082         menu_set_sensitive( addrbook.menu_factory, "/File/Edit",      canEditTr );
1083         menu_set_sensitive( addrbook.menu_factory, "/File/Delete",    canEditTr );
1084 }
1085
1086 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1087                                       gint column, gpointer data)
1088 {
1089         AddressObject *obj = NULL;
1090         AdapterDSource *ads = NULL;
1091         AddressDataSource *ds = NULL;
1092         ItemFolder *rootFolder = NULL;
1093
1094         addrbook.treeSelected = node;
1095         addrbook.listSelected = NULL;
1096         addressbook_status_show( "" );
1097         if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1098
1099         if( addrbook.clist ) gtk_clist_clear( GTK_CLIST(addrbook.clist) );
1100         if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1101         if( obj == NULL ) return;
1102
1103         addrbook.opened = node;
1104
1105         if( obj->type == ADDR_DATASOURCE ) {
1106                 // Read from file
1107                 static gboolean tVal = TRUE;
1108
1109                 ads = ADAPTER_DSOURCE(obj);
1110                 if( ads == NULL ) return;
1111                 ds = ads->dataSource;
1112                 if( ds == NULL ) return;                
1113
1114                 if( addrindex_ds_get_modify_flag( ds ) ) {
1115                         addrindex_ds_read_data( ds );
1116                 }
1117
1118                 if( ! addrindex_ds_get_read_flag( ds ) ) {
1119                         addrindex_ds_read_data( ds );
1120                 }
1121                 addressbook_ds_show_message( ds );
1122
1123                 if( ! addrindex_ds_get_access_flag( ds ) ) {
1124                         // Remove existing folders and groups
1125                         gtk_clist_freeze( GTK_CLIST(ctree) );
1126                         addressbook_tree_remove_children( ctree, node );
1127                         gtk_clist_thaw( GTK_CLIST(ctree) );
1128
1129                         // Load folders into the tree
1130                         rootFolder = addrindex_ds_get_root_folder( ds );
1131                         if( ds->type == ADDR_IF_JPILOT ) {
1132                                 addressbook_node_add_folder( node, ds, rootFolder, ADDR_CATEGORY );
1133                         }
1134                         else {
1135                                 addressbook_node_add_folder( node, ds, rootFolder, ADDR_ITEM_FOLDER );
1136                         }
1137                         addrindex_ds_set_access_flag( ds, &tVal );
1138                         gtk_ctree_expand( ctree, node );
1139                 }
1140         }
1141
1142         // Update address list
1143         addressbook_set_clist( obj );
1144
1145         // Setup main menu selections
1146         addressbook_menubar_set_sensitive( FALSE );
1147         addressbook_menuitem_set_sensitive( obj, node );
1148
1149         addressbook_list_select_clear();
1150
1151 }
1152
1153 static void addressbook_list_selected(GtkCList *clist, gint row, gint column,
1154                                       GdkEvent *event, gpointer data)
1155 {
1156         if (event && event->type == GDK_2BUTTON_PRESS) {
1157                 // Handle double click
1158                 if (prefs_common.add_address_by_click &&
1159                     addrbook.target_compose)
1160                         addressbook_to_clicked(NULL, NULL);
1161                 else
1162                         addressbook_edit_address_cb(NULL, 0, NULL);
1163         }
1164 }
1165
1166 static void addressbook_list_select_show() {
1167         GList *node = _addressListSelection_;
1168         gchar *addr = NULL;
1169         printf( "show selection...>>>\n" );
1170         while( node != NULL ) {
1171                 AddressObject *obj = ( AddressObject * ) node->data;
1172                 if( obj ) {
1173                         printf( "- %d : '%s'\n", obj->type, obj->name );
1174                         if( obj->type == ADDR_ITEM_GROUP ) {
1175                                 ItemGroup *group = ( ItemGroup * ) obj;
1176                                 GList *node = group->listEMail;
1177                                 while( node ) {
1178                                         ItemEMail *email = node->data;
1179                                         addr = addressbook_format_address( ( AddressObject * ) email );
1180                                         if( addr ) {
1181                                                 printf( "\tgrp >%s<\n", addr );
1182                                                 g_free( addr );
1183                                         }
1184                                         node = g_list_next( node );
1185                                 }
1186                         }
1187                         else {
1188                                 addr = addressbook_format_address( obj );
1189                                 if( addr ) {
1190                                         printf( "\t>%s<\n", addr );
1191                                         g_free( addr );
1192                                 }
1193                         }
1194                 }
1195                 else {
1196                         printf( "- NULL" );
1197                 }
1198                 node = g_list_next( node );
1199         }
1200         printf( "show selection...<<<\n" );
1201 }
1202
1203 static void addressbook_list_select_clear() {
1204         if( _addressListSelection_ ) {
1205                 g_list_free( _addressListSelection_ );
1206         }
1207         _addressListSelection_ = NULL;
1208 }
1209
1210 static void addressbook_list_select_add( AddressObject *obj ) {
1211         GList *node;
1212         if( obj ) {
1213                 if(     obj->type == ADDR_ITEM_PERSON ||
1214                         obj->type == ADDR_ITEM_EMAIL ||
1215                         obj->type == ADDR_ITEM_GROUP ) {
1216                         if( ! g_list_find( _addressListSelection_, obj ) ) {
1217                                 _addressListSelection_ = g_list_append( _addressListSelection_, obj );
1218                         }
1219                 }
1220         }
1221         // addressbook_list_select_show();
1222 }
1223
1224 static void addressbook_list_select_remove( AddressObject *obj ) {
1225         if( obj == NULL ) return;
1226         if( _addressListSelection_ ) {
1227                 _addressListSelection_ = g_list_remove( _addressListSelection_, obj );
1228         }
1229         // addressbook_list_select_show();
1230 }
1231
1232 static void addressbook_list_row_selected( GtkCTree *clist, GtkCTreeNode *node, gint column, gpointer data ) {
1233         GtkEntry *entry = GTK_ENTRY(addrbook.entry);
1234         AddressObject *obj = NULL;
1235         AddressObject *pobj = NULL;
1236         AdapterDSource *ads = NULL;
1237         AddressInterface *iface = NULL;
1238         AddressDataSource *ds = NULL;
1239         gboolean canEdit = FALSE;
1240         gboolean canDelete = FALSE;
1241
1242         gtk_entry_set_text( entry, "" );
1243         addrbook.listSelected = node;
1244         obj = gtk_ctree_node_get_row_data( clist, node );
1245         if( obj != NULL ) {
1246                 // printf( "list select: %d : '%s'\n", obj->type, obj->name );
1247                 addressbook_list_select_add( obj );
1248         }
1249
1250         pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1251         if( pobj == NULL ) return;
1252
1253         menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1254
1255         if( pobj->type == ADDR_DATASOURCE ) {
1256                 ads = ADAPTER_DSOURCE(pobj);
1257                 ds = ads->dataSource;
1258                 iface = ds->interface;
1259                 if( ! iface->readOnly ) {
1260                         canEdit = TRUE;
1261                         menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1262                         menu_set_sensitive( addrbook.list_factory, "/New Folder", TRUE );
1263                         menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1264                         gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1265                 }
1266         }
1267         else if( pobj->type != ADDR_INTERFACE ) {
1268                 ds = addressbook_find_datasource( addrbook.treeSelected );
1269                 iface = ds->interface;
1270                 if( ! iface->readOnly ) {
1271                         if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1272                                 canEdit = TRUE;
1273                                 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1274                                 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1275                         }
1276                         if( pobj->type == ADDR_ITEM_FOLDER ) {
1277                                 canEdit = TRUE;
1278                                 menu_set_sensitive( addrbook.list_factory, "/New Folder", TRUE );
1279                                 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1280                         }
1281                 }
1282         }
1283         if( obj == NULL ) canEdit = FALSE;
1284         canDelete = canEdit;
1285         if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) canEdit = FALSE;
1286
1287         menu_set_sensitive( addrbook.list_factory, "/Edit",   canEdit );
1288         menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1289
1290         menu_set_sensitive( addrbook.menu_factory, "/Address/Edit",   canEdit );
1291         menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1292
1293         gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1294
1295 }
1296
1297 static void addressbook_list_row_unselected( GtkCTree *clist, GtkCTreeNode *node, gint column, gpointer data ) {
1298         GtkEntry *entry = GTK_ENTRY(addrbook.entry);
1299         AddressObject *obj;
1300
1301         obj = gtk_ctree_node_get_row_data( clist, node );
1302         if( obj != NULL ) {
1303                 // printf( "list unselect: %d : '%s'\n", obj->type, obj->name );
1304                 addressbook_list_select_remove( obj );
1305         }
1306 }
1307
1308 static void addressbook_entry_gotfocus( GtkWidget *widget ) {
1309         gtk_editable_select_region( GTK_EDITABLE(addrbook.entry), 0, -1 );
1310 }
1311
1312 static void addressbook_list_button_pressed(GtkWidget *widget,
1313                                             GdkEventButton *event,
1314                                             gpointer data)
1315 {
1316         if( ! event ) return;
1317         if( event->button == 3 ) {
1318                 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
1319                        event->button, event->time );
1320         }
1321 }
1322
1323 static void addressbook_list_button_released(GtkWidget *widget,
1324                                              GdkEventButton *event,
1325                                              gpointer data)
1326 {
1327 }
1328
1329 static void addressbook_tree_button_pressed(GtkWidget *ctree,
1330                                             GdkEventButton *event,
1331                                             gpointer data)
1332 {
1333         GtkCList *clist = GTK_CLIST(ctree);
1334         gint row, column;
1335         AddressObject *obj = NULL;
1336         GtkCTreeNode *node;
1337         AdapterDSource *ads = NULL;
1338         AddressInterface *iface = NULL;
1339         AddressDataSource *ds = NULL;
1340         AddressTypeControlItem *atci = NULL;
1341         gboolean canEdit = FALSE;
1342
1343         if( ! event ) return;
1344         addressbook_menubar_set_sensitive( FALSE );
1345 /* */
1346         if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
1347                 gtk_clist_select_row( clist, row, column );
1348                 gtkut_clist_set_focus_row(clist, row);
1349                 obj = gtk_clist_get_row_data( clist, row );
1350         }
1351 /* */
1352         menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
1353
1354         if( obj == NULL ) return;
1355         if (obj->type == ADDR_DATASOURCE) {
1356                 ads = ADAPTER_DSOURCE(obj);
1357                 ds = ads->dataSource;
1358                 iface = ds->interface;
1359                 canEdit = TRUE;
1360                 if( ! iface->readOnly ) {
1361                         menu_set_sensitive( addrbook.tree_factory, "/New Address", TRUE );
1362                         menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
1363                         menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
1364                         gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1365                 }
1366         }
1367         else if (obj->type == ADDR_ITEM_FOLDER) {
1368                 ds = addressbook_find_datasource( addrbook.treeSelected );
1369                 iface = ds->interface;
1370                 if( ! iface->readOnly ) {
1371                         canEdit = TRUE;
1372                         menu_set_sensitive( addrbook.tree_factory, "/New Address", TRUE );
1373                         menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
1374                         menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
1375                         gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1376                 }
1377         }
1378         else if (obj->type == ADDR_ITEM_GROUP) {
1379                 ds = addressbook_find_datasource( addrbook.treeSelected );
1380                 iface = ds->interface;
1381                 if( ! iface->readOnly ) {
1382                         canEdit = TRUE;
1383                         menu_set_sensitive( addrbook.tree_factory, "/New Address", TRUE );
1384                         gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1385                 }
1386         }
1387
1388         // Enable edit
1389         menu_set_sensitive( addrbook.tree_factory, "/Edit",   canEdit );
1390         menu_set_sensitive( addrbook.tree_factory, "/Delete", canEdit );
1391         menu_set_sensitive( addrbook.menu_factory, "/File/Edit",   canEdit );
1392         menu_set_sensitive( addrbook.menu_factory, "/File/Delete", canEdit );
1393
1394         if( event->button == 3 ) {
1395                 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
1396                                event->button, event->time);
1397         }
1398
1399 }
1400
1401 static void addressbook_tree_button_released(GtkWidget *ctree,
1402                                              GdkEventButton *event,
1403                                              gpointer data)
1404 {
1405         gtk_ctree_select(GTK_CTREE(addrbook.ctree), addrbook.opened);
1406         gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
1407 }
1408
1409 static void addressbook_popup_close(GtkMenuShell *menu_shell, gpointer data)
1410 {
1411         if (!addrbook.opened) return;
1412
1413         gtk_ctree_select(GTK_CTREE(addrbook.ctree), addrbook.opened);
1414         gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree),
1415                                   addrbook.opened);
1416 }
1417
1418 static void addressbook_new_folder_cb(gpointer data, guint action,
1419                                       GtkWidget *widget)
1420 {
1421         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1422         AddressObject *obj = NULL;
1423         AddressDataSource *ds = NULL;
1424         AddressBookFile *abf = NULL;
1425         ItemFolder *parentFolder = NULL;
1426         ItemFolder *folder = NULL;
1427
1428         if( ! addrbook.treeSelected ) return;
1429         obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
1430         if( obj == NULL ) return;
1431         ds = addressbook_find_datasource( addrbook.treeSelected );
1432         if( ds == NULL ) return;
1433
1434         if( obj->type == ADDR_DATASOURCE ) {
1435                 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
1436         }
1437         else if( obj->type == ADDR_ITEM_FOLDER ) {
1438                 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
1439         }
1440         else {
1441                 return;
1442         }
1443
1444         abf = ds->rawDataSource;
1445         if( abf == NULL ) return;
1446         folder = addressbook_edit_folder( abf, parentFolder, NULL );
1447         if( folder ) {
1448                 GtkCTreeNode *nn;
1449                 nn = addressbook_node_add_folder( addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
1450                 gtk_ctree_expand( ctree, addrbook.treeSelected );
1451                 if( addrbook.treeSelected == addrbook.opened ) addressbook_set_clist(obj);
1452         }
1453
1454 }
1455
1456 static void addressbook_new_group_cb(gpointer data, guint action,
1457                                      GtkWidget *widget)
1458 {
1459         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1460         AddressObject *obj = NULL;
1461         AddressDataSource *ds = NULL;
1462         AddressBookFile *abf = NULL;
1463         ItemFolder *parentFolder = NULL;
1464         ItemGroup *group = NULL;
1465
1466         if( ! addrbook.treeSelected ) return;
1467         obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
1468         if( obj == NULL ) return;
1469         ds = addressbook_find_datasource( addrbook.treeSelected );
1470         if( ds == NULL ) return;
1471
1472         if( obj->type == ADDR_DATASOURCE ) {
1473                 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
1474         }
1475         else if( obj->type == ADDR_ITEM_FOLDER ) {
1476                 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
1477         }
1478         else {
1479                 return;
1480         }
1481
1482         abf = ds->rawDataSource;
1483         if( abf == NULL ) return;
1484         group = addressbook_edit_group( abf, parentFolder, NULL );
1485         if( group ) {
1486                 GtkCTreeNode *nn;
1487                 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
1488                 gtk_ctree_expand( ctree, addrbook.treeSelected );
1489                 if( addrbook.treeSelected == addrbook.opened ) addressbook_set_clist(obj);
1490         }
1491
1492 }
1493
1494 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
1495 {
1496         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1497         gchar *text[1];
1498         guint8 spacing;
1499         GdkPixmap *pix_cl, *pix_op;
1500         GdkBitmap *mask_cl, *mask_op;
1501         gboolean is_leaf, expanded;
1502
1503         gtk_ctree_get_node_info(ctree, node, text, &spacing,
1504                                 &pix_cl, &mask_cl, &pix_op, &mask_op,
1505                                 &is_leaf, &expanded);
1506         gtk_ctree_set_node_info(ctree, node, name, spacing,
1507                                 pix_cl, mask_cl, pix_op, mask_op,
1508                                 is_leaf, expanded);
1509 }
1510
1511 /*
1512 * Edit data source.
1513 * Enter: obj   Address object to edit.
1514 *        node  Node in tree.
1515 * Return: New name of data source.
1516 */
1517 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
1518         gchar *newName = NULL;
1519         AddressDataSource *ds = NULL;
1520         AddressInterface *iface = NULL;
1521         AdapterDSource *ads = NULL;
1522
1523         ds = addressbook_find_datasource( node );
1524         if( ds == NULL ) return NULL;
1525         iface = ds->interface;
1526         if( ! iface->haveLibrary ) return NULL;
1527
1528         // Read data from data source
1529         if( ! addrindex_ds_get_read_flag( ds ) ) {
1530                 addrindex_ds_read_data( ds );
1531         }
1532
1533         // Handle edit
1534         ads = ADAPTER_DSOURCE(obj);
1535         if( ads->subType == ADDR_BOOK ) {
1536                 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
1537         }
1538         else if( ads->subType == ADDR_VCARD ) {
1539                 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
1540         }
1541 #ifdef USE_JPILOT
1542         else if( ads->subType == ADDR_JPILOT ) {
1543                 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
1544         }
1545 #endif
1546 #ifdef USE_LDAP
1547         else if( ads->subType == ADDR_LDAP ) {
1548                 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
1549         }
1550 #endif
1551         else {
1552                 return NULL;
1553         }
1554         newName = obj->name;
1555         return newName;
1556 }
1557
1558 /*
1559 * Edit an object that is in the address tree area.
1560 */
1561 static void addressbook_treenode_edit_cb(gpointer data, guint action,
1562                                        GtkWidget *widget)
1563 {
1564         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1565         AddressObject *obj;
1566         AddressDataSource *ds = NULL;
1567         AddressBookFile *abf = NULL;
1568         GtkCTreeNode *node = NULL, *parentNode = NULL;
1569         gchar *name = NULL;
1570
1571         if( ! addrbook.treeSelected ) return;
1572         node = addrbook.treeSelected;
1573         if( GTK_CTREE_ROW(node)->level == 1 ) return;
1574         obj = gtk_ctree_node_get_row_data( ctree, node );
1575         if( obj == NULL ) return;
1576         parentNode = GTK_CTREE_ROW(node)->parent;
1577
1578         ds = addressbook_find_datasource( node );
1579         if( ds == NULL ) return;
1580
1581         if( obj->type == ADDR_DATASOURCE ) {
1582                 name = addressbook_edit_datasource( obj, node );
1583                 if( name == NULL ) return;
1584         }
1585         else {
1586                 abf = ds->rawDataSource;
1587                 if( abf == NULL ) return;
1588                 if( obj->type == ADDR_ITEM_FOLDER ) {
1589                         AdapterFolder *adapter = ADAPTER_FOLDER(obj);
1590                         ItemFolder *item = adapter->itemFolder;
1591                         ItemFolder *parentFolder = NULL;
1592                         parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
1593                         if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
1594                         name = ADDRITEM_NAME(item);
1595                 }
1596                 else if( obj->type == ADDR_ITEM_GROUP ) {
1597                         AdapterGroup *adapter = ADAPTER_GROUP(obj);
1598                         ItemGroup *item = adapter->itemGroup;
1599                         ItemFolder *parentFolder = NULL;
1600                         parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
1601                         if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
1602                         name = ADDRITEM_NAME(item);
1603                 }
1604         }
1605         if( name && parentNode ) {
1606                 // Update node in tree view
1607                 addressbook_change_node_name( node, name );
1608                 gtk_ctree_sort_node(ctree, parentNode);
1609                 gtk_ctree_expand( ctree, node );
1610                 gtk_ctree_select( ctree, node );
1611         }
1612 }
1613
1614 /*
1615 * Delete an item from the tree widget.
1616 */
1617 static void addressbook_treenode_delete_cb(gpointer data, guint action,
1618                                          GtkWidget *widget)
1619 {
1620         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1621         GtkCTreeNode *node = NULL;
1622         AddressObject *obj;
1623         gchar *message;
1624         AlertValue aval;
1625         AddressBookFile *abf = NULL;
1626         AdapterDSource *ads = NULL;
1627         AddressInterface *iface = NULL;
1628         AddressDataSource *ds = NULL;
1629         gboolean remFlag = FALSE;
1630
1631         if( ! addrbook.treeSelected ) return;
1632         node = addrbook.treeSelected;
1633         if( GTK_CTREE_ROW(node)->level == 1 ) return;
1634
1635         obj = gtk_ctree_node_get_row_data( ctree, node );
1636         g_return_if_fail(obj != NULL);
1637
1638         if( obj->type == ADDR_DATASOURCE ) {
1639                 ads = ADAPTER_DSOURCE(obj);
1640                 if( ads == NULL ) return;
1641                 ds = ads->dataSource;
1642                 if( ds == NULL ) return;
1643         }
1644         else {
1645                 // Must be folder or something else
1646                 ds = addressbook_find_datasource( node );
1647                 if( ds == NULL ) return;
1648
1649                 // Only allow deletion from non-readOnly data sources
1650                 iface = ds->interface;
1651                 if( iface->readOnly ) return;
1652         }
1653
1654         // Confirm deletion
1655         if( obj->type == ADDR_ITEM_FOLDER ) {
1656                 message = g_strdup_printf( _(
1657                                 "Do you want to delete the folder AND all addresses in `%s' ? \n" \
1658                                 "If deleting the folder only, addresses will be moved into parent folder." ),
1659                                 obj->name );
1660                 aval = alertpanel( _("Delete"), message, _("Folder only"), _("Folder and Addresses"), _("Cancel") );
1661                 g_free(message);
1662                 if( aval == G_ALERTOTHER ) return;
1663         }
1664         else {
1665                 message = g_strdup_printf(_("Really delete `%s' ?"), obj->name);
1666                 aval = alertpanel(_("Delete"), message, _("Yes"), _("No"), NULL);
1667                 g_free(message);
1668                 if (aval != G_ALERTDEFAULT) return;
1669         }
1670
1671         // Proceed with deletion
1672         if( obj->type == ADDR_DATASOURCE ) {
1673                 // Remove data source.
1674                 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
1675                         addressbook_free_child_adapters( node );
1676                         remFlag = TRUE;
1677                 }
1678         }
1679         else {
1680                 abf = addressbook_get_book_file();
1681                 if( abf == NULL ) return;
1682         }
1683
1684         if( obj->type == ADDR_ITEM_FOLDER ) {
1685                 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
1686                 ItemFolder *item = adapter->itemFolder;
1687                 if( aval == G_ALERTDEFAULT ) {
1688                         // Remove folder only
1689                         item = addrbook_remove_folder( abf, item );
1690                         if( item ) {
1691                                 addritem_free_item_folder( item );
1692                                 addressbook_move_nodes_up( ctree, node );
1693                                 remFlag = TRUE;
1694                         }
1695                 }
1696                 else if( aval == G_ALERTALTERNATE ) {
1697                         // Remove folder and addresses
1698                         item = addrbook_remove_folder_delete( abf, item );
1699                         if( item ) {
1700                                 addritem_free_item_folder( item );
1701                                 addressbook_free_child_adapters( node );
1702                                 remFlag = TRUE;
1703                         }
1704                 }
1705         }
1706         else if( obj->type == ADDR_ITEM_GROUP ) {
1707                 AdapterGroup *adapter = ADAPTER_GROUP(obj);
1708                 ItemGroup *item = adapter->itemGroup;
1709
1710                 item = addrbook_remove_group( abf, item );
1711                 if( item ) {
1712                         addritem_free_item_group( item );
1713                         remFlag = TRUE;
1714                 }
1715         }
1716
1717         if( remFlag ) {
1718                 // Free up adapter and remove node.
1719                 addressbook_free_adapter( node );
1720                 gtk_ctree_remove_node(ctree, node );
1721         }
1722 }
1723
1724 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
1725         AddressObject *pobj = NULL;
1726         AddressDataSource *ds = NULL;
1727         AddressBookFile *abf = NULL;
1728
1729         pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
1730         if( pobj == NULL ) return;
1731         ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
1732         if( ds == NULL ) return;
1733
1734         abf = ds->rawDataSource;
1735         if( abf == NULL ) return;
1736
1737         if( pobj->type == ADDR_DATASOURCE ) {
1738                 if( ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ) {
1739                         // New address
1740                         ItemPerson *person = addressbook_edit_person( abf, NULL, NULL, FALSE );
1741                         if( person ) {
1742                                 if( addrbook.treeSelected == addrbook.opened ) {
1743                                         gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
1744                                 }
1745                         }
1746                 }
1747         }
1748         else if( pobj->type == ADDR_ITEM_FOLDER ) {
1749                 // New address
1750                 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
1751                 ItemPerson *person = addressbook_edit_person( abf, folder, NULL, FALSE );
1752                 if( person ) {
1753                         if (addrbook.treeSelected == addrbook.opened) {
1754                                 gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
1755                         }
1756                 }
1757         }
1758         else if( pobj->type == ADDR_ITEM_GROUP ) {
1759                 // New address in group
1760                 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
1761                 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
1762                 if (addrbook.treeSelected == addrbook.opened) {
1763                         // Change node name in tree.
1764                         addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
1765                         gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
1766                 }
1767         }
1768 }
1769
1770 /*
1771 * Search for specified group in address index tree.
1772 */
1773 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
1774         GtkCTreeNode *node = NULL;
1775         GtkCTreeRow *currRow;
1776
1777         currRow = GTK_CTREE_ROW( parent );
1778         if( currRow ) {
1779                 node = currRow->children;
1780                 while( node ) {
1781                         AddressObject *obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
1782                         if( obj->type == ADDR_ITEM_GROUP ) {
1783                                 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
1784                                 if( g == group ) return node;
1785                         }
1786                         currRow = GTK_CTREE_ROW(node);
1787                         node = currRow->sibling;
1788                 }
1789         }
1790         return NULL;
1791 }
1792
1793 static AddressBookFile *addressbook_get_book_file() {
1794         AddressBookFile *abf = NULL;
1795         AddressDataSource *ds = NULL;
1796         ds = addressbook_find_datasource( addrbook.treeSelected );
1797         if( ds == NULL ) return;
1798         if( ds->type == ADDR_IF_BOOK ) abf = ds->rawDataSource;
1799         return abf;
1800 }
1801
1802 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
1803         GtkCTreeNode *node;
1804         GtkCTreeRow *row;
1805
1806         // Remove existing folders and groups
1807         row = GTK_CTREE_ROW( parent );
1808         if( row ) {
1809                 while( node = row->children ) {
1810                         gtk_ctree_remove_node( ctree, node );
1811                 }
1812         }
1813 }
1814
1815 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
1816         GtkCTreeNode *parent, *child;
1817         GtkCTreeRow *currRow;
1818         currRow = GTK_CTREE_ROW( node );
1819         if( currRow ) {
1820                 parent = currRow->parent;
1821                 while( child = currRow->children ) {
1822                         gtk_ctree_move( ctree, child, parent, node );
1823                 }
1824                 gtk_ctree_sort_node( ctree, parent );
1825         }
1826 }
1827
1828 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
1829         GtkCTree *clist = GTK_CTREE(addrbook.clist);
1830         GtkCTree *ctree;
1831         AddressObject *obj = NULL, *pobj = NULL;
1832         AddressDataSource *ds = NULL;
1833         GtkCTreeNode *node = NULL, *parentNode = NULL;
1834         gchar *name = NULL;
1835         AddressBookFile *abf = NULL;
1836
1837         if( addrbook.listSelected == NULL ) return;
1838         obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1839         g_return_if_fail(obj != NULL);
1840
1841         ctree = GTK_CTREE( addrbook.ctree );
1842         pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
1843         node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
1844
1845         ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
1846         if( ds == NULL ) return;
1847
1848         abf = addressbook_get_book_file();
1849         if( abf == NULL ) return;
1850         if( obj->type == ADDR_ITEM_EMAIL ) {
1851                 ItemEMail *email = ( ItemEMail * ) obj;
1852                 ItemPerson *person;
1853                 if( email == NULL ) return;
1854                 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
1855                         // Edit parent group
1856                         AdapterGroup *adapter = ADAPTER_GROUP(pobj);
1857                         ItemGroup *itemGrp = adapter->itemGroup;
1858                         if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
1859                         name = ADDRITEM_NAME(itemGrp);
1860                         node = addrbook.treeSelected;
1861                         parentNode = GTK_CTREE_ROW(node)->parent;
1862                 }
1863                 else {
1864                         // Edit person - email page
1865                         person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1866                         if( addressbook_edit_person( abf, NULL, person, TRUE ) == NULL ) return;
1867                         gtk_ctree_select( ctree, addrbook.opened );
1868                         return;
1869                 }
1870         }
1871         else if( obj->type == ADDR_ITEM_PERSON ) {
1872                 // Edit person - basic page
1873                 ItemPerson *person = ( ItemPerson * ) obj;
1874                 if( addressbook_edit_person( abf, NULL, person, FALSE ) == NULL ) return;
1875                 gtk_ctree_select( ctree, addrbook.opened);
1876                 return;
1877         }
1878         else if( obj->type == ADDR_ITEM_GROUP ) {
1879                 ItemGroup *itemGrp = ( ItemGroup * ) obj;
1880                 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
1881                 parentNode = addrbook.treeSelected;
1882                 node = addressbook_find_group_node( parentNode, itemGrp );
1883                 name = ADDRITEM_NAME(itemGrp);
1884         }
1885         else {
1886                 return;
1887         }
1888
1889         // Update tree node with node name
1890         if( node == NULL ) return;
1891         addressbook_change_node_name( node, name );
1892         gtk_ctree_sort_node( ctree, parentNode );
1893         gtk_ctree_select( ctree, addrbook.opened );
1894 }
1895
1896 static void addressbook_delete_address_cb(gpointer data, guint action,
1897                                           GtkWidget *widget)
1898 {
1899         addressbook_del_clicked(NULL, NULL);
1900 }
1901
1902 static void close_cb(gpointer data, guint action, GtkWidget *widget)
1903 {
1904         addressbook_close();
1905 }
1906
1907 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
1908         addressbook_export_to_file();
1909 }
1910
1911 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
1912         if( node ) {
1913                 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
1914                 if( person ) addritem_person_set_opened( person, TRUE );
1915         }
1916 }
1917
1918 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
1919         if( node ) {
1920                 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
1921                 if( person ) addritem_person_set_opened( person, FALSE );
1922         }
1923 }
1924
1925 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
1926         gchar *str = NULL;
1927         gchar *eMailAlias = ADDRITEM_NAME(email);
1928         if( eMailAlias && *eMailAlias != '\0' ) {
1929                 if( person ) {
1930                         str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
1931                 }
1932                 else {
1933                         str = g_strdup( eMailAlias );
1934                 }
1935         }
1936         return str;
1937 }
1938
1939 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
1940         GList *items = itemGroup->listEMail;
1941         AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
1942         for( ; items != NULL; items = g_list_next( items ) ) {
1943                 GtkCTreeNode *nodeEMail = NULL;
1944                 gchar *text[N_COLS];
1945                 ItemEMail *email = items->data;
1946                 ItemPerson *person;
1947                 gchar *str = NULL;
1948
1949                 if( ! email ) continue;
1950
1951                 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1952                 str = addressbook_format_item_clist( person, email );
1953                 if( str ) {
1954                         text[COL_NAME] = str;
1955                 }
1956                 else {
1957                         text[COL_NAME] = ADDRITEM_NAME(person);
1958                 }
1959                 text[COL_ADDRESS] = email->address;
1960                 text[COL_REMARKS] = email->remarks;
1961                 nodeEMail = gtk_ctree_insert_node(
1962                                 clist, NULL, NULL,
1963                                 text, FOLDER_SPACING,
1964                                 atci->iconXpm, atci->maskXpm,
1965                                 atci->iconXpmOpen, atci->maskXpmOpen,
1966                                 FALSE, FALSE );
1967                 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
1968                 g_free( str );
1969                 str = NULL;
1970         }
1971 }
1972
1973 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
1974         GList *items;
1975         AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
1976         AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
1977
1978         if( atci == NULL ) return;
1979         if( atciMail == NULL ) return;
1980
1981         // Load email addresses
1982         items = addritem_folder_get_person_list( itemFolder );
1983         for( ; items != NULL; items = g_list_next( items ) ) {
1984                 GtkCTreeNode *nodePerson = NULL;
1985                 GtkCTreeNode *nodeEMail = NULL;
1986                 gchar *text[N_COLS];
1987                 gboolean flgFirst = TRUE, haveAddr = FALSE;
1988                 gint row;
1989                 ItemPerson *person;
1990                 GList *node;
1991
1992                 person = ( ItemPerson * ) items->data;
1993                 if( person == NULL ) continue;
1994
1995                 text[COL_NAME] = NULL;
1996                 node = person->listEMail;
1997                 while( node ) {
1998                         ItemEMail *email = node->data;
1999                         gchar *eMailAddr = NULL;
2000                         node = g_list_next( node );
2001
2002                         text[COL_ADDRESS] = email->address;
2003                         text[COL_REMARKS] = email->remarks;
2004                         eMailAddr = ADDRITEM_NAME(email);
2005                         if( *eMailAddr == '\0' ) eMailAddr = NULL;
2006                         if( flgFirst ) {
2007                                 // First email belongs with person
2008                                 gchar *str = addressbook_format_item_clist( person, email );
2009                                 if( str ) {
2010                                         text[COL_NAME] = str;
2011                                 }
2012                                 else {
2013                                         text[COL_NAME] = ADDRITEM_NAME(person);
2014                                 }
2015                                 nodePerson = gtk_ctree_insert_node(
2016                                                 clist, NULL, NULL,
2017                                                 text, FOLDER_SPACING,
2018                                                 atci->iconXpm, atci->maskXpm,
2019                                                 atci->iconXpmOpen, atci->maskXpmOpen,
2020                                                 FALSE, person->isOpened );
2021                                 g_free( str );
2022                                 str = NULL;
2023                                 gtk_ctree_node_set_row_data(clist, nodePerson, person );
2024                         }
2025                         else {
2026                                 // Subsequent email is a child node of person
2027                                 text[COL_NAME] = ADDRITEM_NAME(email);
2028                                 nodeEMail = gtk_ctree_insert_node(
2029                                                 clist, nodePerson, NULL,
2030                                                 text, FOLDER_SPACING,
2031                                                 atciMail->iconXpm, atciMail->maskXpm,
2032                                                 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
2033                                                 FALSE, TRUE );
2034                                 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
2035                         }
2036                         flgFirst = FALSE;
2037                         haveAddr = TRUE;
2038                 }
2039                 if( ! haveAddr ) {
2040                         // Have name without EMail
2041                         text[COL_NAME] = ADDRITEM_NAME(person);
2042                         text[COL_ADDRESS] = NULL;
2043                         text[COL_REMARKS] = NULL;
2044                         nodePerson = gtk_ctree_insert_node(
2045                                         clist, NULL, NULL,
2046                                         text, FOLDER_SPACING,
2047                                         atci->iconXpm, atci->maskXpm,
2048                                         atci->iconXpmOpen, atci->maskXpmOpen,
2049                                         FALSE, person->isOpened );
2050                         gtk_ctree_node_set_row_data(clist, nodePerson, person );
2051                 }
2052                 gtk_ctree_sort_node(GTK_CTREE(clist), NULL);
2053         }
2054         // Free up the list
2055         mgu_clear_list( items );
2056         g_list_free( items );
2057 }
2058
2059 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
2060         GList *items;
2061         AddressTypeControlItem *atci =  addrbookctl_lookup( ADDR_ITEM_GROUP );
2062
2063         // Load any groups
2064         if( ! atci ) return;
2065         items = addritem_folder_get_group_list( itemFolder );
2066         for( ; items != NULL; items = g_list_next( items ) ) {
2067                 GtkCTreeNode *nodeGroup = NULL;
2068                 gchar *text[N_COLS];
2069                 ItemGroup *group = items->data;
2070                 if( group == NULL ) continue;
2071                 text[COL_NAME] = ADDRITEM_NAME(group);
2072                 text[COL_ADDRESS] = NULL;
2073                 text[COL_REMARKS] = NULL;
2074                 nodeGroup = gtk_ctree_insert_node(clist, NULL, NULL,
2075                                       text, FOLDER_SPACING,
2076                                       atci->iconXpm, atci->maskXpm,
2077                                       atci->iconXpmOpen, atci->maskXpmOpen,
2078                                       FALSE, FALSE);
2079                 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
2080                 gtk_ctree_sort_node(clist, NULL);
2081         }
2082         // Free up the list
2083         mgu_clear_list( items );
2084         g_list_free( items );
2085 }
2086
2087 /*
2088  * Load data sources into list.
2089  */
2090 static void addressbook_node_load_datasource( GtkCTree *clist, AddressObject *obj ) {
2091         AdapterInterface *adapter;
2092         AddressInterface *iface;
2093         AddressTypeControlItem *atci = NULL;
2094         AddressDataSource *ds;
2095         GtkCTreeNode *newNode, *node;
2096         GtkCTreeRow *row;
2097         GtkCell *cell = NULL;
2098         gchar *text[N_COLS];
2099
2100         adapter = ADAPTER_INTERFACE(obj);
2101         if( adapter == NULL ) return;
2102         iface = adapter->interface;
2103         atci = adapter->atci;
2104         if( atci == NULL ) return;
2105
2106         // Create nodes in list copying values for data sources in tree
2107         row = GTK_CTREE_ROW( adapter->treeNode );
2108         if( row ) {
2109                 node = row->children;
2110                 while( node ) {
2111                         gpointer data = gtk_ctree_node_get_row_data( clist, node );
2112                         row = GTK_CTREE_ROW( node );
2113                         cell = ( ( GtkCListRow * )row )->cell;
2114                         text[COL_NAME] = cell->u.text;
2115                         text[COL_ADDRESS] = NULL;
2116                         text[COL_REMARKS] = NULL;
2117                         newNode = gtk_ctree_insert_node( clist, NULL, NULL,
2118                                       text, FOLDER_SPACING,
2119                                       atci->iconXpm, atci->maskXpm,
2120                                       atci->iconXpmOpen, atci->maskXpmOpen,
2121                                       FALSE, FALSE);
2122                         gtk_ctree_node_set_row_data( clist, newNode, data );
2123                         node = row->sibling;
2124
2125                 }
2126         }
2127         gtk_ctree_sort_node( clist, NULL );
2128 }
2129
2130 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
2131         AddressDataSource *ds = NULL;
2132         AddressObject *ao;
2133
2134         g_return_if_fail(addrbook.ctree != NULL);
2135
2136         while( node ) {
2137                 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
2138                 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
2139                 if( ao ) {
2140 //                      printf( "ao->type = %d\n", ao->type );
2141                         if( ao->type == ADDR_DATASOURCE ) {
2142                                 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
2143 //                              printf( "found it\n" );
2144                                 ds = ads->dataSource;
2145                                 break;
2146                         }
2147                 }
2148                 node = GTK_CTREE_ROW(node)->parent;
2149         }
2150         return ds;
2151 }
2152
2153 /*
2154 * Load address list widget with children of specified object.
2155 * Enter: obj    Parent object to be loaded.
2156 */
2157 static void addressbook_set_clist( AddressObject *obj ) {
2158         GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
2159         GtkCList *clist = GTK_CLIST(addrbook.clist);
2160         AddressDataSource *ds = NULL;
2161         AdapterDSource *ads = NULL;
2162
2163         if( obj == NULL ) {
2164                 gtk_clist_clear(clist);
2165                 return;
2166         }
2167
2168         if( obj->type == ADDR_INTERFACE ) {
2169                 // printf( "set_clist: loading datasource...\n" );
2170                 // addressbook_node_load_datasource( clist, obj );
2171                 return;
2172         }
2173
2174         gtk_clist_freeze(clist);
2175         gtk_clist_clear(clist);
2176
2177         if( obj->type == ADDR_DATASOURCE ) {
2178                 ads = ADAPTER_DSOURCE(obj);
2179                 ds = ADAPTER_DSOURCE(obj)->dataSource;
2180                 if( ds ) {
2181                         // Load root folder
2182                         ItemFolder *rootFolder = NULL;
2183                         rootFolder = addrindex_ds_get_root_folder( ds );
2184                         addressbook_folder_load_person( ctreelist, addrindex_ds_get_root_folder( ds ) );
2185                         addressbook_folder_load_group( ctreelist, addrindex_ds_get_root_folder( ds ) );
2186                 }
2187         }
2188         else {
2189                 if( obj->type == ADDR_ITEM_GROUP ) {
2190                         // Load groups
2191                         ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
2192                         addressbook_load_group( ctreelist, itemGroup );
2193                 }
2194                 else if( obj->type == ADDR_ITEM_FOLDER ) {
2195                         // Load folders
2196                         ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
2197                         addressbook_folder_load_person( ctreelist, itemFolder );
2198                         addressbook_folder_load_group( ctreelist, itemFolder );
2199                 }
2200         }
2201
2202         gtk_clist_sort(clist);
2203         gtk_clist_thaw(clist);
2204 }
2205
2206 /*
2207 * Free adaptor for specified node.
2208 */
2209 static void addressbook_free_adapter( GtkCTreeNode *node ) {
2210         AddressObject *ao;
2211
2212         g_return_if_fail(addrbook.ctree != NULL);
2213
2214         if( node ) {
2215                 if( GTK_CTREE_ROW(node)->level < 2 ) return;
2216                 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
2217                 if( ao == NULL ) return;
2218                 if( ao->type == ADDR_INTERFACE ) {
2219                         AdapterInterface *ai = ADAPTER_INTERFACE(ao);
2220                         addrbookctl_free_interface( ai );
2221                 }
2222                 else if( ao->type == ADDR_DATASOURCE ) {
2223                         AdapterDSource *ads = ADAPTER_DSOURCE(ao);
2224                         addrbookctl_free_datasource( ads );
2225                 }
2226                 else if( ao->type == ADDR_ITEM_FOLDER ) {
2227                         AdapterFolder *af = ADAPTER_FOLDER(ao);
2228                         addrbookctl_free_folder( af );
2229                 }
2230                 else if( ao->type == ADDR_ITEM_GROUP ) {
2231                         AdapterGroup *ag = ADAPTER_GROUP(ao);
2232                         addrbookctl_free_group( ag );
2233                 }
2234                 gtk_ctree_node_set_row_data( GTK_CTREE(addrbook.ctree), node, NULL );
2235         }
2236 }
2237
2238 /*
2239 * Free all children adapters.
2240 */
2241 static void addressbook_free_child_adapters( GtkCTreeNode *node ) {
2242         GtkCTreeNode *parent, *child;
2243         GtkCTreeRow *currRow;
2244
2245         if( node == NULL ) return;
2246         currRow = GTK_CTREE_ROW( node );
2247         if( currRow ) {
2248                 parent = currRow->parent;
2249                 child = currRow->children;
2250                 while( child ) {
2251                         addressbook_free_child_adapters( child );
2252                         addressbook_free_adapter( child );
2253                         currRow = GTK_CTREE_ROW( child );
2254                         child = currRow->sibling;
2255                 }
2256         }
2257 }
2258
2259 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
2260                                 AddressObjectType otype, gchar *name )
2261 {
2262         AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
2263         ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
2264         ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
2265         adapter->dataSource = ds;
2266         adapter->subType = otype;
2267         return adapter;
2268 }
2269
2270 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
2271         ADDRESS_OBJECT_NAME(adapter) = mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
2272 }
2273
2274 /*
2275  * Load tree from address index with the initial data.
2276  */
2277 static void addressbook_load_tree( void ) {
2278         GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2279         GList *nodeIf, *nodeDS;
2280         AdapterInterface *adapter;
2281         AddressInterface *iface;
2282         AddressTypeControlItem *atci;
2283         AddressDataSource *ds;
2284         AdapterDSource *ads;
2285         GtkCTreeNode *node, *newNode;
2286         gchar *name;
2287
2288         nodeIf = _addressInterfaceList_;
2289         while( nodeIf ) {
2290                 adapter = nodeIf->data;
2291                 node = adapter->treeNode;
2292                 iface = adapter->interface;
2293                 atci = adapter->atci;
2294                 if( iface ) {
2295                         if( iface->useInterface ) {
2296                                 // Load data sources below interface node
2297                                 nodeDS = iface->listSource;
2298                                 while( nodeDS ) {
2299                                         ds = nodeDS->data;
2300                                         newNode = NULL;
2301                                         name = addrindex_ds_get_name( ds );
2302                                         ads = addressbook_create_ds_adapter( ds, atci->objectType, name );
2303                                         newNode = addressbook_add_object( node, ADDRESS_OBJECT(ads) );
2304                                         nodeDS = g_list_next( nodeDS );
2305                                 }
2306                                 gtk_ctree_expand( ctree, node );
2307                         }
2308                 }
2309                 nodeIf = g_list_next( nodeIf );
2310         }
2311 }
2312
2313 /*
2314  * Convert the old address book to new format.
2315  */
2316 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
2317         gboolean retVal = FALSE;
2318         gboolean errFlag = TRUE;
2319         gchar *msg = NULL;
2320
2321         // Read old address book, performing conversion
2322         debug_print( "Reading and converting old address book...\n" );
2323         addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
2324         addrindex_read_data( addrIndex );
2325         if( addrIndex->retVal == MGU_NO_FILE ) {
2326                 // We do not have a file - new user
2327                 debug_print( "New user... create new books...\n" );
2328                 addrindex_create_new_books( addrIndex );
2329                 if( addrIndex->retVal == MGU_SUCCESS ) {
2330                         // Save index file
2331                         addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2332                         addrindex_save_data( addrIndex );
2333                         if( addrIndex->retVal == MGU_SUCCESS ) {
2334                                 retVal = TRUE;
2335                                 errFlag = FALSE;
2336                         }
2337                         else {
2338                                 msg = g_strdup( _( "New user, could not save index file." ) );
2339                         }
2340                 }
2341                 else {
2342                         msg = g_strdup( _( "New user, could not save address book files." ) );
2343                 }
2344         }
2345         else {
2346                 // We have an old file
2347                 if( addrIndex->wasConverted ) {
2348                         // Converted successfully - save address index
2349                         addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2350                         addrindex_save_data( addrIndex );
2351                         if( addrIndex->retVal == MGU_SUCCESS ) {
2352                                 msg = g_strdup( _( "Old address book converted successfully." ) );
2353                                 retVal = TRUE;
2354                                 errFlag = FALSE;
2355                         }
2356                         else {
2357                                 msg = g_strdup( _(
2358                                         "Old address book converted, " \
2359                                         "could not save new address index file" ) );
2360                         }
2361                 }
2362                 else {
2363                         // File conversion failed - just create new books
2364                         debug_print( "File conversion failed... just create new books...\n" );
2365                         addrindex_create_new_books( addrIndex );
2366                         if( addrIndex->retVal == MGU_SUCCESS ) {
2367                                 // Save index
2368                                 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2369                                 addrindex_save_data( addrIndex );
2370                                 if( addrIndex->retVal == MGU_SUCCESS ) {
2371                                         msg = g_strdup( _(
2372                                                 "Could not convert address book, " \
2373                                                 "but created empty new address book files." ) );
2374                                         retVal = TRUE;
2375                                         errFlag = FALSE;
2376                                 }
2377                                 else {
2378                                         msg = g_strdup( _(
2379                                                 "Could not convert address book, " \
2380                                                 "could not create new address book files." ) );
2381                                 }
2382                         }
2383                         else {
2384                                 msg = g_strdup( _(
2385                                         "Could not convert address book " \
2386                                         "and could not create new address book files." ) );
2387                         }
2388                 }
2389         }
2390         if( errFlag ) {
2391                 debug_print( "Error\n%s\n", msg );
2392                 alertpanel( _( "Sylpheed Addressbook Conversion Error" ), msg, _( "Close" ), NULL, NULL );
2393         }
2394         else {
2395                 if( msg ) {
2396                         debug_print( "Warning\n%s\n", msg );
2397                         alertpanel( _( "Sylpheed Addressbook Conversion" ), msg, _( "Close" ), NULL, NULL );
2398                 }
2399         }
2400         if( msg ) g_free( msg );
2401         return retVal;
2402 }
2403
2404 void addressbook_read_file( void ) {
2405         AddressIndex *addrIndex = NULL;
2406
2407         debug_print( "Reading address index...\n" );
2408         if( _addressIndex_ ) {
2409                 debug_print( "address book already read!!!\n" );
2410                 return;
2411         }
2412
2413         addrIndex = addrindex_create_index();
2414
2415         // Use new address book index.
2416         addrindex_set_file_path( addrIndex, get_rc_dir() );
2417         addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2418         addrindex_read_data( addrIndex );
2419         if( addrIndex->retVal == MGU_NO_FILE ) {
2420                 // Conversion required
2421                 printf( "Converting...\n" );
2422                 if( addressbook_convert( addrIndex ) ) {
2423                         _addressIndex_ = addrIndex;
2424                 }
2425         }
2426         else if( addrIndex->retVal == MGU_SUCCESS ) {
2427                 _addressIndex_ = addrIndex;
2428         }
2429         else {
2430                 // Error reading address book
2431                 gchar *msg = NULL;
2432                 debug_print( "Could not read address index.\n" );
2433                 addrindex_print_index( addrIndex, stdout );
2434                 msg = g_strdup( _( "Could not read address index" ) );
2435                 alertpanel( _( "Sylpheed Addressbook Error" ), msg, _( "Close" ), NULL, NULL );
2436                 g_free( msg );
2437         }
2438         debug_print( "done.\n" );
2439 }
2440
2441 void addressbook_read_file_old( void ) {
2442         AddressIndex *addrIndex = NULL;
2443         gboolean errFlag = TRUE;
2444         gchar *msg = NULL;
2445
2446         if( _addressIndex_ ) {
2447                 debug_print( "address book already read!!!\n" );
2448                 return;
2449         }
2450
2451         addrIndex = addrindex_create_index();
2452
2453         // Use use new address book.
2454         // addrindex_set_file_path( addrIndex, "/home/match/tmp/empty-dir" );
2455         addrindex_set_file_path( addrIndex, get_rc_dir() );
2456         addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2457
2458         debug_print( "Reading address index...\n" );
2459         addrindex_read_data( addrIndex );
2460         if( addrIndex->retVal == MGU_NO_FILE ) {
2461                 // Read old address book, performing conversion
2462                 debug_print( "Reading and converting old address book...\n" );
2463                 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
2464                 addrindex_read_data( addrIndex );
2465                 if( addrIndex->retVal == MGU_NO_FILE ) {
2466                         // We do not have a file - new user
2467                         debug_print( "New user... create new books...\n" );
2468                         addrindex_create_new_books( addrIndex );
2469                         if( addrIndex->retVal == MGU_SUCCESS ) {
2470                                 // Save index file
2471                                 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2472                                 addrindex_save_data( addrIndex );
2473                                 if( addrIndex->retVal == MGU_SUCCESS ) {
2474                                         errFlag = FALSE;
2475                                 }
2476                                 else {
2477                                         msg = g_strdup( _( "New user, could not save index file." ) );
2478                                 }
2479                         }
2480                         else {
2481                                 msg = g_strdup( _( "New user, could not save address book files." ) );
2482                         }
2483                 }
2484                 else {
2485                         // We have an old file
2486                         if( addrIndex->wasConverted ) {
2487                                 // Converted successfully - save address index
2488                                 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2489                                 addrindex_save_data( addrIndex );
2490                                 if( addrIndex->retVal == MGU_SUCCESS ) {
2491                                         msg = g_strdup( _( "Old address book converted successfully." ) );
2492                                         errFlag = FALSE;
2493                                 }
2494                                 else {
2495                                         msg = g_strdup( _(
2496                                                 "Old address book converted, " \
2497                                                 "could not save new address index file" ) );
2498                                 }
2499                         }
2500                         else {
2501                                 // File conversion failed - just create new books
2502                                 debug_print( "File conversion failed... just create new books...\n" );
2503                                 addrindex_create_new_books( addrIndex );
2504                                 if( addrIndex->retVal == MGU_SUCCESS ) {
2505                                         // Save index
2506                                         addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2507                                         addrindex_save_data( addrIndex );
2508                                         if( addrIndex->retVal == MGU_SUCCESS ) {
2509                                                 msg = g_strdup( _(
2510                                                         "Could not convert address book, " \
2511                                                         "but created empty new address book files." ) );
2512                                                 errFlag = FALSE;
2513                                         }
2514                                         else {
2515                                                 msg = g_strdup( _(
2516                                                         "Could not convert address book, " \
2517                                                         "could not create new address book files." ) );
2518                                         }
2519                                 }
2520                                 else {
2521                                         msg = g_strdup( _(
2522                                                 "Could not convert address book " \
2523                                                 "and could not create new address book files." ) );
2524                                 }
2525                         }
2526                 }
2527         }
2528         else if( addrIndex->retVal == MGU_SUCCESS ) {
2529                 errFlag = FALSE;
2530         }
2531         else {
2532                 debug_print( "Could not read address index.\n" );
2533                 addrindex_print_index( addrIndex, stdout );
2534                 msg = g_strdup( _( "Could not read address index" ) );
2535         }
2536         _addressIndex_ = addrIndex;
2537
2538         if( errFlag ) {
2539                 debug_print( "Error\n%s\n", msg );
2540                 alertpanel( _( "Sylpheed Addressbook Conversion Error" ), msg, _( "Close" ), NULL, NULL );
2541         }
2542         else {
2543                 if( msg ) {
2544                         debug_print( "Warning\n%s\n", msg );
2545                         alertpanel( _( "Sylpheed Addressbook Conversion" ), msg, _( "Close" ), NULL, NULL );
2546                 }
2547         }
2548         if( msg ) g_free( msg );
2549         debug_print( "done.\n" );
2550 }
2551
2552 /*
2553 * Add object into the address index tree widget.
2554 * Enter: node   Parent node.
2555 *        obj    Object to add.
2556 * Return: Node that was added, or NULL if object not added.
2557 */
2558 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
2559                                             AddressObject *obj)
2560 {
2561         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2562         GtkCTreeNode *added;
2563         AddressObject *pobj;
2564         AddressObjectType otype;
2565         AddressTypeControlItem *atci = NULL;
2566
2567         g_return_val_if_fail(node != NULL, NULL);
2568         g_return_val_if_fail(obj  != NULL, NULL);
2569
2570         pobj = gtk_ctree_node_get_row_data(ctree, node);
2571         g_return_val_if_fail(pobj != NULL, NULL);
2572
2573         // Determine object type to be displayed
2574         if( obj->type == ADDR_DATASOURCE ) {
2575                 otype = ADAPTER_DSOURCE(obj)->subType;
2576         }
2577         else {
2578                 otype = obj->type;
2579         }
2580
2581         // Handle any special conditions.
2582         added = node;
2583         atci = addrbookctl_lookup( otype );
2584         if( atci ) {
2585                 if( atci->showInTree ) {
2586                         // Add object to tree
2587                         gchar **name;
2588                         name = &obj->name;
2589                         added = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
2590                                 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
2591                                 atci->treeLeaf, atci->treeExpand );
2592                         gtk_ctree_node_set_row_data(ctree, added, obj);
2593                 }
2594         }
2595
2596         gtk_ctree_sort_node(ctree, node);
2597
2598         return added;
2599 }
2600
2601 /*
2602 * Add group into the address index tree.
2603 * Enter: node      Parent node.
2604 *        ds        Data source.
2605 *        itemGroup Group to add.
2606 * Return: Inserted node.
2607 */
2608 static GtkCTreeNode *addressbook_node_add_group( GtkCTreeNode *node, AddressDataSource *ds, ItemGroup *itemGroup ) {
2609         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2610         GtkCTreeNode *newNode;
2611         AdapterGroup *adapter;
2612         AddressTypeControlItem *atci = NULL;
2613         gchar **name;
2614
2615         if( ds == NULL ) return;
2616         if( node == NULL || itemGroup == NULL ) return;
2617
2618         name = &itemGroup->obj.name;
2619
2620         atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
2621
2622         adapter = g_new0( AdapterGroup, 1 );
2623         ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
2624         ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
2625         adapter->itemGroup = itemGroup;
2626
2627         newNode = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
2628                         atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
2629                         atci->treeLeaf, atci->treeExpand );
2630         gtk_ctree_node_set_row_data( ctree, newNode, adapter );
2631         gtk_ctree_sort_node( ctree, node );
2632         return newNode;
2633 }
2634
2635 /*
2636 * Add folder into the address index tree.
2637 * Enter: node       Parent node.
2638 *        ds         Data source.
2639 *        itemFolder Folder to add.
2640 *        otype      Object type to display.
2641 * Return: Inserted node.
2642 */
2643 static GtkCTreeNode *addressbook_node_add_folder(
2644                 GtkCTreeNode *node, AddressDataSource *ds, ItemFolder *itemFolder, AddressObjectType otype )
2645 {
2646         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2647         GtkCTreeNode *newNode = NULL;
2648         AdapterFolder *adapter;
2649         AddressTypeControlItem *atci = NULL;
2650         GList *listItems = NULL;
2651         gchar **name;
2652         ItemFolder *rootFolder;
2653
2654         if( ds == NULL ) return NULL;
2655         if( node == NULL || itemFolder == NULL ) return NULL;
2656
2657         // Determine object type
2658         atci = addrbookctl_lookup( otype );
2659         if( atci == NULL ) return NULL;
2660
2661         rootFolder = addrindex_ds_get_root_folder( ds );
2662         if( itemFolder == rootFolder ) {
2663                 newNode = node;
2664         }
2665         else {
2666                 name = &itemFolder->obj.name;
2667
2668                 adapter = g_new0( AdapterFolder, 1 );
2669                 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
2670                 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
2671                 adapter->itemFolder = itemFolder;
2672
2673                 newNode = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
2674                                 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
2675                                 atci->treeLeaf, atci->treeExpand );
2676                 gtk_ctree_node_set_row_data( ctree, newNode, adapter );
2677         }
2678
2679         listItems = itemFolder->listFolder;
2680         while( listItems ) {
2681                 ItemFolder *item = listItems->data;
2682                 addressbook_node_add_folder( newNode, ds, item, otype );
2683                 listItems = g_list_next( listItems );
2684         }
2685         listItems = itemFolder->listGroup;
2686         while( listItems ) {
2687                 ItemGroup *item = listItems->data;
2688                 addressbook_node_add_group( newNode, ds, item );
2689                 listItems = g_list_next( listItems );
2690         }
2691         gtk_ctree_sort_node( ctree, node );
2692         return newNode;
2693 }
2694
2695 static void addressbook_delete_object(AddressObject *obj) {
2696         AdapterDSource *ads = NULL;
2697         AddressDataSource *ds = NULL;
2698         if (!obj) return;
2699
2700         // Remove data source.
2701         printf( "Delete obj type : %d\n", obj->type );
2702
2703         ads = ADAPTER_DSOURCE(obj);
2704         if( ads == NULL ) return;
2705         ds = ads->dataSource;
2706         if( ds == NULL ) return;
2707
2708         // Remove data source
2709         if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2710                 addrindex_free_datasource( _addressIndex_, ds );
2711         }
2712         // Free up Adapter object
2713         g_free( ADAPTER_DSOURCE(obj) );
2714 }
2715
2716 void addressbook_export_to_file( void ) {
2717         if( _addressIndex_ ) {
2718                 // Save all new address book data
2719                 debug_print( "Saving address books...\n" );
2720                 addrindex_save_all_books( _addressIndex_ );
2721
2722                 debug_print( "Exporting addressbook to file...\n" );
2723                 addrindex_save_data( _addressIndex_ );
2724                 if( _addressIndex_->retVal != MGU_SUCCESS ) {
2725                         addrindex_print_index( _addressIndex_, stdout );
2726                 }
2727
2728                 // Notify address completion of new data
2729                 invalidate_address_completion();
2730         }
2731 }
2732
2733 static void key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
2734 {
2735         if (event && event->keyval == GDK_Escape)
2736                 addressbook_close();
2737 }
2738
2739 /*
2740 * Comparsion using names of AddressItem objects.
2741 */
2742 /*
2743 static gint addressbook_list_compare_func(GtkCList *clist,
2744                                           gconstpointer ptr1,
2745                                           gconstpointer ptr2)
2746 {
2747         AddressObject *obj1 = ((GtkCListRow *)ptr1)->data;
2748         AddressObject *obj2 = ((GtkCListRow *)ptr2)->data;
2749         gchar *name1 = NULL, *name2 = NULL;
2750         if( obj1 ) name1 = obj1->name;
2751         if( obj2 ) name2 = obj2->name;
2752         if( ! name1 ) return ( name2 != NULL );
2753         if( ! name2 ) return -1;
2754         return strcasecmp(name1, name2);
2755 }
2756 */
2757
2758 /*
2759 * Comparison using cell contents (text in first column).
2760 */
2761 static gint addressbook_list_compare_func( GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 ) {
2762         GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
2763         GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
2764         gchar *name1 = NULL, *name2 = NULL;
2765         if( cell1 ) name1 = cell1->u.text;
2766         if( cell2 ) name2 = cell2->u.text;
2767         if( ! name1 ) return ( name2 != NULL );
2768         if( ! name2 ) return -1;
2769         return strcasecmp( name1, name2 );
2770 }
2771
2772 /* static */ 
2773 gint addressbook_obj_name_compare(gconstpointer a, gconstpointer b)
2774 {
2775         const AddressObject *obj = a;
2776         const gchar *name = b;
2777         AddressTypeControlItem *atci = NULL;
2778
2779         if (!obj || !name) return -1;
2780
2781         atci = addrbookctl_lookup( obj->type );
2782         if( ! atci ) return -1;
2783         if( ! obj->name ) return -1;
2784         return strcasecmp(obj->name, name);
2785 }
2786
2787 static void addressbook_book_show_message( AddressBookFile *abf ) {
2788         *addressbook_msgbuf = '\0';
2789         if( abf ) {
2790                 if( abf->retVal == MGU_SUCCESS ) {
2791                         sprintf( addressbook_msgbuf, "%s", abf->name );
2792                 }
2793                 else {
2794                         sprintf( addressbook_msgbuf, "%s: %s", abf->name, mgu_error2string( abf->retVal ) );
2795                 }
2796         }
2797         addressbook_status_show( addressbook_msgbuf );
2798 }
2799
2800 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
2801         AdapterDSource *ads;
2802         AdapterInterface *adapter;
2803
2804         adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
2805         if( adapter == NULL ) return;
2806         if( addrbook.treeSelected == NULL ) return;
2807         if( addrbook.treeSelected != adapter->treeNode ) return;
2808         ads = addressbook_edit_book( _addressIndex_, NULL );
2809         if( ads ) {
2810                 addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
2811                 if( addrbook.treeSelected == addrbook.opened ) {
2812                         gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
2813                 }
2814         }
2815 }
2816
2817 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
2818         AdapterDSource *ads;
2819         AdapterInterface *adapter;
2820
2821         adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
2822         if( adapter == NULL ) return;
2823         if( addrbook.treeSelected != adapter->treeNode ) return;
2824         ads = addressbook_edit_vcard( _addressIndex_, NULL );
2825         if( ads ) {
2826                 addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
2827                 if( addrbook.treeSelected == addrbook.opened ) {
2828                         gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
2829                 }
2830         }
2831 }
2832
2833 static void addressbook_vcard_show_message( VCardFile *vcf ) {
2834         *addressbook_msgbuf = '\0';
2835         if( vcf ) {
2836                 if( vcf->retVal == MGU_SUCCESS ) {
2837                         sprintf( addressbook_msgbuf, "%s", vcf->name );
2838                 }
2839                 else {
2840                         sprintf( addressbook_msgbuf, "%s: %s", vcf->name, mgu_error2string( vcf->retVal ) );
2841                 }
2842         }
2843         addressbook_status_show( addressbook_msgbuf );
2844 }
2845
2846 #ifdef USE_JPILOT
2847 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
2848         AdapterDSource *ads;
2849         AdapterInterface *adapter;
2850         AddressInterface *iface;
2851
2852         adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
2853         if( adapter == NULL ) return;
2854         if( addrbook.treeSelected != adapter->treeNode ) return;
2855         iface = adapter->interface;
2856         if( ! iface->haveLibrary ) return;
2857         ads = addressbook_edit_jpilot( _addressIndex_, NULL );
2858         if( ads ) {
2859                 addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
2860                 if( addrbook.treeSelected == addrbook.opened ) {
2861                         gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
2862                 }
2863         }
2864 }
2865
2866 static void addressbook_jpilot_show_message( JPilotFile *jpf ) {
2867         *addressbook_msgbuf = '\0';
2868         if( jpf ) {
2869                 if( jpf->retVal == MGU_SUCCESS ) {
2870                         sprintf( addressbook_msgbuf, "%s", jpf->name );
2871                 }
2872                 else {
2873                         sprintf( addressbook_msgbuf, "%s: %s", jpf->name, mgu_error2string( jpf->retVal ) );
2874                 }
2875         }
2876         addressbook_status_show( addressbook_msgbuf );
2877 }
2878
2879 #endif
2880
2881 #ifdef USE_LDAP
2882 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
2883         AdapterDSource *ads;
2884         AdapterInterface *adapter;
2885         AddressInterface *iface;
2886
2887         adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
2888         if( adapter == NULL ) return;
2889         if( addrbook.treeSelected != adapter->treeNode ) return;
2890         iface = adapter->interface;
2891         if( ! iface->haveLibrary ) return;
2892         ads = addressbook_edit_ldap( _addressIndex_, NULL );
2893         if( ads ) {
2894                 addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
2895                 if( addrbook.treeSelected == addrbook.opened ) {
2896                         gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
2897                 }
2898         }
2899 }
2900
2901 static void addressbook_ldap_show_message( SyldapServer *svr ) {
2902         *addressbook_msgbuf = '\0';
2903         if( svr ) {
2904                 if( svr->busyFlag ) {
2905                         sprintf( addressbook_msgbuf, "%s: %s", svr->name, ADDRESSBOOK_LDAP_BUSYMSG );
2906                 }
2907                 else {
2908                         if( svr->retVal == MGU_SUCCESS ) {
2909                                 sprintf( addressbook_msgbuf, "%s", svr->name );
2910                         }
2911                         else {
2912                                 sprintf( addressbook_msgbuf, "%s: %s", svr->name, mgu_error2string( svr->retVal ) );
2913                         }
2914                 }
2915         }
2916         addressbook_status_show( addressbook_msgbuf );
2917 }
2918
2919 static void ldapsearch_callback( SyldapServer *sls ) {
2920         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2921         AddressObject *obj;
2922         AdapterDSource *ads = NULL;
2923         AddressDataSource *ds = NULL;
2924         AddressInterface *iface = NULL;
2925
2926         if( sls == NULL ) return;
2927         if( ! addrbook.treeSelected ) return;
2928         if( GTK_CTREE_ROW( addrbook.treeSelected )->level == 1 ) return;
2929
2930         obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2931         if( obj == NULL ) return;
2932         if( obj->type == ADDR_DATASOURCE ) {
2933                 ads = ADAPTER_DSOURCE(obj);
2934                 if( ads->subType == ADDR_LDAP ) {
2935                         SyldapServer *server;
2936
2937                         ds = ads->dataSource;
2938                         if( ds == NULL ) return;
2939                         iface = ds->interface;
2940                         if( ! iface->haveLibrary ) return;
2941                         server = ds->rawDataSource;
2942                         if( server == sls ) {
2943                                 // Read from cache
2944                                 gtk_widget_show_all(addrbook.window);
2945                                 addressbook_set_clist( obj );
2946                                 addressbook_ldap_show_message( sls );
2947                                 gtk_widget_show_all(addrbook.window);
2948                                 gtk_entry_set_text( GTK_ENTRY(addrbook.entry), "" );
2949                         }
2950                 }
2951         }
2952 }
2953 #endif
2954
2955 /*
2956  * Lookup button handler.
2957  */
2958 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
2959         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2960         AddressObject *obj;
2961         AdapterDSource *ads = NULL;
2962         AddressDataSource *ds = NULL;
2963         AddressInterface *iface = NULL;
2964         gchar *sLookup;
2965
2966         sLookup = gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
2967         g_strchomp( sLookup );
2968
2969         if( ! addrbook.treeSelected ) return;
2970         if( GTK_CTREE_ROW( addrbook.treeSelected )->level == 1 ) return;
2971
2972         obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2973         if( obj == NULL ) return;
2974
2975 #ifdef USE_LDAP
2976         if( obj->type == ADDR_DATASOURCE ) {
2977                 ads = ADAPTER_DSOURCE(obj);
2978                 if( ads->subType == ADDR_LDAP ) {
2979                         SyldapServer *server;
2980
2981                         ds = ads->dataSource;
2982                         if( ds == NULL ) return;
2983                         iface = ds->interface;
2984                         if( ! iface->haveLibrary ) return;
2985                         server = ds->rawDataSource;
2986                         if( server ) {
2987                                 syldap_cancel_read( server );
2988                                 if( *sLookup == '\0' || strlen( sLookup ) < 1 ) return;
2989                                 syldap_set_search_value( server, sLookup );
2990                                 syldap_set_callback( server, ldapsearch_callback );
2991                                 syldap_read_data_th( server );
2992                                 addressbook_ldap_show_message( server );
2993                         }
2994                 }
2995         }
2996 #endif
2997
2998 }
2999
3000 /* **********************************************************************
3001 * Build lookup tables.
3002 * ***********************************************************************
3003 */
3004
3005 /*
3006 * Build table that controls the rendering of object types.
3007 */
3008 void addrbookctl_build_map( GtkWidget *window ) {
3009         AddressTypeControlItem *atci;
3010
3011         // Build icons
3012         PIXMAP_CREATE(window, folderxpm, folderxpmmask, DIRECTORY_CLOSE_XPM);
3013         PIXMAP_CREATE(window, folderopenxpm, folderopenxpmmask, DIRECTORY_OPEN_XPM);
3014         PIXMAP_CREATE(window, groupxpm, groupxpmmask, group_xpm);
3015         PIXMAP_CREATE(window, vcardxpm, vcardxpmmask, vcard_xpm);
3016         PIXMAP_CREATE(window, bookxpm, bookxpmmask, book_xpm);
3017         PIXMAP_CREATE(window, addressxpm, addressxpmmask, address_xpm);
3018         PIXMAP_CREATE(window, jpilotxpm, jpilotxpmmask, jpilot_xpm);
3019         PIXMAP_CREATE(window, categoryxpm, categoryxpmmask, category_xpm);
3020         PIXMAP_CREATE(window, ldapxpm, ldapxpmmask, ldap_xpm);
3021
3022         _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
3023         _addressBookTypeList_ = NULL;
3024
3025         // Interface
3026         atci = g_new0( AddressTypeControlItem, 1 );
3027         atci->objectType = ADDR_INTERFACE;
3028         atci->interfaceType = ADDR_IF_NONE;
3029         atci->showInTree = TRUE;
3030         atci->treeExpand = TRUE;
3031         atci->treeLeaf = FALSE;
3032         atci->displayName = _( "Interface" );
3033         atci->iconXpm = folderxpm;
3034         atci->maskXpm = folderxpmmask;
3035         atci->iconXpmOpen = folderopenxpm;
3036         atci->maskXpmOpen = folderopenxpmmask;
3037         atci->menuCommand = NULL;
3038         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3039         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3040
3041         // Address book
3042         atci = g_new0( AddressTypeControlItem, 1 );
3043         atci->objectType = ADDR_BOOK;
3044         atci->interfaceType = ADDR_IF_BOOK;
3045         atci->showInTree = TRUE;
3046         atci->treeExpand = TRUE;
3047         atci->treeLeaf = FALSE;
3048         atci->displayName = _( "Address Book" );
3049         atci->iconXpm = bookxpm;
3050         atci->maskXpm = bookxpmmask;
3051         atci->iconXpmOpen = bookxpm;
3052         atci->maskXpmOpen = bookxpmmask;
3053         atci->menuCommand = "/File/New Book";
3054         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3055         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3056
3057         // Item person
3058         atci = g_new0( AddressTypeControlItem, 1 );
3059         atci->objectType = ADDR_ITEM_PERSON;
3060         atci->interfaceType = ADDR_IF_NONE;
3061         atci->showInTree = FALSE;
3062         atci->treeExpand = FALSE;
3063         atci->treeLeaf = FALSE;
3064         atci->displayName = _( "Person" );
3065         atci->iconXpm = NULL;
3066         atci->maskXpm = NULL;
3067         atci->iconXpmOpen = NULL;
3068         atci->maskXpmOpen = NULL;
3069         atci->menuCommand = NULL;
3070         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3071         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3072
3073         // Item email
3074         atci = g_new0( AddressTypeControlItem, 1 );
3075         atci->objectType = ADDR_ITEM_EMAIL;
3076         atci->interfaceType = ADDR_IF_NONE;
3077         atci->showInTree = FALSE;
3078         atci->treeExpand = FALSE;
3079         atci->treeLeaf = TRUE;
3080         atci->displayName = _( "EMail Address" );
3081         atci->iconXpm = addressxpm;
3082         atci->maskXpm = addressxpmmask;
3083         atci->iconXpmOpen = addressxpm;
3084         atci->maskXpmOpen = addressxpmmask;
3085         atci->menuCommand = NULL;
3086         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3087         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3088
3089         // Item group
3090         atci = g_new0( AddressTypeControlItem, 1 );
3091         atci->objectType = ADDR_ITEM_GROUP;
3092         atci->interfaceType = ADDR_IF_BOOK;
3093         atci->showInTree = TRUE;
3094         atci->treeExpand = FALSE;
3095         atci->treeLeaf = FALSE;
3096         atci->displayName = _( "Group" );
3097         atci->iconXpm = groupxpm;
3098         atci->maskXpm = groupxpmmask;
3099         atci->iconXpmOpen = groupxpm;
3100         atci->maskXpmOpen = groupxpmmask;
3101         atci->menuCommand = NULL;
3102         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3103         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3104
3105         // Item folder
3106         atci = g_new0( AddressTypeControlItem, 1 );
3107         atci->objectType = ADDR_ITEM_FOLDER;
3108         atci->interfaceType = ADDR_IF_BOOK;
3109         atci->showInTree = TRUE;
3110         atci->treeExpand = FALSE;
3111         atci->treeLeaf = FALSE;
3112         atci->displayName = _( "Folder" );
3113         atci->iconXpm = folderxpm;
3114         atci->maskXpm = folderxpmmask;
3115         atci->iconXpmOpen = folderopenxpm;
3116         atci->maskXpmOpen = folderopenxpmmask;
3117         atci->menuCommand = NULL;
3118         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3119         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3120
3121         // V-Card
3122         atci = g_new0( AddressTypeControlItem, 1 );
3123         atci->objectType = ADDR_VCARD;
3124         atci->interfaceType = ADDR_IF_VCARD;
3125         atci->showInTree = TRUE;
3126         atci->treeExpand = TRUE;
3127         atci->treeLeaf = TRUE;
3128         atci->displayName = _( "V-Card" );
3129         atci->iconXpm = vcardxpm;
3130         atci->maskXpm = vcardxpmmask;
3131         atci->iconXpmOpen = vcardxpm;
3132         atci->maskXpmOpen = vcardxpmmask;
3133         atci->menuCommand = "/File/New V-Card";
3134         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3135         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3136
3137         // J-Pilot
3138         atci = g_new0( AddressTypeControlItem, 1 );
3139         atci->objectType = ADDR_JPILOT;
3140         atci->interfaceType = ADDR_IF_JPILOT;
3141         atci->showInTree = TRUE;
3142         atci->treeExpand = TRUE;
3143         atci->treeLeaf = FALSE;
3144         atci->displayName = _( "J-Pilot" );
3145         atci->iconXpm = jpilotxpm;
3146         atci->maskXpm = jpilotxpmmask;
3147         atci->iconXpmOpen = jpilotxpm;
3148         atci->maskXpmOpen = jpilotxpmmask;
3149         atci->menuCommand = "/File/New J-Pilot";
3150         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3151         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3152
3153         // Category
3154         atci = g_new0( AddressTypeControlItem, 1 );
3155         atci->objectType = ADDR_CATEGORY;
3156         atci->interfaceType = ADDR_IF_JPILOT;
3157         atci->showInTree = TRUE;
3158         atci->treeExpand = TRUE;
3159         atci->treeLeaf = TRUE;
3160         atci->displayName = _( "J-Pilot" );
3161         atci->iconXpm = categoryxpm;
3162         atci->maskXpm = categoryxpmmask;
3163         atci->iconXpmOpen = categoryxpm;
3164         atci->maskXpmOpen = categoryxpmmask;
3165         atci->menuCommand = NULL;
3166         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3167         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3168
3169         // LDAP Server
3170         atci = g_new0( AddressTypeControlItem, 1 );
3171         atci->objectType = ADDR_LDAP;
3172         atci->interfaceType = ADDR_IF_LDAP;
3173         atci->showInTree = TRUE;
3174         atci->treeExpand = TRUE;
3175         atci->treeLeaf = TRUE;
3176         atci->displayName = _( "LDAP Server" );
3177         atci->iconXpm = ldapxpm;
3178         atci->maskXpm = ldapxpmmask;
3179         atci->iconXpmOpen = ldapxpm;
3180         atci->maskXpmOpen = ldapxpmmask;
3181         atci->menuCommand = "/File/New Server";
3182         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3183         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3184
3185 }
3186
3187 /*
3188 * Search for specified object type.
3189 */
3190 AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
3191         gint objType = ot;
3192         return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
3193 }
3194
3195 /*
3196 * Search for specified interface type.
3197 */
3198 AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
3199         GList *node = _addressBookTypeList_;
3200         while( node ) {
3201                 AddressTypeControlItem *atci = node->data;
3202                 if( atci->interfaceType == ifType ) return atci;
3203                 node = g_list_next( node );
3204         }
3205         return NULL;
3206 }
3207
3208 static void addrbookctl_free_address( AddressObject *obj ) {
3209         g_free( obj->name );
3210         obj->type = ADDR_NONE;
3211         obj->name = NULL;
3212 }
3213
3214 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
3215         addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
3216         adapter->interface = NULL;
3217         adapter->interfaceType = ADDR_IF_NONE;
3218         adapter->atci = NULL;
3219         adapter->enabled = FALSE;
3220         adapter->haveLibrary = FALSE;
3221         adapter->treeNode = NULL;
3222         g_free( adapter );
3223 }
3224
3225 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
3226         addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
3227         adapter->dataSource = NULL;
3228         adapter->subType = ADDR_NONE;
3229         g_free( adapter );
3230 }
3231
3232 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
3233         addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
3234         adapter->itemFolder = NULL;
3235         g_free( adapter );
3236 }
3237
3238 static void addrbookctl_free_group( AdapterGroup *adapter ) {
3239         addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
3240         adapter->itemGroup = NULL;
3241         g_free( adapter );
3242 }
3243
3244 /*
3245  * Build GUI interface list.
3246  */
3247 void addrbookctl_build_iflist() {
3248         AddressTypeControlItem *atci;
3249         AdapterInterface *adapter;
3250         GList *list = NULL;
3251
3252         if( _addressIndex_ == NULL ) {
3253                 _addressIndex_ = addrindex_create_index();
3254         }
3255         _addressInterfaceList_ = NULL;
3256         list = addrindex_get_interface_list( _addressIndex_ );
3257         while( list ) {
3258                 AddressInterface *interface = list->data;
3259                 atci = addrbookctl_lookup_iface( interface->type );
3260                 if( atci ) {
3261                         adapter = g_new0( AdapterInterface, 1 );
3262                         adapter->interfaceType = interface->type;
3263                         adapter->atci = atci;
3264                         adapter->interface = interface;
3265                         adapter->treeNode = NULL;
3266                         adapter->enabled = TRUE;
3267                         adapter->haveLibrary = interface->haveLibrary;
3268                         ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
3269                         ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
3270                         _addressInterfaceList_ = g_list_append( _addressInterfaceList_, adapter );
3271                 }
3272                 list = g_list_next( list );
3273         }
3274 }
3275
3276 void addrbookctl_free_selection( GList *list ) {
3277         GList *node = list;
3278         while( node ) {
3279                 AdapterInterface *adapter = node->data;
3280                 adapter = NULL;
3281                 node = g_list_next( node );
3282         }
3283         g_list_free( list );
3284 }
3285
3286 /*
3287 * Find GUI interface type specified interface type.
3288 * Return: Interface item, or NULL if not found.
3289 */
3290 AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
3291         GList *node = _addressInterfaceList_;
3292         while( node ) {
3293                 AdapterInterface *adapter = node->data;
3294                 if( adapter->interfaceType == ifType ) return adapter;
3295                 node = g_list_next( node );
3296         }
3297         return NULL;
3298 }
3299
3300 /*
3301 * Build interface list selection.
3302 */
3303 void addrbookctl_build_ifselect() {
3304         GList *newList = NULL;
3305         gchar *selectStr;
3306         gchar **splitStr;
3307         gint ifType;
3308         gint i;
3309         gchar *endptr = NULL;
3310         gboolean enabled;
3311         AdapterInterface *adapter;
3312         GList *node;
3313
3314         selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
3315
3316         // Parse string
3317         splitStr = g_strsplit( selectStr, ",", -1 );
3318         for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
3319                 if( splitStr[i] ) {
3320                         // printf( "%d : %s\n", i, splitStr[i] );
3321                         ifType = strtol( splitStr[i], &endptr, 10 );
3322                         enabled = TRUE;
3323                         if( *endptr ) {
3324                                 if( strcmp( endptr, "/n" ) == 0 ) {
3325                                         enabled = FALSE;
3326                                 }
3327                         }
3328                         // printf( "\t%d : %s\n", ifType, enabled ? "yes" : "no" );
3329                         adapter = addrbookctl_find_interface( ifType );
3330                         if( adapter ) {
3331                                 newList = g_list_append( newList, adapter );
3332                         }
3333                 }
3334                 else {
3335                         break;
3336                 }
3337         }
3338         // printf( "i=%d\n", i );
3339         g_strfreev( splitStr );
3340         g_free( selectStr );
3341
3342         // Replace existing list
3343         mgu_clear_list( _addressIFaceSelection_ );
3344         g_list_free( _addressIFaceSelection_ );
3345         _addressIFaceSelection_ = newList;
3346         newList = NULL;
3347
3348 }
3349
3350 /* **********************************************************************
3351 * Add sender to address book.
3352 * ***********************************************************************
3353 */
3354
3355 /*
3356  * This function is used by the Add sender to address book function.
3357  */
3358 gboolean addressbook_add_contact( const gchar *name, const gchar *address, const gchar *remarks ) {
3359         debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
3360         if( addressadd_selection( _addressIndex_, name, address, remarks ) ) {
3361                 debug_print( "addressbook_add_contact - added\n" );
3362                 addressbook_refresh();
3363         }
3364         return TRUE;
3365 }
3366
3367 /* **********************************************************************
3368 * Address completion support.
3369 * ***********************************************************************
3370 */
3371
3372 /*
3373 * This function is used by the address completion function to load
3374 * addresses.
3375 * Enter: callBackFunc Function to be called when an address is
3376 *                     to be loaded.
3377 * Return: TRUE if data loaded, FALSE if address index not loaded.
3378 */
3379 gboolean addressbook_load_completion( gint (*callBackFunc) ( const gchar *, const gchar * ) ) {
3380         AddressInterface *interface;
3381         AddressDataSource *ds;
3382         GList *nodeIf, *nodeDS;
3383         GList *listP, *nodeP;
3384         GList *nodeM;
3385         gchar *sName, *sAddress, *sAlias, *sFriendly;
3386
3387         debug_print( "addressbook_load_completion\n" );
3388
3389         if( _addressIndex_ == NULL ) return FALSE;
3390
3391         nodeIf = addrindex_get_interface_list( _addressIndex_ );
3392         while( nodeIf ) {
3393                 AddressInterface *interface = nodeIf->data;
3394                 nodeDS = interface->listSource;
3395                 while( nodeDS ) {
3396                         ds = nodeDS->data;
3397
3398                         // Read address book
3399                         if( ! addrindex_ds_get_read_flag( ds ) ) {
3400                                 addrindex_ds_read_data( ds );
3401                         }
3402
3403                         // Get all persons
3404                         listP = addrindex_ds_get_all_persons( ds );
3405                         nodeP = listP;
3406                         while( nodeP ) {
3407                                 ItemPerson *person = nodeP->data;
3408                                 nodeM = person->listEMail;
3409
3410                                 // Figure out name to use
3411                                 sName = person->nickName;
3412                                 if( sName == NULL || *sName == '\0' ) {
3413                                         sName = ADDRITEM_NAME(person);
3414                                 }
3415
3416                                 // Process each E-Mail address
3417                                 while( nodeM ) {
3418                                         ItemEMail *email = nodeM->data;
3419                                         // Have mail
3420                                         sFriendly = sName;
3421                                         sAddress = email->address;
3422                                         if( sAddress || *sAddress != '\0' ) {
3423                                                 sAlias = ADDRITEM_NAME(email);
3424                                                 if( sAlias && *sAlias != '\0' ) {
3425                                                         sFriendly = sAlias;
3426                                                 }
3427                                                 ( callBackFunc ) ( sFriendly, sAddress );
3428                                         }
3429
3430                                         nodeM = g_list_next( nodeM );
3431                                 }
3432                                 nodeP = g_list_next( nodeP );
3433                         }
3434                         // Free up the list
3435                         g_list_free( listP );
3436
3437                         nodeDS = g_list_next( nodeDS );
3438                 }
3439                 nodeIf = g_list_next( nodeIf );
3440         }
3441         debug_print( "addressbook_load_completion... done\n" );
3442
3443         return TRUE;
3444 }
3445
3446 /*
3447 * End of Source.
3448 */
3449