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