sync with sylpheed 0.6.1cvs2
[claws.git] / src / addressbook.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2001 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 "addressadd.h"
71 #include "vcard.h"
72 #include "editvcard.h"
73 #include "editgroup.h"
74 #include "editaddress.h"
75 #include "editbook.h"
76
77 #ifdef USE_JPILOT
78 #include "jpilot.h"
79 #include "editjpilot.h"
80 #endif
81
82 #ifdef USE_LDAP
83 #include <pthread.h>
84 #include "syldap.h"
85 #include "editldap.h"
86
87 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
88 #endif
89
90 #include "pixmaps/dir-close.xpm"
91 #include "pixmaps/dir-open.xpm"
92 #include "pixmaps/group.xpm"
93 #include "pixmaps/interface.xpm"
94 #include "pixmaps/book.xpm"
95 #include "pixmaps/address.xpm"
96 #include "pixmaps/vcard.xpm"
97 #include "pixmaps/jpilot.xpm"
98 #include "pixmaps/category.xpm"
99 #include "pixmaps/ldap.xpm"
100
101 typedef enum
102 {
103         COL_NAME        = 0,
104         COL_ADDRESS     = 1,
105         COL_REMARKS     = 2
106 } AddressBookColumnPos;
107
108 #define N_COLS  3
109 #define COL_NAME_WIDTH          164
110 #define COL_ADDRESS_WIDTH       156
111
112 #define COL_FOLDER_WIDTH        170
113 #define ADDRESSBOOK_WIDTH       640
114 #define ADDRESSBOOK_HEIGHT      360
115
116 #define ADDRESSBOOK_MSGBUF_SIZE 2048
117
118 static GdkPixmap *folderxpm;
119 static GdkBitmap *folderxpmmask;
120 static GdkPixmap *folderopenxpm;
121 static GdkBitmap *folderopenxpmmask;
122 static GdkPixmap *groupxpm;
123 static GdkBitmap *groupxpmmask;
124 static GdkPixmap *interfacexpm;
125 static GdkBitmap *interfacexpmmask;
126 static GdkPixmap *bookxpm;
127 static GdkBitmap *bookxpmmask;
128 static GdkPixmap *addressxpm;
129 static GdkBitmap *addressxpmmask;
130 static GdkPixmap *vcardxpm;
131 static GdkBitmap *vcardxpmmask;
132 static GdkPixmap *jpilotxpm;
133 static GdkBitmap *jpilotxpmmask;
134 static GdkPixmap *categoryxpm;
135 static GdkBitmap *categoryxpmmask;
136 static GdkPixmap *ldapxpm;
137 static GdkBitmap *ldapxpmmask;
138
139 /* Message buffer  */
140 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
141
142 /* Address list selection  */
143 static GList *_addressListSelection_ = NULL;
144
145 /* Address index file and interfaces */
146 static AddressIndex *_addressIndex_ = NULL;
147 static GList *_addressInterfaceList_ = NULL;
148 static GList *_addressIFaceSelection_ = NULL;
149 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
150
151 static AddressBook_win addrbook;
152
153 static GHashTable *_addressBookTypeHash_ = NULL;
154 static GList *_addressBookTypeList_ = NULL;
155
156 static void addressbook_create                  ( void );
157 static gint addressbook_close                   (void);
158 static void addressbook_button_set_sensitive    (void);
159
160 /* callback functions */
161 static void addressbook_del_clicked             (GtkButton      *button,
162                                                  gpointer        data);
163 static void addressbook_reg_clicked             (GtkButton      *button,
164                                                  gpointer        data);
165 static void addressbook_to_clicked              (GtkButton      *button,
166                                                  gpointer        data);
167 static void addressbook_lup_clicked             (GtkButton      *button,
168                                                  gpointer       data);
169
170 static void addressbook_tree_selected           (GtkCTree       *ctree,
171                                                  GtkCTreeNode   *node,
172                                                  gint            column,
173                                                  gpointer        data);
174 static void addressbook_list_selected           (GtkCList       *clist,
175                                                  gint            row,
176                                                  gint            column,
177                                                  GdkEvent       *event,
178                                                  gpointer        data);
179 static void addressbook_list_row_selected       (GtkCTree       *clist,
180                                                  GtkCTreeNode   *node,
181                                                  gint            column,
182                                                  gpointer        data);
183 static void addressbook_list_row_unselected     (GtkCTree       *clist,
184                                                  GtkCTreeNode   *node,
185                                                  gint            column,
186                                                  gpointer        data);
187 static void addressbook_person_expand_node      (GtkCTree       *ctree,
188                                                  GList          *node,
189                                                  gpointer       *data );
190 static void addressbook_person_collapse_node    (GtkCTree       *ctree,
191                                                  GList          *node,
192                                                  gpointer       *data );
193 static void addressbook_entry_gotfocus          (GtkWidget      *widget);
194
195 #if 0
196 static void addressbook_entry_changed           (GtkWidget      *widget);
197 #endif
198
199 static void addressbook_list_button_pressed     (GtkWidget      *widget,
200                                                  GdkEventButton *event,
201                                                  gpointer        data);
202 static void addressbook_list_button_released    (GtkWidget      *widget,
203                                                  GdkEventButton *event,
204                                                  gpointer        data);
205 static void addressbook_tree_button_pressed     (GtkWidget      *ctree,
206                                                  GdkEventButton *event,
207                                                  gpointer        data);
208 static void addressbook_tree_button_released    (GtkWidget      *ctree,
209                                                  GdkEventButton *event,
210                                                  gpointer        data);
211 static void addressbook_popup_close             (GtkMenuShell   *menu_shell,
212                                                  gpointer        data);
213
214 static void addressbook_new_folder_cb           (gpointer        data,
215                                                  guint           action,
216                                                  GtkWidget      *widget);
217 static void addressbook_new_group_cb            (gpointer        data,
218                                                  guint           action,
219                                                  GtkWidget      *widget);
220 static void addressbook_treenode_edit_cb        (gpointer        data,
221                                                  guint           action,
222                                                  GtkWidget      *widget);
223 static void addressbook_treenode_delete_cb      (gpointer        data,
224                                                  guint           action,
225                                                  GtkWidget      *widget);
226
227 static void addressbook_change_node_name        (GtkCTreeNode   *node,
228                                                  const gchar    *name);
229
230 static void addressbook_new_address_cb          (gpointer        data,
231                                                  guint           action,
232                                                  GtkWidget      *widget);
233 static void addressbook_edit_address_cb         (gpointer        data,
234                                                  guint           action,
235                                                  GtkWidget      *widget);
236 static void addressbook_delete_address_cb       (gpointer        data,
237                                                  guint           action,
238                                                  GtkWidget      *widget);
239
240 static void close_cb                            (gpointer        data,
241                                                  guint           action,
242                                                  GtkWidget      *widget);
243 static void addressbook_file_save_cb            (gpointer        data,
244                                                  guint           action,
245                                                  GtkWidget      *widget);
246
247 /* Data source edit stuff  */
248 static void addressbook_new_book_cb             ( gpointer      data,
249                                                   guint         action,
250                                                   GtkWidget     *widget );
251 static void addressbook_new_vcard_cb            ( gpointer      data,
252                                                   guint         action,
253                                                   GtkWidget     *widget );
254
255 #ifdef USE_JPILOT
256 static void addressbook_new_jpilot_cb           ( gpointer      data,
257                                                   guint         action,
258                                                   GtkWidget     *widget );
259 #endif
260
261 #ifdef USE_LDAP
262 static void addressbook_new_ldap_cb             ( gpointer      data,
263                                                   guint         action,
264                                                   GtkWidget     *widget );
265 #endif
266
267 static void addressbook_set_clist               (AddressObject  *obj);
268
269 static void addressbook_load_tree               (void);
270 void addressbook_read_file                      (void);
271
272 static GtkCTreeNode *addressbook_add_object     (GtkCTreeNode   *node,
273                                                  AddressObject  *obj);
274 static AddressDataSource *addressbook_find_datasource
275                                                 (GtkCTreeNode   *node );
276
277 static AddressBookFile *addressbook_get_book_file();
278
279 static GtkCTreeNode *addressbook_node_add_folder
280                                                 (GtkCTreeNode   *node,
281                                                 AddressDataSource *ds,
282                                                 ItemFolder      *itemFolder,
283                                                 AddressObjectType otype );
284 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode   *node,
285                                                 AddressDataSource *ds,
286                                                 ItemGroup       *itemGroup );
287 /* static GtkCTreeNode *addressbook_node_add_category
288                                                 (GtkCTreeNode   *node,
289                                                  AddressDataSource *ds,
290                                                  ItemFolder     *itemFolder );  */
291 static void addressbook_tree_remove_children    (GtkCTree       *ctree,
292                                                 GtkCTreeNode    *parent );
293 static void addressbook_move_nodes_up           (GtkCTree       *ctree,
294                                                 GtkCTreeNode    *node );
295 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode  *parent,
296                                                 ItemGroup       *group );
297
298 static void addressbook_delete_object           (AddressObject  *obj);
299
300 static void key_pressed                         (GtkWidget      *widget,
301                                                  GdkEventKey    *event,
302                                                  gpointer        data);
303 static gint addressbook_list_compare_func       (GtkCList       *clist,
304                                                  gconstpointer   ptr1,
305                                                  gconstpointer   ptr2);
306 /* static gint addressbook_obj_name_compare     (gconstpointer   a,
307                                                  gconstpointer   b);  */
308
309 static void addressbook_book_show_message       ( AddressBookFile *book );
310 static void addressbook_vcard_show_message      ( VCardFile *vcf );
311 #ifdef USE_JPILOT
312 static void addressbook_jpilot_show_message     ( JPilotFile *jpf );
313 #endif
314 #ifdef USE_LDAP
315 static void addressbook_ldap_show_message       ( SyldapServer *server );
316 #endif
317
318 /* LUT's and IF stuff  */
319 static void addressbook_free_adapter            ( GtkCTreeNode  *node );
320 static void addressbook_free_child_adapters     ( GtkCTreeNode  *node );
321 AddressTypeControlItem *addrbookctl_lookup      ( gint          ot );
322 AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType );
323
324 void addrbookctl_build_map                      ( GtkWidget     *window );
325 void addrbookctl_build_iflist                   ( void );
326 AdapterInterface *addrbookctl_find_interface    ( AddressIfType ifType );
327 void addrbookctl_build_ifselect();
328
329 static void addrbookctl_free_interface          ( AdapterInterface      *adapter );
330 static void addrbookctl_free_datasource         ( AdapterDSource        *adapter );
331 static void addrbookctl_free_folder             ( AdapterFolder *adapter );
332 static void addrbookctl_free_group              ( AdapterGroup  *adapter );
333
334 static void addressbook_list_select_clear       ( void );
335 static void addressbook_list_select_add         ( AddressObject *obj );
336 static void addressbook_list_select_remove      ( AddressObject *obj );
337
338 static GtkItemFactoryEntry addressbook_entries[] =
339 {
340         {N_("/_File"),                  NULL,           NULL, 0, "<Branch>"},
341         {N_("/_File/New _Book"),        "<alt>B",       addressbook_new_book_cb,        0, NULL},
342         {N_("/_File/New _V-Card"),      "<alt>D",       addressbook_new_vcard_cb,       0, NULL},
343 #ifdef USE_JPILOT
344         {N_("/_File/New _J-Pilot"),     "<alt>J",       addressbook_new_jpilot_cb,      0, NULL},
345 #endif
346 #ifdef USE_LDAP
347         {N_("/_File/New _Server"),      "<alt>S",       addressbook_new_ldap_cb,        0, NULL},
348 #endif
349         {N_("/_File/---"),              NULL,           NULL, 0, "<Separator>"},
350         {N_("/_File/_Edit"),            NULL,           addressbook_treenode_edit_cb,   0, NULL},
351         {N_("/_File/_Delete"),          NULL,           addressbook_treenode_delete_cb, 0, NULL},
352         {N_("/_File/---"),              NULL,           NULL, 0, "<Separator>"},
353         {N_("/_File/_Save"),            "<alt>S",       addressbook_file_save_cb,       0, NULL},
354         {N_("/_File/_Close"),           "<alt>W",       close_cb, 0, NULL},
355         {N_("/_Address"),               NULL,           NULL, 0, "<Branch>"},
356         {N_("/_Address/New _Address"),  "<alt>N",       addressbook_new_address_cb,     0, NULL},
357         {N_("/_Address/New _Group"),    "<alt>G",       addressbook_new_group_cb,       0, NULL},
358         {N_("/_Address/New _Folder"),   "<alt>R",       addressbook_new_folder_cb,      0, NULL},
359         {N_("/_Address/---"),           NULL,           NULL, 0, "<Separator>"},
360         {N_("/_Address/_Edit"),         "<alt>Return",  addressbook_edit_address_cb,    0, NULL},
361         {N_("/_Address/_Delete"),       NULL,           addressbook_delete_address_cb,  0, NULL},
362         {N_("/_Help"),                  NULL,           NULL, 0, "<LastBranch>"},
363         {N_("/_Help/_About"),           NULL,           about_show, 0, NULL}
364 };
365
366 /* New options to be added. */
367 /*
368         {N_("/_Edit"),                  NULL,           NULL, 0, "<Branch>"},
369         {N_("/_Edit/C_ut"),             "<ctl>X",       NULL,                           0, NULL},
370         {N_("/_Edit/_Copy"),            "<ctl>C",       NULL,                           0, NULL},
371         {N_("/_Edit/_Paste"),           "<ctl>V",       NULL,                           0, NULL},
372         {N_("/_Tools"),                 NULL,           NULL, 0, "<Branch>"},
373         {N_("/_Tools/Import _Mozilla"), NULL,           NULL,                           0, NULL},
374         {N_("/_Tools/Import _LDIF"),    NULL,           NULL,                           0, NULL},
375         {N_("/_Tools/Import _V-Card"),  NULL,           NULL,                           0, NULL},
376         {N_("/_Tools/---"),             NULL,           NULL, 0, "<Separator>"},
377         {N_("/_Tools/Export _LDIF"),    NULL,           NULL,                           0, NULL},
378         {N_("/_Tools/Export V-_Card"),  NULL,           NULL,                           0, NULL},
379 */
380
381 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
382 {
383         {N_("/New _Address"),   NULL, addressbook_new_address_cb, 0, NULL},
384         {N_("/New _Group"),     NULL, addressbook_new_group_cb,   0, NULL},
385         {N_("/New _Folder"),    NULL, addressbook_new_folder_cb,  0, NULL},
386         {N_("/---"),            NULL, NULL, 0, "<Separator>"},
387         {N_("/_Edit"),          NULL, addressbook_treenode_edit_cb,   0, NULL},
388         {N_("/_Delete"),        NULL, addressbook_treenode_delete_cb, 0, NULL}
389 };
390
391 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
392 {
393         {N_("/New _Address"),   NULL, addressbook_new_address_cb,  0, NULL},
394         {N_("/New _Group"),     NULL, addressbook_new_group_cb,    0, NULL},
395         {N_("/New _Folder"),    NULL, addressbook_new_folder_cb,   0, NULL},
396         {N_("/---"),            NULL, NULL, 0, "<Separator>"},
397         {N_("/_Edit"),          NULL, addressbook_edit_address_cb,   0, NULL},
398         {N_("/_Delete"),        NULL, addressbook_delete_address_cb, 0, NULL}
399 };
400
401 void addressbook_open(Compose *target)
402 {
403         if (!addrbook.window) {
404                 addressbook_read_file();
405                 addressbook_create();
406                 addressbook_load_tree();
407                 gtk_ctree_select(GTK_CTREE(addrbook.ctree),
408                                  GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
409         } else
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 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 #if 0
1167 static void addressbook_list_select_show() {
1168         GList *node = _addressListSelection_;
1169         gchar *addr = NULL;
1170         printf( "show selection...>>>\n" );
1171         while( node != NULL ) {
1172                 AddressObject *obj = ( AddressObject * ) node->data;
1173                 if( obj ) {
1174                         printf( "- %d : '%s'\n", obj->type, obj->name );
1175                         if( obj->type == ADDR_ITEM_GROUP ) {
1176                                 ItemGroup *group = ( ItemGroup * ) obj;
1177                                 GList *node = group->listEMail;
1178                                 while( node ) {
1179                                         ItemEMail *email = node->data;
1180                                         addr = addressbook_format_address( ( AddressObject * ) email );
1181                                         if( addr ) {
1182                                                 printf( "\tgrp >%s<\n", addr );
1183                                                 g_free( addr );
1184                                         }
1185                                         node = g_list_next( node );
1186                                 }
1187                         }
1188                         else {
1189                                 addr = addressbook_format_address( obj );
1190                                 if( addr ) {
1191                                         printf( "\t>%s<\n", addr );
1192                                         g_free( addr );
1193                                 }
1194                         }
1195                 }
1196                 else {
1197                         printf( "- NULL" );
1198                 }
1199                 node = g_list_next( node );
1200         }
1201         printf( "show selection...<<<\n" );
1202 }
1203 #endif
1204
1205 static void addressbook_list_select_clear() {
1206         if( _addressListSelection_ ) {
1207                 g_list_free( _addressListSelection_ );
1208         }
1209         _addressListSelection_ = NULL;
1210 }
1211
1212 static void addressbook_list_select_add( AddressObject *obj ) {
1213         if( obj ) {
1214                 if(     obj->type == ADDR_ITEM_PERSON ||
1215                         obj->type == ADDR_ITEM_EMAIL ||
1216                         obj->type == ADDR_ITEM_GROUP ) {
1217                         if( ! g_list_find( _addressListSelection_, obj ) ) {
1218                                 _addressListSelection_ = g_list_append( _addressListSelection_, obj );
1219                         }
1220                 }
1221         }
1222         /* addressbook_list_select_show(); */
1223 }
1224
1225 static void addressbook_list_select_remove( AddressObject *obj ) {
1226         if( obj == NULL ) return;
1227         if( _addressListSelection_ ) {
1228                 _addressListSelection_ = g_list_remove( _addressListSelection_, obj );
1229         }
1230         /* addressbook_list_select_show(); */
1231 }
1232
1233 static void addressbook_list_row_selected( GtkCTree *clist, GtkCTreeNode *node, gint column, gpointer data ) {
1234         GtkEntry *entry = GTK_ENTRY(addrbook.entry);
1235         AddressObject *obj = NULL;
1236         AddressObject *pobj = NULL;
1237         AdapterDSource *ads = NULL;
1238         AddressInterface *iface = NULL;
1239         AddressDataSource *ds = NULL;
1240         gboolean canEdit = FALSE;
1241         gboolean canDelete = FALSE;
1242
1243         gtk_entry_set_text( entry, "" );
1244         addrbook.listSelected = node;
1245         obj = gtk_ctree_node_get_row_data( clist, node );
1246         if( obj != NULL ) {
1247                 /* printf( "list select: %d : '%s'\n", obj->type, obj->name ); */
1248                 addressbook_list_select_add( obj );
1249         }
1250
1251         pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1252         if( pobj == NULL ) return;
1253
1254         menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1255
1256         if( pobj->type == ADDR_DATASOURCE ) {
1257                 ads = ADAPTER_DSOURCE(pobj);
1258                 ds = ads->dataSource;
1259                 iface = ds->interface;
1260                 if( ! iface->readOnly ) {
1261                         canEdit = TRUE;
1262                         menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1263                         menu_set_sensitive( addrbook.list_factory, "/New Folder", TRUE );
1264                         menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1265                         gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1266                 }
1267         }
1268         else if( pobj->type != ADDR_INTERFACE ) {
1269                 ds = addressbook_find_datasource( addrbook.treeSelected );
1270                 iface = ds->interface;
1271                 if( ! iface->readOnly ) {
1272                         if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1273                                 canEdit = TRUE;
1274                                 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1275                                 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1276                         }
1277                         if( pobj->type == ADDR_ITEM_FOLDER ) {
1278                                 canEdit = TRUE;
1279                                 menu_set_sensitive( addrbook.list_factory, "/New Folder", TRUE );
1280                                 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1281                         }
1282                 }
1283         }
1284         if( obj == NULL ) canEdit = FALSE;
1285         canDelete = canEdit;
1286         if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) canEdit = FALSE;
1287
1288         menu_set_sensitive( addrbook.list_factory, "/Edit",   canEdit );
1289         menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1290
1291         menu_set_sensitive( addrbook.menu_factory, "/Address/Edit",   canEdit );
1292         menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1293
1294         gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1295
1296 }
1297
1298 static void addressbook_list_row_unselected( GtkCTree *ctree, GtkCTreeNode *node, gint column, gpointer data ) {
1299         AddressObject *obj;
1300
1301         obj = gtk_ctree_node_get_row_data( ctree, node );
1302         if( obj != NULL ) {
1303                 /* g_print( "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
1797         ds = addressbook_find_datasource( addrbook.treeSelected );
1798         if( ds == NULL ) return NULL;
1799         if( ds->type == ADDR_IF_BOOK ) abf = ds->rawDataSource;
1800         return abf;
1801 }
1802
1803 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
1804         GtkCTreeNode *node;
1805         GtkCTreeRow *row;
1806
1807         /* Remove existing folders and groups */
1808         row = GTK_CTREE_ROW( parent );
1809         if( row ) {
1810                 while( (node = row->children) ) {
1811                         gtk_ctree_remove_node( ctree, node );
1812                 }
1813         }
1814 }
1815
1816 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
1817         GtkCTreeNode *parent, *child;
1818         GtkCTreeRow *currRow;
1819         currRow = GTK_CTREE_ROW( node );
1820         if( currRow ) {
1821                 parent = currRow->parent;
1822                 while( (child = currRow->children) ) {
1823                         gtk_ctree_move( ctree, child, parent, node );
1824                 }
1825                 gtk_ctree_sort_node( ctree, parent );
1826         }
1827 }
1828
1829 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
1830         GtkCTree *clist = GTK_CTREE(addrbook.clist);
1831         GtkCTree *ctree;
1832         AddressObject *obj = NULL, *pobj = NULL;
1833         AddressDataSource *ds = NULL;
1834         GtkCTreeNode *node = NULL, *parentNode = NULL;
1835         gchar *name = NULL;
1836         AddressBookFile *abf = NULL;
1837
1838         if( addrbook.listSelected == NULL ) return;
1839         obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1840         g_return_if_fail(obj != NULL);
1841
1842         ctree = GTK_CTREE( addrbook.ctree );
1843         pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
1844         node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
1845
1846         ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
1847         if( ds == NULL ) return;
1848
1849         abf = addressbook_get_book_file();
1850         if( abf == NULL ) return;
1851         if( obj->type == ADDR_ITEM_EMAIL ) {
1852                 ItemEMail *email = ( ItemEMail * ) obj;
1853                 ItemPerson *person;
1854                 if( email == NULL ) return;
1855                 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
1856                         /* Edit parent group  */
1857                         AdapterGroup *adapter = ADAPTER_GROUP(pobj);
1858                         ItemGroup *itemGrp = adapter->itemGroup;
1859                         if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
1860                         name = ADDRITEM_NAME(itemGrp);
1861                         node = addrbook.treeSelected;
1862                         parentNode = GTK_CTREE_ROW(node)->parent;
1863                 }
1864                 else {
1865                         /* Edit person - email page */
1866                         person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1867                         if( addressbook_edit_person( abf, NULL, person, TRUE ) == NULL ) return;
1868                         gtk_ctree_select( ctree, addrbook.opened );
1869                         return;
1870                 }
1871         }
1872         else if( obj->type == ADDR_ITEM_PERSON ) {
1873                 /* Edit person - basic page */
1874                 ItemPerson *person = ( ItemPerson * ) obj;
1875                 if( addressbook_edit_person( abf, NULL, person, FALSE ) == NULL ) return;
1876                 gtk_ctree_select( ctree, addrbook.opened);
1877                 return;
1878         }
1879         else if( obj->type == ADDR_ITEM_GROUP ) {
1880                 ItemGroup *itemGrp = ( ItemGroup * ) obj;
1881                 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
1882                 parentNode = addrbook.treeSelected;
1883                 node = addressbook_find_group_node( parentNode, itemGrp );
1884                 name = ADDRITEM_NAME(itemGrp);
1885         }
1886         else {
1887                 return;
1888         }
1889
1890         /* Update tree node with node name */
1891         if( node == NULL ) return;
1892         addressbook_change_node_name( node, name );
1893         gtk_ctree_sort_node( ctree, parentNode );
1894         gtk_ctree_select( ctree, addrbook.opened );
1895 }
1896
1897 static void addressbook_delete_address_cb(gpointer data, guint action,
1898                                           GtkWidget *widget)
1899 {
1900         addressbook_del_clicked(NULL, NULL);
1901 }
1902
1903 static void close_cb(gpointer data, guint action, GtkWidget *widget)
1904 {
1905         addressbook_close();
1906 }
1907
1908 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
1909         addressbook_export_to_file();
1910 }
1911
1912 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
1913         if( node ) {
1914                 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
1915                 if( person ) addritem_person_set_opened( person, TRUE );
1916         }
1917 }
1918
1919 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
1920         if( node ) {
1921                 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
1922                 if( person ) addritem_person_set_opened( person, FALSE );
1923         }
1924 }
1925
1926 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
1927         gchar *str = NULL;
1928         gchar *eMailAlias = ADDRITEM_NAME(email);
1929         if( eMailAlias && *eMailAlias != '\0' ) {
1930                 if( person ) {
1931                         str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
1932                 }
1933                 else {
1934                         str = g_strdup( eMailAlias );
1935                 }
1936         }
1937         return str;
1938 }
1939
1940 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
1941         GList *items = itemGroup->listEMail;
1942         AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
1943         for( ; items != NULL; items = g_list_next( items ) ) {
1944                 GtkCTreeNode *nodeEMail = NULL;
1945                 gchar *text[N_COLS];
1946                 ItemEMail *email = items->data;
1947                 ItemPerson *person;
1948                 gchar *str = NULL;
1949
1950                 if( ! email ) continue;
1951
1952                 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1953                 str = addressbook_format_item_clist( person, email );
1954                 if( str ) {
1955                         text[COL_NAME] = str;
1956                 }
1957                 else {
1958                         text[COL_NAME] = ADDRITEM_NAME(person);
1959                 }
1960                 text[COL_ADDRESS] = email->address;
1961                 text[COL_REMARKS] = email->remarks;
1962                 nodeEMail = gtk_ctree_insert_node(
1963                                 clist, NULL, NULL,
1964                                 text, FOLDER_SPACING,
1965                                 atci->iconXpm, atci->maskXpm,
1966                                 atci->iconXpmOpen, atci->maskXpmOpen,
1967                                 FALSE, FALSE );
1968                 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
1969                 g_free( str );
1970                 str = NULL;
1971         }
1972 }
1973
1974 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
1975         GList *items;
1976         AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
1977         AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
1978
1979         if( atci == NULL ) return;
1980         if( atciMail == NULL ) return;
1981
1982         /* Load email addresses  */
1983         items = addritem_folder_get_person_list( itemFolder );
1984         for( ; items != NULL; items = g_list_next( items ) ) {
1985                 GtkCTreeNode *nodePerson = NULL;
1986                 GtkCTreeNode *nodeEMail = NULL;
1987                 gchar *text[N_COLS];
1988                 gboolean flgFirst = TRUE, haveAddr = FALSE;
1989                 /* gint row; */
1990                 ItemPerson *person;
1991                 GList *node;
1992
1993                 person = ( ItemPerson * ) items->data;
1994                 if( person == NULL ) continue;
1995
1996                 text[COL_NAME] = NULL;
1997                 node = person->listEMail;
1998                 while( node ) {
1999                         ItemEMail *email = node->data;
2000                         gchar *eMailAddr = NULL;
2001                         node = g_list_next( node );
2002
2003                         text[COL_ADDRESS] = email->address;
2004                         text[COL_REMARKS] = email->remarks;
2005                         eMailAddr = ADDRITEM_NAME(email);
2006                         if( *eMailAddr == '\0' ) eMailAddr = NULL;
2007                         if( flgFirst ) {
2008                                 /* First email belongs with person  */
2009                                 gchar *str = addressbook_format_item_clist( person, email );
2010                                 if( str ) {
2011                                         text[COL_NAME] = str;
2012                                 }
2013                                 else {
2014                                         text[COL_NAME] = ADDRITEM_NAME(person);
2015                                 }
2016                                 nodePerson = gtk_ctree_insert_node(
2017                                                 clist, NULL, NULL,
2018                                                 text, FOLDER_SPACING,
2019                                                 atci->iconXpm, atci->maskXpm,
2020                                                 atci->iconXpmOpen, atci->maskXpmOpen,
2021                                                 FALSE, person->isOpened );
2022                                 g_free( str );
2023                                 str = NULL;
2024                                 gtk_ctree_node_set_row_data(clist, nodePerson, person );
2025                         }
2026                         else {
2027                                 /* Subsequent email is a child node of person */
2028                                 text[COL_NAME] = ADDRITEM_NAME(email);
2029                                 nodeEMail = gtk_ctree_insert_node(
2030                                                 clist, nodePerson, NULL,
2031                                                 text, FOLDER_SPACING,
2032                                                 atciMail->iconXpm, atciMail->maskXpm,
2033                                                 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
2034                                                 FALSE, TRUE );
2035                                 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
2036                         }
2037                         flgFirst = FALSE;
2038                         haveAddr = TRUE;
2039                 }
2040                 if( ! haveAddr ) {
2041                         /* Have name without EMail */
2042                         text[COL_NAME] = ADDRITEM_NAME(person);
2043                         text[COL_ADDRESS] = NULL;
2044                         text[COL_REMARKS] = NULL;
2045                         nodePerson = gtk_ctree_insert_node(
2046                                         clist, NULL, NULL,
2047                                         text, FOLDER_SPACING,
2048                                         atci->iconXpm, atci->maskXpm,
2049                                         atci->iconXpmOpen, atci->maskXpmOpen,
2050                                         FALSE, person->isOpened );
2051                         gtk_ctree_node_set_row_data(clist, nodePerson, person );
2052                 }
2053                 gtk_ctree_sort_node(GTK_CTREE(clist), NULL);
2054         }
2055         /* Free up the list */
2056         mgu_clear_list( items );
2057         g_list_free( items );
2058 }
2059
2060 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
2061         GList *items;
2062         AddressTypeControlItem *atci =  addrbookctl_lookup( ADDR_ITEM_GROUP );
2063
2064         /* Load any groups */
2065         if( ! atci ) return;
2066         items = addritem_folder_get_group_list( itemFolder );
2067         for( ; items != NULL; items = g_list_next( items ) ) {
2068                 GtkCTreeNode *nodeGroup = NULL;
2069                 gchar *text[N_COLS];
2070                 ItemGroup *group = items->data;
2071                 if( group == NULL ) continue;
2072                 text[COL_NAME] = ADDRITEM_NAME(group);
2073                 text[COL_ADDRESS] = NULL;
2074                 text[COL_REMARKS] = NULL;
2075                 nodeGroup = gtk_ctree_insert_node(clist, NULL, NULL,
2076                                       text, FOLDER_SPACING,
2077                                       atci->iconXpm, atci->maskXpm,
2078                                       atci->iconXpmOpen, atci->maskXpmOpen,
2079                                       FALSE, FALSE);
2080                 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
2081                 gtk_ctree_sort_node(clist, NULL);
2082         }
2083         /* Free up the list */
2084         mgu_clear_list( items );
2085         g_list_free( items );
2086 }
2087
2088 /*
2089  * Load data sources into list.
2090  */
2091 static void addressbook_node_load_datasource( GtkCTree *clist, AddressObject *obj ) {
2092         AdapterInterface *adapter;
2093         AddressInterface *iface;
2094         AddressTypeControlItem *atci = NULL;
2095         /* AddressDataSource *ds; */
2096         GtkCTreeNode *newNode, *node;
2097         GtkCTreeRow *row;
2098         GtkCell *cell = NULL;
2099         gchar *text[N_COLS];
2100
2101         adapter = ADAPTER_INTERFACE(obj);
2102         if( adapter == NULL ) return;
2103         iface = adapter->interface;
2104         atci = adapter->atci;
2105         if( atci == NULL ) return;
2106
2107         /* Create nodes in list copying values for data sources in tree  */
2108         row = GTK_CTREE_ROW( adapter->treeNode );
2109         if( row ) {
2110                 node = row->children;
2111                 while( node ) {
2112                         gpointer data = gtk_ctree_node_get_row_data( clist, node );
2113                         row = GTK_CTREE_ROW( node );
2114                         cell = ( ( GtkCListRow * )row )->cell;
2115                         text[COL_NAME] = cell->u.text;
2116                         text[COL_ADDRESS] = NULL;
2117                         text[COL_REMARKS] = NULL;
2118                         newNode = gtk_ctree_insert_node( clist, NULL, NULL,
2119                                       text, FOLDER_SPACING,
2120                                       atci->iconXpm, atci->maskXpm,
2121                                       atci->iconXpmOpen, atci->maskXpmOpen,
2122                                       FALSE, FALSE);
2123                         gtk_ctree_node_set_row_data( clist, newNode, data );
2124                         node = row->sibling;
2125
2126                 }
2127         }
2128         gtk_ctree_sort_node( clist, NULL );
2129 }
2130
2131 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
2132         AddressDataSource *ds = NULL;
2133         AddressObject *ao;
2134
2135         g_return_val_if_fail(addrbook.ctree != NULL, NULL);
2136
2137         while( node ) {
2138                 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
2139                 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
2140                 if( ao ) {
2141 /*                      printf( "ao->type = %d\n", ao->type );   */
2142                         if( ao->type == ADDR_DATASOURCE ) {
2143                                 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
2144 /*                              printf( "found it\n" );           */
2145                                 ds = ads->dataSource;
2146                                 break;
2147                         }
2148                 }
2149                 node = GTK_CTREE_ROW(node)->parent;
2150         }
2151         return ds;
2152 }
2153
2154 /*
2155 * Load address list widget with children of specified object.
2156 * Enter: obj    Parent object to be loaded.
2157 */
2158 static void addressbook_set_clist( AddressObject *obj ) {
2159         GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
2160         GtkCList *clist = GTK_CLIST(addrbook.clist);
2161         AddressDataSource *ds = NULL;
2162         AdapterDSource *ads = NULL;
2163
2164         if( obj == NULL ) {
2165                 gtk_clist_clear(clist);
2166                 return;
2167         }
2168
2169         if( obj->type == ADDR_INTERFACE ) {
2170                 /* printf( "set_clist: loading datasource...\n" );
2171                  addressbook_node_load_datasource( clist, obj ); */
2172                 return;
2173         }
2174
2175         gtk_clist_freeze(clist);
2176         gtk_clist_clear(clist);
2177
2178         if( obj->type == ADDR_DATASOURCE ) {
2179                 ads = ADAPTER_DSOURCE(obj);
2180                 ds = ADAPTER_DSOURCE(obj)->dataSource;
2181                 if( ds ) {
2182                         /* Load root folder */
2183                         ItemFolder *rootFolder = NULL;
2184                         rootFolder = addrindex_ds_get_root_folder( ds );
2185                         addressbook_folder_load_person( ctreelist, addrindex_ds_get_root_folder( ds ) );
2186                         addressbook_folder_load_group( ctreelist, addrindex_ds_get_root_folder( ds ) );
2187                 }
2188         }
2189         else {
2190                 if( obj->type == ADDR_ITEM_GROUP ) {
2191                         /* Load groups */
2192                         ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
2193                         addressbook_load_group( ctreelist, itemGroup );
2194                 }
2195                 else if( obj->type == ADDR_ITEM_FOLDER ) {
2196                         /* Load folders  */
2197                         ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
2198                         addressbook_folder_load_person( ctreelist, itemFolder );
2199                         addressbook_folder_load_group( ctreelist, itemFolder );
2200                 }
2201         }
2202
2203         gtk_clist_sort(clist);
2204         gtk_clist_thaw(clist);
2205 }
2206
2207 /*
2208 * Free adaptor for specified node.
2209 */
2210 static void addressbook_free_adapter( GtkCTreeNode *node ) {
2211         AddressObject *ao;
2212
2213         g_return_if_fail(addrbook.ctree != NULL);
2214
2215         if( node ) {
2216                 if( GTK_CTREE_ROW(node)->level < 2 ) return;
2217                 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
2218                 if( ao == NULL ) return;
2219                 if( ao->type == ADDR_INTERFACE ) {
2220                         AdapterInterface *ai = ADAPTER_INTERFACE(ao);
2221                         addrbookctl_free_interface( ai );
2222                 }
2223                 else if( ao->type == ADDR_DATASOURCE ) {
2224                         AdapterDSource *ads = ADAPTER_DSOURCE(ao);
2225                         addrbookctl_free_datasource( ads );
2226                 }
2227                 else if( ao->type == ADDR_ITEM_FOLDER ) {
2228                         AdapterFolder *af = ADAPTER_FOLDER(ao);
2229                         addrbookctl_free_folder( af );
2230                 }
2231                 else if( ao->type == ADDR_ITEM_GROUP ) {
2232                         AdapterGroup *ag = ADAPTER_GROUP(ao);
2233                         addrbookctl_free_group( ag );
2234                 }
2235                 gtk_ctree_node_set_row_data( GTK_CTREE(addrbook.ctree), node, NULL );
2236         }
2237 }
2238
2239 /*
2240 * Free all children adapters.
2241 */
2242 static void addressbook_free_child_adapters( GtkCTreeNode *node ) {
2243         GtkCTreeNode *parent, *child;
2244         GtkCTreeRow *currRow;
2245
2246         if( node == NULL ) return;
2247         currRow = GTK_CTREE_ROW( node );
2248         if( currRow ) {
2249                 parent = currRow->parent;
2250                 child = currRow->children;
2251                 while( child ) {
2252                         addressbook_free_child_adapters( child );
2253                         addressbook_free_adapter( child );
2254                         currRow = GTK_CTREE_ROW( child );
2255                         child = currRow->sibling;
2256                 }
2257         }
2258 }
2259
2260 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
2261                                 AddressObjectType otype, gchar *name )
2262 {
2263         AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
2264         ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
2265         ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
2266         adapter->dataSource = ds;
2267         adapter->subType = otype;
2268         return adapter;
2269 }
2270
2271 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
2272         ADDRESS_OBJECT_NAME(adapter) = mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
2273 }
2274
2275 /*
2276  * Load tree from address index with the initial data.
2277  */
2278 static void addressbook_load_tree( void ) {
2279         GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2280         GList *nodeIf, *nodeDS;
2281         AdapterInterface *adapter;
2282         AddressInterface *iface;
2283         AddressTypeControlItem *atci;
2284         AddressDataSource *ds;
2285         AdapterDSource *ads;
2286         GtkCTreeNode *node, *newNode;
2287         gchar *name;
2288
2289         nodeIf = _addressInterfaceList_;
2290         while( nodeIf ) {
2291                 adapter = nodeIf->data;
2292                 node = adapter->treeNode;
2293                 iface = adapter->interface;
2294                 atci = adapter->atci;
2295                 if( iface ) {
2296                         if( iface->useInterface ) {
2297                                 /* Load data sources below interface node  */
2298                                 nodeDS = iface->listSource;
2299                                 while( nodeDS ) {
2300                                         ds = nodeDS->data;
2301                                         newNode = NULL;
2302                                         name = addrindex_ds_get_name( ds );
2303                                         ads = addressbook_create_ds_adapter( ds, atci->objectType, name );
2304                                         newNode = addressbook_add_object( node, ADDRESS_OBJECT(ads) );
2305                                         nodeDS = g_list_next( nodeDS );
2306                                 }
2307                                 gtk_ctree_expand( ctree, node );
2308                         }
2309                 }
2310                 nodeIf = g_list_next( nodeIf );
2311         }
2312 }
2313
2314 /*
2315  * Convert the old address book to new format.
2316  */
2317 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
2318         gboolean retVal = FALSE;
2319         gboolean errFlag = TRUE;
2320         gchar *msg = NULL;
2321
2322         /* Read old address book, performing conversion */
2323         debug_print( "Reading and converting old address book...\n" );
2324         addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
2325         addrindex_read_data( addrIndex );
2326         if( addrIndex->retVal == MGU_NO_FILE ) {
2327                 /* We do not have a file - new user */
2328                 debug_print( "New user... create new books...\n" );
2329                 addrindex_create_new_books( addrIndex );
2330                 if( addrIndex->retVal == MGU_SUCCESS ) {
2331                         /* Save index file */
2332                         addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2333                         addrindex_save_data( addrIndex );
2334                         if( addrIndex->retVal == MGU_SUCCESS ) {
2335                                 retVal = TRUE;
2336                                 errFlag = FALSE;
2337                         }
2338                         else {
2339                                 msg = _( "New user, could not save index file." );
2340                         }
2341                 }
2342                 else {
2343                         msg = _( "New user, could not save address book files." );
2344                 }
2345         }
2346         else {
2347                 /* We have an old file */
2348                 if( addrIndex->wasConverted ) {
2349                         /* Converted successfully - save address index  */
2350                         addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2351                         addrindex_save_data( addrIndex );
2352                         if( addrIndex->retVal == MGU_SUCCESS ) {
2353                                 msg = _( "Old address book converted successfully." );
2354                                 retVal = TRUE;
2355                                 errFlag = FALSE;
2356                         }
2357                         else {
2358                                 msg = _("Old address book converted,\n"
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 = _("Could not convert address book,\n"
2372                                                 "but created empty new address book files." );
2373                                         retVal = TRUE;
2374                                         errFlag = FALSE;
2375                                 }
2376                                 else {
2377                                         msg = _("Could not convert address book,\n"
2378                                                 "could not create new address book files." );
2379                                 }
2380                         }
2381                         else {
2382                                 msg = _("Could not convert address book\n"
2383                                         "and could not create new address book files." );
2384                         }
2385                 }
2386         }
2387         if( errFlag ) {
2388                 debug_print( "Error\n%s\n", msg );
2389                 alertpanel( _( "Addressbook conversion error" ), msg, _( "Close" ), NULL, NULL );
2390         }
2391         else if( msg ) {
2392                 debug_print( "Warning\n%s\n", msg );
2393                 alertpanel( _( "Addressbook conversion" ), msg, _( "Close" ), NULL, NULL );
2394         }
2395
2396         return retVal;
2397 }
2398
2399 void addressbook_read_file( void ) {
2400         AddressIndex *addrIndex = NULL;
2401
2402         debug_print( "Reading address index...\n" );
2403         if( _addressIndex_ ) {
2404                 debug_print( "address book already read!!!\n" );
2405                 return;
2406         }
2407
2408         addrIndex = addrindex_create_index();
2409
2410         /* Use new address book index. */
2411         addrindex_set_file_path( addrIndex, get_rc_dir() );
2412         addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2413         addrindex_read_data( addrIndex );
2414         if( addrIndex->retVal == MGU_NO_FILE ) {
2415                 /* Conversion required */
2416                 debug_print( "Converting...\n" );
2417                 if( addressbook_convert( addrIndex ) ) {
2418                         _addressIndex_ = addrIndex;
2419                 }
2420         }
2421         else if( addrIndex->retVal == MGU_SUCCESS ) {
2422                 _addressIndex_ = addrIndex;
2423         }
2424         else {
2425                 /* Error reading address book */
2426                 debug_print( "Could not read address index.\n" );
2427                 addrindex_print_index( addrIndex, stdout );
2428                 alertpanel( _( "Addressbook Error" ),
2429                             _( "Could not read address index" ),
2430                             _( "Close" ), NULL, NULL );
2431         }
2432         debug_print( "done.\n" );
2433 }
2434
2435 #if 0
2436 void addressbook_read_file_old( void ) {
2437         AddressIndex *addrIndex = NULL;
2438         gboolean errFlag = TRUE;
2439         gchar *msg = NULL;
2440
2441         if( _addressIndex_ ) {
2442                 debug_print( "address book already read!!!\n" );
2443                 return;
2444         }
2445
2446         addrIndex = addrindex_create_index();
2447
2448         /* Use use new address book. */
2449         /* addrindex_set_file_path( addrIndex, "/home/match/tmp/empty-dir" );  */
2450         addrindex_set_file_path( addrIndex, get_rc_dir() );
2451         addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2452
2453         debug_print( "Reading address index...\n" );
2454         addrindex_read_data( addrIndex );
2455         if( addrIndex->retVal == MGU_NO_FILE ) {
2456                 /* Read old address book, performing conversion */
2457                 debug_print( "Reading and converting old address book...\n" );
2458                 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
2459                 addrindex_read_data( addrIndex );
2460                 if( addrIndex->retVal == MGU_NO_FILE ) {
2461                         /* We do not have a file - new user */
2462                         debug_print( "New user... create new books...\n" );
2463                         addrindex_create_new_books( addrIndex );
2464                         if( addrIndex->retVal == MGU_SUCCESS ) {
2465                                 /* Save index file */
2466                                 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2467                                 addrindex_save_data( addrIndex );
2468                                 if( addrIndex->retVal == MGU_SUCCESS ) {
2469                                         errFlag = FALSE;
2470                                 }
2471                                 else {
2472                                         msg = g_strdup( _( "New user, could not save index file." ) );
2473                                 }
2474                         }
2475                         else {
2476                                 msg = g_strdup( _( "New user, could not save address book files." ) );
2477                         }
2478                 }
2479                 else {
2480                         /* We have an old file */
2481                         if( addrIndex->wasConverted ) {
2482                                 /* Converted successfully - save address index  */
2483                                 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2484                                 addrindex_save_data( addrIndex );
2485                                 if( addrIndex->retVal == MGU_SUCCESS ) {
2486                                         msg = g_strdup( _( "Old address book converted successfully." ) );
2487                                         errFlag = FALSE;
2488                                 }
2489                                 else {
2490                                         msg = g_strdup( _(
2491                                                 "Old address book converted, " \
2492                                                 "could not save new address index file" ) );
2493                                 }
2494                         }
2495                         else {
2496                                 /* File conversion failed - just create new books */
2497                                 debug_print( "File conversion failed... just create new books...\n" );
2498                                 addrindex_create_new_books( addrIndex );
2499                                 if( addrIndex->retVal == MGU_SUCCESS ) {
2500                                         /* Save index */
2501                                         addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
2502                                         addrindex_save_data( addrIndex );
2503                                         if( addrIndex->retVal == MGU_SUCCESS ) {
2504                                                 msg = g_strdup( _(
2505                                                         "Could not convert address book, " \
2506                                                         "but created empty new address book files." ) );
2507                                                 errFlag = FALSE;
2508                                         }
2509                                         else {
2510                                                 msg = g_strdup( _(
2511                                                         "Could not convert address book, " \
2512                                                         "could not create new address book files." ) );
2513                                         }
2514                                 }
2515                                 else {
2516                                         msg = g_strdup( _(
2517                                                 "Could not convert address book " \
2518                                                 "and could not create new address book files." ) );
2519                                 }
2520                         }
2521                 }
2522         }
2523         else if( addrIndex->retVal == MGU_SUCCESS ) {
2524                 errFlag = FALSE;
2525         }
2526         else {
2527                 debug_print( "Could not read address index.\n" );
2528                 addrindex_print_index( addrIndex, stdout );
2529                 msg = g_strdup( _( "Could not read address index" ) );
2530         }
2531         _addressIndex_ = addrIndex;
2532
2533         if( errFlag ) {
2534                 debug_print( "Error\n%s\n", msg );
2535                 alertpanel( _( "Sylpheed Addressbook Conversion Error" ), msg, _( "Close" ), NULL, NULL );
2536         }
2537         else {
2538                 if( msg ) {
2539                         debug_print( "Warning\n%s\n", msg );
2540                         alertpanel( _( "Sylpheed Addressbook Conversion" ), msg, _( "Close" ), NULL, NULL );
2541                 }
2542         }
2543         if( msg ) g_free( msg );
2544         debug_print( "done.\n" );
2545 }
2546 #endif
2547
2548 /*
2549 * Add object into the address index tree widget.
2550 * Enter: node   Parent node.
2551 *        obj    Object to add.
2552 * Return: Node that was added, or NULL if object not added.
2553 */
2554 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
2555                                             AddressObject *obj)
2556 {
2557         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2558         GtkCTreeNode *added;
2559         AddressObject *pobj;
2560         AddressObjectType otype;
2561         AddressTypeControlItem *atci = NULL;
2562
2563         g_return_val_if_fail(node != NULL, NULL);
2564         g_return_val_if_fail(obj  != NULL, NULL);
2565
2566         pobj = gtk_ctree_node_get_row_data(ctree, node);
2567         g_return_val_if_fail(pobj != NULL, NULL);
2568
2569         /* Determine object type to be displayed  */
2570         if( obj->type == ADDR_DATASOURCE ) {
2571                 otype = ADAPTER_DSOURCE(obj)->subType;
2572         }
2573         else {
2574                 otype = obj->type;
2575         }
2576
2577         /* Handle any special conditions. */
2578         added = node;
2579         atci = addrbookctl_lookup( otype );
2580         if( atci ) {
2581                 if( atci->showInTree ) {
2582                         /* Add object to tree */
2583                         gchar **name;
2584                         name = &obj->name;
2585                         added = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
2586                                 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
2587                                 atci->treeLeaf, atci->treeExpand );
2588                         gtk_ctree_node_set_row_data(ctree, added, obj);
2589                 }
2590         }
2591
2592         gtk_ctree_sort_node(ctree, node);
2593
2594         return added;
2595 }
2596
2597 /*
2598 * Add group into the address index tree.
2599 * Enter: node      Parent node.
2600 *        ds        Data source.
2601 *        itemGroup Group to add.
2602 * Return: Inserted node.
2603 */
2604 static GtkCTreeNode *addressbook_node_add_group( GtkCTreeNode *node, AddressDataSource *ds, ItemGroup *itemGroup ) {
2605         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2606         GtkCTreeNode *newNode;
2607         AdapterGroup *adapter;
2608         AddressTypeControlItem *atci = NULL;
2609         gchar **name;
2610
2611         if( ds == NULL ) return NULL;
2612         if( node == NULL || itemGroup == NULL ) return NULL;
2613
2614         name = &itemGroup->obj.name;
2615
2616         atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
2617
2618         adapter = g_new0( AdapterGroup, 1 );
2619         ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
2620         ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
2621         adapter->itemGroup = itemGroup;
2622
2623         newNode = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
2624                         atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
2625                         atci->treeLeaf, atci->treeExpand );
2626         gtk_ctree_node_set_row_data( ctree, newNode, adapter );
2627         gtk_ctree_sort_node( ctree, node );
2628         return newNode;
2629 }
2630
2631 /*
2632 * Add folder into the address index tree.
2633 * Enter: node       Parent node.
2634 *        ds         Data source.
2635 *        itemFolder Folder to add.
2636 *        otype      Object type to display.
2637 * Return: Inserted node.
2638 */
2639 static GtkCTreeNode *addressbook_node_add_folder(
2640                 GtkCTreeNode *node, AddressDataSource *ds, ItemFolder *itemFolder, AddressObjectType otype )
2641 {
2642         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2643         GtkCTreeNode *newNode = NULL;
2644         AdapterFolder *adapter;
2645         AddressTypeControlItem *atci = NULL;
2646         GList *listItems = NULL;
2647         gchar **name;
2648         ItemFolder *rootFolder;
2649
2650         if( ds == NULL ) return NULL;
2651         if( node == NULL || itemFolder == NULL ) return NULL;
2652
2653         /* Determine object type */
2654         atci = addrbookctl_lookup( otype );
2655         if( atci == NULL ) return NULL;
2656
2657         rootFolder = addrindex_ds_get_root_folder( ds );
2658         if( itemFolder == rootFolder ) {
2659                 newNode = node;
2660         }
2661         else {
2662                 name = &itemFolder->obj.name;
2663
2664                 adapter = g_new0( AdapterFolder, 1 );
2665                 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
2666                 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
2667                 adapter->itemFolder = itemFolder;
2668
2669                 newNode = gtk_ctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
2670                                 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
2671                                 atci->treeLeaf, atci->treeExpand );
2672                 gtk_ctree_node_set_row_data( ctree, newNode, adapter );
2673         }
2674
2675         listItems = itemFolder->listFolder;
2676         while( listItems ) {
2677                 ItemFolder *item = listItems->data;
2678                 addressbook_node_add_folder( newNode, ds, item, otype );
2679                 listItems = g_list_next( listItems );
2680         }
2681         listItems = itemFolder->listGroup;
2682         while( listItems ) {
2683                 ItemGroup *item = listItems->data;
2684                 addressbook_node_add_group( newNode, ds, item );
2685                 listItems = g_list_next( listItems );
2686         }
2687         gtk_ctree_sort_node( ctree, node );
2688         return newNode;
2689 }
2690
2691 static void addressbook_delete_object(AddressObject *obj) {
2692         AdapterDSource *ads = NULL;
2693         AddressDataSource *ds = NULL;
2694         if (!obj) return;
2695
2696         /* Remove data source. */
2697         printf( "Delete obj type : %d\n", obj->type );
2698
2699         ads = ADAPTER_DSOURCE(obj);
2700         if( ads == NULL ) return;
2701         ds = ads->dataSource;
2702         if( ds == NULL ) return;
2703
2704         /* Remove data source */
2705         if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2706                 addrindex_free_datasource( _addressIndex_, ds );
2707         }
2708         /* Free up Adapter object */
2709         g_free( ADAPTER_DSOURCE(obj) );
2710 }
2711
2712 void addressbook_export_to_file( void ) {
2713         if( _addressIndex_ ) {
2714                 /* Save all new address book data */
2715                 debug_print( "Saving address books...\n" );
2716                 addrindex_save_all_books( _addressIndex_ );
2717
2718                 debug_print( "Exporting addressbook to file...\n" );
2719                 addrindex_save_data( _addressIndex_ );
2720                 if( _addressIndex_->retVal != MGU_SUCCESS ) {
2721                         addrindex_print_index( _addressIndex_, stdout );
2722                 }
2723
2724                 /* Notify address completion of new data  */
2725                 invalidate_address_completion();
2726         }
2727 }
2728
2729 static void key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
2730 {
2731         if (event && event->keyval == GDK_Escape)
2732                 addressbook_close();
2733 }
2734
2735 /*
2736 * Comparsion using names of AddressItem objects.
2737 */
2738 /*
2739 static gint addressbook_list_compare_func(GtkCList *clist,
2740                                           gconstpointer ptr1,
2741                                           gconstpointer ptr2)
2742 {
2743         AddressObject *obj1 = ((GtkCListRow *)ptr1)->data;
2744         AddressObject *obj2 = ((GtkCListRow *)ptr2)->data;
2745         gchar *name1 = NULL, *name2 = NULL;
2746         if( obj1 ) name1 = obj1->name;
2747         if( obj2 ) name2 = obj2->name;
2748         if( ! name1 ) return ( name2 != NULL );
2749         if( ! name2 ) return -1;
2750         return strcasecmp(name1, name2);
2751 }
2752 */
2753
2754 /*
2755 * Comparison using cell contents (text in first column).
2756 */
2757 static gint addressbook_list_compare_func( GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 ) {
2758         GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
2759         GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
2760         gchar *name1 = NULL, *name2 = NULL;
2761         if( cell1 ) name1 = cell1->u.text;
2762         if( cell2 ) name2 = cell2->u.text;
2763         if( ! name1 ) return ( name2 != NULL );
2764         if( ! name2 ) return -1;
2765         return strcasecmp( name1, name2 );
2766 }
2767
2768 /* static */ 
2769 gint addressbook_obj_name_compare(gconstpointer a, gconstpointer b)
2770 {
2771         const AddressObject *obj = a;
2772         const gchar *name = b;
2773         AddressTypeControlItem *atci = NULL;
2774
2775         if (!obj || !name) return -1;
2776
2777         atci = addrbookctl_lookup( obj->type );
2778         if( ! atci ) return -1;
2779         if( ! obj->name ) return -1;
2780         return strcasecmp(obj->name, name);
2781 }
2782
2783 static void addressbook_book_show_message( AddressBookFile *abf ) {
2784         *addressbook_msgbuf = '\0';
2785         if( abf ) {
2786                 if( abf->retVal == MGU_SUCCESS ) {
2787                         sprintf( addressbook_msgbuf, "%s", abf->name );
2788                 }
2789                 else {
2790                         sprintf( addressbook_msgbuf, "%s: %s", abf->name, mgu_error2string( abf->retVal ) );
2791                 }
2792         }
2793         addressbook_status_show( addressbook_msgbuf );
2794 }
2795
2796 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
2797         AdapterDSource *ads;
2798         AdapterInterface *adapter;
2799
2800         adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
2801         if( adapter == NULL ) return;
2802         if( addrbook.treeSelected == NULL ) return;
2803         if( addrbook.treeSelected != adapter->treeNode ) return;
2804         ads = addressbook_edit_book( _addressIndex_, NULL );
2805         if( ads ) {
2806                 addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
2807                 if( addrbook.treeSelected == addrbook.opened ) {
2808                         gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
2809                 }
2810         }
2811 }
2812
2813 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
2814         AdapterDSource *ads;
2815         AdapterInterface *adapter;
2816
2817         adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
2818         if( adapter == NULL ) return;
2819         if( addrbook.treeSelected != adapter->treeNode ) return;
2820         ads = addressbook_edit_vcard( _addressIndex_, NULL );
2821         if( ads ) {
2822                 addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
2823                 if( addrbook.treeSelected == addrbook.opened ) {
2824                         gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
2825                 }
2826         }
2827 }
2828
2829 static void addressbook_vcard_show_message( VCardFile *vcf ) {
2830         *addressbook_msgbuf = '\0';
2831         if( vcf ) {
2832                 if( vcf->retVal == MGU_SUCCESS ) {
2833                         sprintf( addressbook_msgbuf, "%s", vcf->name );
2834                 }
2835                 else {
2836                         sprintf( addressbook_msgbuf, "%s: %s", vcf->name, mgu_error2string( vcf->retVal ) );
2837                 }
2838         }
2839         addressbook_status_show( addressbook_msgbuf );
2840 }
2841
2842 #ifdef USE_JPILOT
2843 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
2844         AdapterDSource *ads;
2845         AdapterInterface *adapter;
2846         AddressInterface *iface;
2847
2848         adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
2849         if( adapter == NULL ) return;
2850         if( addrbook.treeSelected != adapter->treeNode ) return;
2851         iface = adapter->interface;
2852         if( ! iface->haveLibrary ) return;
2853         ads = addressbook_edit_jpilot( _addressIndex_, NULL );
2854         if( ads ) {
2855                 addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
2856                 if( addrbook.treeSelected == addrbook.opened ) {
2857                         gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
2858                 }
2859         }
2860 }
2861
2862 static void addressbook_jpilot_show_message( JPilotFile *jpf ) {
2863         *addressbook_msgbuf = '\0';
2864         if( jpf ) {
2865                 if( jpf->retVal == MGU_SUCCESS ) {
2866                         sprintf( addressbook_msgbuf, "%s", jpf->name );
2867                 }
2868                 else {
2869                         sprintf( addressbook_msgbuf, "%s: %s", jpf->name, mgu_error2string( jpf->retVal ) );
2870                 }
2871         }
2872         addressbook_status_show( addressbook_msgbuf );
2873 }
2874
2875 #endif
2876
2877 #ifdef USE_LDAP
2878 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
2879         AdapterDSource *ads;
2880         AdapterInterface *adapter;
2881         AddressInterface *iface;
2882
2883         adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
2884         if( adapter == NULL ) return;
2885         if( addrbook.treeSelected != adapter->treeNode ) return;
2886         iface = adapter->interface;
2887         if( ! iface->haveLibrary ) return;
2888         ads = addressbook_edit_ldap( _addressIndex_, NULL );
2889         if( ads ) {
2890                 addressbook_add_object( addrbook.treeSelected, ADDRESS_OBJECT(ads) );
2891                 if( addrbook.treeSelected == addrbook.opened ) {
2892                         gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
2893                 }
2894         }
2895 }
2896
2897 static void addressbook_ldap_show_message( SyldapServer *svr ) {
2898         *addressbook_msgbuf = '\0';
2899         if( svr ) {
2900                 if( svr->busyFlag ) {
2901                         sprintf( addressbook_msgbuf, "%s: %s", svr->name, ADDRESSBOOK_LDAP_BUSYMSG );
2902                 }
2903                 else {
2904                         if( svr->retVal == MGU_SUCCESS ) {
2905                                 sprintf( addressbook_msgbuf, "%s", svr->name );
2906                         }
2907                         else {
2908                                 sprintf( addressbook_msgbuf, "%s: %s", svr->name, mgu_error2string( svr->retVal ) );
2909                         }
2910                 }
2911         }
2912         addressbook_status_show( addressbook_msgbuf );
2913 }
2914
2915 static void ldapsearch_callback( SyldapServer *sls ) {
2916         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2917         AddressObject *obj;
2918         AdapterDSource *ads = NULL;
2919         AddressDataSource *ds = NULL;
2920         AddressInterface *iface = NULL;
2921
2922         if( sls == NULL ) return;
2923         if( ! addrbook.treeSelected ) return;
2924         if( GTK_CTREE_ROW( addrbook.treeSelected )->level == 1 ) return;
2925
2926         obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2927         if( obj == NULL ) return;
2928         if( obj->type == ADDR_DATASOURCE ) {
2929                 ads = ADAPTER_DSOURCE(obj);
2930                 if( ads->subType == ADDR_LDAP ) {
2931                         SyldapServer *server;
2932
2933                         ds = ads->dataSource;
2934                         if( ds == NULL ) return;
2935                         iface = ds->interface;
2936                         if( ! iface->haveLibrary ) return;
2937                         server = ds->rawDataSource;
2938                         if( server == sls ) {
2939                                 /* Read from cache */
2940                                 gtk_widget_show_all(addrbook.window);
2941                                 addressbook_set_clist( obj );
2942                                 addressbook_ldap_show_message( sls );
2943                                 gtk_widget_show_all(addrbook.window);
2944                                 gtk_entry_set_text( GTK_ENTRY(addrbook.entry), "" );
2945                         }
2946                 }
2947         }
2948 }
2949 #endif
2950
2951 /*
2952  * Lookup button handler.
2953  */
2954 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
2955         GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2956         AddressObject *obj;
2957 #ifdef USE_LDAP
2958         AdapterDSource *ads = NULL;
2959         AddressDataSource *ds = NULL;
2960         AddressInterface *iface = NULL;
2961 #endif
2962         gchar *sLookup;
2963
2964         sLookup = gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
2965         g_strchomp( sLookup );
2966
2967         if( ! addrbook.treeSelected ) return;
2968         if( GTK_CTREE_ROW( addrbook.treeSelected )->level == 1 ) return;
2969
2970         obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2971         if( obj == NULL ) return;
2972
2973 #ifdef USE_LDAP
2974         if( obj->type == ADDR_DATASOURCE ) {
2975                 ads = ADAPTER_DSOURCE(obj);
2976                 if( ads->subType == ADDR_LDAP ) {
2977                         SyldapServer *server;
2978
2979                         ds = ads->dataSource;
2980                         if( ds == NULL ) return;
2981                         iface = ds->interface;
2982                         if( ! iface->haveLibrary ) return;
2983                         server = ds->rawDataSource;
2984                         if( server ) {
2985                                 syldap_cancel_read( server );
2986                                 if( *sLookup == '\0' || strlen( sLookup ) < 1 ) return;
2987                                 syldap_set_search_value( server, sLookup );
2988                                 syldap_set_callback( server, ldapsearch_callback );
2989                                 syldap_read_data_th( server );
2990                                 addressbook_ldap_show_message( server );
2991                         }
2992                 }
2993         }
2994 #endif
2995
2996 }
2997
2998 /* **********************************************************************
2999 * Build lookup tables.
3000 * ***********************************************************************
3001 */
3002
3003 /*
3004 * Build table that controls the rendering of object types.
3005 */
3006 void addrbookctl_build_map( GtkWidget *window ) {
3007         AddressTypeControlItem *atci;
3008
3009         /* Build icons */
3010         PIXMAP_CREATE(window, folderxpm, folderxpmmask, DIRECTORY_CLOSE_XPM);
3011         PIXMAP_CREATE(window, folderopenxpm, folderopenxpmmask, DIRECTORY_OPEN_XPM);
3012         PIXMAP_CREATE(window, groupxpm, groupxpmmask, group_xpm);
3013         PIXMAP_CREATE(window, vcardxpm, vcardxpmmask, vcard_xpm);
3014         PIXMAP_CREATE(window, bookxpm, bookxpmmask, book_xpm);
3015         PIXMAP_CREATE(window, addressxpm, addressxpmmask, address_xpm);
3016         PIXMAP_CREATE(window, jpilotxpm, jpilotxpmmask, jpilot_xpm);
3017         PIXMAP_CREATE(window, categoryxpm, categoryxpmmask, category_xpm);
3018         PIXMAP_CREATE(window, ldapxpm, ldapxpmmask, ldap_xpm);
3019
3020         _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
3021         _addressBookTypeList_ = NULL;
3022
3023         /* Interface */
3024         atci = g_new0( AddressTypeControlItem, 1 );
3025         atci->objectType = ADDR_INTERFACE;
3026         atci->interfaceType = ADDR_IF_NONE;
3027         atci->showInTree = TRUE;
3028         atci->treeExpand = TRUE;
3029         atci->treeLeaf = FALSE;
3030         atci->displayName = _( "Interface" );
3031         atci->iconXpm = folderxpm;
3032         atci->maskXpm = folderxpmmask;
3033         atci->iconXpmOpen = folderopenxpm;
3034         atci->maskXpmOpen = folderopenxpmmask;
3035         atci->menuCommand = NULL;
3036         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3037         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3038
3039         /* Address book  */
3040         atci = g_new0( AddressTypeControlItem, 1 );
3041         atci->objectType = ADDR_BOOK;
3042         atci->interfaceType = ADDR_IF_BOOK;
3043         atci->showInTree = TRUE;
3044         atci->treeExpand = TRUE;
3045         atci->treeLeaf = FALSE;
3046         atci->displayName = _( "Address Book" );
3047         atci->iconXpm = bookxpm;
3048         atci->maskXpm = bookxpmmask;
3049         atci->iconXpmOpen = bookxpm;
3050         atci->maskXpmOpen = bookxpmmask;
3051         atci->menuCommand = "/File/New Book";
3052         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3053         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3054
3055         /* Item person */
3056         atci = g_new0( AddressTypeControlItem, 1 );
3057         atci->objectType = ADDR_ITEM_PERSON;
3058         atci->interfaceType = ADDR_IF_NONE;
3059         atci->showInTree = FALSE;
3060         atci->treeExpand = FALSE;
3061         atci->treeLeaf = FALSE;
3062         atci->displayName = _( "Person" );
3063         atci->iconXpm = NULL;
3064         atci->maskXpm = NULL;
3065         atci->iconXpmOpen = NULL;
3066         atci->maskXpmOpen = NULL;
3067         atci->menuCommand = NULL;
3068         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3069         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3070
3071         /* Item email */
3072         atci = g_new0( AddressTypeControlItem, 1 );
3073         atci->objectType = ADDR_ITEM_EMAIL;
3074         atci->interfaceType = ADDR_IF_NONE;
3075         atci->showInTree = FALSE;
3076         atci->treeExpand = FALSE;
3077         atci->treeLeaf = TRUE;
3078         atci->displayName = _( "EMail Address" );
3079         atci->iconXpm = addressxpm;
3080         atci->maskXpm = addressxpmmask;
3081         atci->iconXpmOpen = addressxpm;
3082         atci->maskXpmOpen = addressxpmmask;
3083         atci->menuCommand = NULL;
3084         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3085         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3086
3087         /* Item group */
3088         atci = g_new0( AddressTypeControlItem, 1 );
3089         atci->objectType = ADDR_ITEM_GROUP;
3090         atci->interfaceType = ADDR_IF_BOOK;
3091         atci->showInTree = TRUE;
3092         atci->treeExpand = FALSE;
3093         atci->treeLeaf = FALSE;
3094         atci->displayName = _( "Group" );
3095         atci->iconXpm = groupxpm;
3096         atci->maskXpm = groupxpmmask;
3097         atci->iconXpmOpen = groupxpm;
3098         atci->maskXpmOpen = groupxpmmask;
3099         atci->menuCommand = NULL;
3100         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3101         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3102
3103         /* Item folder */
3104         atci = g_new0( AddressTypeControlItem, 1 );
3105         atci->objectType = ADDR_ITEM_FOLDER;
3106         atci->interfaceType = ADDR_IF_BOOK;
3107         atci->showInTree = TRUE;
3108         atci->treeExpand = FALSE;
3109         atci->treeLeaf = FALSE;
3110         atci->displayName = _( "Folder" );
3111         atci->iconXpm = folderxpm;
3112         atci->maskXpm = folderxpmmask;
3113         atci->iconXpmOpen = folderopenxpm;
3114         atci->maskXpmOpen = folderopenxpmmask;
3115         atci->menuCommand = NULL;
3116         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3117         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3118
3119         /* V-Card */
3120         atci = g_new0( AddressTypeControlItem, 1 );
3121         atci->objectType = ADDR_VCARD;
3122         atci->interfaceType = ADDR_IF_VCARD;
3123         atci->showInTree = TRUE;
3124         atci->treeExpand = TRUE;
3125         atci->treeLeaf = TRUE;
3126         atci->displayName = _( "V-Card" );
3127         atci->iconXpm = vcardxpm;
3128         atci->maskXpm = vcardxpmmask;
3129         atci->iconXpmOpen = vcardxpm;
3130         atci->maskXpmOpen = vcardxpmmask;
3131         atci->menuCommand = "/File/New V-Card";
3132         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3133         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3134
3135         /* J-Pilot */
3136         atci = g_new0( AddressTypeControlItem, 1 );
3137         atci->objectType = ADDR_JPILOT;
3138         atci->interfaceType = ADDR_IF_JPILOT;
3139         atci->showInTree = TRUE;
3140         atci->treeExpand = TRUE;
3141         atci->treeLeaf = FALSE;
3142         atci->displayName = _( "J-Pilot" );
3143         atci->iconXpm = jpilotxpm;
3144         atci->maskXpm = jpilotxpmmask;
3145         atci->iconXpmOpen = jpilotxpm;
3146         atci->maskXpmOpen = jpilotxpmmask;
3147         atci->menuCommand = "/File/New J-Pilot";
3148         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3149         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3150
3151         /* Category */
3152         atci = g_new0( AddressTypeControlItem, 1 );
3153         atci->objectType = ADDR_CATEGORY;
3154         atci->interfaceType = ADDR_IF_JPILOT;
3155         atci->showInTree = TRUE;
3156         atci->treeExpand = TRUE;
3157         atci->treeLeaf = TRUE;
3158         atci->displayName = _( "J-Pilot" );
3159         atci->iconXpm = categoryxpm;
3160         atci->maskXpm = categoryxpmmask;
3161         atci->iconXpmOpen = categoryxpm;
3162         atci->maskXpmOpen = categoryxpmmask;
3163         atci->menuCommand = NULL;
3164         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3165         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3166
3167         /* LDAP Server */
3168         atci = g_new0( AddressTypeControlItem, 1 );
3169         atci->objectType = ADDR_LDAP;
3170         atci->interfaceType = ADDR_IF_LDAP;
3171         atci->showInTree = TRUE;
3172         atci->treeExpand = TRUE;
3173         atci->treeLeaf = TRUE;
3174         atci->displayName = _( "LDAP Server" );
3175         atci->iconXpm = ldapxpm;
3176         atci->maskXpm = ldapxpmmask;
3177         atci->iconXpmOpen = ldapxpm;
3178         atci->maskXpmOpen = ldapxpmmask;
3179         atci->menuCommand = "/File/New Server";
3180         g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
3181         _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
3182
3183 }
3184
3185 /*
3186 * Search for specified object type.
3187 */
3188 AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
3189         gint objType = ot;
3190         return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
3191 }
3192
3193 /*
3194 * Search for specified interface type.
3195 */
3196 AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
3197         GList *node = _addressBookTypeList_;
3198         while( node ) {
3199                 AddressTypeControlItem *atci = node->data;
3200                 if( atci->interfaceType == ifType ) return atci;
3201                 node = g_list_next( node );
3202         }
3203         return NULL;
3204 }
3205
3206 static void addrbookctl_free_address( AddressObject *obj ) {
3207         g_free( obj->name );
3208         obj->type = ADDR_NONE;
3209         obj->name = NULL;
3210 }
3211
3212 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
3213         addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
3214         adapter->interface = NULL;
3215         adapter->interfaceType = ADDR_IF_NONE;
3216         adapter->atci = NULL;
3217         adapter->enabled = FALSE;
3218         adapter->haveLibrary = FALSE;
3219         adapter->treeNode = NULL;
3220         g_free( adapter );
3221 }
3222
3223 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
3224         addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
3225         adapter->dataSource = NULL;
3226         adapter->subType = ADDR_NONE;
3227         g_free( adapter );
3228 }
3229
3230 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
3231         addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
3232         adapter->itemFolder = NULL;
3233         g_free( adapter );
3234 }
3235
3236 static void addrbookctl_free_group( AdapterGroup *adapter ) {
3237         addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
3238         adapter->itemGroup = NULL;
3239         g_free( adapter );
3240 }
3241
3242 /*
3243  * Build GUI interface list.
3244  */
3245 void addrbookctl_build_iflist() {
3246         AddressTypeControlItem *atci;
3247         AdapterInterface *adapter;
3248         GList *list = NULL;
3249
3250         if( _addressIndex_ == NULL ) {
3251                 _addressIndex_ = addrindex_create_index();
3252         }
3253         _addressInterfaceList_ = NULL;
3254         list = addrindex_get_interface_list( _addressIndex_ );
3255         while( list ) {
3256                 AddressInterface *interface = list->data;
3257                 atci = addrbookctl_lookup_iface( interface->type );
3258                 if( atci ) {
3259                         adapter = g_new0( AdapterInterface, 1 );
3260                         adapter->interfaceType = interface->type;
3261                         adapter->atci = atci;
3262                         adapter->interface = interface;
3263                         adapter->treeNode = NULL;
3264                         adapter->enabled = TRUE;
3265                         adapter->haveLibrary = interface->haveLibrary;
3266                         ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
3267                         ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
3268                         _addressInterfaceList_ = g_list_append( _addressInterfaceList_, adapter );
3269                 }
3270                 list = g_list_next( list );
3271         }
3272 }
3273
3274 void addrbookctl_free_selection( GList *list ) {
3275         GList *node = list;
3276         while( node ) {
3277                 AdapterInterface *adapter = node->data;
3278                 adapter = NULL;
3279                 node = g_list_next( node );
3280         }
3281         g_list_free( list );
3282 }
3283
3284 /*
3285 * Find GUI interface type specified interface type.
3286 * Return: Interface item, or NULL if not found.
3287 */
3288 AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
3289         GList *node = _addressInterfaceList_;
3290         while( node ) {
3291                 AdapterInterface *adapter = node->data;
3292                 if( adapter->interfaceType == ifType ) return adapter;
3293                 node = g_list_next( node );
3294         }
3295         return NULL;
3296 }
3297
3298 /*
3299 * Build interface list selection.
3300 */
3301 void addrbookctl_build_ifselect() {
3302         GList *newList = NULL;
3303         gchar *selectStr;
3304         gchar **splitStr;
3305         gint ifType;
3306         gint i;
3307         gchar *endptr = NULL;
3308         gboolean enabled;
3309         AdapterInterface *adapter;
3310         /* GList *node; */
3311
3312         selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
3313
3314         /* Parse string */
3315         splitStr = g_strsplit( selectStr, ",", -1 );
3316         for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
3317                 if( splitStr[i] ) {
3318                         /* printf( "%d : %s\n", i, splitStr[i] ); */
3319                         ifType = strtol( splitStr[i], &endptr, 10 );
3320                         enabled = TRUE;
3321                         if( *endptr ) {
3322                                 if( strcmp( endptr, "/n" ) == 0 ) {
3323                                         enabled = FALSE;
3324                                 }
3325                         }
3326                         /* printf( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
3327                         adapter = addrbookctl_find_interface( ifType );
3328                         if( adapter ) {
3329                                 newList = g_list_append( newList, adapter );
3330                         }
3331                 }
3332                 else {
3333                         break;
3334                 }
3335         }
3336         /* printf( "i=%d\n", i ); */
3337         g_strfreev( splitStr );
3338         g_free( selectStr );
3339
3340         /* Replace existing list */
3341         mgu_clear_list( _addressIFaceSelection_ );
3342         g_list_free( _addressIFaceSelection_ );
3343         _addressIFaceSelection_ = newList;
3344         newList = NULL;
3345
3346 }
3347
3348 /* **********************************************************************
3349 * Add sender to address book.
3350 * ***********************************************************************
3351 */
3352
3353 /*
3354  * This function is used by the Add sender to address book function.
3355  */
3356 gboolean addressbook_add_contact( const gchar *name, const gchar *address, const gchar *remarks ) {
3357         debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
3358         if( addressadd_selection( _addressIndex_, name, address, remarks ) ) {
3359                 debug_print( "addressbook_add_contact - added\n" );
3360                 addressbook_refresh();
3361         }
3362         return TRUE;
3363 }
3364
3365 /* **********************************************************************
3366 * Address completion support.
3367 * ***********************************************************************
3368 */
3369
3370 /*
3371 * This function is used by the address completion function to load
3372 * addresses.
3373 * Enter: callBackFunc Function to be called when an address is
3374 *                     to be loaded.
3375 * Return: TRUE if data loaded, FALSE if address index not loaded.
3376 */
3377 gboolean addressbook_load_completion( gint (*callBackFunc) ( const gchar *, const gchar * ) ) {
3378         /* AddressInterface *interface; */
3379         AddressDataSource *ds;
3380         GList *nodeIf, *nodeDS;
3381         GList *listP, *nodeP;
3382         GList *nodeM;
3383         gchar *sName, *sAddress, *sAlias, *sFriendly;
3384
3385         debug_print( "addressbook_load_completion\n" );
3386
3387         if( _addressIndex_ == NULL ) return FALSE;
3388
3389         nodeIf = addrindex_get_interface_list( _addressIndex_ );
3390         while( nodeIf ) {
3391                 AddressInterface *interface = nodeIf->data;
3392                 nodeDS = interface->listSource;
3393                 while( nodeDS ) {
3394                         ds = nodeDS->data;
3395
3396                         /* Read address book */
3397                         if( ! addrindex_ds_get_read_flag( ds ) ) {
3398                                 addrindex_ds_read_data( ds );
3399                         }
3400
3401                         /* Get all persons */
3402                         listP = addrindex_ds_get_all_persons( ds );
3403                         nodeP = listP;
3404                         while( nodeP ) {
3405                                 ItemPerson *person = nodeP->data;
3406                                 nodeM = person->listEMail;
3407
3408                                 /* Figure out name to use */
3409                                 sName = person->nickName;
3410                                 if( sName == NULL || *sName == '\0' ) {
3411                                         sName = ADDRITEM_NAME(person);
3412                                 }
3413
3414                                 /* Process each E-Mail address */
3415                                 while( nodeM ) {
3416                                         ItemEMail *email = nodeM->data;
3417                                         /* Have mail */
3418                                         sFriendly = sName;
3419                                         sAddress = email->address;
3420                                         if( sAddress || *sAddress != '\0' ) {
3421                                                 sAlias = ADDRITEM_NAME(email);
3422                                                 if( sAlias && *sAlias != '\0' ) {
3423                                                         sFriendly = sAlias;
3424                                                 }
3425                                                 ( callBackFunc ) ( sFriendly, sAddress );
3426                                         }
3427
3428                                         nodeM = g_list_next( nodeM );
3429                                 }
3430                                 nodeP = g_list_next( nodeP );
3431                         }
3432                         /* Free up the list */
3433                         g_list_free( listP );
3434
3435                         nodeDS = g_list_next( nodeDS );
3436                 }
3437                 nodeIf = g_list_next( nodeIf );
3438         }
3439         debug_print( "addressbook_load_completion... done\n" );
3440
3441         return TRUE;
3442 }
3443
3444 /*
3445 * End of Source.
3446 */
3447