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