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