initial message templates support
[claws.git] / src / addressbook.c
blob53ee299655e89049b54d695a1fec43b4cca2415d
1 /*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999,2000 Hiroyuki Yamamoto
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.
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.
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.
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
24 #include "defs.h"
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>
47 #include "intl.h"
48 #include "main.h"
49 #include "addressbook.h"
50 #include "manage_window.h"
51 #include "prefs_common.h"
52 #include "alertpanel.h"
53 #include "inputdialog.h"
54 #include "menu.h"
55 #include "xml.h"
56 #include "prefs.h"
57 #include "procmime.h"
58 #include "utils.h"
59 #include "gtkutils.h"
60 #include "codeconv.h"
61 #include "about.h"
62 #include "addr_compl.h"
64 #include "addressitem.h"
65 #include "vcard.h"
66 #include "editvcard.h"
68 #ifdef USE_JPILOT
69 #include "jpilot.h"
70 #include "editjpilot.h"
71 #endif
73 #ifdef USE_LDAP
74 #include <pthread.h>
75 #include "syldap.h"
76 #include "editldap.h"
78 // Interval to check for LDAP search results
79 // #define ADDRESSBOOK_LDAP_TIMER_INTERVAL 100
80 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
82 #endif
84 #include "pixmaps/dir-close.xpm"
85 #include "pixmaps/dir-open.xpm"
86 #include "pixmaps/group.xpm"
87 #include "pixmaps/vcard.xpm"
88 #ifdef USE_JPILOT
89 #include "pixmaps/jpilot.xpm"
90 #include "pixmaps/category.xpm"
91 #endif
92 #ifdef USE_LDAP
93 #include "pixmaps/ldap.xpm"
94 #endif
96 // XML tag names for top level folders
97 #define ADDRESS_TAG_COMMON "common_address"
98 #define ADDRESS_TAG_PERSONAL "personal_address"
99 #define ADDRESS_TAG_VCARD "vcard_list"
100 #ifdef USE_JPILOT
101 #define ADDRESS_TAG_JPILOT "jpilot_list"
102 #endif
103 #ifdef USE_LDAP
104 #define ADDRESS_TAG_LDAP "ldap_list"
105 #endif
107 typedef enum
109 COL_NAME = 0,
110 COL_ADDRESS = 1,
111 COL_REMARKS = 2
112 } AddressBookColumnPos;
114 #define N_COLS 3
115 #define COL_NAME_WIDTH 144
116 #define COL_ADDRESS_WIDTH 156
118 #define COL_FOLDER_WIDTH 170
119 #define ADDRESSBOOK_WIDTH 640
120 #define ADDRESSBOOK_HEIGHT 360
122 #define ADDRESSBOOK_MSGBUF_SIZE 2048
124 static GdkPixmap *folderxpm;
125 static GdkBitmap *folderxpmmask;
126 static GdkPixmap *folderopenxpm;
127 static GdkBitmap *folderopenxpmmask;
128 static GdkPixmap *groupxpm;
129 static GdkBitmap *groupxpmmask;
130 static GdkPixmap *vcardxpm;
131 static GdkBitmap *vcardxpmmask;
132 #ifdef USE_JPILOT
133 static GdkPixmap *jpilotxpm;
134 static GdkBitmap *jpilotxpmmask;
135 static GdkPixmap *categoryxpm;
136 static GdkBitmap *categoryxpmmask;
137 #endif
138 #ifdef USE_LDAP
139 static GdkPixmap *ldapxpm;
140 static GdkBitmap *ldapxpmmask;
141 #endif
143 // Pilot library indicator (set at run-time)
144 static _have_pilot_library_;
146 // LDAP library indicator (set at run-time)
147 static _have_ldap_library_;
149 // Message buffer
150 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
152 static AddressBook addrbook;
154 static struct _AddressEdit
156 GtkWidget *window;
157 GtkWidget *name_entry;
158 GtkWidget *addr_entry;
159 GtkWidget *rem_entry;
160 GtkWidget *ok_btn;
161 GtkWidget *cancel_btn;
162 } addredit;
164 static void addressbook_create (gboolean show);
165 static gint addressbook_close (void);
166 static void addressbook_button_set_sensitive (void);
168 /* callback functions */
169 static void addressbook_del_clicked (GtkButton *button,
170 gpointer data);
171 static void addressbook_reg_clicked (GtkButton *button,
172 gpointer data);
173 static void addressbook_to_clicked (GtkButton *button,
174 gpointer data);
175 static void addressbook_lup_clicked (GtkButton *button,
176 gpointer data);
178 static void addressbook_tree_selected (GtkCTree *ctree,
179 GtkCTreeNode *node,
180 gint column,
181 gpointer data);
182 static void addressbook_list_selected (GtkCList *clist,
183 gint row,
184 gint column,
185 GdkEvent *event,
186 gpointer data);
187 static void addressbook_entry_gotfocus (GtkWidget *widget);
189 #if 0
190 static void addressbook_entry_changed (GtkWidget *widget);
191 #endif
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);
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_edit_folder_cb (gpointer data,
215 guint action,
216 GtkWidget *widget);
217 static void addressbook_delete_folder_cb (gpointer data,
218 guint action,
219 GtkWidget *widget);
221 static void addressbook_change_node_name (GtkCTreeNode *node,
222 const gchar *name);
223 static void addressbook_edit_group (GtkCTreeNode *group_node);
225 static void addressbook_edit_address_create (gboolean *cancelled);
226 static void edit_address_ok (GtkWidget *widget,
227 gboolean *cancelled);
228 static void edit_address_cancel (GtkWidget *widget,
229 gboolean *cancelled);
230 static gint edit_address_delete_event (GtkWidget *widget,
231 GdkEventAny *event,
232 gboolean *cancelled);
233 static void edit_address_key_pressed (GtkWidget *widget,
234 GdkEventKey *event,
235 gboolean *cancelled);
236 static AddressItem *addressbook_edit_address (AddressItem *item);
238 static void addressbook_new_address_cb (gpointer data,
239 guint action,
240 GtkWidget *widget);
241 static void addressbook_edit_address_cb (gpointer data,
242 guint action,
243 GtkWidget *widget);
244 static void addressbook_delete_address_cb (gpointer data,
245 guint action,
246 GtkWidget *widget);
248 static void close_cb (gpointer data,
249 guint action,
250 GtkWidget *widget);
252 // VCard edit stuff
253 static void addressbook_new_vcard_cb ( gpointer data,
254 guint action,
255 GtkWidget *widget );
257 #ifdef USE_JPILOT
258 // JPilot edit stuff
259 static void addressbook_new_jpilot_cb ( gpointer data,
260 guint action,
261 GtkWidget *widget );
262 #endif
264 #ifdef USE_LDAP
265 // LDAP edit stuff
266 static void addressbook_new_ldap_cb ( gpointer data,
267 guint action,
268 GtkWidget *widget );
269 #endif
271 static AddressItem *addressbook_parse_address (const gchar *str);
272 static void addressbook_append_to_compose_entry (AddressItem *item,
273 ComposeEntryType type);
275 static void addressbook_set_clist (AddressObject *obj);
277 static void addressbook_read_file (void);
278 static void addressbook_get_tree (XMLFile *file,
279 GtkCTreeNode *node,
280 const gchar *folder_tag);
281 static void addressbook_add_objs (XMLFile *file,
282 GtkCTreeNode *node);
284 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
285 AddressObject *obj);
286 static void addressbook_delete_object (AddressObject *obj);
287 static AddressObject *addressbook_find_object_by_name
288 (GtkCTreeNode *node,
289 const gchar *name);
291 static AddressItem *addressbook_parse_item (XMLFile *file);
292 static void addressbook_xml_recursive_write (GtkCTreeNode *node,
293 FILE *fp);
294 static void addressbook_node_write_begin (GtkCTreeNode *node,
295 FILE *fp);
296 static void addressbook_node_write_end (GtkCTreeNode *node,
297 FILE *fp);
298 static void addressbook_write_items (FILE *fp,
299 GList *items,
300 guint level);
301 static void tab_indent_out (FILE *fp,
302 guint level);
304 static void key_pressed (GtkWidget *widget,
305 GdkEventKey *event,
306 gpointer data);
307 static gint addressbook_list_compare_func (GtkCList *clist,
308 gconstpointer ptr1,
309 gconstpointer ptr2);
310 static gint addressbook_obj_name_compare (gconstpointer a,
311 gconstpointer b);
313 static AddressVCard *addressbook_parse_vcard ( XMLFile *file );
314 static void addressbook_write_vcard ( FILE *fp,
315 AddressVCard *vcard,
316 guint level );
317 static void addressbook_vcard_show_message ( VCardFile *vcf );
319 #ifdef USE_JPILOT
320 static AddressJPilot *addressbook_parse_jpilot ( XMLFile *file );
321 static void addressbook_write_jpilot ( FILE *fp,
322 AddressJPilot *jpilot,
323 guint level );
324 static void addressbook_jpilot_show_message ( JPilotFile *jpf );
325 #endif
326 #ifdef USE_LDAP
327 static AddressLDAP *addressbook_parse_ldap ( XMLFile *file );
328 static void addressbook_write_ldap ( FILE *fp,
329 AddressLDAP *ldapi,
330 guint level );
331 static void addressbook_ldap_show_message ( SyldapServer *server );
332 #endif
334 static GtkItemFactoryEntry addressbook_entries[] =
336 {N_("/_File"), NULL, NULL, 0, "<Branch>"},
337 {N_("/_File/New _Address"), "<alt>N", addressbook_new_address_cb, 0, NULL},
338 {N_("/_File/New _Group"), "<alt>G", addressbook_new_group_cb, 0, NULL},
339 {N_("/_File/New _Folder"), "<alt>R", addressbook_new_folder_cb, 0, NULL},
340 {N_("/_File/New _V-Card"), "<alt>D", addressbook_new_vcard_cb, 0, NULL},
341 #ifdef USE_JPILOT
342 {N_("/_File/New _J-Pilot"), "<alt>J", addressbook_new_jpilot_cb, 0, NULL},
343 #endif
344 #ifdef USE_LDAP
345 {N_("/_File/New _Server"), "<alt>S", addressbook_new_ldap_cb, 0, NULL},
346 #endif
347 {N_("/_File/---"), NULL, NULL, 0, "<Separator>"},
348 {N_("/_File/_Edit"), "<alt>Return", addressbook_edit_address_cb, 0, NULL},
349 {N_("/_File/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL},
350 {N_("/_File/---"), NULL, NULL, 0, "<Separator>"},
351 {N_("/_File/_Close"), "<alt>W", close_cb, 0, NULL},
352 {N_("/_Help"), NULL, NULL, 0, "<LastBranch>"},
353 {N_("/_Help/_About"), NULL, about_show, 0, NULL}
356 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
358 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL},
359 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
360 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL},
361 {N_("/New _V-Card"), NULL, addressbook_new_vcard_cb, 0, NULL},
362 #ifdef USE_JPILOT
363 {N_("/New _J-Pilot"), NULL, addressbook_new_jpilot_cb, 0, NULL},
364 #endif
365 #ifdef USE_LDAP
366 {N_("/New _Server"), NULL, addressbook_new_ldap_cb, 0, NULL},
367 #endif
368 {N_("/---"), NULL, NULL, 0, "<Separator>"},
369 {N_("/_Edit"), NULL, addressbook_edit_folder_cb, 0, NULL},
370 {N_("/_Delete"), NULL, addressbook_delete_folder_cb, 0, NULL}
373 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
375 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL},
376 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL},
377 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL},
378 {N_("/---"), NULL, NULL, 0, "<Separator>"},
379 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL},
380 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL}
383 void addressbook_open(Compose *target)
385 if (!addrbook.window) {
386 addressbook_create(TRUE);
387 addressbook_read_file();
388 addrbook.open_folder = TRUE;
389 gtk_ctree_select(GTK_CTREE(addrbook.ctree),
390 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
391 } else
392 gtk_widget_hide(addrbook.window);
394 gtk_widget_show_all(addrbook.window);
396 addressbook_set_target_compose(target);
399 void addressbook_set_target_compose(Compose *target)
401 addrbook.target_compose = target;
403 addressbook_button_set_sensitive();
406 Compose *addressbook_get_target_compose(void)
408 return addrbook.target_compose;
411 static void addressbook_create(gboolean show)
413 GtkWidget *window;
414 GtkWidget *vbox;
415 GtkWidget *menubar;
416 GtkWidget *vbox2;
417 GtkWidget *ctree_swin;
418 GtkWidget *ctree;
419 GtkWidget *clist_vbox;
420 GtkWidget *clist_swin;
421 GtkWidget *clist;
422 GtkWidget *paned;
423 GtkWidget *hbox;
424 GtkWidget *label;
425 GtkWidget *entry;
426 GtkWidget *statusbar;
427 GtkWidget *hmbox;
428 GtkWidget *hbbox;
429 GtkWidget *hsbox;
430 GtkWidget *del_btn;
431 GtkWidget *reg_btn;
432 GtkWidget *lup_btn;
433 GtkWidget *to_btn;
434 GtkWidget *cc_btn;
435 GtkWidget *bcc_btn;
436 GtkWidget *tree_popup;
437 GtkWidget *list_popup;
438 GtkItemFactory *tree_factory;
439 GtkItemFactory *list_factory;
440 GtkItemFactory *menu_factory;
441 gint n_entries;
443 gchar *titles[N_COLS] = {_("Name"), _("E-Mail address"), _("Remarks")};
444 gchar *text;
445 gint i;
447 debug_print("Creating addressbook window...\n");
449 // Global flag if we have library installed (at run-time)
450 _have_pilot_library_ = FALSE;
451 _have_ldap_library_ = FALSE;
453 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
454 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
455 gtk_widget_set_usize(window, ADDRESSBOOK_WIDTH, ADDRESSBOOK_HEIGHT);
456 //gtk_container_set_border_width(GTK_CONTAINER(window), BORDER_WIDTH);
457 gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, TRUE);
458 gtk_widget_realize(window);
460 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
461 GTK_SIGNAL_FUNC(addressbook_close), NULL);
462 gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
463 GTK_SIGNAL_FUNC(key_pressed), NULL);
464 gtk_signal_connect(GTK_OBJECT(window), "focus_in_event",
465 GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
466 gtk_signal_connect(GTK_OBJECT(window), "focus_out_event",
467 GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
469 vbox = gtk_vbox_new(FALSE, 0);
470 gtk_container_add(GTK_CONTAINER(window), vbox);
472 n_entries = sizeof(addressbook_entries) /
473 sizeof(addressbook_entries[0]);
474 menubar = menubar_create(window, addressbook_entries, n_entries,
475 "<AddressBook>", NULL);
476 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
477 menu_factory = gtk_item_factory_from_widget(menubar);
479 vbox2 = gtk_vbox_new(FALSE, 4);
480 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
481 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
483 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
484 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
485 GTK_POLICY_AUTOMATIC,
486 GTK_POLICY_ALWAYS);
487 gtk_widget_set_usize(ctree_swin, COL_FOLDER_WIDTH + 40, -1);
489 ctree = gtk_ctree_new(1, 0);
490 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
491 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
492 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
493 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
494 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
495 GTK_CTREE_EXPANDER_SQUARE);
496 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
497 gtk_clist_set_compare_func(GTK_CLIST(ctree),
498 addressbook_list_compare_func);
500 gtk_signal_connect(GTK_OBJECT(ctree), "tree_select_row",
501 GTK_SIGNAL_FUNC(addressbook_tree_selected), NULL);
502 gtk_signal_connect(GTK_OBJECT(ctree), "button_press_event",
503 GTK_SIGNAL_FUNC(addressbook_tree_button_pressed),
504 NULL);
505 gtk_signal_connect(GTK_OBJECT(ctree), "button_release_event",
506 GTK_SIGNAL_FUNC(addressbook_tree_button_released),
507 NULL);
509 clist_vbox = gtk_vbox_new(FALSE, 4);
511 clist_swin = gtk_scrolled_window_new(NULL, NULL);
512 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
513 GTK_POLICY_AUTOMATIC,
514 GTK_POLICY_ALWAYS);
515 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
517 clist = gtk_clist_new_with_titles(N_COLS, titles);
518 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
519 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
520 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
521 COL_NAME_WIDTH);
522 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
523 COL_ADDRESS_WIDTH);
524 gtk_clist_set_compare_func(GTK_CLIST(clist),
525 addressbook_list_compare_func);
527 for (i = 0; i < N_COLS; i++)
528 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
529 GTK_CAN_FOCUS);
531 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
532 GTK_SIGNAL_FUNC(addressbook_list_selected), NULL);
533 gtk_signal_connect(GTK_OBJECT(clist), "button_press_event",
534 GTK_SIGNAL_FUNC(addressbook_list_button_pressed),
535 NULL);
536 gtk_signal_connect(GTK_OBJECT(clist), "button_release_event",
537 GTK_SIGNAL_FUNC(addressbook_list_button_released),
538 NULL);
540 hbox = gtk_hbox_new(FALSE, 4);
541 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
543 label = gtk_label_new(_("Name:"));
544 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
546 entry = gtk_entry_new();
547 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
549 address_completion_register_entry(GTK_ENTRY(entry));
550 gtk_signal_connect(GTK_OBJECT(entry), "focus_in_event",
551 GTK_SIGNAL_FUNC(addressbook_entry_gotfocus), NULL);
553 #if 0
554 gtk_signal_connect(GTK_OBJECT(entry), "changed",
555 GTK_SIGNAL_FUNC(addressbook_entry_changed), NULL);
556 #endif
558 paned = gtk_hpaned_new();
559 gtk_box_pack_start(GTK_BOX(vbox2), paned, TRUE, TRUE, 0);
560 gtk_paned_add1(GTK_PANED(paned), ctree_swin);
561 gtk_paned_add2(GTK_PANED(paned), clist_vbox);
563 // Status bar
564 hsbox = gtk_hbox_new(FALSE, 0);
565 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
566 statusbar = gtk_statusbar_new();
567 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
569 // Button panel
570 hbbox = gtk_hbutton_box_new();
571 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
572 gtk_button_box_set_spacing(GTK_BUTTON_BOX(hbbox), 2);
573 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
575 del_btn = gtk_button_new_with_label(_("Delete"));
576 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
577 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
578 reg_btn = gtk_button_new_with_label(_("Add"));
579 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
580 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
581 lup_btn = gtk_button_new_with_label(_("Lookup"));
582 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
583 gtk_box_pack_start(GTK_BOX(hbbox), lup_btn, TRUE, TRUE, 0);
585 gtk_signal_connect(GTK_OBJECT(del_btn), "clicked",
586 GTK_SIGNAL_FUNC(addressbook_del_clicked), NULL);
587 gtk_signal_connect(GTK_OBJECT(reg_btn), "clicked",
588 GTK_SIGNAL_FUNC(addressbook_reg_clicked), NULL);
589 gtk_signal_connect(GTK_OBJECT(lup_btn), "clicked",
590 GTK_SIGNAL_FUNC(addressbook_lup_clicked), NULL);
592 to_btn = gtk_button_new_with_label
593 (prefs_common.trans_hdr ? _("To:") : "To:");
594 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
595 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
596 cc_btn = gtk_button_new_with_label
597 (prefs_common.trans_hdr ? _("Cc:") : "Cc:");
598 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
599 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
600 bcc_btn = gtk_button_new_with_label
601 (prefs_common.trans_hdr ? _("Bcc:") : "Bcc:");
602 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
603 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
605 gtk_signal_connect(GTK_OBJECT(to_btn), "clicked",
606 GTK_SIGNAL_FUNC(addressbook_to_clicked),
607 GINT_TO_POINTER(COMPOSE_TO));
608 gtk_signal_connect(GTK_OBJECT(cc_btn), "clicked",
609 GTK_SIGNAL_FUNC(addressbook_to_clicked),
610 GINT_TO_POINTER(COMPOSE_CC));
611 gtk_signal_connect(GTK_OBJECT(bcc_btn), "clicked",
612 GTK_SIGNAL_FUNC(addressbook_to_clicked),
613 GINT_TO_POINTER(COMPOSE_BCC));
615 PIXMAP_CREATE(window, folderxpm, folderxpmmask, DIRECTORY_CLOSE_XPM);
616 PIXMAP_CREATE(window, folderopenxpm, folderopenxpmmask,
617 DIRECTORY_OPEN_XPM);
618 PIXMAP_CREATE(window, groupxpm, groupxpmmask, group_xpm);
619 PIXMAP_CREATE(window, vcardxpm, vcardxpmmask, vcard_xpm);
620 #ifdef USE_JPILOT
621 PIXMAP_CREATE(window, jpilotxpm, jpilotxpmmask, jpilot_xpm);
622 PIXMAP_CREATE(window, categoryxpm, categoryxpmmask, category_xpm);
623 #endif
624 #ifdef USE_LDAP
625 PIXMAP_CREATE(window, ldapxpm, ldapxpmmask, ldap_xpm);
626 #endif
628 text = _("Common address");
629 addrbook.common =
630 gtk_ctree_insert_node(GTK_CTREE(ctree),
631 NULL, NULL, &text, FOLDER_SPACING,
632 folderxpm, folderxpmmask,
633 folderopenxpm, folderopenxpmmask,
634 FALSE, FALSE);
635 text = _("Personal address");
636 addrbook.personal =
637 gtk_ctree_insert_node(GTK_CTREE(ctree),
638 NULL, NULL, &text, FOLDER_SPACING,
639 folderxpm, folderxpmmask,
640 folderopenxpm, folderopenxpmmask,
641 FALSE, FALSE);
643 text = _("V-Card");
644 addrbook.vcard =
645 gtk_ctree_insert_node(GTK_CTREE(ctree),
646 NULL, NULL, &text, FOLDER_SPACING,
647 folderxpm, folderxpmmask,
648 folderopenxpm, folderopenxpmmask,
649 FALSE, FALSE);
651 #ifdef USE_JPILOT
652 text = _("J-Pllot");
653 addrbook.jpilot =
654 gtk_ctree_insert_node(GTK_CTREE(ctree),
655 NULL, NULL, &text, FOLDER_SPACING,
656 folderxpm, folderxpmmask,
657 folderopenxpm, folderopenxpmmask,
658 FALSE, FALSE);
659 if( jpilot_test_pilot_lib() ) {
660 _have_pilot_library_ = TRUE;
661 menu_set_sensitive( menu_factory, "/File/New J-Pilot", TRUE );
663 else {
664 menu_set_sensitive( menu_factory, "/File/New J-Pilot", FALSE );
666 #endif
668 #ifdef USE_LDAP
669 text = _("Directory");
670 addrbook.ldap =
671 gtk_ctree_insert_node(GTK_CTREE(ctree),
672 NULL, NULL, &text, FOLDER_SPACING,
673 folderxpm, folderxpmmask,
674 folderopenxpm, folderopenxpmmask,
675 FALSE, FALSE);
676 if( syldap_test_ldap_lib() ) {
677 _have_ldap_library_ = TRUE;
678 menu_set_sensitive( menu_factory, "/File/New Server", TRUE );
680 else {
681 menu_set_sensitive( menu_factory, "/File/New Server", FALSE );
683 #endif
685 /* popup menu */
686 n_entries = sizeof(addressbook_tree_popup_entries) /
687 sizeof(addressbook_tree_popup_entries[0]);
688 tree_popup = menu_create_items(addressbook_tree_popup_entries,
689 n_entries,
690 "<AddressBookTree>", &tree_factory,
691 NULL);
692 gtk_signal_connect(GTK_OBJECT(tree_popup), "selection_done",
693 GTK_SIGNAL_FUNC(addressbook_popup_close), NULL);
694 n_entries = sizeof(addressbook_list_popup_entries) /
695 sizeof(addressbook_list_popup_entries[0]);
696 list_popup = menu_create_items(addressbook_list_popup_entries,
697 n_entries,
698 "<AddressBookList>", &list_factory,
699 NULL);
701 addrbook.window = window;
702 addrbook.menubar = menubar;
703 addrbook.ctree = ctree;
704 addrbook.clist = clist;
705 addrbook.entry = entry;
706 addrbook.statusbar = statusbar;
707 addrbook.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Addressbook Window" );
709 addrbook.del_btn = del_btn;
710 addrbook.reg_btn = reg_btn;
711 addrbook.lup_btn = lup_btn;
712 addrbook.to_btn = to_btn;
713 addrbook.cc_btn = cc_btn;
714 addrbook.bcc_btn = bcc_btn;
716 addrbook.tree_popup = tree_popup;
717 addrbook.list_popup = list_popup;
718 addrbook.tree_factory = tree_factory;
719 addrbook.list_factory = list_factory;
720 addrbook.menu_factory = menu_factory;
722 address_completion_start(window);
724 if (show)
725 gtk_widget_show_all(window);
728 static gint addressbook_close(void)
730 gtk_widget_hide(addrbook.window);
731 addressbook_export_to_file();
732 /* tell addr_compl that there's a new addressbook file */
733 invalidate_address_completion();
734 return TRUE;
737 static void addressbook_status_show( gchar *msg ) {
738 if( addrbook.statusbar != NULL ) {
739 gtk_statusbar_pop( GTK_STATUSBAR(addrbook.statusbar), addrbook.status_cid );
740 if( msg ) {
741 gtk_statusbar_push( GTK_STATUSBAR(addrbook.statusbar), addrbook.status_cid, msg );
746 static void addressbook_button_set_sensitive(void)
748 gboolean to_sens = FALSE;
749 gboolean cc_sens = FALSE;
750 gboolean bcc_sens = FALSE;
752 if (!addrbook.window) return;
754 if (addrbook.target_compose) {
755 to_sens = TRUE;
756 cc_sens = TRUE;
757 if (addrbook.target_compose->use_bcc)
758 bcc_sens = TRUE;
761 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
762 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
763 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
766 static void addressbook_del_clicked(GtkButton *button, gpointer data)
768 GtkCList *clist = GTK_CLIST(addrbook.clist);
769 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
770 AddressObject *pobj, *obj;
771 GList *cur, *next;
772 gint row;
773 gboolean remFlag;
775 if (!clist->selection) {
776 addressbook_delete_folder_cb(NULL, 0, NULL);
777 return;
780 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened);
781 g_return_if_fail(pobj != NULL);
783 if (alertpanel(_("Delete address(es)"),
784 _("Really delete the address(es)?"),
785 _("Yes"), _("No"), NULL) != G_ALERTDEFAULT)
786 return;
788 for (cur = clist->selection; cur != NULL; cur = next) {
789 next = cur->next;
790 row = GPOINTER_TO_INT(cur->data);
791 remFlag = FALSE;
793 obj = gtk_clist_get_row_data(clist, row);
794 if (!obj) continue;
796 if (pobj->type == ADDR_GROUP) {
797 AddressGroup *group = ADDRESS_GROUP(pobj);
798 group->items = g_list_remove(group->items, obj);
799 } else if (pobj->type == ADDR_FOLDER) {
800 AddressFolder *folder = ADDRESS_FOLDER(pobj);
802 folder->items = g_list_remove(folder->items, obj);
803 if (obj->type == ADDR_GROUP) {
804 remFlag = TRUE;
806 else if (obj->type == ADDR_VCARD) {
807 remFlag = TRUE;
809 else if (obj->type == ADDR_JPILOT) {
810 remFlag = TRUE;
812 else if (obj->type == ADDR_LDAP) {
813 remFlag = TRUE;
816 if( remFlag ) {
817 GtkCTreeNode *node;
818 node = gtk_ctree_find_by_row_data
819 (ctree, addrbook.opened, obj);
820 if (node) gtk_ctree_remove_node(ctree, node);
822 } else
823 continue;
825 addressbook_delete_object(obj);
827 gtk_clist_remove(clist, row);
831 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
833 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
834 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
835 AddressObject *obj;
836 AddressItem *item;
837 gchar *str;
839 if (*gtk_entry_get_text(entry) == '\0') {
840 addressbook_new_address_cb(NULL, 0, NULL);
841 return;
843 if (!addrbook.opened) return;
845 obj = gtk_ctree_node_get_row_data(ctree, addrbook.opened);
846 if (!obj) return;
848 g_return_if_fail(obj->type == ADDR_GROUP || obj->type == ADDR_FOLDER);
850 str = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
852 item = addressbook_parse_address(str);
853 g_free(str);
854 if (item) {
855 if (addressbook_find_object_by_name
856 (addrbook.opened, item->name) != NULL) {
857 addressbook_delete_object(ADDRESS_OBJECT(item));
858 item = NULL;
859 } else if (addressbook_edit_address(item) == NULL) {
860 addressbook_delete_object(ADDRESS_OBJECT(item));
861 return;
865 if (!item) {
866 item = addressbook_edit_address(NULL);
867 if (!item) return;
870 if (addressbook_find_object_by_name(addrbook.opened, item->name)) {
871 addressbook_delete_object(ADDRESS_OBJECT(item));
872 return;
875 addressbook_add_object(addrbook.opened, ADDRESS_OBJECT(item));
876 addrbook.open_folder = TRUE;
877 gtk_ctree_select(GTK_CTREE(addrbook.ctree), addrbook.opened);
880 static AddressItem *addressbook_parse_address(const gchar *str)
882 gchar *name = NULL;
883 gchar *address = NULL;
884 AddressItem *item;
885 gchar *buf;
886 gchar *start, *end;
888 Xalloca(buf, strlen(str) + 1, return NULL);
890 strcpy(buf, str);
891 g_strstrip(buf);
892 if (*buf == '\0') return NULL;
894 if ((start = strchr(buf, '<'))) {
895 if (start > buf) {
896 *start = '\0';
897 g_strstrip(buf);
898 if (*buf != '\0')
899 name = g_strdup(buf);
901 start++;
902 if ((end = strchr(start, '>'))) {
903 *end = '\0';
904 g_strstrip(start);
905 if (*start != '\0')
906 address = g_strdup(start);
908 } else
909 name = g_strdup(buf);
911 if (!name && !address) return NULL;
913 item = mgu_create_address();
914 ADDRESS_OBJECT_TYPE(item) = ADDR_ITEM;
915 item->name = name;
916 item->address = address;
917 item->remarks = NULL;
919 return item;
922 static void addressbook_to_clicked(GtkButton *button, gpointer data)
924 GtkCList *clist = GTK_CLIST(addrbook.clist);
925 GList *cur;
927 if (!addrbook.target_compose) return;
929 for (cur = clist->selection; cur != NULL; cur = cur->next) {
930 AddressObject *obj;
932 obj = gtk_clist_get_row_data(clist,
933 GPOINTER_TO_INT(cur->data));
934 if (!obj) return;
936 if (obj->type == ADDR_ITEM) {
937 addressbook_append_to_compose_entry
938 (ADDRESS_ITEM(obj), (ComposeEntryType)data);
939 } else if (obj->type == ADDR_GROUP) {
940 AddressGroup *group;
941 GList *cur_item;
943 group = ADDRESS_GROUP(obj);
944 for (cur_item = group->items; cur_item != NULL;
945 cur_item = cur_item->next) {
946 if (ADDRESS_OBJECT(cur_item->data)->type
947 != ADDR_ITEM)
948 continue;
949 addressbook_append_to_compose_entry
950 (ADDRESS_ITEM(cur_item->data),
951 (ComposeEntryType)data);
957 static void addressbook_append_to_compose_entry(AddressItem *item,
958 ComposeEntryType type)
960 Compose *compose = addrbook.target_compose;
962 if (item->name && item->address) {
963 gchar *buf;
965 buf = g_strdup_printf
966 ("%s <%s>", item->name, item->address);
967 compose_entry_append(compose, buf, type);
968 g_free(buf);
969 } else if (item->address)
970 compose_entry_append(compose, item->address, type);
973 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
974 menu_set_sensitive( addrbook.menu_factory, "/File/New Address", sensitive );
975 menu_set_sensitive( addrbook.menu_factory, "/File/New Group", sensitive );
976 menu_set_sensitive( addrbook.menu_factory, "/File/New Folder", sensitive );
977 menu_set_sensitive( addrbook.menu_factory, "/File/New V-Card", sensitive );
978 #ifdef USE_JPILOT
979 menu_set_sensitive( addrbook.menu_factory, "/File/New J-Pilot", sensitive );
980 #endif
981 #ifdef USE_LDAP
982 menu_set_sensitive( addrbook.menu_factory, "/File/New Server", sensitive );
983 #endif
984 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
985 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
988 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
989 gboolean canEdit = TRUE;
990 if( obj->type == ADDR_FOLDER ) {
991 if( node == addrbook.common ) {
992 canEdit = FALSE;
994 if( node == addrbook.personal ) {
995 canEdit = FALSE;
997 if( node == addrbook.vcard ) {
998 canEdit = FALSE;
999 menu_set_sensitive( addrbook.menu_factory, "/File/New V-Card", TRUE );
1001 #ifdef USE_JPILOT
1002 else if( node == addrbook.jpilot ) {
1003 canEdit = FALSE;
1004 if( _have_pilot_library_ ) {
1005 menu_set_sensitive( addrbook.menu_factory, "/File/New J-Pilot", TRUE );
1008 #endif
1009 #ifdef USE_LDAP
1010 else if( node == addrbook.ldap ) {
1011 canEdit = FALSE;
1012 if( _have_ldap_library_ ) {
1013 menu_set_sensitive( addrbook.menu_factory, "/File/New Server", TRUE );
1016 #endif
1017 else {
1018 menu_set_sensitive( addrbook.menu_factory, "/File/New Address", TRUE );
1019 menu_set_sensitive( addrbook.menu_factory, "/File/New Group", TRUE );
1020 menu_set_sensitive( addrbook.menu_factory, "/File/New Folder", TRUE );
1021 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1022 gtk_widget_set_sensitive( addrbook.del_btn, TRUE );
1025 else if( obj->type == ADDR_GROUP ) {
1026 menu_set_sensitive( addrbook.menu_factory, "/File/New Address", TRUE );
1027 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1028 gtk_widget_set_sensitive( addrbook.del_btn, TRUE );
1030 #ifdef USE_JPILOT
1031 else if( obj->type == ADDR_JPILOT ) {
1032 if( ! _have_pilot_library_ ) canEdit = FALSE;
1034 else if( obj->type == ADDR_CATEGORY ) {
1035 canEdit = FALSE;
1037 #endif
1038 #ifdef USE_LDAP
1039 else if( obj->type == ADDR_LDAP ) {
1040 if( ! _have_ldap_library_ ) canEdit = FALSE;
1042 #endif
1043 menu_set_sensitive( addrbook.menu_factory, "/File/Edit", canEdit );
1044 menu_set_sensitive( addrbook.menu_factory, "/File/Delete", canEdit );
1047 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1048 gint column, gpointer data)
1050 AddressObject *obj;
1052 addrbook.selected = node;
1053 addrbook.open_folder = FALSE;
1054 addressbook_status_show( "" );
1055 if( addrbook.entry != NULL ) {
1056 gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1059 obj = gtk_ctree_node_get_row_data(ctree, node);
1060 if( obj == NULL ) return;
1062 addrbook.opened = node;
1064 if( obj->type == ADDR_GROUP || obj->type == ADDR_FOLDER ||
1065 obj->type == ADDR_VCARD || obj->type == ADDR_JPILOT ||
1066 obj->type == ADDR_CATEGORY || obj->type == ADDR_LDAP ) {
1067 addressbook_set_clist(obj);
1070 if( obj->type == ADDR_VCARD ) {
1071 // Read from file
1072 VCardFile *vcf;
1073 vcf = ADDRESS_VCARD(obj)->cardFile;
1074 vcard_read_data( vcf );
1075 addressbook_vcard_show_message( vcf );
1076 ADDRESS_VCARD(obj)->items = vcard_get_address_list( vcf );
1077 addressbook_set_clist( obj );
1079 #ifdef USE_JPILOT
1080 else if( obj->type == ADDR_JPILOT ) {
1081 if( _have_pilot_library_ ) {
1082 // Read from file
1083 JPilotFile *jpf;
1084 GList *catList, *catNode;
1085 AddressCategory *acat;
1086 GtkCTreeNode *childNode, *nextNode;
1087 GtkCTreeRow *currRow;
1089 jpf = ADDRESS_JPILOT(obj)->pilotFile;
1090 addressbook_jpilot_show_message( jpf );
1091 if( jpilot_get_modified( jpf ) ) {
1092 jpilot_read_data( jpf );
1093 catList = jpilot_get_category_items( jpf );
1095 // Remove existing categories
1096 currRow = GTK_CTREE_ROW( node );
1097 if( currRow ) {
1098 while( nextNode = currRow->children ) {
1099 gtk_ctree_remove_node( ctree, nextNode );
1103 // Load new categories into the tree.
1104 catNode = catList;
1105 while( catNode ) {
1106 AddressItem *item = catNode->data;
1107 acat = g_new(AddressCategory, 1);
1108 ADDRESS_OBJECT_TYPE(acat) = ADDR_CATEGORY;
1109 acat->name = g_strdup( item->name );
1110 acat->items = NULL;
1111 acat->pilotFile = jpf;
1112 acat->category = item;
1113 catNode = g_list_next( catNode );
1114 addressbook_add_object(node, ADDRESS_OBJECT(acat));
1117 ADDRESS_JPILOT(obj)->items = catList;
1119 addressbook_set_clist( obj );
1122 else if( obj->type == ADDR_CATEGORY ) {
1123 if( _have_pilot_library_ ) {
1124 // Read from file
1125 JPilotFile *jpf;
1127 jpf = ADDRESS_JPILOT(obj)->pilotFile;
1128 if( jpilot_get_modified( jpf ) ) {
1129 // Force parent to be reloaded
1130 gtk_ctree_select( GTK_CTREE(addrbook.ctree), GTK_CTREE_ROW(node)->parent);
1131 gtk_ctree_expand( GTK_CTREE(addrbook.ctree), GTK_CTREE_ROW(node)->parent);
1133 else {
1134 AddressItem *item = NULL;
1135 AddressCategory *acat = ADDRESS_CATEGORY(obj);
1136 if( acat ) item = acat->category;
1137 if( item ) {
1138 ADDRESS_CATEGORY(obj)->items =
1139 jpilot_get_address_list_cat( jpf, item->categoryID );
1141 addressbook_set_clist( obj );
1145 #endif
1146 #ifdef USE_LDAP
1147 else if( obj->type == ADDR_LDAP ) {
1148 if( _have_ldap_library_ ) {
1149 // Read from cache
1150 SyldapServer *server;
1151 server = ADDRESS_LDAP(obj)->ldapServer;
1152 addressbook_ldap_show_message( server );
1153 if( ! server->busyFlag ) {
1154 ADDRESS_LDAP(obj)->items = syldap_get_address_list( server );
1155 addressbook_set_clist( obj );
1159 #endif
1161 // Setup main menu selections
1162 addressbook_menubar_set_sensitive( FALSE );
1163 addressbook_menuitem_set_sensitive( obj, node );
1166 static void addressbook_list_selected(GtkCList *clist, gint row, gint column,
1167 GdkEvent *event, gpointer data)
1169 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
1170 AddressObject *obj;
1171 GList *cur;
1173 if (event && event->type == GDK_2BUTTON_PRESS) {
1174 if (prefs_common.add_address_by_click &&
1175 addrbook.target_compose)
1176 addressbook_to_clicked(NULL, NULL);
1177 else
1178 addressbook_edit_address_cb(NULL, 0, NULL);
1179 return;
1182 #if 0
1183 gtk_signal_handler_block_by_func
1184 (GTK_OBJECT(entry),
1185 GTK_SIGNAL_FUNC(addressbook_entry_changed), NULL);
1186 #endif
1188 gtk_entry_set_text(entry, "");
1190 for (cur = clist->selection; cur != NULL; cur = cur->next) {
1191 obj = gtk_clist_get_row_data(clist,
1192 GPOINTER_TO_INT(cur->data));
1193 g_return_if_fail(obj != NULL);
1195 if (obj->type == ADDR_ITEM) {
1196 AddressItem *item;
1198 item = ADDRESS_ITEM(obj);
1199 if (item->name && item->address) {
1200 gchar *buf;
1202 buf = g_strdup_printf
1203 ("%s <%s>", item->name, item->address);
1204 if (*gtk_entry_get_text(entry) != '\0')
1205 gtk_entry_append_text(entry, ", ");
1206 gtk_entry_append_text(entry, buf);
1207 g_free(buf);
1208 } else if (item->address) {
1209 if (*gtk_entry_get_text(entry) != '\0')
1210 gtk_entry_append_text(entry, ", ");
1211 gtk_entry_append_text(entry, item->address);
1216 #if 0
1217 gtk_signal_handler_unblock_by_func
1218 (GTK_OBJECT(entry),
1219 GTK_SIGNAL_FUNC(addressbook_entry_changed), NULL);
1220 #endif
1223 #if 0
1224 static void addressbook_entry_changed(GtkWidget *widget)
1226 GtkCList *clist = GTK_CLIST(addrbook.clist);
1227 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
1228 const gchar *str;
1229 gint len;
1230 gint row;
1232 //if (clist->selection && clist->selection->next) return;
1234 str = gtk_entry_get_text(entry);
1235 if (*str == '\0') {
1236 gtk_clist_unselect_all(clist);
1237 return;
1239 len = strlen(str);
1241 for (row = 0; row < clist->rows; row++) {
1242 AddressObject *obj;
1243 const gchar *name;
1245 obj = ADDRESS_OBJECT(gtk_clist_get_row_data(clist, row));
1246 if (!obj) continue;
1247 if (obj->type == ADDR_ITEM)
1248 name = ADDRESS_ITEM(obj)->name;
1249 else if (obj->type == ADDR_GROUP)
1250 name = ADDRESS_GROUP(obj)->name;
1251 else
1252 continue;
1254 if (name && !strncasecmp(name, str, len)) {
1255 gtk_clist_unselect_all(clist);
1256 gtk_clist_select_row(clist, row, -1);
1257 return;
1261 gtk_clist_unselect_all(clist);
1263 #endif
1265 static void addressbook_entry_gotfocus( GtkWidget *widget ) {
1266 gtk_editable_select_region( GTK_EDITABLE(addrbook.entry), 0, -1 );
1269 static void addressbook_list_button_pressed(GtkWidget *widget,
1270 GdkEventButton *event,
1271 gpointer data)
1273 GtkCList *clist = GTK_CLIST(widget);
1274 gint row, column;
1275 gint tRow, tCol;
1276 AddressObject *obj, *pobj;
1278 if (!event) return;
1280 obj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1281 addrbook.opened);
1282 g_return_if_fail(obj != NULL);
1284 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.selected);
1285 if( pobj ) {
1286 if( pobj->type == ADDR_VCARD ||
1287 pobj->type == ADDR_JPILOT ||
1288 pobj->type == ADDR_CATEGORY ||
1289 pobj->type == ADDR_LDAP ) {
1290 menu_set_sensitive(addrbook.menu_factory, "/File/Edit", FALSE);
1291 menu_set_sensitive(addrbook.menu_factory, "/File/Delete", FALSE);
1295 if (event->button != 3) return;
1296 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.list_popup));
1298 if (gtk_clist_get_selection_info
1299 (clist, event->x, event->y, &row, &column)) {
1300 GtkCListRow *clist_row;
1302 clist_row = g_list_nth(clist->row_list, row)->data;
1303 if (clist_row->state != GTK_STATE_SELECTED) {
1304 gtk_clist_unselect_all(clist);
1305 gtk_clist_select_row(clist, row, column);
1307 gtkut_clist_set_focus_row(clist, row);
1309 if( obj->type != ADDR_VCARD &&
1310 obj->type != ADDR_JPILOT &&
1311 obj->type != ADDR_CATEGORY &&
1312 obj->type != ADDR_LDAP ) {
1313 menu_set_sensitive(addrbook.list_factory, "/Edit", TRUE);
1314 menu_set_sensitive(addrbook.list_factory, "/Delete", TRUE);
1318 if( !( addrbook.opened == addrbook.vcard ||
1319 addrbook.opened == addrbook.jpilot ||
1320 addrbook.opened == addrbook.ldap ) ) {
1322 if( obj->type == ADDR_FOLDER || obj->type == ADDR_GROUP ) {
1323 menu_set_sensitive(addrbook.list_factory, "/New Address", TRUE);
1324 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1325 gtk_widget_set_sensitive( addrbook.del_btn, TRUE );
1327 if (obj->type == ADDR_FOLDER) {
1328 menu_set_sensitive(addrbook.list_factory, "/New Folder", TRUE);
1329 menu_set_sensitive(addrbook.list_factory, "/New Group", TRUE);
1332 gtk_menu_popup(GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
1333 event->button, event->time);
1336 static void addressbook_list_button_released(GtkWidget *widget,
1337 GdkEventButton *event,
1338 gpointer data)
1342 static void addressbook_tree_button_pressed(GtkWidget *ctree,
1343 GdkEventButton *event,
1344 gpointer data)
1346 GtkCList *clist = GTK_CLIST(ctree);
1347 gint row, column;
1348 AddressObject *obj;
1349 GtkCTreeNode *node;
1351 if (!event) return;
1352 if (event->button == 1) {
1353 addrbook.open_folder = TRUE;
1354 return;
1356 if (event->button != 3) return;
1358 if (!gtk_clist_get_selection_info
1359 (clist, event->x, event->y, &row, &column)) return;
1360 gtk_clist_select_row(clist, row, column);
1362 obj = gtk_clist_get_row_data(clist, row);
1363 g_return_if_fail(obj != NULL);
1365 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
1367 if (obj->type == ADDR_FOLDER) {
1368 node = gtk_ctree_node_nth(GTK_CTREE(ctree), row);
1369 if( node == addrbook.vcard ) {
1370 menu_set_sensitive(addrbook.tree_factory, "/New V-Card", TRUE);
1372 #ifdef USE_JPILOT
1373 else if( node == addrbook.jpilot ) {
1374 if( _have_pilot_library_ ) {
1375 menu_set_sensitive(addrbook.tree_factory, "/New J-Pilot", TRUE);
1378 #endif
1379 #ifdef USE_LDAP
1380 else if( node == addrbook.ldap ) {
1381 if( _have_ldap_library_ ) {
1382 menu_set_sensitive(addrbook.tree_factory, "/New Server", TRUE);
1385 #endif
1386 else {
1387 menu_set_sensitive(addrbook.tree_factory, "/New Address", TRUE);
1388 menu_set_sensitive(addrbook.tree_factory, "/New Folder", TRUE);
1389 menu_set_sensitive(addrbook.tree_factory, "/New Group", TRUE);
1390 if (node && GTK_CTREE_ROW(node)->level >= 2) {
1391 menu_set_sensitive(addrbook.tree_factory, "/Edit", TRUE);
1392 menu_set_sensitive(addrbook.tree_factory, "/Delete", TRUE);
1394 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1395 gtk_widget_set_sensitive( addrbook.del_btn, TRUE );
1398 else if (obj->type == ADDR_GROUP) {
1399 menu_set_sensitive(addrbook.tree_factory, "/New Address", TRUE);
1400 menu_set_sensitive(addrbook.tree_factory, "/Edit", TRUE);
1401 menu_set_sensitive(addrbook.tree_factory, "/Delete", TRUE);
1402 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1403 gtk_widget_set_sensitive( addrbook.del_btn, TRUE );
1405 else if (obj->type == ADDR_VCARD) {
1406 menu_set_sensitive(addrbook.tree_factory, "/Edit", TRUE);
1407 menu_set_sensitive(addrbook.tree_factory, "/Delete", TRUE);
1409 #ifdef USE_JPILOT
1410 else if (obj->type == ADDR_JPILOT) {
1411 if( _have_pilot_library_ ) {
1412 menu_set_sensitive(addrbook.tree_factory, "/Edit", TRUE);
1413 menu_set_sensitive(addrbook.tree_factory, "/Delete", TRUE);
1416 else if (obj->type == ADDR_CATEGORY) {
1417 if( _have_pilot_library_ ) {
1418 menu_set_sensitive(addrbook.tree_factory, "/Edit", FALSE);
1419 menu_set_sensitive(addrbook.tree_factory, "/Delete", FALSE);
1422 #endif
1423 #ifdef USE_LDAP
1424 else if (obj->type == ADDR_LDAP) {
1425 if( _have_ldap_library_ ) {
1426 menu_set_sensitive(addrbook.tree_factory, "/Edit", TRUE);
1427 menu_set_sensitive(addrbook.tree_factory, "/Delete", TRUE);
1430 #endif
1431 else {
1432 return;
1434 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
1435 event->button, event->time);
1438 static void addressbook_tree_button_released(GtkWidget *ctree,
1439 GdkEventButton *event,
1440 gpointer data)
1442 gtk_ctree_select(GTK_CTREE(addrbook.ctree), addrbook.opened);
1443 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
1446 static void addressbook_popup_close(GtkMenuShell *menu_shell, gpointer data)
1448 if (!addrbook.opened) return;
1450 gtk_ctree_select(GTK_CTREE(addrbook.ctree), addrbook.opened);
1451 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree),
1452 addrbook.opened);
1455 static void addressbook_new_folder_cb(gpointer data, guint action,
1456 GtkWidget *widget)
1458 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1459 AddressObject *obj;
1460 AddressFolder *folder;
1461 gchar *new_folder;
1463 if (!addrbook.selected) return;
1465 obj = gtk_ctree_node_get_row_data(ctree, addrbook.selected);
1466 g_return_if_fail(obj != NULL);
1467 if (obj->type != ADDR_FOLDER) return;
1469 new_folder = input_dialog(_("New folder"),
1470 _("Input the name of new folder:"),
1471 _("NewFolder"));
1472 if (!new_folder) return;
1473 g_strstrip(new_folder);
1474 if (*new_folder == '\0') {
1475 g_free(new_folder);
1476 return;
1479 if (gtk_ctree_find_by_row_data_custom(ctree, addrbook.selected,
1480 new_folder,
1481 addressbook_obj_name_compare)) {
1482 alertpanel_error(_("The name already exists."));
1483 g_free(new_folder);
1484 return;
1487 folder = g_new(AddressFolder, 1);
1488 ADDRESS_OBJECT_TYPE(folder) = ADDR_FOLDER;
1489 folder->name = g_strdup(new_folder);
1490 folder->items = NULL;
1492 addressbook_add_object(addrbook.selected, ADDRESS_OBJECT(folder));
1494 g_free(new_folder);
1496 if (addrbook.selected == addrbook.opened)
1497 addressbook_set_clist(obj);
1500 static void addressbook_new_group_cb(gpointer data, guint action,
1501 GtkWidget *widget)
1503 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1504 AddressObject *obj;
1505 AddressGroup *group;
1506 gchar *new_group;
1508 if (!addrbook.selected) return;
1510 obj = gtk_ctree_node_get_row_data(ctree, addrbook.selected);
1511 g_return_if_fail(obj != NULL);
1512 if (obj->type != ADDR_FOLDER) return;
1514 new_group = input_dialog(_("New group"),
1515 _("Input the name of new group:"),
1516 _("NewGroup"));
1517 if (!new_group) return;
1518 g_strstrip(new_group);
1519 if (*new_group == '\0') {
1520 g_free(new_group);
1521 return;
1524 if (gtk_ctree_find_by_row_data_custom(ctree, addrbook.selected,
1525 new_group,
1526 addressbook_obj_name_compare)) {
1527 alertpanel_error(_("The name already exists."));
1528 g_free(new_group);
1529 return;
1532 group = g_new(AddressGroup, 1);
1533 ADDRESS_OBJECT_TYPE(group) = ADDR_GROUP;
1534 group->name = g_strdup(new_group);
1535 group->items = NULL;
1537 addressbook_add_object(addrbook.selected, ADDRESS_OBJECT(group));
1539 g_free(new_group);
1541 if (addrbook.selected == addrbook.opened)
1542 addressbook_set_clist(obj);
1545 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
1547 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1548 gchar *text[1];
1549 guint8 spacing;
1550 GdkPixmap *pix_cl, *pix_op;
1551 GdkBitmap *mask_cl, *mask_op;
1552 gboolean is_leaf, expanded;
1554 gtk_ctree_get_node_info(ctree, node, text, &spacing,
1555 &pix_cl, &mask_cl, &pix_op, &mask_op,
1556 &is_leaf, &expanded);
1557 gtk_ctree_set_node_info(ctree, node, name, spacing,
1558 pix_cl, mask_cl, pix_op, mask_op,
1559 is_leaf, expanded);
1562 static void addressbook_edit_group(GtkCTreeNode *group_node)
1564 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1565 GtkCList *clist = GTK_CLIST(addrbook.clist);
1566 AddressObject *obj;
1567 AddressGroup *group;
1568 gchar *new_name;
1569 GtkCTreeNode *node;
1571 if (!group_node && clist->selection) {
1572 obj = gtk_clist_get_row_data(clist,
1573 GPOINTER_TO_INT(clist->selection->data));
1574 g_return_if_fail(obj != NULL);
1575 if (obj->type != ADDR_GROUP) return;
1576 node = gtk_ctree_find_by_row_data
1577 (ctree, addrbook.selected, obj);
1578 if (!node) return;
1579 } else {
1580 if (group_node)
1581 node = group_node;
1582 else
1583 node = addrbook.selected;
1584 obj = gtk_ctree_node_get_row_data(ctree, node);
1585 g_return_if_fail(obj != NULL);
1586 if (obj->type != ADDR_GROUP) return;
1589 group = ADDRESS_GROUP(obj);
1591 new_name = input_dialog(_("Edit group"),
1592 _("Input the new name of group:"),
1593 group->name);
1594 if (!new_name) return;
1595 g_strstrip(new_name);
1596 if (*new_name == '\0') {
1597 g_free(new_name);
1598 return;
1601 if (gtk_ctree_find_by_row_data_custom(ctree, addrbook.selected,
1602 new_name,
1603 addressbook_obj_name_compare)) {
1604 alertpanel_error(_("The name already exists."));
1605 g_free(new_name);
1606 return;
1609 g_free(group->name);
1610 group->name = g_strdup(new_name);
1612 addressbook_change_node_name(node, new_name);
1613 gtk_ctree_sort_node(ctree, GTK_CTREE_ROW(node)->parent);
1615 g_free(new_name);
1617 addrbook.open_folder = TRUE;
1618 gtk_ctree_select(ctree, addrbook.opened);
1621 static void addressbook_edit_folder_cb(gpointer data, guint action,
1622 GtkWidget *widget)
1624 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1625 AddressObject *obj;
1626 AddressFolder *folder;
1627 gchar *new_name = NULL;
1628 GtkCTreeNode *node = NULL, *parentNode = NULL;
1630 if (!addrbook.selected) return;
1631 if (GTK_CTREE_ROW(addrbook.selected)->level == 1) return;
1633 obj = gtk_ctree_node_get_row_data(ctree, addrbook.selected);
1634 g_return_if_fail(obj != NULL);
1635 g_return_if_fail(obj->type == ADDR_FOLDER || obj->type == ADDR_GROUP ||
1636 obj->type == ADDR_VCARD || obj->type == ADDR_JPILOT ||
1637 obj->type == ADDR_CATEGORY || obj->type == ADDR_LDAP );
1639 if (obj->type == ADDR_GROUP) {
1640 addressbook_edit_group(addrbook.selected);
1641 return;
1644 if( obj->type == ADDR_VCARD ) {
1645 AddressVCard *vcard = ADDRESS_VCARD(obj);
1646 if( addressbook_edit_vcard( vcard ) == NULL ) return;
1647 new_name = vcard->name;
1648 parentNode = addrbook.vcard;
1650 #ifdef USE_JPILOT
1651 else if( obj->type == ADDR_JPILOT ) {
1652 AddressJPilot *jpilot = ADDRESS_JPILOT(obj);
1653 if( ! _have_pilot_library_ ) return;
1654 if( addressbook_edit_jpilot( jpilot ) == NULL ) return;
1655 new_name = jpilot->name;
1656 parentNode = addrbook.jpilot;
1658 #endif
1659 #ifdef USE_LDAP
1660 else if( obj->type == ADDR_LDAP ) {
1661 AddressLDAP *ldapi = ADDRESS_LDAP(obj);
1662 if( ! _have_ldap_library_ ) return;
1663 if( addressbook_edit_ldap( ldapi ) == NULL ) return;
1664 new_name = ldapi->name;
1665 parentNode = addrbook.ldap;
1667 #endif
1669 if( new_name && parentNode) {
1670 // Update node in tree view
1671 node = gtk_ctree_find_by_row_data( ctree, addrbook.selected, obj );
1672 if( ! node ) return;
1673 addressbook_change_node_name( node, new_name );
1674 gtk_ctree_sort_node(ctree, parentNode);
1675 addrbook.open_folder = TRUE;
1676 gtk_ctree_select( GTK_CTREE(addrbook.ctree), node );
1677 return;
1680 folder = ADDRESS_FOLDER(obj);
1681 new_name = input_dialog(_("Edit folder"),
1682 _("Input the new name of folder:"),
1683 folder->name);
1685 if (!new_name) return;
1686 g_strstrip(new_name);
1687 if (*new_name == '\0') {
1688 g_free(new_name);
1689 return;
1692 if (gtk_ctree_find_by_row_data_custom(ctree, addrbook.selected,
1693 new_name,
1694 addressbook_obj_name_compare)) {
1695 alertpanel_error(_("The name already exists."));
1696 g_free(new_name);
1697 return;
1700 g_free(folder->name);
1701 folder->name = g_strdup(new_name);
1703 addressbook_change_node_name(addrbook.selected, new_name);
1704 gtk_ctree_sort_node(ctree, GTK_CTREE_ROW(addrbook.selected)->parent);
1706 g_free(new_name);
1709 static void addressbook_delete_folder_cb(gpointer data, guint action,
1710 GtkWidget *widget)
1712 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1713 AddressObject *obj, *pobj;
1714 gchar *name;
1715 gchar *message;
1716 AlertValue aval;
1718 if (!addrbook.selected) return;
1719 if (GTK_CTREE_ROW(addrbook.selected)->level == 1) return;
1721 obj = gtk_ctree_node_get_row_data(ctree, addrbook.selected);
1722 g_return_if_fail(obj != NULL);
1724 if (obj->type == ADDR_GROUP)
1725 name = ADDRESS_GROUP(obj)->name;
1726 else if (obj->type == ADDR_FOLDER)
1727 name = ADDRESS_FOLDER(obj)->name;
1728 else if (obj->type == ADDR_VCARD)
1729 name = ADDRESS_VCARD(obj)->name;
1730 #ifdef USE_JPILOT
1731 else if (obj->type == ADDR_JPILOT) {
1732 if( ! _have_pilot_library_ ) return;
1733 name = ADDRESS_JPILOT(obj)->name;
1735 #endif
1736 #ifdef USE_LDAP
1737 else if (obj->type == ADDR_LDAP) {
1738 if( ! _have_ldap_library_ ) return;
1739 name = ADDRESS_LDAP(obj)->name;
1741 #endif
1742 else
1743 return;
1745 message = g_strdup_printf(_("Really delete `%s' ?"), name);
1746 aval = alertpanel(_("Delete"), message, _("Yes"), _("No"), NULL);
1747 g_free(message);
1748 if (aval != G_ALERTDEFAULT) return;
1750 pobj = gtk_ctree_node_get_row_data
1751 (ctree, GTK_CTREE_ROW(addrbook.selected)->parent);
1752 if (!pobj) return;
1753 g_return_if_fail(pobj->type == ADDR_FOLDER);
1754 ADDRESS_FOLDER(pobj)->items =
1755 g_list_remove(ADDRESS_FOLDER(pobj)->items, obj);
1757 addressbook_delete_object(obj);
1758 addrbook.open_folder = TRUE;
1759 gtk_ctree_remove_node(ctree, addrbook.selected);
1760 addrbook.open_folder = FALSE;
1763 #define SET_LABEL_AND_ENTRY(str, entry, top) \
1765 label = gtk_label_new(str); \
1766 gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), \
1767 GTK_FILL, 0, 0, 0); \
1768 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); \
1770 entry = gtk_entry_new(); \
1771 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, top, (top + 1), \
1772 GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); \
1775 static void addressbook_edit_address_create(gboolean *cancelled)
1777 GtkWidget *window;
1778 GtkWidget *vbox;
1779 GtkWidget *table;
1780 GtkWidget *label;
1781 GtkWidget *name_entry;
1782 GtkWidget *addr_entry;
1783 GtkWidget *rem_entry;
1784 GtkWidget *hbbox;
1785 GtkWidget *ok_btn;
1786 GtkWidget *cancel_btn;
1788 debug_print("Creating edit_address window...\n");
1790 window = gtk_window_new(GTK_WINDOW_DIALOG);
1791 gtk_widget_set_usize(window, 400, -1);
1792 gtk_container_set_border_width(GTK_CONTAINER(window), 8);
1793 gtk_window_set_title(GTK_WINDOW(window), _("Edit address"));
1794 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
1795 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1796 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
1797 GTK_SIGNAL_FUNC(edit_address_delete_event),
1798 cancelled);
1799 gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
1800 GTK_SIGNAL_FUNC(edit_address_key_pressed),
1801 cancelled);
1803 vbox = gtk_vbox_new(FALSE, 8);
1804 gtk_container_add(GTK_CONTAINER(window), vbox);
1806 table = gtk_table_new(3, 2, FALSE);
1807 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
1808 gtk_table_set_row_spacings(GTK_TABLE(table), 8);
1809 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
1811 SET_LABEL_AND_ENTRY(_("Name"), name_entry, 0);
1812 SET_LABEL_AND_ENTRY(_("Address"), addr_entry, 1);
1813 SET_LABEL_AND_ENTRY(_("Remarks"), rem_entry, 2);
1815 gtkut_button_set_create(&hbbox, &ok_btn, _("OK"),
1816 &cancel_btn, _("Cancel"), NULL, NULL);
1817 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1818 gtk_widget_grab_default(ok_btn);
1820 gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked",
1821 GTK_SIGNAL_FUNC(edit_address_ok), cancelled);
1822 gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
1823 GTK_SIGNAL_FUNC(edit_address_cancel), cancelled);
1825 gtk_widget_show_all(vbox);
1827 addredit.window = window;
1828 addredit.name_entry = name_entry;
1829 addredit.addr_entry = addr_entry;
1830 addredit.rem_entry = rem_entry;
1831 addredit.ok_btn = ok_btn;
1832 addredit.cancel_btn = cancel_btn;
1835 static void edit_address_ok(GtkWidget *widget, gboolean *cancelled)
1837 *cancelled = FALSE;
1838 gtk_main_quit();
1841 static void edit_address_cancel(GtkWidget *widget, gboolean *cancelled)
1843 *cancelled = TRUE;
1844 gtk_main_quit();
1847 static gint edit_address_delete_event(GtkWidget *widget, GdkEventAny *event,
1848 gboolean *cancelled)
1850 *cancelled = TRUE;
1851 gtk_main_quit();
1853 return TRUE;
1856 static void edit_address_key_pressed(GtkWidget *widget, GdkEventKey *event,
1857 gboolean *cancelled)
1859 if (event && event->keyval == GDK_Escape) {
1860 *cancelled = TRUE;
1861 gtk_main_quit();
1865 static AddressItem *addressbook_edit_address(AddressItem *item)
1867 static gboolean cancelled;
1868 const gchar *str;
1870 if (!addredit.window)
1871 addressbook_edit_address_create(&cancelled);
1872 gtk_widget_grab_focus(addredit.ok_btn);
1873 gtk_widget_grab_focus(addredit.name_entry);
1874 gtk_widget_show(addredit.window);
1875 manage_window_set_transient(GTK_WINDOW(addredit.window));
1877 gtk_entry_set_text(GTK_ENTRY(addredit.name_entry), "");
1878 gtk_entry_set_text(GTK_ENTRY(addredit.addr_entry), "");
1879 gtk_entry_set_text(GTK_ENTRY(addredit.rem_entry), "");
1881 if (item) {
1882 if (item->name)
1883 gtk_entry_set_text(GTK_ENTRY(addredit.name_entry),
1884 item->name);
1885 if (item->address)
1886 gtk_entry_set_text(GTK_ENTRY(addredit.addr_entry),
1887 item->address);
1888 if (item->remarks)
1889 gtk_entry_set_text(GTK_ENTRY(addredit.rem_entry),
1890 item->remarks);
1893 gtk_main();
1894 gtk_widget_hide(addredit.window);
1895 if (cancelled == TRUE) return NULL;
1897 str = gtk_entry_get_text(GTK_ENTRY(addredit.name_entry));
1898 if (*str == '\0') return NULL;
1900 if (!item) {
1901 item = mgu_create_address();
1902 ADDRESS_OBJECT_TYPE(item) = ADDR_ITEM;
1905 g_free(item->name);
1906 item->name = g_strdup(str);
1908 str = gtk_entry_get_text(GTK_ENTRY(addredit.addr_entry));
1909 g_free(item->address);
1910 if (*str == '\0')
1911 item->address = NULL;
1912 else
1913 item->address = g_strdup(str);
1915 str = gtk_entry_get_text(GTK_ENTRY(addredit.rem_entry));
1916 g_free(item->remarks);
1917 if (*str == '\0')
1918 item->remarks = NULL;
1919 else
1920 item->remarks = g_strdup(str);
1922 return item;
1925 static void addressbook_new_address_cb(gpointer data, guint action,
1926 GtkWidget *widget)
1928 AddressItem *item;
1930 item = addressbook_edit_address(NULL);
1932 if (item) {
1933 addressbook_add_object(addrbook.selected,
1934 ADDRESS_OBJECT(item));
1935 if (addrbook.selected == addrbook.opened) {
1936 addrbook.open_folder = TRUE;
1937 gtk_ctree_select(GTK_CTREE(addrbook.ctree),
1938 addrbook.opened);
1943 static void addressbook_edit_address_cb(gpointer data, guint action,
1944 GtkWidget *widget)
1946 GtkCList *clist = GTK_CLIST(addrbook.clist);
1947 GtkCTree *ctree;
1948 AddressObject *obj, *pobj;
1949 GtkCTreeNode *node = NULL, *parentNode = NULL;
1950 gchar *nodeName;
1952 if (!clist->selection) {
1953 addressbook_edit_folder_cb(NULL, 0, NULL);
1954 return;
1957 obj = gtk_clist_get_row_data(clist, GPOINTER_TO_INT(clist->selection->data));
1958 g_return_if_fail(obj != NULL);
1960 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.selected);
1962 if (obj->type == ADDR_ITEM) {
1963 AddressItem *item = ADDRESS_ITEM(obj);
1965 if( pobj ) {
1966 // Prevent edit of readonly items
1967 if( pobj->type == ADDR_VCARD ||
1968 pobj->type == ADDR_JPILOT ||
1969 pobj->type == ADDR_CATEGORY ||
1970 pobj->type == ADDR_LDAP ) return;
1973 if (addressbook_edit_address(item) == NULL) return;
1975 addrbook.open_folder = TRUE;
1976 gtk_ctree_select(GTK_CTREE(addrbook.ctree), addrbook.opened);
1977 return;
1979 else if (obj->type == ADDR_GROUP) {
1980 addressbook_edit_group(NULL);
1981 return;
1983 else if( obj->type == ADDR_VCARD ) {
1984 AddressVCard *vcard = ADDRESS_VCARD(obj);
1985 if( addressbook_edit_vcard( vcard ) == NULL ) return;
1986 nodeName = vcard->name;
1987 parentNode = addrbook.vcard;
1989 #ifdef USE_JPILOT
1990 else if( obj->type == ADDR_JPILOT ) {
1991 AddressJPilot *jpilot = ADDRESS_JPILOT(obj);
1992 if( addressbook_edit_jpilot( jpilot ) == NULL ) return;
1993 nodeName = jpilot->name;
1994 parentNode = addrbook.jpilot;
1996 #endif
1997 #ifdef USE_LDAP
1998 else if( obj->type == ADDR_LDAP ) {
1999 AddressLDAP *ldapi = ADDRESS_LDAP(obj);
2000 if( addressbook_edit_ldap( ldapi ) == NULL ) return;
2001 nodeName = ldapi->name;
2002 parentNode = addrbook.ldap;
2004 #endif
2005 else {
2006 return;
2009 // Update tree node with node name
2010 ctree = GTK_CTREE( addrbook.ctree );
2011 node = gtk_ctree_find_by_row_data( ctree, addrbook.selected, obj );
2012 if( ! node ) return;
2013 addressbook_change_node_name( node, nodeName );
2014 gtk_ctree_sort_node(ctree, parentNode );
2015 addrbook.open_folder = TRUE;
2016 gtk_ctree_select( ctree, addrbook.opened );
2019 static void addressbook_delete_address_cb(gpointer data, guint action,
2020 GtkWidget *widget)
2022 addressbook_del_clicked(NULL, NULL);
2025 static void close_cb(gpointer data, guint action, GtkWidget *widget)
2027 addressbook_close();
2030 static void addressbook_set_clist(AddressObject *obj)
2032 GtkCList *clist = GTK_CLIST(addrbook.clist);
2033 GList *items;
2034 gchar *text[N_COLS];
2036 if (!obj) {
2037 gtk_clist_clear(clist);
2038 return;
2041 gtk_clist_freeze(clist);
2042 gtk_clist_clear(clist);
2044 if (obj->type == ADDR_GROUP)
2045 items = ADDRESS_GROUP(obj)->items;
2046 else if (obj->type == ADDR_FOLDER) {
2047 items = ADDRESS_FOLDER(obj)->items;
2049 else if (obj->type == ADDR_VCARD) {
2050 items = ADDRESS_VCARD(obj)->items;
2052 #ifdef USE_JPILOT
2053 else if (obj->type == ADDR_JPILOT) {
2054 items = ADDRESS_JPILOT(obj)->items;
2056 else if (obj->type == ADDR_CATEGORY) {
2057 items = ADDRESS_CATEGORY(obj)->items;
2059 #endif
2060 #ifdef USE_LDAP
2061 else if (obj->type == ADDR_LDAP) {
2062 items = ADDRESS_LDAP(obj)->items;
2064 #endif
2065 else {
2066 gtk_clist_thaw(clist);
2067 return;
2070 for (; items != NULL; items = items->next) {
2071 AddressObject *iobj;
2072 gint row;
2073 iobj = ADDRESS_OBJECT(items->data);
2074 if( iobj == NULL ) continue;
2076 if (iobj->type == ADDR_GROUP) {
2077 AddressGroup *group;
2079 group = ADDRESS_GROUP(iobj);
2080 text[COL_NAME] = group->name;
2081 text[COL_ADDRESS] = NULL;
2082 text[COL_REMARKS] = NULL;
2083 row = gtk_clist_append(clist, text);
2084 gtk_clist_set_pixtext(clist, row, COL_NAME,
2085 group->name, 4,
2086 groupxpm, groupxpmmask);
2087 gtk_clist_set_row_data(clist, row, iobj);
2088 } if (iobj->type == ADDR_VCARD) {
2089 AddressVCard *vcard;
2091 vcard = ADDRESS_VCARD(iobj);
2092 text[COL_NAME] = vcard->name;
2093 text[COL_ADDRESS] = NULL;
2094 text[COL_REMARKS] = NULL;
2095 row = gtk_clist_append(clist, text);
2096 gtk_clist_set_pixtext(clist, row, COL_NAME,
2097 vcard->name, 4,
2098 vcardxpm, vcardxpmmask);
2099 gtk_clist_set_row_data(clist, row, iobj);
2100 #ifdef USE_JPILOT
2101 } if (iobj->type == ADDR_JPILOT) {
2102 AddressJPilot *jpilot;
2104 jpilot = ADDRESS_JPILOT(iobj);
2105 text[COL_NAME] = jpilot->name;
2106 text[COL_ADDRESS] = NULL;
2107 text[COL_REMARKS] = NULL;
2108 row = gtk_clist_append(clist, text);
2109 gtk_clist_set_pixtext(clist, row, COL_NAME,
2110 jpilot->name, 4,
2111 jpilotxpm, jpilotxpmmask);
2112 gtk_clist_set_row_data(clist, row, iobj);
2113 } if (iobj->type == ADDR_CATEGORY) {
2114 AddressCategory *category;
2116 category = ADDRESS_CATEGORY(iobj);
2117 text[COL_NAME] = category->name;
2118 text[COL_ADDRESS] = NULL;
2119 text[COL_REMARKS] = NULL;
2120 row = gtk_clist_append(clist, text);
2121 gtk_clist_set_pixtext(clist, row, COL_NAME,
2122 category->name, 4,
2123 categoryxpm, categoryxpmmask);
2124 gtk_clist_set_row_data(clist, row, iobj);
2125 #endif
2126 #ifdef USE_LDAP
2127 } if (iobj->type == ADDR_LDAP) {
2128 AddressLDAP *ldapi;
2130 ldapi = ADDRESS_LDAP(iobj);
2131 text[COL_NAME] = ldapi->name;
2132 text[COL_ADDRESS] = NULL;
2133 text[COL_REMARKS] = NULL;
2134 row = gtk_clist_append(clist, text);
2135 gtk_clist_set_pixtext(clist, row, COL_NAME,
2136 ldapi->name, 4,
2137 ldapxpm, ldapxpmmask);
2138 gtk_clist_set_row_data(clist, row, iobj);
2139 #endif
2140 } else if (iobj->type == ADDR_ITEM) {
2141 AddressItem *item;
2143 item = ADDRESS_ITEM(iobj);
2144 text[COL_NAME] = item->name;
2145 text[COL_ADDRESS] = item->address;
2146 text[COL_REMARKS] = item->remarks;
2147 row = gtk_clist_append(clist, text);
2148 gtk_clist_set_row_data(clist, row, iobj);
2152 gtk_clist_sort(clist);
2153 gtk_clist_thaw(clist);
2156 static void addressbook_read_file(void)
2158 XMLFile *file;
2159 gchar *path;
2161 debug_print(_("Reading addressbook file..."));
2163 path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRESS_BOOK, NULL);
2164 if ((file = xml_open_file(path)) == NULL) {
2165 debug_print(_("%s doesn't exist.\n"), path);
2166 g_free(path);
2167 addressbook_get_tree(NULL, addrbook.common, ADDRESS_TAG_COMMON);
2168 addressbook_get_tree(NULL, addrbook.personal, ADDRESS_TAG_PERSONAL);
2169 addressbook_get_tree(NULL, addrbook.vcard, ADDRESS_TAG_VCARD);
2170 #ifdef USE_JPILOT
2171 addressbook_get_tree(NULL, addrbook.jpilot, ADDRESS_TAG_JPILOT);
2172 #endif
2173 #ifdef USE_LDAP
2174 addressbook_get_tree(NULL, addrbook.ldap, ADDRESS_TAG_LDAP);
2175 #endif
2176 return;
2178 g_free(path);
2180 xml_get_dtd(file);
2182 if (xml_parse_next_tag(file) < 0 ||
2183 xml_compare_tag(file, "addressbook") == FALSE) {
2184 g_warning("Invalid addressbook data\n");
2185 xml_close_file(file);
2186 return;
2189 addressbook_get_tree(file, addrbook.common, ADDRESS_TAG_COMMON);
2190 addressbook_get_tree(file, addrbook.personal, ADDRESS_TAG_PERSONAL);
2191 addressbook_get_tree(file, addrbook.vcard, ADDRESS_TAG_VCARD);
2192 #ifdef USE_JPILOT
2193 addressbook_get_tree(file, addrbook.jpilot, ADDRESS_TAG_JPILOT);
2194 #endif
2195 #ifdef USE_LDAP
2196 addressbook_get_tree(file, addrbook.ldap, ADDRESS_TAG_LDAP);
2197 #endif
2199 xml_close_file(file);
2201 debug_print(_("done.\n"));
2204 static void addressbook_get_tree(XMLFile *file, GtkCTreeNode *node,
2205 const gchar *folder_tag)
2207 AddressFolder *folder;
2209 g_return_if_fail(node != NULL);
2211 folder = g_new(AddressFolder, 1);
2212 ADDRESS_OBJECT(folder)->type = ADDR_FOLDER;
2213 folder->name = g_strdup(folder_tag);
2214 folder->items = NULL;
2215 gtk_ctree_node_set_row_data(GTK_CTREE(addrbook.ctree), node, folder);
2217 if (file) {
2218 if (xml_parse_next_tag(file) < 0 ||
2219 xml_compare_tag(file, folder_tag) == FALSE) {
2220 g_warning("Invalid addressbook data\n");
2221 return;
2225 if (file) addressbook_add_objs(file, node);
2228 static void addressbook_add_objs(XMLFile *file, GtkCTreeNode *node)
2230 GList *attr;
2231 guint prev_level;
2232 GtkCTreeNode *new_node;
2234 for (;;) {
2235 prev_level = file->level;
2236 if (xml_parse_next_tag(file) < 0) return;
2237 if (file->level < prev_level) return;
2239 if (xml_compare_tag(file, "group")) {
2240 AddressGroup *group;
2242 group = g_new(AddressGroup, 1);
2243 ADDRESS_OBJECT_TYPE(group) = ADDR_GROUP;
2244 attr = xml_get_current_tag_attr(file);
2245 if (attr)
2246 group->name = g_strdup(((XMLAttr *)attr->data)->value);
2247 else
2248 group->name = NULL;
2249 group->items = NULL;
2251 new_node = addressbook_add_object
2252 (node, ADDRESS_OBJECT(group));
2254 addressbook_add_objs(file, new_node);
2255 } else if (xml_compare_tag(file, "folder")) {
2256 AddressFolder *folder;
2258 folder = g_new(AddressFolder, 1);
2259 ADDRESS_OBJECT_TYPE(folder) = ADDR_FOLDER;
2260 attr = xml_get_current_tag_attr(file);
2261 if (attr)
2262 folder->name = g_strdup(((XMLAttr *)attr->data)->value);
2263 else
2264 folder->name = NULL;
2265 folder->items = NULL;
2267 new_node = addressbook_add_object
2268 (node, ADDRESS_OBJECT(folder));
2270 addressbook_add_objs(file, new_node);
2272 else if( xml_compare_tag( file, "vcard" ) ) {
2273 AddressVCard *vcard;
2274 vcard = addressbook_parse_vcard( file );
2275 if( ! vcard ) return;
2276 new_node = addressbook_add_object
2277 (node, ADDRESS_OBJECT(vcard));
2279 #ifdef USE_JPILOT
2280 else if( xml_compare_tag( file, "jpilot" ) ) {
2281 AddressJPilot *jpilot;
2282 jpilot = addressbook_parse_jpilot( file );
2283 if( ! jpilot ) return;
2284 new_node = addressbook_add_object
2285 (node, ADDRESS_OBJECT(jpilot));
2287 #endif
2288 #ifdef USE_LDAP
2289 else if( xml_compare_tag( file, "server" ) ) {
2290 AddressLDAP *ldapi;
2291 ldapi = addressbook_parse_ldap( file );
2292 if( ! ldapi ) return;
2293 new_node = addressbook_add_object
2294 (node, ADDRESS_OBJECT(ldapi));
2296 #endif
2297 else if (xml_compare_tag(file, "item")) {
2298 AddressItem *item;
2300 item = addressbook_parse_item(file);
2301 if (!item) return;
2302 new_node = addressbook_add_object
2303 (node, ADDRESS_OBJECT(item));
2304 } else {
2305 g_warning("Invalid tag\n");
2306 return;
2311 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
2312 AddressObject *obj)
2314 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2315 GtkCTreeNode *added;
2316 AddressObject *pobj;
2318 g_return_val_if_fail(node != NULL, NULL);
2319 g_return_val_if_fail(obj != NULL, NULL);
2321 pobj = gtk_ctree_node_get_row_data(ctree, node);
2322 g_return_val_if_fail(pobj != NULL, NULL);
2324 if (pobj->type == ADDR_ITEM) {
2325 g_warning("Parent object mustn't be an item.\n");
2326 return NULL;
2328 if (pobj->type == ADDR_FOLDER &&
2329 (obj->type == ADDR_GROUP || obj->type == ADDR_FOLDER))
2330 gtk_ctree_expand(ctree, node);
2332 if (pobj->type == ADDR_FOLDER && obj->type == ADDR_VCARD )
2333 gtk_ctree_expand(ctree, node);
2335 if (pobj->type == ADDR_FOLDER && obj->type == ADDR_JPILOT )
2336 gtk_ctree_expand(ctree, node);
2338 if (pobj->type == ADDR_FOLDER && obj->type == ADDR_LDAP )
2339 gtk_ctree_expand(ctree, node);
2341 if (obj->type == ADDR_GROUP) {
2342 AddressGroup *group = ADDRESS_GROUP(obj);
2344 if (pobj->type != ADDR_FOLDER) {
2345 g_warning("Group can't be added in another group.\n");
2346 return NULL;
2349 added = gtk_ctree_insert_node(ctree, node, NULL,
2350 &group->name, FOLDER_SPACING,
2351 groupxpm, groupxpmmask,
2352 groupxpm, groupxpmmask,
2353 TRUE, FALSE);
2354 gtk_ctree_node_set_row_data(ctree, added, obj);
2355 } else if (obj->type == ADDR_FOLDER) {
2356 AddressFolder *folder = ADDRESS_FOLDER(obj);
2358 if (pobj->type != ADDR_FOLDER) {
2359 g_warning("Group can't contain folder.\n");
2360 return NULL;
2363 added = gtk_ctree_insert_node(ctree, node, NULL,
2364 &folder->name, FOLDER_SPACING,
2365 folderxpm, folderxpmmask,
2366 folderopenxpm, folderopenxpmmask,
2367 FALSE, FALSE);
2368 gtk_ctree_node_set_row_data(ctree, added, obj);
2371 else if (obj->type == ADDR_VCARD) {
2372 AddressVCard *vcard = ADDRESS_VCARD(obj);
2373 added = gtk_ctree_insert_node(ctree, node, NULL,
2374 &vcard->name, FOLDER_SPACING,
2375 vcardxpm, vcardxpmmask,
2376 vcardxpm, vcardxpmmask,
2377 TRUE, FALSE);
2378 gtk_ctree_node_set_row_data(ctree, added, obj);
2380 #ifdef USE_JPILOT
2381 else if (obj->type == ADDR_JPILOT) {
2382 AddressJPilot *jpilot = ADDRESS_JPILOT(obj);
2383 added = gtk_ctree_insert_node(ctree, node, NULL,
2384 &jpilot->name, FOLDER_SPACING,
2385 jpilotxpm, jpilotxpmmask,
2386 jpilotxpm, jpilotxpmmask,
2387 FALSE, FALSE);
2388 gtk_ctree_node_set_row_data(ctree, added, obj);
2390 else if (obj->type == ADDR_CATEGORY) {
2391 AddressCategory *category = ADDRESS_CATEGORY(obj);
2392 added = gtk_ctree_insert_node(ctree, node, NULL,
2393 &category->name, FOLDER_SPACING,
2394 categoryxpm, categoryxpmmask,
2395 categoryxpm, categoryxpmmask,
2396 TRUE, FALSE);
2397 gtk_ctree_node_set_row_data(ctree, added, obj);
2399 #endif
2400 #ifdef USE_LDAP
2401 else if (obj->type == ADDR_LDAP) {
2402 AddressLDAP *server = ADDRESS_LDAP(obj);
2403 added = gtk_ctree_insert_node(ctree, node, NULL,
2404 &server->name, FOLDER_SPACING,
2405 ldapxpm, ldapxpmmask,
2406 ldapxpm, ldapxpmmask,
2407 TRUE, FALSE);
2408 gtk_ctree_node_set_row_data(ctree, added, obj);
2410 #endif
2411 else {
2412 added = node;
2415 if (obj->type == ADDR_GROUP || obj->type == ADDR_ITEM) {
2416 if (pobj->type == ADDR_GROUP) {
2417 AddressGroup *group = ADDRESS_GROUP(pobj);
2419 group->items = g_list_append(group->items, obj);
2420 } else if (pobj->type == ADDR_FOLDER) {
2421 AddressFolder *folder = ADDRESS_FOLDER(pobj);
2423 folder->items = g_list_append(folder->items, obj);
2427 if (pobj->type == ADDR_FOLDER) {
2428 if (obj->type == ADDR_VCARD || obj->type == ADDR_JPILOT || obj->type == ADDR_LDAP) {
2429 AddressFolder *folder = ADDRESS_FOLDER(pobj);
2430 folder->items = g_list_append(folder->items, obj);
2434 gtk_ctree_sort_node(ctree, node);
2436 return added;
2439 static void addressbook_delete_object(AddressObject *obj)
2441 if (!obj) return;
2443 if (obj->type == ADDR_ITEM) {
2444 AddressItem *item = ADDRESS_ITEM(obj);
2446 mgu_free_address( item );
2447 } else if (obj->type == ADDR_GROUP) {
2448 AddressGroup *group = ADDRESS_GROUP(obj);
2450 g_free(group->name);
2451 while (group->items != NULL) {
2452 addressbook_delete_object
2453 (ADDRESS_OBJECT(group->items->data));
2454 group->items = g_list_remove(group->items,
2455 group->items->data);
2457 g_free(group);
2458 } else if (obj->type == ADDR_FOLDER) {
2459 AddressFolder *folder = ADDRESS_FOLDER(obj);
2461 g_free(folder->name);
2462 while (folder->items != NULL) {
2463 addressbook_delete_object
2464 (ADDRESS_OBJECT(folder->items->data));
2465 folder->items = g_list_remove(folder->items,
2466 folder->items->data);
2468 g_free(folder);
2470 else if( obj->type == ADDR_VCARD ) {
2471 AddressVCard *vcard = ADDRESS_VCARD(obj);
2472 g_free( vcard->name );
2473 vcard_free( vcard->cardFile );
2474 vcard->cardFile = NULL;
2475 vcard->items = NULL;
2476 g_free( vcard );
2478 #ifdef USE_JPILOT
2479 else if( obj->type == ADDR_JPILOT ) {
2480 AddressJPilot *jpilot = ADDRESS_JPILOT(obj);
2481 g_free( jpilot->name );
2482 jpilot_free( jpilot->pilotFile );
2483 jpilot->pilotFile = NULL;
2484 jpilot->items = NULL;
2485 g_free( jpilot );
2487 #endif
2488 #ifdef USE_LDAP
2489 else if( obj->type == ADDR_LDAP ) {
2490 AddressLDAP *ldapi = ADDRESS_LDAP(obj);
2491 g_free( ldapi->name );
2492 syldap_free( ldapi->ldapServer );
2493 ldapi->ldapServer = NULL;
2494 ldapi->items = NULL;
2495 g_free( ldapi );
2497 #endif
2500 static AddressObject *addressbook_find_object_by_name(GtkCTreeNode *node,
2501 const gchar *name)
2503 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2504 AddressObject *obj;
2505 GList *found;
2507 g_return_val_if_fail(node != NULL, NULL);
2509 obj = gtk_ctree_node_get_row_data(ctree, node);
2510 g_return_val_if_fail(obj != NULL, NULL);
2512 if (obj->type == ADDR_GROUP) {
2513 AddressGroup *group = ADDRESS_GROUP(obj);
2515 found = g_list_find_custom(group->items, (gpointer)name,
2516 addressbook_obj_name_compare);
2517 if (found) return ADDRESS_OBJECT(found->data);
2518 } else if (obj->type == ADDR_FOLDER) {
2519 AddressFolder *folder = ADDRESS_FOLDER(obj);
2521 found = g_list_find_custom(folder->items, (gpointer)name,
2522 addressbook_obj_name_compare);
2523 if (found) return ADDRESS_OBJECT(found->data);
2524 } else if (obj->type == ADDR_ITEM) {
2525 if (!addressbook_obj_name_compare(obj, name)) return obj;
2528 return NULL;
2531 static AddressItem *addressbook_parse_item(XMLFile *file)
2533 gchar *element;
2534 AddressItem *item;
2535 guint level;
2537 item = mgu_create_address();
2538 ADDRESS_OBJECT(item)->type = ADDR_ITEM;
2540 level = file->level;
2542 while (xml_parse_next_tag(file) == 0) {
2543 if (file->level < level) return item;
2544 if (file->level == level) break;
2546 element = xml_get_element(file);
2548 if (xml_compare_tag(file, "name")) {
2549 item->name = element;
2550 } else if (xml_compare_tag(file, "address")) {
2551 item->address = element;
2552 } else if (xml_compare_tag(file, "remarks")) {
2553 item->remarks = element;
2556 if (xml_parse_next_tag(file) < 0) break;
2557 if (file->level != level) break;
2560 g_warning("addressbook_parse_item(): Parse error\n");
2561 mgu_free_address( item );
2564 void addressbook_export_to_file(void)
2566 PrefFile *pfile;
2567 gchar *path;
2569 if (!addrbook.ctree) return;
2571 debug_print(_("Exporting addressbook to file..."));
2573 path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRESS_BOOK, NULL);
2574 if ((pfile = prefs_write_open(path)) == NULL) {
2575 g_free(path);
2576 return;
2578 g_free(path);
2580 fprintf(pfile->fp, "<?xml version=\"1.0\" encoding=\"%s\"?>\n",
2581 conv_get_current_charset_str());
2582 fputs("<addressbook>\n\n", pfile->fp);
2584 addressbook_xml_recursive_write(NULL, pfile->fp);
2586 fputs("</addressbook>\n", pfile->fp);
2588 if (prefs_write_close(pfile) < 0) {
2589 g_warning(_("failed to write addressbook data.\n"));
2590 return;
2593 debug_print(_("done.\n"));
2596 /* Most part of this function was taken from gtk_ctree_pre_recursive() and
2597 gtk_ctree_post_recursive(). */
2598 static void addressbook_xml_recursive_write(GtkCTreeNode *node, FILE *fp)
2600 GtkCTreeNode *work;
2601 GtkCTreeNode *tmp;
2603 if (node) {
2604 work = GTK_CTREE_ROW(node)->children;
2605 addressbook_node_write_begin(node, fp);
2606 } else
2607 work = GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list);
2609 while (work) {
2610 tmp = GTK_CTREE_ROW(work)->sibling;
2611 addressbook_xml_recursive_write(work, fp);
2612 work = tmp;
2615 if (node)
2616 addressbook_node_write_end(node, fp);
2619 static void addressbook_node_write_begin(GtkCTreeNode *node, FILE *fp)
2621 AddressObject *obj;
2623 obj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node);
2624 g_return_if_fail(obj != NULL);
2626 if (obj->type == ADDR_FOLDER) {
2627 AddressFolder *folder = ADDRESS_FOLDER(obj);
2629 if (GTK_CTREE_ROW(node)->level == 1) {
2630 fprintf(fp, "<%s>\n", folder->name);
2631 } else {
2632 tab_indent_out(fp, GTK_CTREE_ROW(node)->level - 1);
2633 fputs("<folder name=\"", fp);
2634 xml_file_put_escape_str(fp, folder->name);
2635 fputs("\">\n", fp);
2637 } else if (obj->type == ADDR_GROUP) {
2638 AddressGroup *group = ADDRESS_GROUP(obj);
2640 tab_indent_out(fp, GTK_CTREE_ROW(node)->level - 1);
2641 fputs("<group name=\"", fp);
2642 xml_file_put_escape_str(fp, group->name);
2643 fputs("\">\n", fp);
2647 static void addressbook_node_write_end(GtkCTreeNode *node, FILE *fp)
2649 AddressObject *obj;
2651 obj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node);
2652 g_return_if_fail(obj != NULL);
2654 if (obj->type == ADDR_FOLDER) {
2655 AddressFolder *folder = ADDRESS_FOLDER(obj);
2657 addressbook_write_items(fp, folder->items,
2658 GTK_CTREE_ROW(node)->level);
2660 if (GTK_CTREE_ROW(node)->level == 1) {
2661 fprintf(fp, "</%s>\n\n", folder->name);
2662 } else {
2663 tab_indent_out(fp, GTK_CTREE_ROW(node)->level - 1);
2664 fputs("</folder>\n", fp);
2666 } else if (obj->type == ADDR_GROUP) {
2667 AddressGroup *group = ADDRESS_GROUP(obj);
2669 addressbook_write_items(fp, group->items,
2670 GTK_CTREE_ROW(node)->level);
2672 tab_indent_out(fp, GTK_CTREE_ROW(node)->level - 1);
2673 fputs("</group>\n", fp);
2675 else if (obj->type == ADDR_VCARD) {
2676 AddressVCard *vcard = ADDRESS_VCARD(obj);
2677 addressbook_write_vcard( fp, vcard, GTK_CTREE_ROW(node)->level);
2679 #ifdef USE_JPILOT
2680 else if (obj->type == ADDR_JPILOT) {
2681 AddressJPilot *jpilot = ADDRESS_JPILOT(obj);
2682 addressbook_write_jpilot( fp, jpilot, GTK_CTREE_ROW(node)->level);
2684 #endif
2685 #ifdef USE_LDAP
2686 else if (obj->type == ADDR_LDAP) {
2687 AddressLDAP *ldap = ADDRESS_LDAP(obj);
2688 addressbook_write_ldap( fp, ldap, GTK_CTREE_ROW(node)->level);
2690 #endif
2693 static void addressbook_write_items(FILE *fp, GList *items, guint level)
2695 AddressItem *item;
2697 for (; items != NULL; items = items->next) {
2698 if (ADDRESS_OBJECT_TYPE(items->data) == ADDR_ITEM) {
2699 item = ADDRESS_ITEM(items->data);
2701 tab_indent_out(fp, level);
2702 fputs("<item>\n", fp);
2704 tab_indent_out(fp, level + 1);
2705 fputs("<name>", fp);
2706 xml_file_put_escape_str(fp, item->name);
2707 fputs("</name>\n", fp);
2709 tab_indent_out(fp, level + 1);
2710 fputs("<address>", fp);
2711 xml_file_put_escape_str(fp, item->address);
2712 fputs("</address>\n", fp);
2714 tab_indent_out(fp, level + 1);
2715 fputs("<remarks>", fp);
2716 xml_file_put_escape_str(fp, item->remarks);
2717 fputs("</remarks>\n", fp);
2719 tab_indent_out(fp, level);
2720 fputs("</item>\n", fp);
2725 static void tab_indent_out(FILE *fp, guint level)
2727 gint i;
2729 for (i = 0; i < level; i++)
2730 fputs(" ", fp);
2733 static void key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
2735 if (event && event->keyval == GDK_Escape)
2736 addressbook_close();
2739 static gint addressbook_list_compare_func(GtkCList *clist,
2740 gconstpointer ptr1,
2741 gconstpointer ptr2)
2743 AddressObject *obj1 = ((GtkCListRow *)ptr1)->data;
2744 AddressObject *obj2 = ((GtkCListRow *)ptr2)->data;
2745 gchar *name1, *name2;
2747 if (obj1) {
2748 if (obj1->type == ADDR_ITEM)
2749 name1 = ADDRESS_ITEM(obj1)->name;
2750 else if (obj1->type == ADDR_GROUP)
2751 name1 = ADDRESS_GROUP(obj1)->name;
2752 else if (obj1->type == ADDR_FOLDER)
2753 name1 = ADDRESS_FOLDER(obj1)->name;
2754 else if (obj1->type == ADDR_VCARD)
2755 name1 = ADDRESS_VCARD(obj1)->name;
2756 #ifdef USE_JPILOT
2757 else if (obj1->type == ADDR_JPILOT)
2758 name1 = ADDRESS_JPILOT(obj1)->name;
2759 else if (obj1->type == ADDR_CATEGORY)
2760 name1 = ADDRESS_CATEGORY(obj1)->name;
2761 #endif
2762 #ifdef USE_LDAP
2763 else if (obj1->type == ADDR_LDAP)
2764 name1 = ADDRESS_LDAP(obj1)->name;
2765 #endif
2766 else
2767 name1 = NULL;
2768 } else
2769 name1 = NULL;
2771 if (obj2) {
2772 if (obj2->type == ADDR_ITEM)
2773 name2 = ADDRESS_ITEM(obj2)->name;
2774 else if (obj2->type == ADDR_GROUP)
2775 name2 = ADDRESS_GROUP(obj2)->name;
2776 else if (obj2->type == ADDR_FOLDER)
2777 name2 = ADDRESS_FOLDER(obj2)->name;
2778 else if (obj2->type == ADDR_VCARD)
2779 name2 = ADDRESS_VCARD(obj2)->name;
2780 #ifdef USE_JPILOT
2781 else if (obj2->type == ADDR_JPILOT)
2782 name2 = ADDRESS_JPILOT(obj2)->name;
2783 else if (obj2->type == ADDR_CATEGORY)
2784 name2 = ADDRESS_CATEGORY(obj2)->name;
2785 #endif
2786 #ifdef USE_LDAP
2787 else if (obj2->type == ADDR_LDAP)
2788 name2 = ADDRESS_LDAP(obj2)->name;
2789 #endif
2790 else
2791 name2 = NULL;
2792 } else
2793 name2 = NULL;
2795 if (!name1)
2796 return (name2 != NULL);
2797 if (!name2)
2798 return -1;
2800 return strcasecmp(name1, name2);
2803 static gint addressbook_obj_name_compare(gconstpointer a, gconstpointer b)
2805 const AddressObject *obj = a;
2806 const gchar *name = b;
2808 if (!obj || !name) return -1;
2810 if (obj->type == ADDR_GROUP) {
2811 AddressGroup *group = ADDRESS_GROUP(obj);
2812 if (!group->name)
2813 return -1;
2814 else
2815 return strcasecmp(group->name, name);
2816 } else if (obj->type == ADDR_FOLDER) {
2817 AddressFolder *folder = ADDRESS_FOLDER(obj);
2818 if (!folder->name)
2819 return -1;
2820 else
2821 return strcasecmp(folder->name, name);
2823 else if (obj->type == ADDR_VCARD) {
2824 AddressVCard *vcard = ADDRESS_VCARD(obj);
2825 if (!vcard->name)
2826 return -1;
2827 else
2828 return strcasecmp(vcard->name, name);
2830 #ifdef USE_JPILOT
2831 else if (obj->type == ADDR_JPILOT) {
2832 AddressJPilot *jpilot = ADDRESS_JPILOT(obj);
2833 if (!jpilot->name)
2834 return -1;
2835 else
2836 return strcasecmp(jpilot->name, name);
2838 else if (obj->type == ADDR_CATEGORY) {
2839 AddressCategory *category = ADDRESS_CATEGORY(obj);
2840 if (!category->name)
2841 return -1;
2842 else
2843 return strcasecmp(category->name, name);
2845 #endif
2846 #ifdef USE_LDAP
2847 else if (obj->type == ADDR_LDAP) {
2848 AddressLDAP *server = ADDRESS_LDAP(obj);
2849 if (!server->name)
2850 return -1;
2851 else
2852 return strcasecmp(server->name, name);
2854 #endif
2855 else if (obj->type == ADDR_ITEM) {
2856 AddressItem *item = ADDRESS_ITEM(obj);
2857 if (!item->name)
2858 return -1;
2859 else
2860 return strcasecmp(item->name, name);
2861 } else
2862 return -1;
2865 static AddressVCard *addressbook_parse_vcard(XMLFile *file) {
2866 AddressVCard *item = NULL;
2867 VCardFile *vcf;
2868 GList *attr;
2869 gchar *name, *value;
2871 vcf = vcard_create();
2872 attr = xml_get_current_tag_attr( file );
2873 while( attr ) {
2874 name = ((XMLAttr *)attr->data)->name;
2875 value = ((XMLAttr *)attr->data)->value;
2876 if( strcmp( name, "name" ) == 0 ) {
2877 vcard_set_name( vcf, value );
2879 else if( strcmp( name, "file" ) == 0) {
2880 vcard_set_file( vcf, value );
2882 attr = g_list_next( attr );
2885 // Move to next tag
2886 if( xml_parse_next_tag( file ) >= 0 ) {
2887 if( vcard_validate( vcf ) ) {
2888 item = g_new( AddressVCard, 1 );
2889 ADDRESS_OBJECT(item)->type = ADDR_VCARD;
2890 item->name = g_strdup( vcf->name );
2891 item->cardFile = vcf;
2892 item->items = NULL;
2893 return item;
2897 // Must be an invalid tag or data.
2898 g_warning( "addressbook_parse_vcard(): Parse error\n");
2899 vcard_free( vcf );
2900 vcf = NULL;
2901 item = NULL;
2902 return NULL;
2905 static void addressbook_write_vcard( FILE *fp, AddressVCard *vcard, guint level ) {
2906 VCardFile *cardFile = vcard->cardFile;
2907 if( cardFile ) {
2908 tab_indent_out(fp, 1);
2909 fputs("<vcard ", fp);
2910 fputs("name=\"", fp);
2911 xml_file_put_escape_str(fp, cardFile->name);
2912 fputs("\"", fp);
2913 fputs(" file=\"", fp);
2914 xml_file_put_escape_str(fp, cardFile->path);
2915 fputs("\"", fp);
2916 fputs(" />\n", fp);
2920 #ifdef USE_JPILOT
2921 static AddressJPilot *addressbook_parse_jpilot(XMLFile *file) {
2922 AddressJPilot *item = NULL;
2923 JPilotFile *jpf;
2924 GList *attr;
2925 gchar *name, *value;
2927 jpf = jpilot_create();
2928 attr = xml_get_current_tag_attr( file );
2929 while( attr ) {
2930 name = ((XMLAttr *)attr->data)->name;
2931 value = ((XMLAttr *)attr->data)->value;
2932 if( strcmp( name, "name" ) == 0 ) {
2933 jpilot_set_name( jpf, value );
2935 else if( strcmp( name, "file" ) == 0 ) {
2936 jpilot_set_file( jpf, value );
2938 else if( strcmp( name, "custom-1" ) == 0 ) {
2939 jpilot_add_custom_label( jpf, value );
2941 else if( strcmp( name, "custom-2" ) == 0 ) {
2942 jpilot_add_custom_label( jpf, value );
2944 else if( strcmp( name, "custom-3" ) == 0 ) {
2945 jpilot_add_custom_label( jpf, value );
2947 else if( strcmp( name, "custom-4" ) == 0 ) {
2948 jpilot_add_custom_label( jpf, value );
2950 attr = g_list_next( attr );
2953 // Move to next tag
2954 if( xml_parse_next_tag( file ) >= 0 ) {
2955 if( jpilot_validate( jpf ) ) {
2956 item = g_new( AddressJPilot, 1 );
2957 ADDRESS_OBJECT(item)->type = ADDR_JPILOT;
2958 item->name = g_strdup( jpf->name );
2959 item->pilotFile = jpf;
2960 item->items = NULL;
2961 return item;
2965 // Must be an invalid tag or data.
2966 g_warning( "addressbook_parse_jpilot(): Parse error\n");
2967 jpilot_free( jpf );
2968 jpf = NULL;
2969 item = NULL;
2970 return NULL;
2973 static void addressbook_write_jpilot( FILE *fp, AddressJPilot *jpilot, guint level ) {
2974 JPilotFile *pilotFile = jpilot->pilotFile;
2975 if( pilotFile ) {
2976 gint ind;
2977 GList *node;
2978 GList *customLbl = jpilot_get_custom_labels( pilotFile );
2979 tab_indent_out(fp, 1);
2980 fputs("<jpilot ", fp);
2981 fputs("name=\"", fp);
2982 xml_file_put_escape_str(fp, pilotFile->name);
2983 fputs("\" file=\"", fp);
2984 xml_file_put_escape_str(fp, pilotFile->path);
2986 fputs( "\" ", fp );
2987 node = customLbl;
2988 ind = 1;
2989 while( node ) {
2990 fprintf( fp, "custom-%d=\"", ind );
2991 xml_file_put_escape_str( fp, node->data );
2992 fputs( "\" ", fp );
2993 ind++;
2994 node = g_list_next( node );
2996 fputs("/>\n", fp);
2999 #endif
3001 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
3002 AddressVCard *vcard;
3004 if( addrbook.selected != addrbook.vcard ) return;
3005 vcard = addressbook_edit_vcard( NULL );
3006 if( vcard ) {
3007 addressbook_add_object( addrbook.selected, ADDRESS_OBJECT(vcard) );
3008 if( addrbook.selected == addrbook.opened ) {
3009 addrbook.open_folder = TRUE;
3010 gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
3015 static void addressbook_vcard_show_message( VCardFile *vcf ) {
3016 *addressbook_msgbuf = '\0';
3017 if( vcf ) {
3018 if( vcf->retVal == MGU_SUCCESS ) {
3019 sprintf( addressbook_msgbuf, "%s", vcf->name );
3021 else {
3022 sprintf( addressbook_msgbuf, "%s: %s", vcf->name, mgu_error2string( vcf->retVal ) );
3025 addressbook_status_show( addressbook_msgbuf );
3028 #ifdef USE_JPILOT
3029 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
3030 AddressJPilot *jpilot;
3032 if( addrbook.selected != addrbook.jpilot ) return;
3033 if( ! _have_pilot_library_ ) return;
3034 jpilot = addressbook_edit_jpilot( NULL );
3035 if( jpilot ) {
3036 addressbook_add_object( addrbook.selected, ADDRESS_OBJECT(jpilot) );
3037 if( addrbook.selected == addrbook.opened ) {
3038 addrbook.open_folder = TRUE;
3039 gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
3044 static void addressbook_jpilot_show_message( JPilotFile *jpf ) {
3045 *addressbook_msgbuf = '\0';
3046 if( jpf ) {
3047 if( jpf->retVal == MGU_SUCCESS ) {
3048 sprintf( addressbook_msgbuf, "%s", jpf->name );
3050 else {
3051 sprintf( addressbook_msgbuf, "%s: %s", jpf->name, mgu_error2string( jpf->retVal ) );
3054 addressbook_status_show( addressbook_msgbuf );
3057 #endif
3059 #ifdef USE_LDAP
3060 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
3061 AddressLDAP *ldapi;
3063 if( addrbook.selected != addrbook.ldap ) return;
3064 if( ! _have_ldap_library_ ) return;
3065 ldapi = addressbook_edit_ldap( NULL );
3066 if( ldapi ) {
3067 addressbook_add_object( addrbook.selected, ADDRESS_OBJECT(ldapi) );
3068 if( addrbook.selected == addrbook.opened ) {
3069 addrbook.open_folder = TRUE;
3070 gtk_ctree_select( GTK_CTREE(addrbook.ctree), addrbook.opened );
3075 static AddressLDAP *addressbook_parse_ldap(XMLFile *file) {
3076 AddressLDAP *item = NULL;
3077 SyldapServer *server;
3078 GList *attr;
3079 gchar *name, *value;
3080 gint ivalue;
3082 server = syldap_create();
3083 attr = xml_get_current_tag_attr( file );
3084 while( attr ) {
3085 name = ((XMLAttr *)attr->data)->name;
3086 value = ((XMLAttr *)attr->data)->value;
3087 ivalue = atoi( value );
3088 if( strcmp( name, "name" ) == 0 ) {
3089 syldap_set_name( server, value );
3091 else if( strcmp( name, "host" ) == 0 ) {
3092 syldap_set_host( server, value );
3094 else if( strcmp( name, "port" ) == 0 ) {
3095 syldap_set_port( server, ivalue );
3097 else if( strcmp( name, "base-dn" ) == 0 ) {
3098 syldap_set_base_dn( server, value );
3100 else if( strcmp( name, "bind-dn" ) == 0 ) {
3101 syldap_set_bind_dn( server, value );
3103 else if( strcmp( name, "bind-pass" ) == 0 ) {
3104 syldap_set_bind_password( server, value );
3106 else if( strcmp( name, "criteria" ) == 0 ) {
3107 syldap_set_search_criteria( server, value );
3109 else if( strcmp( name, "max-entry" ) == 0 ) {
3110 syldap_set_max_entries( server, ivalue );
3112 else if( strcmp( name, "timeout" ) == 0 ) {
3113 syldap_set_timeout( server, ivalue );
3115 attr = g_list_next( attr );
3118 // Move to next tag
3119 if( xml_parse_next_tag( file ) >= 0 ) {
3120 item = g_new( AddressLDAP, 1 );
3121 ADDRESS_OBJECT(item)->type = ADDR_LDAP;
3122 item->name = g_strdup( server->name );
3123 item->ldapServer = server;
3124 item->items = NULL;
3125 return item;
3128 // Must be an invalid tag or data.
3129 g_warning( "addressbook_parse_ldap(): Parse error\n");
3130 syldap_free( server );
3131 server = NULL;
3132 item = NULL;
3133 return NULL;
3136 static void addressbook_write_ldap( FILE *fp, AddressLDAP *ldapi, guint level ) {
3137 SyldapServer *server = ldapi->ldapServer;
3138 if( server ) {
3139 tab_indent_out(fp, 1);
3140 fputs("<server ", fp);
3141 fputs("name=\"", fp);
3142 xml_file_put_escape_str(fp, server->name);
3143 fputs("\" host=\"", fp);
3144 xml_file_put_escape_str(fp, server->hostName);
3145 fprintf( fp, "\" port=\"%d", server->port);
3146 fputs("\" base-dn=\"", fp);
3147 xml_file_put_escape_str(fp, server->baseDN);
3148 fputs("\" bind-dn=\"", fp);
3149 xml_file_put_escape_str(fp, server->bindDN);
3150 fputs("\" bind-pass=\"", fp);
3151 xml_file_put_escape_str(fp, server->bindPass);
3152 fputs("\" criteria=\"", fp);
3153 xml_file_put_escape_str(fp, server->searchCriteria);
3154 fprintf( fp, "\" max-entry=\"%d", server->maxEntries);
3155 fprintf( fp, "\" timeout=\"%d", server->timeOut);
3156 fputs("\" />\n", fp);
3160 static void addressbook_ldap_show_message( SyldapServer *svr ) {
3161 *addressbook_msgbuf = '\0';
3162 if( svr ) {
3163 if( svr->busyFlag ) {
3164 sprintf( addressbook_msgbuf, "%s: %s", svr->name, ADDRESSBOOK_LDAP_BUSYMSG );
3166 else {
3167 if( svr->retVal == MGU_SUCCESS ) {
3168 sprintf( addressbook_msgbuf, "%s", svr->name );
3170 else {
3171 sprintf( addressbook_msgbuf, "%s: %s", svr->name, mgu_error2string( svr->retVal ) );
3175 addressbook_status_show( addressbook_msgbuf );
3178 static gint ldapsearch_callback( SyldapServer *sls ) {
3179 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3180 AddressObject *obj;
3182 if( sls == NULL ) return;
3183 if( ! addrbook.selected ) return;
3184 if( GTK_CTREE_ROW( addrbook.selected )->level == 1 ) return;
3186 obj = gtk_ctree_node_get_row_data( ctree, addrbook.selected );
3187 if( obj == NULL ) return;
3188 if( obj->type == ADDR_LDAP ) {
3189 AddressLDAP *ldapi = ADDRESS_LDAP(obj);
3190 SyldapServer *server = ldapi->ldapServer;
3191 if( server == sls ) {
3192 if( ! _have_ldap_library_ ) return;
3193 // Read from cache
3194 gtk_widget_show_all(addrbook.window);
3195 ADDRESS_LDAP(obj)->items = syldap_get_address_list( sls );
3196 addressbook_set_clist( obj );
3197 addressbook_ldap_show_message( sls );
3198 gtk_widget_show_all(addrbook.window);
3202 #endif
3205 * Lookup button handler.
3207 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
3208 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
3209 AddressObject *obj;
3210 gchar *sLookup;
3211 #ifdef USE_LDAP
3212 AddressLDAP *ldapi;
3213 SyldapServer *server;
3214 #endif
3216 sLookup = gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
3217 g_strchomp( sLookup );
3219 if( ! addrbook.selected ) return;
3220 if( GTK_CTREE_ROW( addrbook.selected )->level == 1 ) return;
3222 obj = gtk_ctree_node_get_row_data( ctree, addrbook.selected );
3223 if( obj == NULL ) return;
3225 #ifdef USE_LDAP
3226 if( obj->type == ADDR_LDAP ) {
3227 ldapi = ADDRESS_LDAP(obj);
3228 server = ldapi->ldapServer;
3229 if( server ) {
3230 if( ! _have_ldap_library_ ) return;
3231 syldap_cancel_read( server );
3232 if( *sLookup == '\0' || strlen( sLookup ) < 1 ) return;
3233 syldap_set_search_value( server, sLookup );
3234 syldap_set_callback( server, ldapsearch_callback );
3235 syldap_read_data_th( server );
3236 addressbook_ldap_show_message( server );
3239 #endif
3243 /***/
3245 typedef struct {
3246 gboolean init; /* if FALSE should init jump buffer */
3247 GtkCTreeNode *node_found; /* match (can be used to backtrack folders) */
3248 AddressObject *addr_found; /* match */
3249 int level; /* current recursion level (0 is root level) */
3250 jmp_buf jumper; /* jump buffer */
3251 } FindObject;
3253 typedef struct {
3254 FindObject ancestor;
3255 const gchar *groupname;
3256 } FindGroup;
3258 typedef struct {
3259 FindObject ancestor;
3260 const gchar *name;
3261 const gchar *address;
3262 } FindAddress;
3264 typedef struct {
3265 FindObject ancestor;
3266 GList *grouplist;
3267 } FindAllGroups;
3269 typedef gboolean (*ADDRESSBOOK_TRAVERSE_FUNC)(AddressObject *node, gpointer data);
3271 /***/
3273 static gboolean traverse_find_group_by_name(AddressObject *ao, FindGroup *find)
3275 AddressFolder *folder;
3276 AddressGroup *group;
3278 /* a group or folder: both are groups */
3279 if (ADDRESS_OBJECT_TYPE(ao) == ADDR_GROUP) {
3280 group = ADDRESS_GROUP(ao);
3281 if (0 == g_strcasecmp(group->name, find->groupname)) {
3282 return TRUE;
3285 else if (ADDRESS_OBJECT_TYPE(ao) == ADDR_FOLDER) {
3286 folder = ADDRESS_FOLDER(ao);
3287 if (0 == g_strcasecmp(folder->name, find->groupname)) {
3288 return TRUE;
3291 return FALSE;
3294 static gboolean traverse_find_name_email(AddressObject *ao, FindAddress *find)
3296 AddressItem *item;
3297 if (ADDRESS_OBJECT_TYPE(ao) == ADDR_ITEM) {
3298 gboolean nmatch = FALSE, amatch = FALSE;
3299 item = ADDRESS_ITEM(ao);
3300 /* conditions:
3301 * o only match at the first characters in item strings
3302 * o match either name or address */
3303 if (find->name && item->name) {
3304 nmatch = item->name == strcasestr(item->name, find->name);
3306 if (find->address && item->address) {
3307 amatch = item->address == strcasestr(item->address, find->address);
3309 return nmatch || amatch;
3311 return FALSE;
3314 static gboolean traverse_find_all_groups(AddressObject *ao, FindAllGroups *find)
3316 /* NOTE: added strings come from the address book. should perhaps
3317 * strdup() them, especially if the address book is invalidated */
3318 if (ADDRESS_OBJECT_TYPE(ao) == ADDR_FOLDER) {
3319 AddressFolder *folder = ADDRESS_FOLDER(ao);
3320 find->grouplist = g_list_insert_sorted(find->grouplist, (gpointer) folder->name, (GCompareFunc) g_strcasecmp);
3322 else if (ADDRESS_OBJECT_TYPE(ao) == ADDR_GROUP) {
3323 AddressGroup *group = ADDRESS_GROUP(ao);
3324 find->grouplist = g_list_insert_sorted(find->grouplist, (gpointer) group->name, (GCompareFunc) g_strcasecmp);
3326 return FALSE;
3329 /* addressbook_traverse() - traverses all address objects stored in the address book.
3330 * for some reason gtkctree's recursive tree functions don't allow a premature return,
3331 * which is what we need if we need to enumerate the tree and check for a condition
3332 * and then skipping other nodes. */
3333 static AddressObject *addressbook_traverse(GtkCTreeNode *node, ADDRESSBOOK_TRAVERSE_FUNC func, FindObject *data, int level)
3335 GtkCTreeNode *current, *tmp;
3336 AddressObject *ao;
3338 if (data->init == FALSE) {
3339 /* initialize non-local exit */
3340 data->init = TRUE;
3341 data->level = 0;
3342 /* HANDLE NON-LOCAL EXIT */
3343 if (setjmp(data->jumper)) {
3344 return data->addr_found;
3348 /* actual recursive code */
3349 if (!node) {
3350 current = GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list);
3352 else {
3353 current = node;
3356 while (current) {
3357 tmp = GTK_CTREE_ROW(current)->sibling;
3358 ao = (AddressObject *) gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), current);
3359 if (ao) {
3360 GList *next;
3362 next = (ADDRESS_OBJECT_TYPE(ao) == ADDR_FOLDER) ?
3363 g_list_first(((ADDRESS_FOLDER(ao))->items)) :
3364 (ADDRESS_OBJECT_TYPE(ao) == ADDR_GROUP) ?
3365 g_list_first(((ADDRESS_GROUP(ao))->items)) : NULL;
3367 while (ao) {
3368 /* NOTE: first iteration of the root calls callback for the tree
3369 * node, other iterations call callback for the address book items */
3370 if (func(ao, data)) {
3371 /* unwind */
3372 data->node_found = current;
3373 data->addr_found = ao;
3374 longjmp(data->jumper, 1);
3376 /* ctree node only stores folders and groups. now descend into
3377 * address object data, searching for address items. */
3378 for ( ; next && ADDRESS_OBJECT_TYPE((next->data)) != ADDR_ITEM
3379 ; next = g_list_next(next))
3381 ao = next ? (AddressObject *) next->data : NULL;
3382 next = next ? g_list_next(next) : NULL;
3385 /* check the children (if level permits) */
3386 if (level == -1 || data->level < level) {
3387 current = GTK_CTREE_ROW(current)->children;
3388 if (current) {
3389 data->level++;
3390 addressbook_traverse(current, func, data, level);
3391 data->level--;
3394 /* check the siblings */
3395 current = tmp;
3397 return NULL;
3400 static GtkCTreeNode *addressbook_get_group_node(const gchar *name)
3402 FindGroup fg = { { FALSE, NULL, NULL }, NULL };
3403 fg.groupname = name;
3404 addressbook_traverse(NULL, (void *)traverse_find_group_by_name, (FindObject *)&fg, -1);
3405 return fg.ancestor.node_found;
3408 static void addressbook_free_item(AddressItem *item)
3410 if (item) {
3411 if (item->name) g_free(item->name);
3412 if (item->address) g_free(item->address);
3413 if (item->remarks) g_free(item->remarks);
3414 g_free(item);
3418 static AddressItem *addressbook_alloc_item(const gchar *name, const gchar *address, const gchar *remarks)
3420 AddressItem *item = g_new0(AddressItem, 1);
3422 if (item) {
3423 item->obj.type = ADDR_ITEM;
3424 if (item->name = g_strdup(name))
3425 if (item->address = g_strdup(address)) {
3426 if (remarks) {
3427 item->remarks = g_strdup(remarks);
3429 return item;
3432 addressbook_free_item(item);
3433 return NULL;
3436 /***/
3438 /* public provisional API */
3440 /* addressbook_access() - should be called before using any of the following apis. it
3441 * reloads the address book. */
3442 void addressbook_access(void)
3444 log_message("accessing address book\n");
3445 if (!addrbook.window) {
3446 addressbook_create(FALSE);
3447 addressbook_read_file();
3448 addrbook.open_folder = TRUE;
3449 gtk_ctree_select(GTK_CTREE(addrbook.ctree), GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
3453 /* addressbook_unaccess() - should only be called after changing the address book's
3454 * contents */
3455 void addressbook_unaccess(void)
3457 log_message("unaccessing address book\n");
3458 addressbook_export_to_file();
3459 invalidate_address_completion();
3462 const gchar *addressbook_get_personal_folder_name(void)
3464 return _("Personal addresses"); /* human readable */
3467 const gchar *addressbook_get_common_folder_name(void)
3469 return _("Common addresses"); /* human readable */
3472 /* addressbook_find_group_by_name() - finds a group (folder or group) by
3473 * its name */
3474 AddressObject *addressbook_find_group_by_name(const gchar *name)
3476 FindGroup fg = { { FALSE, NULL, NULL } };
3477 AddressObject *ao;
3479 /* initialize obj members */
3480 fg.groupname = name;
3481 ao = addressbook_traverse(NULL,
3482 (ADDRESSBOOK_TRAVERSE_FUNC)traverse_find_group_by_name,
3483 (FindObject *)&fg, -1);
3484 return ao;
3487 /* addressbook_find_contact() - finds an address item by either name or address
3488 * or both. the comparison is done on the first few characters of the strings */
3489 AddressObject *addressbook_find_contact(const gchar *name, const gchar *address)
3491 FindAddress fa = { { FALSE, NULL, NULL } };
3492 AddressObject *ao;
3494 fa.name = name;
3495 fa.address = address;
3496 ao = addressbook_traverse(NULL, (ADDRESSBOOK_TRAVERSE_FUNC)traverse_find_name_email,
3497 (FindObject *)&fa, -1);
3498 return ao;
3501 /* addressbook_get_group_list() - returns a list of strings with group names (both
3502 * groups and folders). free the list using g_list_free(). note that another
3503 * call may invalidate the returned list */
3504 GList *addressbook_get_group_list(void)
3506 FindAllGroups fag = { { FALSE, NULL, NULL }, NULL };
3507 addressbook_traverse(NULL, (ADDRESSBOOK_TRAVERSE_FUNC)traverse_find_all_groups,
3508 (FindObject *)&fag, -1);
3509 return fag.grouplist;
3512 /* addressbook_add_contact() - adds a contact to the address book. returns 1
3513 * if succesful else error */
3514 gint addressbook_add_contact(const gchar *group, const gchar *name, const gchar *address,
3515 const gchar *remarks)
3517 GtkCTreeNode *node;
3518 AddressItem *item;
3519 FindAddress fa = { { FALSE, NULL, NULL } };
3521 /* a healthy mix of hiro's and my code */
3522 if (name == NULL || strlen(name) == 0
3523 || address == NULL || strlen(address) == 0
3524 || group == NULL || strlen(group) == 0) {
3525 return __LINE__;
3527 node = addressbook_get_group_node(group);
3528 if (!node) {
3529 return __LINE__;
3532 /* check if it's already in this group */
3533 fa.name = name;
3534 fa.address = address;
3536 if (addressbook_traverse(node, (gpointer)traverse_find_name_email, (gpointer)&fa, 0)) {
3537 log_message("address <%s> already in %s\n", address, group);
3538 return __LINE__;
3541 item = addressbook_alloc_item(name, address, remarks);
3542 if (!item) {
3543 return __LINE__;
3546 if (!addressbook_add_object(node, (AddressObject *)item)) {
3547 addressbook_free_item(item);
3548 return __LINE__;
3551 /* make sure it's updated if selected */
3552 log_message("updating addressbook widgets\n");
3553 addrbook.open_folder = TRUE;
3554 gtk_ctree_select(GTK_CTREE(addrbook.ctree), addrbook.opened);
3556 /* not saved yet. only after unaccessing the address book */
3557 return 0;
3560 static void group_object_data_destroy(gchar *group)
3562 if (group) {
3563 g_free(group);
3567 /***/
3569 typedef struct {
3570 gchar *name;
3571 gchar *address;
3572 gchar *remarks;
3573 } ContactInfo;
3575 static void addressbook_destroy_contact(ContactInfo *ci)
3577 g_return_if_fail(ci != NULL);
3578 if (ci->name) g_free(ci->name);
3579 if (ci->address) g_free(ci->address);
3580 if (ci->remarks) g_free(ci->remarks);
3581 g_free(ci);
3584 static ContactInfo *addressbook_new_contact(const gchar *name, const gchar *address, const gchar *remarks)
3586 ContactInfo *ci = g_new0(ContactInfo, 1);
3588 g_return_val_if_fail(ci != NULL, NULL);
3589 g_return_val_if_fail(address != NULL, NULL); /* address should be valid */
3590 ci->name = name ? g_strdup(name) : NULL;
3591 ci->address = g_strdup(address);
3592 ci->remarks = remarks ? g_strdup(remarks) : NULL;
3593 if (NULL == ci->address) {
3594 addressbook_destroy_contact(ci);
3595 ci = NULL;
3597 return ci;
3600 static void addressbook_group_menu_selected(GtkMenuItem *menuitem,
3601 ContactInfo *data)
3603 const gchar *group_name = (const gchar *) gtk_object_get_data(GTK_OBJECT(menuitem),
3604 "group_name");
3606 if (!group_name) {
3607 g_warning("%s(%d) - invalid group name\n", __FILE__, __LINE__);
3608 return ;
3610 g_return_if_fail(group_name != NULL);
3612 g_message("selected group %s from menu\n", group_name);
3613 g_message("selected %s <%s>\n", data->name ? data->name : data->address, data->address);
3615 addressbook_access();
3616 addressbook_add_contact(group_name, data->name ? data->name : data->address,
3617 data->address, data->remarks ? data->remarks : data->address);
3618 addressbook_unaccess();
3620 g_free(data);
3623 /* addressbook_add_contact_by_meny() - launches menu with group items. submenu may be
3624 * the menu item in the parent menu, or NULL for a normal right-click context menu */
3625 gboolean addressbook_add_submenu(GtkWidget *submenu,
3626 const gchar *name,
3627 const gchar *address,
3628 const gchar *remarks)
3630 GtkWidget *menu, *menuitem;
3631 GList *groups, *tmp;
3632 ContactInfo *ci;
3634 ci = addressbook_new_contact(name, address, remarks);
3635 g_return_val_if_fail(ci != NULL, FALSE);
3637 addressbook_access();
3638 groups = addressbook_get_group_list();
3639 g_return_val_if_fail(groups != NULL, (addressbook_destroy_contact(ci), FALSE));
3641 menu = gtk_menu_new();
3642 g_return_val_if_fail(menu != NULL, (g_list_free(groups), addressbook_destroy_contact(ci), FALSE));
3644 /* add groups to menu */
3645 for (tmp = g_list_first(groups); tmp != NULL; tmp = g_list_next(tmp)) {
3646 const gchar *display_name;
3647 gchar *original_name = (gchar *) tmp->data;
3648 gboolean addItem = TRUE;
3650 if (!g_strcasecmp(original_name, ADDRESS_TAG_PERSONAL)) {
3651 display_name = addressbook_get_personal_folder_name();
3653 else if (!g_strcasecmp(original_name, ADDRESS_TAG_COMMON)) {
3654 display_name = addressbook_get_common_folder_name();
3656 else if( ! g_strcasecmp( original_name, ADDRESS_TAG_VCARD ) ) {
3657 addItem = FALSE;
3659 #ifdef USE_JPILOT
3660 else if( ! g_strcasecmp( original_name, ADDRESS_TAG_JPILOT ) ) {
3661 addItem = FALSE;
3663 #endif
3664 #ifdef USE_LDAP
3665 else if( ! g_strcasecmp( original_name, ADDRESS_TAG_LDAP ) ) {
3666 addItem = FALSE;
3668 #endif
3669 else {
3670 display_name = original_name;
3673 if( addItem ) {
3674 original_name = g_strdup(original_name);
3675 menuitem = gtk_menu_item_new_with_label(display_name);
3676 /* register the duplicated string pointer as object data,
3677 * so we get the opportunity to free it */
3678 gtk_object_set_data_full(GTK_OBJECT(menuitem), "group_name",
3679 original_name,
3680 (GtkDestroyNotify) group_object_data_destroy);
3681 gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
3682 GTK_SIGNAL_FUNC(addressbook_group_menu_selected),
3683 (gpointer)(ci));
3684 gtk_menu_append(GTK_MENU(menu), menuitem);
3685 gtk_widget_show(menuitem);
3689 gtk_widget_show(menu);
3691 if (submenu) {
3692 gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenu), menu);
3693 gtk_widget_set_sensitive(GTK_WIDGET(submenu), TRUE);
3695 else {
3696 gtk_widget_grab_focus(GTK_WIDGET(menu));
3697 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME);
3700 if (groups) g_list_free(groups);
3701 return TRUE;
3705 * End of Source.