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