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