2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
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 3 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, see <http://www.gnu.org/licenses/>.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtkwindow.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkscrolledwindow.h>
33 #include <gtk/gtkhpaned.h>
34 #include <gtk/gtkhbox.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtkentry.h>
37 #include <gtk/gtkctree.h>
38 #include <gtk/gtkclist.h>
39 #include <gtk/gtktable.h>
40 #include <gtk/gtkhbbox.h>
41 #include <gtk/gtkbutton.h>
42 #include <gtk/gtkmenu.h>
43 #include <gtk/gtkmenuitem.h>
44 #include <gtk/gtkitemfactory.h>
47 #include <sys/types.h>
51 #include "addressbook.h"
52 #include "manage_window.h"
53 #include "prefs_common.h"
54 #include "alertpanel.h"
55 #include "inputdialog.h"
57 #include "stock_pixmap.h"
59 #include "prefs_gtk.h"
65 #include "addr_compl.h"
68 #include "addressitem.h"
70 #include "addrcache.h"
72 #include "addrindex.h"
73 #include "addressadd.h"
74 #include "addrduplicates.h"
75 #include "addressbook_foldersel.h"
77 #include "editvcard.h"
78 #include "editgroup.h"
79 #include "editaddress.h"
81 #include "importldif.h"
82 #include "importmutt.h"
83 #include "importpine.h"
88 #include "editjpilot.h"
93 #include "ldapserver.h"
95 #include "ldapupdate.h"
97 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
100 #include "addrquery.h"
101 #include "addrselect.h"
102 #include "addrclip.h"
103 #include "addrgather.h"
104 #include "adbookbase.h"
105 #include "exphtmldlg.h"
106 #include "expldifdlg.h"
107 #include "browseldap.h"
108 #include "addrcustomattr.h"
114 } AddressIndexColumns;
122 } AddressListColumns;
125 AddressBookFile *book;
133 AddressDataSource *book;
137 static gchar *list_titles[] = { N_("Name"),
141 #define COL_NAME_WIDTH 164
142 #define COL_ADDRESS_WIDTH 156
144 #define COL_FOLDER_WIDTH 170
145 #define ADDRESSBOOK_WIDTH 640
146 #define ADDRESSBOOK_HEIGHT 360
148 #define ADDRESSBOOK_MSGBUF_SIZE 2048
150 static GdkPixmap *folderxpm;
151 static GdkBitmap *folderxpmmask;
152 static GdkPixmap *folderopenxpm;
153 static GdkBitmap *folderopenxpmmask;
154 static GdkPixmap *groupxpm;
155 static GdkBitmap *groupxpmmask;
156 static GdkPixmap *interfacexpm;
157 static GdkBitmap *interfacexpmmask;
158 static GdkPixmap *bookxpm;
159 static GdkBitmap *bookxpmmask;
160 static GdkPixmap *addressxpm;
161 static GdkBitmap *addressxpmmask;
162 static GdkPixmap *vcardxpm;
163 static GdkBitmap *vcardxpmmask;
164 static GdkPixmap *jpilotxpm;
165 static GdkBitmap *jpilotxpmmask;
166 static GdkPixmap *categoryxpm;
167 static GdkBitmap *categoryxpmmask;
168 static GdkPixmap *ldapxpm;
169 static GdkBitmap *ldapxpmmask;
170 static GdkPixmap *addrsearchxpm;
171 static GdkPixmap *addrsearchxpmmask;
174 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
176 /* Address list selection */
177 static AddrSelectList *_addressSelect_ = NULL;
178 static AddressClipboard *_clipBoard_ = NULL;
180 /* Address index file and interfaces */
181 static AddressIndex *_addressIndex_ = NULL;
182 static GList *_addressInterfaceList_ = NULL;
183 static GList *_addressIFaceSelection_ = NULL;
184 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
186 static AddressBook_win addrbook;
188 static GHashTable *_addressBookTypeHash_ = NULL;
189 static GList *_addressBookTypeList_ = NULL;
191 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
192 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
193 static void addressbook_edit_address_post_cb( ItemPerson *person );
195 static void addressbook_create (void);
196 static gint addressbook_close (void);
197 static void addressbook_button_set_sensitive (void);
199 static gboolean address_index_has_focus = FALSE;
200 static gboolean address_list_has_focus = FALSE;
202 /* callback functions */
203 static void addressbook_del_clicked (GtkButton *button,
205 static void addressbook_reg_clicked (GtkButton *button,
207 static void addressbook_to_clicked (GtkButton *button,
209 static void addressbook_lup_clicked (GtkButton *button,
211 static void addressbook_close_clicked (GtkButton *button,
214 static void addressbook_tree_selected (GtkCTree *ctree,
218 static void addressbook_select_row_tree (GtkCTree *ctree,
222 static void addressbook_list_row_selected (GtkCTree *clist,
226 static void addressbook_list_row_unselected (GtkCTree *clist,
230 static void addressbook_person_expand_node (GtkCTree *ctree,
233 static void addressbook_person_collapse_node (GtkCTree *ctree,
237 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
238 GdkEventButton *event,
240 static gboolean addressbook_list_button_released(GtkWidget *widget,
241 GdkEventButton *event,
243 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
244 GdkEventButton *event,
246 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
247 GdkEventButton *event,
250 static void addressbook_new_folder_cb (gpointer data,
253 static void addressbook_new_group_cb (gpointer data,
256 static void addressbook_treenode_edit_cb (gpointer data,
259 static void addressbook_treenode_delete_cb (gpointer data,
263 static void addressbook_change_node_name (GtkCTreeNode *node,
266 static void addressbook_new_address_cb (gpointer data,
269 static void addressbook_edit_address_cb (gpointer data,
272 static void addressbook_delete_address_cb (gpointer data,
276 static void close_cb (gpointer data,
279 static void addressbook_file_save_cb (gpointer data,
283 /* Data source edit stuff */
284 static void addressbook_new_book_cb (gpointer data,
287 static void addressbook_new_vcard_cb (gpointer data,
292 static void addressbook_new_jpilot_cb (gpointer data,
298 static void addressbook_new_ldap_cb (gpointer data,
303 static void addressbook_set_clist (AddressObject *obj,
306 static void addressbook_load_tree (void);
307 void addressbook_read_file (void);
309 static GtkCTreeNode *addressbook_add_object (GtkCTreeNode *node,
311 static void addressbook_treenode_remove_item ( void );
313 static AddressDataSource *addressbook_find_datasource
314 (GtkCTreeNode *node );
316 static AddressBookFile *addressbook_get_book_file(void);
318 static GtkCTreeNode *addressbook_node_add_folder
320 AddressDataSource *ds,
321 ItemFolder *itemFolder,
322 AddressObjectType otype);
323 static GtkCTreeNode *addressbook_node_add_group (GtkCTreeNode *node,
324 AddressDataSource *ds,
325 ItemGroup *itemGroup);
326 static void addressbook_tree_remove_children (GtkCTree *ctree,
327 GtkCTreeNode *parent);
328 static void addressbook_move_nodes_up (GtkCTree *ctree,
330 static GtkCTreeNode *addressbook_find_group_node (GtkCTreeNode *parent,
332 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
335 static gint addressbook_treenode_compare_func (GtkCList *clist,
338 static void addressbook_folder_load_one_person (GtkCTree *clist,
340 AddressTypeControlItem *atci,
341 AddressTypeControlItem *atciMail);
342 static void addressbook_folder_refresh_one_person(GtkCTree *clist,
344 static void addressbook_folder_remove_one_person(GtkCTree *clist,
346 static void addressbook_folder_remove_node (GtkCTree *clist,
349 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
350 gboolean force_focus );
352 /* LUT's and IF stuff */
353 static void addressbook_free_treenode ( gpointer data );
354 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
355 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
357 static void addrbookctl_build_map (GtkWidget *window);
358 static void addrbookctl_build_iflist (void);
359 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
360 static void addrbookctl_build_ifselect (void);
362 static void addrbookctl_free_interface (AdapterInterface *adapter);
363 static void addrbookctl_free_datasource (AdapterDSource *adapter);
364 static void addrbookctl_free_folder (AdapterFolder *adapter);
365 static void addrbookctl_free_group (AdapterGroup *adapter);
367 static void addressbook_list_select_clear ( void );
368 static void addressbook_list_select_add ( AddrItemObject *aio,
369 AddressDataSource *ds );
370 static void addressbook_list_select_remove ( AddrItemObject *aio );
372 static void addressbook_import_ldif_cb ( void );
373 static void addressbook_find_duplicates_cb ( void );
374 static void addressbook_edit_custom_attr_cb ( void );
375 static void addressbook_import_mutt_cb ( void );
376 static void addressbook_import_pine_cb ( void );
377 static void addressbook_export_html_cb ( void );
378 static void addressbook_export_ldif_cb ( void );
379 static void addressbook_select_all_cb ( void );
380 static void addressbook_clip_cut_cb ( void );
381 static void addressbook_clip_copy_cb ( void );
382 static void addressbook_clip_paste_cb ( void );
383 static void addressbook_treenode_cut_cb ( void );
384 static void addressbook_treenode_copy_cb ( void );
385 static void addressbook_treenode_paste_cb ( void );
387 static void addressbook_mail_to_cb ( void );
390 static void addressbook_browse_entry_cb ( void );
392 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
394 static void addressbook_start_drag(GtkWidget *widget, gint button,
397 static void addressbook_drag_data_get(GtkWidget *widget,
398 GdkDragContext *drag_context,
399 GtkSelectionData *selection_data,
403 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
404 GdkDragContext *context,
409 static void addressbook_drag_leave_cb(GtkWidget *widget,
410 GdkDragContext *context,
413 static void addressbook_drag_received_cb(GtkWidget *widget,
414 GdkDragContext *drag_context,
417 GtkSelectionData *data,
421 static void addressbook_list_menu_setup( void );
423 static GtkTargetEntry addressbook_drag_types[] =
425 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
428 static GtkTargetList *addressbook_target_list = NULL;
431 static GtkItemFactoryEntry addressbook_entries[] =
433 {N_("/_Book"), NULL, NULL, 0, "<Branch>", NULL},
434 {N_("/_Book/New _Book"), "<control>B", addressbook_new_book_cb, 0, NULL, NULL},
435 {N_("/_Book/New _Folder"), "<control>R", addressbook_new_folder_cb, 0, NULL, NULL},
436 {N_("/_Book/New _vCard"), "<control><shift>D", addressbook_new_vcard_cb, 0, NULL, NULL},
438 {N_("/_Book/New _JPilot"), "<control>J", addressbook_new_jpilot_cb, 0, NULL, NULL},
441 {N_("/_Book/New LDAP _Server"), "<control><shift>S", addressbook_new_ldap_cb, 0, NULL, NULL},
443 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>", NULL},
444 {N_("/_Book/_Edit book"), NULL, addressbook_treenode_edit_cb, 0, NULL, NULL},
445 {N_("/_Book/_Delete book"), NULL, addressbook_treenode_delete_cb, 0, NULL, NULL},
446 {N_("/_Book/---"), NULL, NULL, 0, "<Separator>", NULL},
447 {N_("/_Book/_Save"), "<control>S", addressbook_file_save_cb, 0, NULL, NULL},
448 {N_("/_Book/_Close"), "<control>W", close_cb, 0, NULL, NULL},
449 {N_("/_Address"), NULL, NULL, 0, "<Branch>", NULL},
450 {N_("/_Address/_Select all"), "<control>A", addressbook_select_all_cb, 0, NULL, NULL},
451 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
452 {N_("/_Address/C_ut"), "<control>X", addressbook_clip_cut_cb, 0, NULL, NULL},
453 {N_("/_Address/_Copy"), "<control>C", addressbook_clip_copy_cb, 0, NULL, NULL},
454 {N_("/_Address/_Paste"), "<control>V", addressbook_clip_paste_cb, 0, NULL, NULL},
455 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
456 {N_("/_Address/_Edit"), "<control>Return",addressbook_edit_address_cb, 0, NULL, NULL},
457 {N_("/_Address/_Delete"), "<control>D", addressbook_delete_address_cb, 0, NULL, NULL},
458 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
459 {N_("/_Address/New _Address"), "<control>N", addressbook_new_address_cb, 0, NULL, NULL},
460 {N_("/_Address/New _Group"), "<control>G", addressbook_new_group_cb, 0, NULL, NULL},
461 {N_("/_Address/---"), NULL, NULL, 0, "<Separator>", NULL},
462 {N_("/_Address/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL, NULL},
463 {N_("/_Tools"), NULL, NULL, 0, "<Branch>", NULL},
464 {N_("/_Tools/Import _LDIF file..."), NULL, addressbook_import_ldif_cb, 0, NULL, NULL},
465 {N_("/_Tools/Import M_utt file..."), NULL, addressbook_import_mutt_cb, 0, NULL, NULL},
466 {N_("/_Tools/Import _Pine file..."), NULL, addressbook_import_pine_cb, 0, NULL, NULL},
467 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>", NULL},
468 {N_("/_Tools/Export _HTML..."), NULL, addressbook_export_html_cb, 0, NULL, NULL},
469 {N_("/_Tools/Export LDI_F..."), NULL, addressbook_export_ldif_cb, 0, NULL, NULL},
470 {N_("/_Tools/---"), NULL, NULL, 0, "<Separator>", NULL},
471 {N_("/_Tools/Find duplicates..."), NULL, addressbook_find_duplicates_cb, 0, NULL, NULL},
472 {N_("/_Tools/Edit custom attributes..."), NULL, addressbook_edit_custom_attr_cb, 0, NULL, NULL},
473 {N_("/_Help"), NULL, NULL, 0, "<Branch>", NULL},
474 {N_("/_Help/_About"), NULL, about_show, 0, NULL, NULL}
477 static GtkItemFactoryEntry addressbook_tree_popup_entries[] =
479 {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL, NULL},
480 {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL, NULL},
481 {"/---", NULL, NULL, 0, "<Separator>", NULL},
482 {N_("/New _Book"), NULL, addressbook_new_book_cb, 0, NULL, NULL},
483 {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL, NULL},
484 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL, NULL},
485 {"/---", NULL, NULL, 0, "<Separator>", NULL},
486 {N_("/C_ut"), NULL, addressbook_treenode_cut_cb, 0, NULL, NULL},
487 {N_("/_Copy"), NULL, addressbook_treenode_copy_cb, 0, NULL, NULL},
488 {N_("/_Paste"), NULL, addressbook_treenode_paste_cb, 0, NULL, NULL}
491 static GtkItemFactoryEntry addressbook_list_popup_entries[] =
493 {N_("/_Select all"), NULL, addressbook_select_all_cb, 0, NULL, NULL},
494 {"/---", NULL, NULL, 0, "<Separator>", NULL},
495 {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL, NULL},
496 {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL, NULL},
497 {"/---", NULL, NULL, 0, "<Separator>", NULL},
498 {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL, NULL},
499 {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL, NULL},
500 {"/---", NULL, NULL, 0, "<Separator>", NULL},
501 {N_("/C_ut"), NULL, addressbook_clip_cut_cb, 0, NULL, NULL},
502 {N_("/_Copy"), NULL, addressbook_clip_copy_cb, 0, NULL, NULL},
503 {N_("/_Paste"), NULL, addressbook_clip_paste_cb, 0, NULL, NULL},
504 {"/---", NULL, NULL, 0, "<Separator>", NULL},
505 /* {N_("/Pa_ste Address"), NULL, addressbook_clip_paste_address_cb, 0, NULL, NULL},*/
506 {N_("/_Mail To"), NULL, addressbook_mail_to_cb, 0, NULL, NULL},
508 {N_("/_Browse Entry"), NULL, addressbook_browse_entry_cb, 0, NULL, NULL},
513 * Structure of error message table.
515 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
516 struct _ErrMsgTableEntry {
521 static gchar *_errMsgUnknown_ = N_( "Unknown" );
524 * Lookup table of error messages for general errors. Note that a NULL
525 * description signifies the end of the table.
527 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
528 { MGU_SUCCESS, N_("Success") },
529 { MGU_BAD_ARGS, N_("Bad arguments") },
530 { MGU_NO_FILE, N_("File not specified") },
531 { MGU_OPEN_FILE, N_("Error opening file") },
532 { MGU_ERROR_READ, N_("Error reading file") },
533 { MGU_EOF, N_("End of file encountered") },
534 { MGU_OO_MEMORY, N_("Error allocating memory") },
535 { MGU_BAD_FORMAT, N_("Bad file format") },
536 { MGU_ERROR_WRITE, N_("Error writing to file") },
537 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
538 { MGU_NO_PATH, N_("No path specified") },
544 * Lookup table of error messages for LDAP errors.
546 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
547 { LDAPRC_SUCCESS, N_("Success") },
548 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
549 { LDAPRC_INIT, N_("Error initializing LDAP") },
550 { LDAPRC_BIND, N_("Error binding to LDAP server") },
551 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
552 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
553 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
554 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
555 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
556 { LDAPRC_TLS, N_("Error starting TLS connection") },
557 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
558 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
559 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
560 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
566 * Lookup message for specified error code.
567 * \param lut Lookup table.
568 * \param code Code to lookup.
569 * \return Description associated to code.
571 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
573 ErrMsgTableEntry entry;
576 for( i = 0; ; i++ ) {
578 if( entry.description == NULL ) break;
579 if( entry.code == code ) {
580 desc = entry.description;
585 desc = _errMsgUnknown_;
590 static gboolean lastCanLookup = FALSE;
592 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
594 if (add_and_delete) {
595 gtk_widget_show(addrbook.edit_btn);
596 gtk_widget_show(addrbook.del_btn);
597 gtk_widget_show(addrbook.reg_btn);
599 gtk_widget_hide(addrbook.edit_btn);
600 gtk_widget_hide(addrbook.del_btn);
601 gtk_widget_hide(addrbook.reg_btn);
605 gtk_widget_show(addrbook.lup_btn);
606 gtk_widget_show(addrbook.entry);
607 gtk_widget_show(addrbook.label);
609 gtk_widget_hide(addrbook.lup_btn);
610 gtk_widget_hide(addrbook.entry);
611 gtk_widget_hide(addrbook.label);
614 lastCanLookup = lookup;
617 gtk_widget_show(addrbook.to_btn);
618 gtk_widget_show(addrbook.cc_btn);
619 gtk_widget_show(addrbook.bcc_btn);
621 gtk_widget_hide(addrbook.to_btn);
622 gtk_widget_hide(addrbook.cc_btn);
623 gtk_widget_hide(addrbook.bcc_btn);
627 void addressbook_open(Compose *target)
629 /* Initialize all static members */
630 if( _clipBoard_ == NULL ) {
631 _clipBoard_ = addrclip_create();
633 if( _addressIndex_ != NULL ) {
634 addrclip_set_index( _clipBoard_, _addressIndex_ );
636 if( _addressSelect_ == NULL ) {
637 _addressSelect_ = addrselect_list_create();
639 if (!addrbook.window) {
640 addressbook_read_file();
641 addressbook_create();
642 addressbook_load_tree();
643 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
644 GTK_CTREE_NODE(GTK_CLIST(addrbook.ctree)->row_list));
647 gtk_widget_hide(addrbook.window);
650 gtk_widget_show_all(addrbook.window);
652 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
653 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
655 if (!prefs_common.addressbook_use_editaddress_dialog)
656 addressbook_edit_person_widgetset_hide();
658 address_completion_start(addrbook.window);
660 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
661 addressbook_set_target_compose(target);
665 * Destroy addressbook.
667 void addressbook_destroy( void ) {
668 /* Free up address stuff */
669 if( _addressSelect_ != NULL ) {
670 addrselect_list_free( _addressSelect_ );
672 if( _clipBoard_ != NULL ) {
673 addrclip_free( _clipBoard_ );
675 if( _addressIndex_ != NULL ) {
676 addrindex_free_index( _addressIndex_ );
677 addrindex_teardown();
679 _addressSelect_ = NULL;
681 _addressIndex_ = NULL;
684 void addressbook_set_target_compose(Compose *target)
686 addrbook.target_compose = target;
687 addressbook_button_set_sensitive();
690 Compose *addressbook_get_target_compose(void)
692 return addrbook.target_compose;
696 * Refresh addressbook and save to file(s).
698 void addressbook_refresh( void )
700 if (addrbook.window) {
701 if (addrbook.treeSelected) {
702 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
703 addrbook.treeSelected);
704 addressbook_set_clist(
705 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
706 addrbook.treeSelected),
711 addressbook_export_to_file();
714 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
716 if (event && event->keyval == GDK_Escape)
718 else if (event && event->keyval == GDK_Delete) {
719 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
720 if ( /* address_index_has_focus || */ address_list_has_focus )
721 addressbook_del_clicked(NULL, NULL);
727 *\brief Save Gtk object size to prefs dataset
729 static void addressbook_size_allocate_cb(GtkWidget *widget,
730 GtkAllocation *allocation)
732 g_return_if_fail(allocation != NULL);
734 prefs_common.addressbookwin_width = allocation->width;
735 prefs_common.addressbookwin_height = allocation->height;
738 static gint sort_column_number = 0;
739 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
741 static gint list_case_sort(
742 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
744 GtkCListRow *row1 = (GtkCListRow *) ptr1;
745 GtkCListRow *row2 = (GtkCListRow *) ptr2;
746 gchar *name1 = NULL, *name2 = NULL;
747 AddrItemObject *aio1 = ((GtkCListRow *)ptr1)->data;
748 AddrItemObject *aio2 = ((GtkCListRow *)ptr2)->data;
750 if( aio1->type == aio2->type ) {
752 name1 = GTK_CELL_TEXT (row1->cell[sort_column_number])->text;
754 name2 = GTK_CELL_TEXT (row2->cell[sort_column_number])->text;
755 if( ! name1 ) return ( name2 != NULL );
756 if( ! name2 ) return -1;
757 return g_utf8_collate( name1, name2 );
759 /* Order groups before person */
760 if( aio1->type == ITEMTYPE_GROUP ) {
761 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
762 } else if( aio2->type == ITEMTYPE_GROUP ) {
763 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
769 static void addressbook_sort_list(GtkCList *clist, const gint col,
770 const GtkSortType sort_type)
773 GtkWidget *hbox, *label, *arrow;
775 sort_column_number = col;
776 sort_column_type = sort_type;
777 gtk_clist_set_compare_func(clist, list_case_sort);
778 gtk_clist_set_sort_type(clist, sort_type);
779 gtk_clist_set_sort_column(clist, col);
781 gtk_clist_freeze(clist);
782 gtk_clist_sort(clist);
784 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
785 hbox = gtk_hbox_new(FALSE, 4);
786 label = gtk_label_new(gettext(list_titles[pos]));
787 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
790 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
791 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
792 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
795 gtk_widget_show_all(hbox);
796 gtk_clist_set_column_widget(clist, pos, hbox);
799 gtk_clist_thaw(clist);
802 static void addressbook_name_clicked(GtkWidget *button, GtkCList *clist)
804 static GtkSortType sort_type = GTK_SORT_ASCENDING;
806 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
808 addressbook_sort_list(clist, COL_NAME, sort_type);
811 static void addressbook_address_clicked(GtkWidget *button, GtkCList *clist)
813 static GtkSortType sort_type = GTK_SORT_ASCENDING;
815 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
817 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
820 static void addressbook_remarks_clicked(GtkWidget *button, GtkCList *clist)
822 static GtkSortType sort_type = GTK_SORT_ASCENDING;
824 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
826 addressbook_sort_list(clist, COL_REMARKS, sort_type);
829 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
832 address_index_has_focus = TRUE;
836 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
839 address_index_has_focus = FALSE;
840 if (!prefs_common.addressbook_use_editaddress_dialog
841 && !address_list_has_focus)
842 addressbook_address_list_disable_some_actions();
846 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
849 address_list_has_focus = TRUE;
853 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
856 address_list_has_focus = FALSE;
857 if (!prefs_common.addressbook_use_editaddress_dialog
858 && !address_index_has_focus)
859 addressbook_address_list_disable_some_actions();
863 /* save hpane and vpane's handle position when it moves */
864 static void addressbook_pane_save_position(void)
867 prefs_common.addressbook_hpaned_pos =
868 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
870 prefs_common.addressbook_vpaned_pos =
871 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
875 * Create the address book widgets. The address book contains two CTree widgets: the
876 * address index tree on the left and the address list on the right.
878 * The address index tree displays a hierarchy of interfaces and groups. Each node in
879 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
880 * data sources and folder objects.
882 * The address list displays group, person and email objects. These items are linked
883 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
886 * In the tradition of MVC architecture, the data stores have been separated from the
887 * GUI components. The addrindex.c file provides the interface to all data stores.
889 static void addressbook_create(void)
895 GtkWidget *ctree_swin;
897 GtkWidget *editaddress_vbox;
898 GtkWidget *clist_vbox;
899 GtkWidget *clist_swin;
906 GtkWidget *statusbar;
917 GtkWidget *close_btn;
918 GtkWidget *tree_popup;
919 GtkWidget *list_popup;
920 GtkItemFactory *tree_factory;
921 GtkItemFactory *list_factory;
922 GtkItemFactory *menu_factory;
926 gchar *index_titles[N_INDEX_COLS];
930 static GdkGeometry geometry;
932 debug_print("Creating addressbook window...\n");
934 index_titles[COL_SOURCES] = _("Sources");
936 /* Address book window */
937 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
938 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
939 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
940 gtk_widget_realize(window);
942 g_signal_connect(G_OBJECT(window), "delete_event",
943 G_CALLBACK(addressbook_close), NULL);
944 g_signal_connect(G_OBJECT(window), "size_allocate",
945 G_CALLBACK(addressbook_size_allocate_cb), NULL);
946 g_signal_connect(G_OBJECT(window), "key_press_event",
947 G_CALLBACK(key_pressed), NULL);
948 MANAGE_WINDOW_SIGNALS_CONNECT(window);
950 vbox = gtk_vbox_new(FALSE, 0);
951 gtk_container_add(GTK_CONTAINER(window), vbox);
954 n_entries = sizeof(addressbook_entries) /
955 sizeof(addressbook_entries[0]);
956 menubar = menubar_create(window, addressbook_entries, n_entries,
957 "<AddressBook>", NULL);
958 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
959 menu_factory = gtk_item_factory_from_widget(menubar);
961 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
962 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
963 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
965 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
966 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
967 GTK_POLICY_AUTOMATIC,
968 GTK_POLICY_AUTOMATIC);
969 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
972 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
973 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
974 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
975 gtk_clist_set_column_width(GTK_CLIST(ctree), 0, COL_FOLDER_WIDTH);
976 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
977 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
978 GTK_CTREE_EXPANDER_SQUARE);
979 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
980 gtk_clist_set_compare_func(GTK_CLIST(ctree),
981 addressbook_treenode_compare_func);
983 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
984 G_CALLBACK(addressbook_tree_selected), NULL);
985 g_signal_connect(G_OBJECT(ctree), "button_press_event",
986 G_CALLBACK(addressbook_tree_button_pressed),
988 g_signal_connect(G_OBJECT(ctree), "button_release_event",
989 G_CALLBACK(addressbook_tree_button_released),
992 g_signal_connect(G_OBJECT(ctree), "select_row",
993 G_CALLBACK(addressbook_select_row_tree), NULL);
995 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
996 addressbook_drag_types, 1,
997 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
998 g_signal_connect(G_OBJECT(ctree), "drag_motion",
999 G_CALLBACK(addressbook_drag_motion_cb),
1001 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1002 G_CALLBACK(addressbook_drag_leave_cb),
1004 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1005 G_CALLBACK(addressbook_drag_received_cb),
1007 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1008 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1009 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1010 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1012 clist_vbox = gtk_vbox_new(FALSE, 4);
1014 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1015 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1016 GTK_POLICY_AUTOMATIC,
1017 GTK_POLICY_AUTOMATIC);
1018 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1021 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1022 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1023 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_EXTENDED);
1024 gtk_ctree_set_line_style(GTK_CTREE(clist), GTK_CTREE_LINES_NONE);
1025 gtk_ctree_set_expander_style(GTK_CTREE(clist), GTK_CTREE_EXPANDER_SQUARE);
1026 gtk_ctree_set_indent(GTK_CTREE(clist), CTREE_INDENT);
1027 gtk_clist_set_column_width(GTK_CLIST(clist), COL_NAME,
1029 gtk_clist_set_column_width(GTK_CLIST(clist), COL_ADDRESS,
1031 gtk_widget_set_size_request(clist, -1, 80);
1033 addressbook_sort_list(GTK_CLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1034 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
1035 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1036 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_ADDRESS].button),
1037 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1038 g_signal_connect(G_OBJECT(GTK_CLIST(clist)->column[COL_REMARKS].button),
1039 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1040 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1041 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1042 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1043 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1045 for (i = 0; i < N_LIST_COLS; i++)
1046 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
1049 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1050 G_CALLBACK(addressbook_list_row_selected), NULL);
1051 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1052 G_CALLBACK(addressbook_list_row_unselected), NULL);
1053 g_signal_connect(G_OBJECT(clist), "button_press_event",
1054 G_CALLBACK(addressbook_list_button_pressed),
1056 g_signal_connect(G_OBJECT(clist), "button_release_event",
1057 G_CALLBACK(addressbook_list_button_released),
1059 g_signal_connect(G_OBJECT(clist), "tree_expand",
1060 G_CALLBACK(addressbook_person_expand_node), NULL );
1061 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1062 G_CALLBACK(addressbook_person_collapse_node), NULL );
1063 g_signal_connect(G_OBJECT(clist), "start_drag",
1064 G_CALLBACK(addressbook_start_drag), NULL);
1065 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1066 G_CALLBACK(addressbook_drag_data_get), NULL);
1067 hbox = gtk_hbox_new(FALSE, 4);
1068 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1070 label = gtk_label_new(_("Lookup name:"));
1071 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1073 entry = gtk_entry_new();
1074 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1076 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1078 g_signal_connect(G_OBJECT(entry), "key_press_event",
1079 G_CALLBACK(addressbook_entry_key_pressed),
1082 if (!prefs_common.addressbook_use_editaddress_dialog) {
1083 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1084 vpaned = gtk_vpaned_new();
1085 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1086 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1089 editaddress_vbox = NULL;
1091 hpaned = gtk_hpaned_new();
1092 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1093 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1094 if (prefs_common.addressbook_use_editaddress_dialog)
1095 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1097 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1100 hsbox = gtk_hbox_new(FALSE, 0);
1101 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1102 statusbar = gtk_statusbar_new();
1103 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1106 hbbox = gtk_hbutton_box_new();
1107 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1108 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1109 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1110 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1112 gtkut_stock_button_add_help(hbbox, &help_btn);
1114 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1115 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1116 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1117 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1118 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1119 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1120 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1121 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1122 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1125 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1126 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1127 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1129 g_signal_connect(G_OBJECT(help_btn), "clicked",
1130 G_CALLBACK(manual_open_with_anchor_cb),
1131 MANUAL_ANCHOR_ADDRBOOK);
1133 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1134 G_CALLBACK(addressbook_edit_clicked), NULL);
1135 g_signal_connect(G_OBJECT(del_btn), "clicked",
1136 G_CALLBACK(addressbook_del_clicked), NULL);
1137 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1138 G_CALLBACK(addressbook_reg_clicked), NULL);
1139 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1140 G_CALLBACK(addressbook_lup_clicked), NULL);
1142 to_btn = gtk_button_new_with_label
1143 (prefs_common_translated_header_name("To:"));
1144 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1145 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1146 cc_btn = gtk_button_new_with_label
1147 (prefs_common_translated_header_name("Cc:"));
1148 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1149 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1150 bcc_btn = gtk_button_new_with_label
1151 (prefs_common_translated_header_name("Bcc:"));
1152 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1153 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1155 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1156 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1157 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1159 g_signal_connect(G_OBJECT(to_btn), "clicked",
1160 G_CALLBACK(addressbook_to_clicked),
1161 GINT_TO_POINTER(COMPOSE_TO));
1162 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1163 G_CALLBACK(addressbook_to_clicked),
1164 GINT_TO_POINTER(COMPOSE_CC));
1165 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1166 G_CALLBACK(addressbook_to_clicked),
1167 GINT_TO_POINTER(COMPOSE_BCC));
1168 g_signal_connect(G_OBJECT(close_btn), "clicked",
1169 G_CALLBACK(addressbook_close_clicked), NULL);
1171 /* Build icons for interface */
1172 stock_pixmap_gdk( window, STOCK_PIXMAP_INTERFACE,
1173 &interfacexpm, &interfacexpmmask );
1175 /* Build control tables */
1176 addrbookctl_build_map(window);
1177 addrbookctl_build_iflist();
1178 addrbookctl_build_ifselect();
1180 addrbook.clist = NULL;
1182 /* Add each interface into the tree as a root level folder */
1183 nodeIf = _addressInterfaceList_;
1185 AdapterInterface *adapter = nodeIf->data;
1186 AddressInterface *iface = adapter->interface;
1187 nodeIf = g_list_next(nodeIf);
1189 if(iface->useInterface) {
1190 AddressTypeControlItem *atci = adapter->atci;
1191 text = atci->displayName;
1193 gtk_sctree_insert_node( GTK_CTREE(ctree),
1194 NULL, NULL, &text, FOLDER_SPACING,
1195 interfacexpm, interfacexpmmask,
1196 interfacexpm, interfacexpmmask,
1198 menu_set_sensitive( menu_factory, atci->menuCommand, adapter->haveLibrary );
1199 gtk_ctree_node_set_row_data_full(
1200 GTK_CTREE(ctree), adapter->treeNode, adapter,
1201 addressbook_free_treenode );
1206 n_entries = sizeof(addressbook_tree_popup_entries) /
1207 sizeof(addressbook_tree_popup_entries[0]);
1208 tree_popup = menu_create_items(addressbook_tree_popup_entries,
1210 "<AddressBookTree>", &tree_factory,
1212 n_entries = sizeof(addressbook_list_popup_entries) /
1213 sizeof(addressbook_list_popup_entries[0]);
1214 list_popup = menu_create_items(addressbook_list_popup_entries,
1216 "<AddressBookList>", &list_factory,
1219 addrbook.window = window;
1220 addrbook.hpaned = hpaned;
1221 addrbook.vpaned = vpaned;
1222 addrbook.menubar = menubar;
1223 addrbook.ctree = ctree;
1226 addrbook.editaddress_vbox = editaddress_vbox;
1227 addrbook.clist = clist;
1228 addrbook.label = label;
1229 addrbook.entry = entry;
1230 addrbook.statusbar = statusbar;
1231 addrbook.status_cid = gtk_statusbar_get_context_id(
1232 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1234 addrbook.help_btn = help_btn;
1235 addrbook.edit_btn = edit_btn;
1236 addrbook.del_btn = del_btn;
1237 addrbook.reg_btn = reg_btn;
1238 addrbook.lup_btn = lup_btn;
1239 addrbook.to_btn = to_btn;
1240 addrbook.cc_btn = cc_btn;
1241 addrbook.bcc_btn = bcc_btn;
1243 addrbook.tree_popup = tree_popup;
1244 addrbook.list_popup = list_popup;
1245 addrbook.tree_factory = tree_factory;
1246 addrbook.list_factory = list_factory;
1247 addrbook.menu_factory = menu_factory;
1249 addrbook.listSelected = NULL;
1251 if (!geometry.min_height) {
1252 geometry.min_width = ADDRESSBOOK_WIDTH;
1253 geometry.min_height = ADDRESSBOOK_HEIGHT;
1256 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1258 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1259 prefs_common.addressbookwin_height);
1261 if (!prefs_common.addressbook_use_editaddress_dialog) {
1262 if (prefs_common.addressbook_vpaned_pos > 0)
1263 gtk_paned_set_position(GTK_PANED(vpaned),
1264 prefs_common.addressbook_vpaned_pos);
1266 if (prefs_common.addressbook_hpaned_pos > 0)
1267 gtk_paned_set_position(GTK_PANED(hpaned),
1268 prefs_common.addressbook_hpaned_pos);
1271 gtk_widget_show_all(window);
1275 * Close address book window and save to file(s).
1277 static gint addressbook_close( void ) {
1278 address_completion_end(addrbook.window);
1279 if (!prefs_common.addressbook_use_editaddress_dialog)
1280 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1282 addressbook_pane_save_position();
1284 gtk_widget_hide(addrbook.window);
1285 addressbook_export_to_file();
1290 * Display message in status line.
1291 * \param msg Message to display.
1293 static void addressbook_status_show( gchar *msg ) {
1294 if( addrbook.statusbar != NULL ) {
1296 GTK_STATUSBAR(addrbook.statusbar),
1297 addrbook.status_cid );
1300 GTK_STATUSBAR(addrbook.statusbar),
1301 addrbook.status_cid, msg );
1306 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1310 *addressbook_msgbuf = '\0';
1312 name = addrindex_ds_get_name( ds );
1313 retVal = addrindex_ds_get_status_code( ds );
1314 if( retVal == MGU_SUCCESS ) {
1315 g_snprintf( addressbook_msgbuf,
1316 sizeof(addressbook_msgbuf), "%s", name );
1319 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1320 g_snprintf( addressbook_msgbuf,
1321 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1324 addressbook_status_show( addressbook_msgbuf );
1327 static void addressbook_button_set_sensitive(void)
1329 gboolean to_sens = FALSE;
1330 gboolean cc_sens = FALSE;
1331 gboolean bcc_sens = FALSE;
1333 if (!addrbook.window) return;
1335 if (addrbook.target_compose) {
1341 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1342 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1343 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1346 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1348 addressbook_edit_address_cb(NULL, 0, NULL);
1352 * Delete one or more objects from address list.
1354 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1356 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1357 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1358 AddressObject *pobj;
1359 AdapterDSource *ads = NULL;
1360 GtkCTreeNode *nodeList;
1363 AddressBookFile *abf = NULL;
1364 AddressDataSource *ds = NULL;
1365 AddressInterface *iface;
1366 AddrItemObject *aio;
1367 AddrSelectItem *item;
1369 gboolean refreshList = FALSE;
1371 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1372 g_return_if_fail(pobj != NULL);
1374 /* Test whether anything selected for deletion */
1375 nodeList = addrbook.listSelected;
1377 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1378 if( aio == NULL) return;
1379 ds = addressbook_find_datasource( addrbook.treeSelected );
1380 if( ds == NULL ) return;
1382 /* Test for read only */
1383 iface = ds->interface;
1384 if( iface->readOnly ) {
1385 alertpanel( _("Delete address(es)"),
1386 _("This address data is readonly and cannot be deleted."),
1387 GTK_STOCK_CLOSE, NULL, NULL );
1391 /* Test whether Ok to proceed */
1393 if( pobj->type == ADDR_DATASOURCE ) {
1394 ads = ADAPTER_DSOURCE(pobj);
1395 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1397 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1400 else if( pobj->type == ADDR_ITEM_GROUP ) {
1403 if( ! procFlag ) return;
1404 abf = ds->rawDataSource;
1405 if( abf == NULL ) return;
1408 /* Process deletions */
1409 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1410 gboolean group_delete = TRUE;
1411 /* Items inside folders */
1412 list = addrselect_get_list( _addressSelect_ );
1413 /* Confirm deletion */
1417 node = g_list_next( node );
1418 aio = ( AddrItemObject * ) item->addressItem;
1419 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1420 group_delete = FALSE;
1425 aval = alertpanel( _("Delete group"),
1426 _("Really delete the group(s)?\n"
1427 "The addresses it contains will not be lost."),
1428 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1429 if( aval != G_ALERTALTERNATE ) return;
1431 aval = alertpanel( _("Delete address(es)"),
1432 _("Really delete the address(es)?"),
1433 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1434 if( aval != G_ALERTALTERNATE ) return;
1440 node = g_list_next( node );
1441 aio = ( AddrItemObject * ) item->addressItem;
1444 if( aio->type == ADDR_ITEM_GROUP ) {
1445 ItemGroup *item = ( ItemGroup * ) aio;
1446 GtkCTreeNode *nd = NULL;
1448 nd = addressbook_find_group_node( addrbook.opened, item );
1449 item = addrbook_remove_group( abf, item );
1451 addritem_free_item_group( item );
1453 /* Remove group from parent node */
1454 gtk_ctree_remove_node( ctree, nd );
1457 else if( aio->type == ADDR_ITEM_PERSON ) {
1458 ItemPerson *item = ( ItemPerson * ) aio;
1459 item->status = DELETE_ENTRY;
1460 addressbook_folder_remove_one_person( clist, item );
1461 if (pobj->type == ADDR_ITEM_FOLDER)
1462 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1463 item = addrbook_remove_person( abf, item );
1465 if (ds && ds->type == ADDR_IF_LDAP) {
1466 LdapServer *server = ds->rawDataSource;
1467 ldapsvr_set_modified(server, TRUE);
1468 ldapsvr_update_book(server, item);
1472 gchar *filename = addritem_person_get_picture(item);
1473 if (filename && is_file_exist(filename))
1476 addritem_free_item_person( item );
1479 else if( aio->type == ADDR_ITEM_EMAIL ) {
1480 ItemEMail *item = ( ItemEMail * ) aio;
1481 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1482 item = addrbook_person_remove_email( abf, person, item );
1484 addrcache_remove_email(abf->addressCache, item);
1485 addritem_free_item_email( item );
1487 addressbook_folder_refresh_one_person( clist, person );
1490 g_list_free( list );
1491 addressbook_list_select_clear();
1493 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1494 addressbook_set_clist(
1495 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1499 addrbook_set_dirty(abf, TRUE);
1500 addressbook_export_to_file();
1501 addressbook_list_menu_setup();
1504 else if( pobj->type == ADDR_ITEM_GROUP ) {
1505 /* Items inside groups */
1506 list = addrselect_get_list( _addressSelect_ );
1510 node = g_list_next( node );
1511 aio = ( AddrItemObject * ) item->addressItem;
1512 if( aio->type == ADDR_ITEM_EMAIL ) {
1513 ItemEMail *item = ( ItemEMail * ) aio;
1514 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1515 item = addrbook_person_remove_email( abf, person, item );
1517 addritem_free_item_email( item );
1521 g_list_free( list );
1522 addressbook_list_select_clear();
1523 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1524 addressbook_set_clist(
1525 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1529 addrbook_set_dirty(abf, TRUE);
1530 addressbook_export_to_file();
1531 addressbook_list_menu_setup();
1535 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1536 gtk_ctree_remove_node( clist, nodeList );
1540 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1542 addressbook_new_address_cb( NULL, 0, NULL );
1545 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1548 gchar *address = NULL;
1550 if( aio->type == ADDR_ITEM_EMAIL ) {
1551 ItemPerson *person = NULL;
1552 ItemEMail *email = ( ItemEMail * ) aio;
1554 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1555 if( email->address ) {
1556 if( ADDRITEM_NAME(email) ) {
1557 name = ADDRITEM_NAME(email);
1558 if( *name == '\0' ) {
1559 name = ADDRITEM_NAME(person);
1562 else if( ADDRITEM_NAME(person) ) {
1563 name = ADDRITEM_NAME(person);
1566 buf = g_strdup( email->address );
1568 address = email->address;
1571 else if( aio->type == ADDR_ITEM_PERSON ) {
1572 ItemPerson *person = ( ItemPerson * ) aio;
1573 GList *node = person->listEMail;
1575 name = ADDRITEM_NAME(person);
1577 ItemEMail *email = ( ItemEMail * ) node->data;
1578 address = email->address;
1582 if( name && name[0] != '\0' ) {
1583 if( strchr_with_skip_quote( name, '"', ',' ) )
1584 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1586 buf = g_strdup_printf( "%s <%s>", name, address );
1589 buf = g_strdup( address );
1596 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1600 AddrSelectItem *item;
1601 AddrItemObject *aio;
1604 compose = addrbook.target_compose;
1605 if( ! compose ) return;
1607 /* Nothing selected, but maybe there is something in text entry */
1608 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1610 compose_entry_append(
1611 compose, addr, (ComposeEntryType)data );
1614 /* Select from address list */
1615 list = addrselect_get_list( _addressSelect_ );
1620 node = g_list_next( node );
1621 aio = item->addressItem;
1622 if( aio->type == ADDR_ITEM_PERSON ||
1623 aio->type == ADDR_ITEM_EMAIL ) {
1624 addr = addressbook_format_address( aio );
1625 compose_entry_append(
1626 compose, addr, (ComposeEntryType) data );
1629 else if( aio->type == ADDR_ITEM_GROUP ) {
1630 ItemGroup *group = ( ItemGroup * ) aio;
1631 GList *nodeMail = group->listEMail;
1633 ItemEMail *email = nodeMail->data;
1635 addr = addressbook_format_address(
1636 ( AddrItemObject * ) email );
1637 compose_entry_append(
1638 compose, addr, (ComposeEntryType) data );
1640 nodeMail = g_list_next( nodeMail );
1645 AddressObject *obj = NULL;
1647 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1649 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1650 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1651 GList *nodeMail = itemGroup->listEMail;
1653 ItemEMail *email = nodeMail->data;
1655 addr = addressbook_format_address(
1656 ( AddrItemObject * ) email );
1657 compose_entry_append(
1658 compose, addr, (ComposeEntryType) data );
1660 nodeMail = g_list_next( nodeMail );
1664 g_list_free( list );
1667 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1668 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1669 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1670 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1672 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1673 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1674 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1675 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1677 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1678 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1679 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1680 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1681 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1682 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1685 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1686 gboolean canEdit = FALSE;
1687 gboolean canDelete = TRUE;
1688 gboolean canAdd = FALSE;
1689 gboolean canEditTr = TRUE;
1690 gboolean editAddress = FALSE;
1691 gboolean canExport = TRUE;
1692 AddressTypeControlItem *atci = NULL;
1693 AddressDataSource *ds = NULL;
1694 AddressInterface *iface = NULL;
1696 if( obj == NULL ) return;
1697 if( obj->type == ADDR_INTERFACE ) {
1698 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1699 iface = adapter->interface;
1701 if( iface->haveLibrary ) {
1702 /* Enable appropriate File / New command */
1703 atci = adapter->atci;
1704 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1707 canEditTr = canExport = FALSE;
1709 else if( obj->type == ADDR_DATASOURCE ) {
1710 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1711 ds = ads->dataSource;
1712 iface = ds->interface;
1713 if( ! iface->readOnly ) {
1714 canAdd = canEdit = editAddress = canDelete = TRUE;
1716 if( ! iface->haveLibrary ) {
1717 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1720 else if( obj->type == ADDR_ITEM_FOLDER ) {
1721 ds = addressbook_find_datasource( addrbook.treeSelected );
1723 iface = ds->interface;
1724 if( iface->readOnly ) {
1729 canAdd = editAddress = TRUE;
1733 else if( obj->type == ADDR_ITEM_GROUP ) {
1734 ds = addressbook_find_datasource( addrbook.treeSelected );
1736 iface = ds->interface;
1737 if( ! iface->readOnly ) {
1743 if( addrbook.listSelected == NULL )
1747 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1748 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1749 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1750 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1753 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1754 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1755 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1756 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1758 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1759 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1762 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1763 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1767 * Address book tree callback function that responds to selection of tree
1770 * \param ctree Tree widget.
1771 * \param node Node that was selected.
1772 * \param column Column number where selected occurred.
1773 * \param data Pointer to user data.
1775 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1776 gint column, gpointer data)
1778 AddressObject *obj = NULL;
1779 AdapterDSource *ads = NULL;
1780 AddressDataSource *ds = NULL;
1781 ItemFolder *rootFolder = NULL;
1782 AddressObjectType aot;
1784 addrbook.treeSelected = node;
1785 addrbook.listSelected = NULL;
1786 addressbook_status_show( "" );
1787 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1789 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1791 addressbook_set_clist(NULL, TRUE);
1794 addrbook.opened = node;
1796 if( obj->type == ADDR_DATASOURCE ) {
1797 /* Read from file */
1798 static gboolean tVal = TRUE;
1800 ads = ADAPTER_DSOURCE(obj);
1801 if( ads == NULL ) return;
1802 ds = ads->dataSource;
1803 if( ds == NULL ) return;
1805 if( addrindex_ds_get_modify_flag( ds ) ) {
1806 addrindex_ds_read_data( ds );
1809 if( ! addrindex_ds_get_read_flag( ds ) ) {
1810 addrindex_ds_read_data( ds );
1812 addressbook_ds_show_message( ds );
1814 if( ! addrindex_ds_get_access_flag( ds ) ) {
1815 /* Remove existing folders and groups */
1816 gtk_clist_freeze( GTK_CLIST(ctree) );
1817 addressbook_tree_remove_children( ctree, node );
1818 gtk_clist_thaw( GTK_CLIST(ctree) );
1820 /* Load folders into the tree */
1821 rootFolder = addrindex_ds_get_root_folder( ds );
1822 if( ds && ds->type == ADDR_IF_JPILOT ) {
1823 aot = ADDR_CATEGORY;
1825 else if( ds && ds->type == ADDR_IF_LDAP ) {
1826 aot = ADDR_LDAP_QUERY;
1829 aot = ADDR_ITEM_FOLDER;
1831 addressbook_node_add_folder( node, ds, rootFolder, aot );
1832 addrindex_ds_set_access_flag( ds, &tVal );
1833 gtk_ctree_expand( ctree, node );
1836 addressbook_set_clist(NULL, TRUE);
1839 /* Update address list */
1840 g_signal_handlers_block_by_func
1842 G_CALLBACK(addressbook_tree_selected), NULL);
1843 addressbook_set_clist( obj, FALSE );
1844 g_signal_handlers_unblock_by_func
1846 G_CALLBACK(addressbook_tree_selected), NULL);
1847 if (!prefs_common.addressbook_use_editaddress_dialog)
1848 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1850 /* Setup main menu selections */
1851 addressbook_menubar_set_sensitive( FALSE );
1852 addressbook_menuitem_set_sensitive( obj, node );
1853 addressbook_list_select_clear();
1854 addressbook_list_menu_setup();
1859 * Setup address list popup menu items. Items are enabled or disabled as
1862 static void addressbook_list_menu_setup( void ) {
1863 GtkCTree *clist = NULL;
1864 AddressObject *pobj = NULL;
1865 AddressObject *obj = NULL;
1866 AdapterDSource *ads = NULL;
1867 AddressInterface *iface = NULL;
1868 AddressDataSource *ds = NULL;
1869 gboolean canEdit = FALSE;
1870 gboolean canDelete = FALSE;
1871 gboolean canCut = FALSE;
1872 gboolean canCopy = FALSE;
1873 gboolean canPaste = FALSE;
1874 gboolean canBrowse = FALSE;
1876 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1877 if( pobj == NULL ) return;
1879 clist = GTK_CTREE(addrbook.clist);
1880 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1881 if( obj == NULL ) canEdit = FALSE;
1883 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1884 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1886 if( pobj->type == ADDR_DATASOURCE ) {
1887 /* Parent object is a data source */
1888 ads = ADAPTER_DSOURCE(pobj);
1889 ds = ads->dataSource;
1892 iface = ds->interface;
1895 if( ! iface->readOnly ) {
1896 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1897 if (iface->type != ADDR_IF_LDAP)
1898 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1899 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1902 canDelete = canEdit;
1905 else if( pobj->type != ADDR_INTERFACE ) {
1906 /* Parent object is not an interface */
1907 ds = addressbook_find_datasource( addrbook.treeSelected );
1910 iface = ds->interface;
1913 if( ! iface->readOnly ) {
1914 /* Folder or group */
1915 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1916 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1917 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1918 if( obj ) canEdit = TRUE;
1921 if( pobj->type == ADDR_ITEM_FOLDER ) {
1922 if (iface->type != ADDR_IF_LDAP)
1923 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1924 if( obj ) canEdit = TRUE;
1926 canDelete = canEdit;
1928 if( iface->type == ADDR_IF_LDAP ) {
1929 if( obj ) canBrowse = TRUE;
1936 /* Enable cut and paste */
1937 if( ! addrclip_is_empty( _clipBoard_ ) )
1939 if( ! addrselect_test_empty( _addressSelect_ ) )
1941 /* Enable copy if something is selected */
1942 if( ! addrselect_test_empty( _addressSelect_ ) )
1946 /* Disable edit or browse if more than one row selected */
1947 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
1952 /* Forbid write changes when read-only */
1953 if( iface && iface->readOnly ) {
1959 /* Now go finalize menu items */
1960 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
1961 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
1963 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
1964 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
1965 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
1967 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
1969 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
1970 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
1971 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
1973 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1974 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1975 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
1977 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1978 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1981 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
1985 static void addressbook_select_row_tree (GtkCTree *ctree,
1993 * Add list of items into tree node below specified tree node.
1994 * \param treeNode Tree node.
1995 * \param ds Data source.
1996 * \param listItems List of items.
1998 static void addressbook_treenode_add_list(
1999 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2005 AddrItemObject *aio;
2009 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2012 group = ( ItemGroup * ) aio;
2013 nn = addressbook_node_add_group( treeNode, ds, group );
2015 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2018 folder = ( ItemFolder * ) aio;
2019 nn = addressbook_node_add_folder(
2020 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2022 node = g_list_next( node );
2026 static void addressbook_select_all_cb( void ) {
2027 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2031 * Cut from address list widget.
2033 static void addressbook_clip_cut_cb( void ) {
2034 _clipBoard_->cutFlag = TRUE;
2035 addrclip_clear( _clipBoard_ );
2036 addrclip_add( _clipBoard_, _addressSelect_ );
2037 /* addrclip_list_show( _clipBoard_, stdout ); */
2041 * Copy from address list widget.
2043 static void addressbook_clip_copy_cb( void ) {
2044 _clipBoard_->cutFlag = FALSE;
2045 addrclip_clear( _clipBoard_ );
2046 addrclip_add( _clipBoard_, _addressSelect_ );
2047 /* addrclip_list_show( _clipBoard_, stdout ); */
2051 * Paste clipboard into address list widget.
2053 static void addressbook_clip_paste_cb( void ) {
2054 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2055 AddressObject *pobj = NULL;
2056 AddressDataSource *ds = NULL;
2057 AddressBookFile *abf = NULL;
2058 ItemFolder *folder = NULL;
2059 GList *folderGroup = NULL;
2061 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2062 if( ds == NULL ) return;
2063 if( addrindex_ds_get_readonly( ds ) ) {
2064 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2068 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2070 if( pobj->type == ADDR_ITEM_FOLDER ) {
2071 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2073 else if( pobj->type == ADDR_ITEM_GROUP ) {
2074 alertpanel_error( _("Cannot paste into an address group.") );
2079 /* Get an address book */
2080 abf = addressbook_get_book_file();
2081 if( abf == NULL ) return;
2083 if( _clipBoard_->cutFlag ) {
2085 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2087 /* Remove all groups and folders in clipboard from tree node */
2088 addressbook_treenode_remove_item();
2090 /* Remove all "cut" items */
2091 addrclip_delete_item( _clipBoard_ );
2093 /* Clear clipboard - cut items??? */
2094 addrclip_clear( _clipBoard_ );
2098 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2101 /* addrclip_list_show( _clipBoard_, stdout ); */
2103 /* Update tree by inserting node for each folder or group */
2104 addressbook_treenode_add_list(
2105 addrbook.treeSelected, ds, folderGroup );
2106 gtk_ctree_expand( ctree, addrbook.treeSelected );
2107 g_list_free( folderGroup );
2111 /* Display items pasted */
2112 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2113 addressbook_set_clist(
2114 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2122 * Add current treenode object to clipboard. Note that widget only allows
2123 * one entry from the tree list to be selected.
2125 static void addressbook_treenode_to_clipboard( void ) {
2126 AddressObject *obj = NULL;
2127 AddressDataSource *ds = NULL;
2128 AddrSelectItem *item;
2129 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2132 node = addrbook.treeSelected;
2133 if( node == NULL ) return;
2134 obj = gtk_ctree_node_get_row_data( ctree, node );
2135 if( obj == NULL ) return;
2137 ds = addressbook_find_datasource( node );
2138 if( ds == NULL ) return;
2141 if( obj->type == ADDR_ITEM_FOLDER ) {
2142 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2143 ItemFolder *folder = adapter->itemFolder;
2145 item = addrselect_create_node( obj );
2146 item->uid = g_strdup( ADDRITEM_ID(folder) );
2148 else if( obj->type == ADDR_ITEM_GROUP ) {
2149 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2150 ItemGroup *group = adapter->itemGroup;
2152 item = addrselect_create_node( obj );
2153 item->uid = g_strdup( ADDRITEM_ID(group) );
2155 else if( obj->type == ADDR_DATASOURCE ) {
2157 item = addrselect_create_node( obj );
2162 /* Clear existing list and add item into list */
2165 addressbook_list_select_clear();
2166 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2167 addrselect_list_add( _addressSelect_, item, cacheID );
2173 * Cut from tree widget.
2175 static void addressbook_treenode_cut_cb( void ) {
2176 _clipBoard_->cutFlag = TRUE;
2177 addressbook_treenode_to_clipboard();
2178 addrclip_clear( _clipBoard_ );
2179 addrclip_add( _clipBoard_, _addressSelect_ );
2180 /* addrclip_list_show( _clipBoard_, stdout ); */
2184 * Copy from tree widget.
2186 static void addressbook_treenode_copy_cb( void ) {
2187 _clipBoard_->cutFlag = FALSE;
2188 addressbook_treenode_to_clipboard();
2189 addrclip_clear( _clipBoard_ );
2190 addrclip_add( _clipBoard_, _addressSelect_ );
2191 /* addrclip_list_show( _clipBoard_, stdout ); */
2195 * Paste clipboard into address tree widget.
2197 static void addressbook_treenode_paste_cb( void ) {
2198 addressbook_clip_paste_cb();
2202 * Clear selected entries in clipboard.
2204 static void addressbook_list_select_clear( void ) {
2205 addrselect_list_clear( _addressSelect_ );
2209 * Add specified address item to selected address list.
2210 * \param aio Address item object.
2211 * \param ds Datasource.
2213 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2216 if( ds == NULL ) return;
2217 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2218 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2223 * Remove specified address item from selected address list.
2224 * \param aio Address item object.
2226 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2227 addrselect_list_remove( _addressSelect_, aio );
2231 * Invoke EMail compose window with addresses in selected address list.
2233 static void addressbook_mail_to_cb( void ) {
2236 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2237 listAddress = addrselect_build_list( _addressSelect_ );
2238 compose_new_with_list( NULL, listAddress );
2239 mgu_free_dlist( listAddress );
2244 static void addressbook_list_row_selected( GtkCTree *clist,
2249 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2250 AddrItemObject *aio = NULL;
2251 AddressObject *pobj = NULL;
2252 AdapterDSource *ads = NULL;
2253 AddressDataSource *ds = NULL;
2255 gtk_entry_set_text( entry, "" );
2256 addrbook.listSelected = node;
2258 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2259 if( pobj == NULL ) return;
2261 if( pobj->type == ADDR_DATASOURCE ) {
2262 ads = ADAPTER_DSOURCE(pobj);
2263 ds = ads->dataSource;
2265 else if( pobj->type != ADDR_INTERFACE ) {
2266 ds = addressbook_find_datasource( addrbook.treeSelected );
2269 aio = gtk_ctree_node_get_row_data( clist, node );
2271 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2272 addressbook_list_select_add( aio, ds );
2275 addressbook_list_menu_setup();
2277 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2278 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2280 if (obj && obj->type != ADDR_ITEM_GROUP)
2281 addressbook_edit_address(NULL, 0, NULL, FALSE);
2285 static void addressbook_list_row_unselected( GtkCTree *ctree,
2290 AddrItemObject *aio;
2292 aio = gtk_ctree_node_get_row_data( ctree, node );
2294 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2295 addressbook_list_select_remove( aio );
2298 if (!prefs_common.addressbook_use_editaddress_dialog)
2299 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2302 /* from gdkevents.c */
2303 #define DOUBLE_CLICK_TIME 250
2305 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2306 GdkEventButton *event,
2309 static guint32 lasttime = 0;
2310 if( ! event ) return FALSE;
2312 addressbook_list_menu_setup();
2314 if( event->button == 3 ) {
2315 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2316 event->button, event->time );
2317 } else if (event->button == 1) {
2318 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2319 if (prefs_common.add_address_by_click &&
2320 addrbook.target_compose)
2321 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2323 if (prefs_common.addressbook_use_editaddress_dialog)
2324 addressbook_edit_address_cb(NULL, 0, NULL);
2326 GtkCTree *clist = GTK_CTREE(addrbook.clist);
2327 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2328 if( obj && obj->type == ADDR_ITEM_GROUP )
2329 addressbook_edit_address_cb(NULL, 0, NULL);
2334 lasttime = event->time;
2340 static gboolean addressbook_list_button_released(GtkWidget *widget,
2341 GdkEventButton *event,
2347 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2348 GdkEventButton *event,
2351 GtkCList *clist = GTK_CLIST(ctree);
2353 AddressObject *obj = NULL;
2354 AdapterDSource *ads = NULL;
2355 AddressInterface *iface = NULL;
2356 AddressDataSource *ds = NULL;
2357 gboolean canEdit = FALSE;
2358 gboolean canDelete = FALSE;
2359 gboolean canCut = FALSE;
2360 gboolean canCopy = FALSE;
2361 gboolean canPaste = FALSE;
2362 gboolean canTreeCut = FALSE;
2363 gboolean canTreeCopy = FALSE;
2364 gboolean canTreePaste = FALSE;
2365 gboolean canLookup = FALSE;
2366 GtkCTreeNode *node = NULL;
2368 if( ! event ) return FALSE;
2369 addressbook_menubar_set_sensitive( FALSE );
2371 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2372 gtkut_clist_set_focus_row(clist, row);
2373 obj = gtk_clist_get_row_data( clist, row );
2376 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2378 if( obj == NULL ) return FALSE;
2379 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2381 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2382 canTreePaste = TRUE;
2384 if (obj->type == ADDR_INTERFACE) {
2385 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2388 iface = adapter->interface;
2391 if( !iface->readOnly ) {
2392 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2393 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2395 if( iface->externalQuery ) canLookup = TRUE;
2397 if (obj->type == ADDR_DATASOURCE) {
2398 ads = ADAPTER_DSOURCE(obj);
2399 ds = ads->dataSource;
2402 iface = ds->interface;
2405 if( !iface->readOnly ) {
2407 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2408 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2409 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2413 if( iface->externalQuery ) canLookup = TRUE;
2415 else if (obj->type == ADDR_ITEM_FOLDER) {
2416 ds = addressbook_find_datasource( node );
2419 iface = ds->interface;
2422 if( !iface->readOnly ) {
2426 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2427 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2428 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2432 if( iface->externalQuery ) {
2433 /* Enable deletion of LDAP folder */
2438 else if (obj->type == ADDR_ITEM_GROUP) {
2439 ds = addressbook_find_datasource( node );
2442 iface = ds->interface;
2445 if( ! iface->readOnly ) {
2448 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2449 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2454 if( ! addrselect_test_empty( _addressSelect_ ) )
2457 if( ! addrselect_test_empty( _addressSelect_ ) )
2459 if( ! addrclip_is_empty( _clipBoard_ ) )
2462 /* Forbid write changes when read-only */
2463 if( iface && iface->readOnly ) {
2465 canTreePaste = FALSE;
2473 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2474 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2475 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2476 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2477 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2479 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2480 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2481 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2482 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2483 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2485 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2486 addrbook.target_compose != NULL);
2488 if( event->button == 3 ) {
2489 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2490 event->button, event->time);
2496 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2497 GdkEventButton *event,
2500 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2504 static void addressbook_new_folder_cb(gpointer data, guint action,
2507 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2508 AddressObject *obj = NULL;
2509 AddressDataSource *ds = NULL;
2510 AddressBookFile *abf = NULL;
2511 ItemFolder *parentFolder = NULL;
2512 ItemFolder *folder = NULL;
2514 if( ! addrbook.treeSelected ) return;
2515 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2516 if( obj == NULL ) return;
2517 ds = addressbook_find_datasource( addrbook.treeSelected );
2518 if( ds == NULL ) return;
2520 if( obj->type == ADDR_DATASOURCE ) {
2521 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2523 else if( obj->type == ADDR_ITEM_FOLDER ) {
2524 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2530 abf = ds->rawDataSource;
2531 if( abf == NULL ) return;
2532 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2535 nn = addressbook_node_add_folder(
2536 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2537 gtk_ctree_expand( ctree, addrbook.treeSelected );
2538 if( addrbook.treeSelected == addrbook.opened )
2539 addressbook_set_clist(obj, TRUE);
2544 static void addressbook_new_group_cb(gpointer data, guint action,
2547 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2548 AddressObject *obj = NULL;
2549 AddressDataSource *ds = NULL;
2550 AddressBookFile *abf = NULL;
2551 ItemFolder *parentFolder = NULL;
2552 ItemGroup *group = NULL;
2554 if( ! addrbook.treeSelected ) return;
2555 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2556 if( obj == NULL ) return;
2557 ds = addressbook_find_datasource( addrbook.treeSelected );
2558 if( ds == NULL ) return;
2560 if( obj->type == ADDR_DATASOURCE ) {
2561 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2563 else if( obj->type == ADDR_ITEM_FOLDER ) {
2564 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2570 abf = ds->rawDataSource;
2571 if( abf == NULL ) return;
2572 group = addressbook_edit_group( abf, parentFolder, NULL );
2575 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2576 gtk_ctree_expand( ctree, addrbook.treeSelected );
2577 if( addrbook.treeSelected == addrbook.opened )
2578 addressbook_set_clist(obj, TRUE);
2583 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2585 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2588 GdkPixmap *pix_cl, *pix_op;
2589 GdkBitmap *mask_cl, *mask_op;
2590 gboolean is_leaf, expanded;
2592 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2593 &pix_cl, &mask_cl, &pix_op, &mask_op,
2594 &is_leaf, &expanded);
2595 gtk_sctree_set_node_info(ctree, node, name, spacing,
2596 pix_cl, mask_cl, pix_op, mask_op,
2602 * \param obj Address object to edit.
2603 * \param node Node in tree.
2604 * \return New name of data source.
2606 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2607 gchar *newName = NULL;
2608 AddressDataSource *ds = NULL;
2609 AddressInterface *iface = NULL;
2610 AdapterDSource *ads = NULL;
2612 ds = addressbook_find_datasource( node );
2613 if( ds == NULL ) return NULL;
2614 iface = ds->interface;
2615 if( ! iface->haveLibrary ) return NULL;
2617 /* Read data from data source */
2618 if( addrindex_ds_get_modify_flag( ds ) ) {
2619 addrindex_ds_read_data( ds );
2622 if( ! addrindex_ds_get_read_flag( ds ) ) {
2623 addrindex_ds_read_data( ds );
2627 ads = ADAPTER_DSOURCE(obj);
2628 if( ads->subType == ADDR_BOOK ) {
2629 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2631 else if( ads->subType == ADDR_VCARD ) {
2632 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2635 else if( ads->subType == ADDR_JPILOT ) {
2636 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2640 else if( ads->subType == ADDR_LDAP ) {
2641 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2647 newName = obj->name;
2652 * Edit an object that is in the address tree area.
2654 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2657 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2659 AddressDataSource *ds = NULL;
2660 AddressBookFile *abf = NULL;
2661 GtkCTreeNode *node = NULL, *parentNode = NULL;
2664 if( ! addrbook.treeSelected ) return;
2665 node = addrbook.treeSelected;
2666 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2667 obj = gtk_ctree_node_get_row_data( ctree, node );
2668 if( obj == NULL ) return;
2669 parentNode = GTK_CTREE_ROW(node)->parent;
2671 ds = addressbook_find_datasource( node );
2672 if( ds == NULL ) return;
2674 if( obj->type == ADDR_DATASOURCE ) {
2675 name = addressbook_edit_datasource( obj, node );
2676 if( name == NULL ) return;
2679 abf = ds->rawDataSource;
2680 if( abf == NULL ) return;
2681 if( obj->type == ADDR_ITEM_FOLDER ) {
2682 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2683 ItemFolder *item = adapter->itemFolder;
2684 ItemFolder *parentFolder = NULL;
2685 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2686 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2687 name = ADDRITEM_NAME(item);
2689 else if( obj->type == ADDR_ITEM_GROUP ) {
2690 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2691 ItemGroup *item = adapter->itemGroup;
2692 ItemFolder *parentFolder = NULL;
2693 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2694 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2695 name = ADDRITEM_NAME(item);
2698 if( name && parentNode ) {
2699 /* Update node in tree view */
2700 addressbook_change_node_name( node, name );
2701 gtk_sctree_sort_node(ctree, parentNode);
2702 gtk_ctree_expand( ctree, node );
2703 gtk_sctree_select( GTK_SCTREE( ctree), node );
2710 ADDRTREE_DEL_FOLDER_ONLY,
2711 ADDRTREE_DEL_FOLDER_ADDR
2715 * Delete an item from the tree widget.
2716 * \param data Data passed in.
2717 * \param action Action.
2718 * \param widget Widget issuing callback.
2720 static void addressbook_treenode_delete_cb(
2721 gpointer data, guint action, GtkWidget *widget )
2723 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2724 GtkCTreeNode *node = NULL;
2728 AddrBookBase *adbase;
2729 AddressCache *cache;
2730 AdapterDSource *ads = NULL;
2731 AddressInterface *iface = NULL;
2732 AddressDataSource *ds = NULL;
2733 gboolean remFlag = FALSE;
2734 TreeItemDelType delType;
2736 if( ! addrbook.treeSelected ) return;
2737 node = addrbook.treeSelected;
2738 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2740 obj = gtk_ctree_node_get_row_data( ctree, node );
2741 g_return_if_fail(obj != NULL);
2743 if( obj->type == ADDR_DATASOURCE ) {
2744 ads = ADAPTER_DSOURCE(obj);
2745 if( ads == NULL ) return;
2746 ds = ads->dataSource;
2747 if( ds == NULL ) return;
2750 /* Must be folder or something else */
2751 ds = addressbook_find_datasource( node );
2752 if( ds == NULL ) return;
2754 /* Only allow deletion from non-readOnly */
2755 iface = ds->interface;
2756 if( iface->readOnly ) {
2757 /* Allow deletion of query results */
2758 if( ! iface->externalQuery ) return;
2762 /* Confirm deletion */
2763 delType = ADDRTREE_DEL_NONE;
2764 if( obj->type == ADDR_ITEM_FOLDER ) {
2765 if( iface->externalQuery ) {
2766 message = g_strdup_printf( _(
2767 "Do you want to delete the query " \
2768 "results and addresses in '%s' ?" ),
2770 aval = alertpanel( _("Delete"), message,
2771 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2773 if( aval == G_ALERTALTERNATE ) {
2774 delType = ADDRTREE_DEL_FOLDER_ADDR;
2778 message = g_strdup_printf
2779 ( _( "Do you want to delete '%s' ?"
2780 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2782 aval = alertpanel( _("Delete folder"), message,
2783 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2785 if( aval == G_ALERTALTERNATE ) {
2786 delType = ADDRTREE_DEL_FOLDER_ONLY;
2788 else if( aval == G_ALERTOTHER ) {
2789 delType = ADDRTREE_DEL_FOLDER_ADDR;
2793 else if( obj->type == ADDR_ITEM_GROUP ) {
2794 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2795 "The addresses it contains will not be lost."), obj->name);
2796 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2797 "+" GTK_STOCK_DELETE, NULL);
2799 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2801 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2802 "The addresses it contains will be lost."), obj->name);
2803 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2804 "+" GTK_STOCK_DELETE, NULL);
2806 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2808 if( delType == ADDRTREE_DEL_NONE ) return;
2810 /* Proceed with deletion */
2811 if( obj->type == ADDR_DATASOURCE ) {
2812 /* Remove node from tree */
2813 gtk_ctree_remove_node( ctree, node );
2815 /* Remove data source. */
2816 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2817 addrindex_free_datasource( ds );
2822 /* Get reference to cache */
2823 adbase = ( AddrBookBase * ) ds->rawDataSource;
2824 if( adbase == NULL ) return;
2825 cache = adbase->addressCache;
2827 /* Remove query results folder */
2828 if( iface->externalQuery ) {
2829 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2830 ItemFolder *folder = adapter->itemFolder;
2832 adapter->itemFolder = NULL;
2834 g_print( "remove folder for ::%s::\n", obj->name );
2835 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2836 g_print( "-------------- remove results\n" );
2838 addrindex_remove_results( ds, folder );
2839 /* g_print( "-------------- remove node\n" ); */
2840 gtk_ctree_remove_node( ctree, node );
2844 /* Code below is valid for regular address book deletion */
2845 if( obj->type == ADDR_ITEM_FOLDER ) {
2846 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2847 ItemFolder *item = adapter->itemFolder;
2849 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2850 /* Remove folder only */
2851 item = addrcache_remove_folder( cache, item );
2853 addritem_free_item_folder( item );
2854 addressbook_move_nodes_up( ctree, node );
2858 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2859 /* Remove folder and addresses */
2860 item = addrcache_remove_folder_delete( cache, item );
2862 addritem_free_item_folder( item );
2867 else if( obj->type == ADDR_ITEM_GROUP ) {
2868 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2869 ItemGroup *item = adapter->itemGroup;
2871 item = addrcache_remove_group( cache, item );
2873 addritem_free_item_group( item );
2880 gtk_ctree_remove_node(ctree, node );
2884 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2886 if( person && addrbook.treeSelected == addrbook.opened ) {
2887 person->status = ADD_ENTRY;
2888 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2889 addressbook_folder_refresh_one_person(
2890 GTK_CTREE(addrbook.clist), person );
2892 addressbook_address_list_set_focus();
2895 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2897 if( person && addrbook.treeSelected == addrbook.opened) {
2898 person->status = ADD_ENTRY;
2899 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2900 addressbook_set_clist(
2901 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2905 addressbook_address_list_set_focus();
2909 * Label (a format string) that is used to name each folder.
2911 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
2914 * Search ctree widget callback function.
2915 * \param pA Pointer to node.
2916 * \param pB Pointer to data item being sought.
2917 * \return Zero (0) if folder found.
2919 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
2922 aoA = ( AddressObject * ) pA;
2923 if( aoA->type == ADDR_ITEM_FOLDER ) {
2924 ItemFolder *folder, *fld;
2926 fld = ADAPTER_FOLDER(aoA)->itemFolder;
2927 folder = ( ItemFolder * ) pB;
2928 if( fld == folder ) return 0; /* Found folder */
2933 static ItemFolder * addressbook_setup_subf(
2934 AddressDataSource *ds, gchar *title,
2935 GtkCTreeNode *pNode )
2937 AddrBookBase *adbase;
2938 AddressCache *cache;
2941 GtkCTreeNode *nNode;
2943 AddressObjectType aoType = ADDR_NONE;
2946 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
2948 if( ds && ds->type == ADDR_IF_LDAP ) {
2950 aoType = ADDR_LDAP_QUERY;
2957 ctree = GTK_CTREE(addrbook.ctree);
2958 /* Get reference to address cache */
2959 adbase = ( AddrBookBase * ) ds->rawDataSource;
2960 cache = adbase->addressCache;
2962 if ((children = addrcache_get_list_folder(cache)) != NULL) {
2963 GList *cur = children;
2964 for (; cur; cur = cur->next) {
2965 ItemFolder *child = (ItemFolder *) cur->data;
2966 if (!strcmp2(ADDRITEM_NAME(child), title)) {
2967 nNode = gtk_ctree_find_by_row_data_custom(
2969 addressbook_treenode_find_folder_cb );
2971 addrindex_remove_results( ds, child );
2972 while( child->listPerson ) {
2973 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
2974 item = addrcache_remove_person( cache, item );
2976 addritem_free_item_person( item );
2980 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
2981 addrbook.treeSelected = nNode;
2988 /* Create a folder */
2989 folder = addrcache_add_new_folder( cache, NULL );
2990 name = g_strdup_printf( "%s", title );
2991 addritem_folder_set_name( folder, name );
2992 addritem_folder_set_remarks( folder, "" );
2995 /* Now let's see the folder */
2996 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
2997 gtk_ctree_expand( ctree, pNode );
2999 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3000 addrbook.treeSelected = nNode;
3006 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3007 AddressObject *pobj = NULL;
3008 AddressDataSource *ds = NULL;
3009 AddressBookFile *abf = NULL;
3010 debug_print("adding address\n");
3011 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3012 if( pobj == NULL ) {
3013 debug_print("no row data\n");
3016 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3018 debug_print("no datasource\n");
3022 abf = ds->rawDataSource;
3024 g_print("no addressbook file\n");
3028 if( pobj->type == ADDR_DATASOURCE ) {
3029 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3030 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3032 ItemFolder *folder = NULL;
3034 if (abf && abf->type == ADDR_IF_LDAP) {
3035 GtkCTreeNode *parentNode;
3036 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3037 if( ds == NULL ) return;
3039 /* We must have a datasource that is an external interface */
3040 if( ! ds->interface->haveLibrary ) return;
3041 if( ! ds->interface->externalQuery ) return;
3043 if( pobj->type == ADDR_ITEM_FOLDER ) {
3044 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3047 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3049 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3051 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3052 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3053 abf = ds->rawDataSource;
3056 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3057 addrbook.editaddress_vbox,
3058 addressbook_new_address_from_book_post_cb,
3061 if (abf && abf->type == ADDR_IF_LDAP) {
3062 LdapServer *server = ds->rawDataSource;
3063 ldapsvr_set_modified(server, TRUE);
3064 ldapsvr_update_book(server, NULL);
3065 if (server->retVal != LDAPRC_SUCCESS) {
3066 alertpanel( _("Add address(es)"),
3067 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3068 GTK_STOCK_CLOSE, NULL, NULL );
3069 server->retVal = LDAPRC_SUCCESS;
3074 if (prefs_common.addressbook_use_editaddress_dialog)
3075 addressbook_new_address_from_book_post_cb( person );
3078 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3080 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3083 if (abf && abf->type == ADDR_IF_LDAP) {
3084 GtkCTreeNode *parentNode;
3085 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3086 if( ds == NULL ) return;
3088 /* We must have a datasource that is an external interface */
3089 if( ! ds->interface->haveLibrary ) return;
3090 if( ! ds->interface->externalQuery ) return;
3092 if( pobj->type == ADDR_ITEM_FOLDER ) {
3093 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3096 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3098 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3101 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3102 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3103 abf = ds->rawDataSource;
3106 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3107 addrbook.editaddress_vbox,
3108 addressbook_new_address_from_folder_post_cb,
3111 if (abf && abf->type == ADDR_IF_LDAP) {
3112 LdapServer *server = ds->rawDataSource;
3113 ldapsvr_set_modified(server, TRUE);
3114 ldapsvr_update_book(server, NULL);
3115 if (server->retVal != LDAPRC_SUCCESS) {
3116 alertpanel( _("Add address(es)"),
3117 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3118 GTK_STOCK_CLOSE, NULL, NULL );
3123 if (prefs_common.addressbook_use_editaddress_dialog)
3124 addressbook_new_address_from_folder_post_cb( person );
3126 else if( pobj->type == ADDR_ITEM_GROUP ) {
3127 /* New address in group */
3128 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3129 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3130 if (addrbook.treeSelected == addrbook.opened) {
3131 /* Change node name in tree. */
3132 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3133 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3134 addressbook_set_clist(
3135 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3143 * Search for specified child group node in address index tree.
3144 * \param parent Parent node.
3145 * \param group Group to find.
3147 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
3148 GtkCTreeNode *node = NULL;
3149 GtkCTreeRow *currRow;
3151 currRow = GTK_CTREE_ROW( parent );
3153 node = currRow->children;
3157 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3158 if( obj->type == ADDR_ITEM_GROUP ) {
3159 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3160 if( g == group ) return node;
3162 currRow = GTK_CTREE_ROW(node);
3163 node = currRow->sibling;
3169 static AddressBookFile *addressbook_get_book_file() {
3170 AddressBookFile *abf = NULL;
3171 AddressDataSource *ds = NULL;
3173 ds = addressbook_find_datasource( addrbook.treeSelected );
3174 if( ds == NULL ) return NULL;
3175 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3179 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
3183 /* Remove existing folders and groups */
3184 row = GTK_CTREE_ROW( parent );
3186 while( (node = row->children) ) {
3187 gtk_ctree_remove_node( ctree, node );
3192 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
3193 GtkCTreeNode *parent, *child;
3194 GtkCTreeRow *currRow;
3195 currRow = GTK_CTREE_ROW( node );
3197 parent = currRow->parent;
3198 while( (child = currRow->children) ) {
3199 gtk_ctree_move( ctree, child, parent, node );
3201 gtk_sctree_sort_node( ctree, parent );
3205 static void addressbook_edit_address_post_cb( ItemPerson *person )
3209 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3210 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3212 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
3213 invalidate_address_completion();
3215 addressbook_address_list_set_focus();
3218 void addressbook_address_list_set_focus( void )
3220 if (!prefs_common.addressbook_use_editaddress_dialog) {
3221 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3222 addressbook_list_menu_setup();
3226 void addressbook_address_list_disable_some_actions(void)
3228 /* disable address copy/pasting when editing contact's detail (embedded form) */
3229 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3230 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3231 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3234 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3235 addressbook_edit_address(data, action, widget, TRUE);
3238 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3239 gboolean force_focus ) {
3240 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3242 AddressObject *obj = NULL, *pobj = NULL;
3243 AddressDataSource *ds = NULL;
3244 GtkCTreeNode *node = NULL, *parentNode = NULL;
3246 AddressBookFile *abf = NULL;
3248 if( addrbook.listSelected == NULL ) return;
3249 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3250 g_return_if_fail(obj != NULL);
3252 ctree = GTK_CTREE( addrbook.ctree );
3253 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3254 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3256 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3257 if( ds == NULL ) return;
3259 abf = addressbook_get_book_file();
3261 if( obj->type == ADDR_ITEM_EMAIL ) {
3262 ItemEMail *email = ( ItemEMail * ) obj;
3263 if( email == NULL ) return;
3264 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3265 /* Edit parent group */
3266 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3267 ItemGroup *itemGrp = adapter->itemGroup;
3268 if( abf == NULL ) return;
3269 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3270 name = ADDRITEM_NAME(itemGrp);
3271 node = addrbook.treeSelected;
3272 parentNode = GTK_CTREE_ROW(node)->parent;
3275 /* Edit person - email page */
3277 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3278 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3279 addressbook_edit_address_post_cb,
3280 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3283 if (abf && abf->type == ADDR_IF_LDAP) {
3284 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3285 person->status = UPDATE_ENTRY;
3288 if (prefs_common.addressbook_use_editaddress_dialog)
3289 addressbook_edit_address_post_cb( person );
3294 else if( obj->type == ADDR_ITEM_PERSON ) {
3295 /* Edit person - basic page */
3296 ItemPerson *person = ( ItemPerson * ) obj;
3297 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3298 addressbook_edit_address_post_cb,
3299 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3302 if (abf && abf->type == ADDR_IF_LDAP) {
3303 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3304 person->status = UPDATE_ENTRY;
3307 if (prefs_common.addressbook_use_editaddress_dialog)
3308 addressbook_edit_address_post_cb( person );
3312 else if( obj->type == ADDR_ITEM_GROUP ) {
3313 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3314 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3315 parentNode = addrbook.treeSelected;
3316 node = addressbook_find_group_node( parentNode, itemGrp );
3317 name = ADDRITEM_NAME(itemGrp);
3318 invalidate_address_completion();
3324 /* Update tree node with node name */
3325 if( node == NULL ) return;
3326 addressbook_change_node_name( node, name );
3327 gtk_sctree_sort_node( ctree, parentNode );
3328 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3329 addressbook_set_clist(
3330 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3335 static void addressbook_delete_address_cb(gpointer data, guint action,
3338 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
3339 addressbook_del_clicked(NULL, NULL);
3340 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
3343 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3345 addressbook_close();
3348 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3349 addressbook_export_to_file();
3352 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3354 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3355 if( person ) addritem_person_set_opened( person, TRUE );
3359 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3361 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3362 if( person ) addritem_person_set_opened( person, FALSE );
3366 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3368 gchar *eMailAlias = ADDRITEM_NAME(email);
3369 if( eMailAlias && *eMailAlias != '\0' ) {
3371 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3374 str = g_strdup( eMailAlias );
3380 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3381 GList *items = itemGroup->listEMail;
3382 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3383 for( ; items != NULL; items = g_list_next( items ) ) {
3384 GtkCTreeNode *nodeEMail = NULL;
3385 gchar *text[N_LIST_COLS];
3386 ItemEMail *email = items->data;
3390 if( ! email ) continue;
3392 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3393 str = addressbook_format_item_clist( person, email );
3395 text[COL_NAME] = addressbook_set_col_name_guard(str);
3398 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3400 text[COL_ADDRESS] = email->address;
3401 text[COL_REMARKS] = email->remarks;
3402 nodeEMail = gtk_sctree_insert_node(
3404 text, FOLDER_SPACING,
3405 atci->iconXpm, atci->maskXpm,
3406 atci->iconXpmOpen, atci->maskXpmOpen,
3408 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3414 gchar *addressbook_set_col_name_guard(gchar *value)
3416 gchar *ret = "<not set>";
3417 gchar *tmp = g_strdup(value);
3419 if (tmp !=NULL && *tmp != '\0')
3425 static void addressbook_folder_load_one_person(
3426 GtkCTree *clist, ItemPerson *person,
3427 AddressTypeControlItem *atci,
3428 AddressTypeControlItem *atciMail )
3430 GtkCTreeNode *nodePerson = NULL;
3431 GtkCTreeNode *nodeEMail = NULL;
3432 gchar *text[N_LIST_COLS];
3433 gboolean flgFirst = TRUE, haveAddr = FALSE;
3436 AddressBookFile *abf = addressbook_get_book_file();
3439 if( person == NULL ) return;
3441 text[COL_NAME] = "";
3442 node = person->listEMail;
3444 ItemEMail *email = node->data;
3445 gchar *eMailAddr = NULL;
3446 node = g_list_next( node );
3448 text[COL_ADDRESS] = email->address;
3449 text[COL_REMARKS] = email->remarks;
3450 eMailAddr = ADDRITEM_NAME(email);
3451 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3453 /* First email belongs with person */
3454 gchar *str = addressbook_format_item_clist( person, email );
3456 text[COL_NAME] = addressbook_set_col_name_guard(str);
3459 else if( abf && abf->type == ADDR_IF_LDAP &&
3460 person && person->nickName ) {
3461 if (person->nickName) {
3462 if (strcmp(person->nickName, "") != 0) {
3463 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3466 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3472 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3474 nodePerson = gtk_sctree_insert_node(
3476 text, FOLDER_SPACING,
3477 atci->iconXpm, atci->maskXpm,
3478 atci->iconXpmOpen, atci->maskXpmOpen,
3479 FALSE, person->isOpened );
3482 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3485 /* Subsequent email is a child node of person */
3486 text[COL_NAME] = ADDRITEM_NAME(email);
3487 nodeEMail = gtk_sctree_insert_node(
3488 clist, nodePerson, NULL,
3489 text, FOLDER_SPACING,
3490 atciMail->iconXpm, atciMail->maskXpm,
3491 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3493 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3499 /* Have name without EMail */
3500 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3501 text[COL_ADDRESS] = "";
3502 text[COL_REMARKS] = "";
3503 nodePerson = gtk_sctree_insert_node(
3505 text, FOLDER_SPACING,
3506 atci->iconXpm, atci->maskXpm,
3507 atci->iconXpmOpen, atci->maskXpmOpen,
3508 FALSE, person->isOpened );
3509 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3514 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3516 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3517 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3519 if( atci == NULL ) return;
3520 if( atciMail == NULL ) return;
3522 /* Load email addresses */
3523 items = addritem_folder_get_person_list( itemFolder );
3524 for( ; items != NULL; items = g_list_next( items ) ) {
3525 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3527 /* Free up the list */
3528 mgu_clear_list( items );
3529 g_list_free( items );
3532 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3533 addrbook.listSelected = NULL;
3534 gtk_ctree_remove_node( clist, node );
3535 addressbook_menubar_set_sensitive( FALSE );
3536 addressbook_menuitem_set_sensitive(
3537 gtk_ctree_node_get_row_data(
3538 GTK_CTREE(clist), addrbook.treeSelected ),
3539 addrbook.treeSelected );
3542 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3543 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3544 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3546 if( atci == NULL ) return;
3547 if( atciMail == NULL ) return;
3548 if( person == NULL ) return;
3549 /* unload the person */
3551 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3553 addressbook_folder_remove_node( clist, node );
3554 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3555 gtk_sctree_sort_node( clist, NULL );
3556 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3558 gtk_sctree_select( GTK_SCTREE(clist), node );
3559 if (!gtk_ctree_node_is_visible( clist, node ) )
3560 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3564 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3568 if( person == NULL ) return;
3569 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3570 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3572 addressbook_folder_remove_node( clist, node );
3576 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3578 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3580 /* Load any groups */
3581 if( ! atci ) return;
3582 items = addritem_folder_get_group_list( itemFolder );
3583 for( ; items != NULL; items = g_list_next( items ) ) {
3584 GtkCTreeNode *nodeGroup = NULL;
3585 gchar *text[N_LIST_COLS];
3586 ItemGroup *group = items->data;
3587 if( group == NULL ) continue;
3588 text[COL_NAME] = ADDRITEM_NAME(group);
3589 text[COL_ADDRESS] = "";
3590 text[COL_REMARKS] = "";
3591 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3592 text, FOLDER_SPACING,
3593 atci->iconXpm, atci->maskXpm,
3594 atci->iconXpmOpen, atci->maskXpmOpen,
3596 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3597 gtk_sctree_sort_node(clist, NULL);
3599 /* Free up the list */
3600 mgu_clear_list( items );
3601 g_list_free( items );
3605 * Search ctree widget callback function.
3606 * \param pA Pointer to node.
3607 * \param pB Pointer to data item being sought.
3608 * \return Zero (0) if group found.
3610 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3613 aoA = ( AddressObject * ) pA;
3614 if( aoA->type == ADDR_ITEM_GROUP ) {
3615 ItemGroup *group, *grp;
3617 grp = ADAPTER_GROUP(aoA)->itemGroup;
3618 group = ( ItemGroup * ) pB;
3619 if( grp == group ) return 0; /* Found group */
3625 * Remove folder and group nodes from tree widget for items contained ("cut")
3628 static void addressbook_treenode_remove_item( void ) {
3630 AddrSelectItem *cutItem;
3631 AddressCache *cache;
3632 AddrItemObject *aio;
3633 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3636 node = _clipBoard_->objectList;
3638 cutItem = node->data;
3639 node = g_list_next( node );
3640 cache = addrindex_get_cache(
3641 _clipBoard_->addressIndex, cutItem->cacheID );
3642 if( cache == NULL ) continue;
3643 aio = addrcache_get_object( cache, cutItem->uid );
3646 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3649 folder = ( ItemFolder * ) aio;
3650 tn = gtk_ctree_find_by_row_data_custom(
3651 ctree, NULL, folder,
3652 addressbook_treenode_find_folder_cb );
3654 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3657 group = ( ItemGroup * ) aio;
3658 tn = gtk_ctree_find_by_row_data_custom(
3660 addressbook_treenode_find_group_cb );
3664 /* Free up adapter and remove node. */
3665 gtk_ctree_remove_node( ctree, tn );
3672 * Find parent datasource for specified tree node.
3673 * \param node Node to test.
3674 * \return Data source, or NULL if not found.
3676 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3677 AddressDataSource *ds = NULL;
3680 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3683 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3684 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3686 /* g_print( "ao->type = %d\n", ao->type ); */
3687 if( ao->type == ADDR_DATASOURCE ) {
3688 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3689 /* g_print( "found it\n" ); */
3690 ds = ads->dataSource;
3694 node = GTK_CTREE_ROW(node)->parent;
3700 * Load address list widget with children of specified object.
3701 * \param obj Parent object to be loaded.
3703 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3704 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3705 GtkCList *clist = GTK_CLIST(addrbook.clist);
3706 AddressDataSource *ds = NULL;
3707 AdapterDSource *ads = NULL;
3708 static AddressObject *last_obj = NULL;
3710 if (addrbook.clist == NULL) {
3713 if (obj == last_obj && !refresh)
3718 gtk_clist_clear(clist);
3722 if( obj->type == ADDR_INTERFACE ) {
3723 /* g_print( "set_clist: loading datasource...\n" ); */
3724 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3728 gtk_clist_freeze(clist);
3729 gtk_clist_clear(clist);
3731 if( obj->type == ADDR_DATASOURCE ) {
3732 ads = ADAPTER_DSOURCE(obj);
3733 ds = ADAPTER_DSOURCE(obj)->dataSource;
3735 /* Load root folder */
3736 ItemFolder *rootFolder = NULL;
3737 rootFolder = addrindex_ds_get_root_folder( ds );
3738 addressbook_folder_load_person(
3739 ctreelist, addrindex_ds_get_root_folder( ds ) );
3740 addressbook_folder_load_group(
3741 ctreelist, addrindex_ds_get_root_folder( ds ) );
3745 if( obj->type == ADDR_ITEM_GROUP ) {
3747 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3748 addressbook_load_group( ctreelist, itemGroup );
3750 else if( obj->type == ADDR_ITEM_FOLDER ) {
3752 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3753 addressbook_folder_load_person( ctreelist, itemFolder );
3754 addressbook_folder_load_group( ctreelist, itemFolder );
3757 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3758 clist->focus_row = -1;
3759 gtk_clist_thaw(clist);
3763 * Call back function to free adaptor. Call back is setup by function
3764 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3765 * called when the address book tree widget node is removed by calling
3766 * function gtk_ctree_remove_node().
3768 * \param data Tree node's row data.
3770 static void addressbook_free_treenode( gpointer data ) {
3773 ao = ( AddressObject * ) data;
3774 if( ao == NULL ) return;
3775 if( ao->type == ADDR_INTERFACE ) {
3776 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3777 addrbookctl_free_interface( ai );
3779 else if( ao->type == ADDR_DATASOURCE ) {
3780 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3781 addrbookctl_free_datasource( ads );
3783 else if( ao->type == ADDR_ITEM_FOLDER ) {
3784 AdapterFolder *af = ADAPTER_FOLDER(ao);
3785 addrbookctl_free_folder( af );
3787 else if( ao->type == ADDR_ITEM_GROUP ) {
3788 AdapterGroup *ag = ADAPTER_GROUP(ao);
3789 addrbookctl_free_group( ag );
3794 * Create new adaptor for specified data source.
3796 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3797 AddressObjectType otype, gchar *name )
3799 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3800 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3801 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3802 adapter->dataSource = ds;
3803 adapter->subType = otype;
3807 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3808 ADDRESS_OBJECT_NAME(adapter) =
3809 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3813 * Load tree from address index with the initial data.
3815 static void addressbook_load_tree( void ) {
3816 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3817 GList *nodeIf, *nodeDS;
3818 AdapterInterface *adapter;
3819 AddressInterface *iface;
3820 AddressTypeControlItem *atci;
3821 AddressDataSource *ds;
3822 AdapterDSource *ads;
3823 GtkCTreeNode *node, *newNode;
3826 nodeIf = _addressInterfaceList_;
3828 adapter = nodeIf->data;
3829 node = adapter->treeNode;
3830 iface = adapter->interface;
3831 atci = adapter->atci;
3833 if( iface->useInterface ) {
3834 /* Load data sources below interface node */
3835 nodeDS = iface->listSource;
3839 name = addrindex_ds_get_name( ds );
3840 ads = addressbook_create_ds_adapter(
3841 ds, atci->objectType, name );
3842 newNode = addressbook_add_object(
3843 node, ADDRESS_OBJECT(ads) );
3844 nodeDS = g_list_next( nodeDS );
3846 gtk_ctree_expand( ctree, node );
3849 nodeIf = g_list_next( nodeIf );
3854 * Convert the old address book to new format.
3856 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3857 gboolean retVal = FALSE;
3858 gboolean errFlag = TRUE;
3861 /* Read old address book, performing conversion */
3862 debug_print( "Reading and converting old address book...\n" );
3863 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3864 addrindex_read_data( addrIndex );
3865 if( addrIndex->retVal == MGU_NO_FILE ) {
3866 /* We do not have a file - new user */
3867 debug_print( "New user... create new books...\n" );
3868 addrindex_create_new_books( addrIndex );
3869 if( addrIndex->retVal == MGU_SUCCESS ) {
3870 /* Save index file */
3871 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3872 addrindex_save_data( addrIndex );
3873 if( addrIndex->retVal == MGU_SUCCESS ) {
3878 msg = _( "New user, could not save index file." );
3882 msg = _( "New user, could not save address book files." );
3886 /* We have an old file */
3887 if( addrIndex->wasConverted ) {
3888 /* Converted successfully - save address index */
3889 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3890 addrindex_save_data( addrIndex );
3891 if( addrIndex->retVal == MGU_SUCCESS ) {
3892 msg = _( "Old address book converted successfully." );
3897 msg = _("Old address book converted,\n"
3898 "could not save new address index file." );
3902 /* File conversion failed - just create new books */
3903 debug_print( "File conversion failed... just create new books...\n" );
3904 addrindex_create_new_books( addrIndex );
3905 if( addrIndex->retVal == MGU_SUCCESS ) {
3907 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3908 addrindex_save_data( addrIndex );
3909 if( addrIndex->retVal == MGU_SUCCESS ) {
3910 msg = _("Could not convert address book,\n"
3911 "but created empty new address book files." );
3916 msg = _("Could not convert address book,\n"
3917 "could not save new address index file." );
3921 msg = _("Could not convert address book\n"
3922 "and could not create new address book files." );
3927 debug_print( "Error\n%s\n", msg );
3928 alertpanel_full(_("Addressbook conversion error"), msg,
3929 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3930 NULL, ALERT_ERROR, G_ALERTDEFAULT);
3933 debug_print( "Warning\n%s\n", msg );
3934 alertpanel_full(_("Addressbook conversion error"), msg,
3935 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
3936 NULL, ALERT_WARNING, G_ALERTDEFAULT);
3942 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
3946 gboolean failed = FALSE;
3948 if( ( dp = opendir( origdir ) ) == NULL ) {
3952 while( ( d = readdir( dp ) ) != NULL ) {
3953 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
3956 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
3958 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
3960 if (copy_file(orig_file, dest_file, FALSE) < 0) {
3973 /* all copies succeeded, we can remove source files */
3974 if( ( dp = opendir( origdir ) ) == NULL ) {
3977 while( ( d = readdir( dp ) ) != NULL ) {
3978 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
3981 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
3983 g_unlink(orig_file);
3993 void addressbook_read_file( void ) {
3994 AddressIndex *addrIndex = NULL;
3995 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
3997 debug_print( "Reading address index...\n" );
3998 if( _addressIndex_ ) {
3999 debug_print( "address book already read!!!\n" );
4003 addrIndex = addrindex_create_index();
4004 addrindex_initialize();
4006 /* Use new address book index. */
4008 if ( !is_dir_exist(indexdir) ) {
4009 if ( make_dir(indexdir) < 0 ) {
4010 addrindex_set_file_path( addrIndex, get_rc_dir() );
4011 g_warning( "couldn't create dir %s\n", indexdir);
4013 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4014 remove_dir_recursive(indexdir);
4015 addrindex_set_file_path( addrIndex, get_rc_dir() );
4016 g_error("couldn't migrate dir %s", indexdir);
4018 addrindex_set_file_path( addrIndex, indexdir);
4022 addrindex_set_file_path( addrIndex, indexdir);
4025 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4026 addrindex_read_data( addrIndex );
4027 if( addrIndex->retVal == MGU_NO_FILE ) {
4028 /* Conversion required */
4029 debug_print( "Converting...\n" );
4030 if( addressbook_convert( addrIndex ) ) {
4031 _addressIndex_ = addrIndex;
4034 else if( addrIndex->retVal == MGU_SUCCESS ) {
4035 _addressIndex_ = addrIndex;
4038 /* Error reading address book */
4039 debug_print( "Could not read address index.\n" );
4040 addrindex_print_index( addrIndex, stdout );
4041 alertpanel_full(_("Addressbook Error"),
4042 _("Could not read address index"),
4043 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4044 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4046 debug_print( "done.\n" );
4050 * Add object into the address index tree widget.
4051 * Enter: node Parent node.
4052 * obj Object to add.
4053 * Return: Node that was added, or NULL if object not added.
4055 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
4058 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4059 GtkCTreeNode *added;
4060 AddressObject *pobj;
4061 AddressObjectType otype;
4062 AddressTypeControlItem *atci = NULL;
4064 g_return_val_if_fail(node != NULL, NULL);
4065 g_return_val_if_fail(obj != NULL, NULL);
4067 pobj = gtk_ctree_node_get_row_data(ctree, node);
4068 g_return_val_if_fail(pobj != NULL, NULL);
4070 /* Determine object type to be displayed */
4071 if( obj->type == ADDR_DATASOURCE ) {
4072 otype = ADAPTER_DSOURCE(obj)->subType;
4078 /* Handle any special conditions. */
4080 atci = addrbookctl_lookup( otype );
4082 if( atci->showInTree ) {
4083 /* Add object to tree */
4086 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4087 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
4088 atci->treeLeaf, atci->treeExpand );
4089 gtk_ctree_node_set_row_data_full( ctree, added, obj,
4090 addressbook_free_treenode );
4094 gtk_sctree_sort_node(ctree, node);
4100 * Add group into the address index tree.
4101 * \param node Parent node.
4102 * \param ds Data source.
4103 * \param itemGroup Group to add.
4104 * \return Inserted node.
4106 static GtkCTreeNode *addressbook_node_add_group(
4107 GtkCTreeNode *node, AddressDataSource *ds,
4108 ItemGroup *itemGroup )
4110 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4111 GtkCTreeNode *newNode;
4112 AdapterGroup *adapter;
4113 AddressTypeControlItem *atci = NULL;
4116 if( ds == NULL ) return NULL;
4117 if( node == NULL || itemGroup == NULL ) return NULL;
4119 name = &itemGroup->obj.name;
4121 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4123 adapter = g_new0( AdapterGroup, 1 );
4124 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4125 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4126 adapter->itemGroup = itemGroup;
4128 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4129 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4130 atci->treeLeaf, atci->treeExpand );
4131 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4132 addressbook_free_treenode );
4133 gtk_sctree_sort_node( ctree, node );
4138 * Add folder into the address index tree. Only visible folders are loaded into
4139 * the address index tree. Note that the root folder is not inserted into the
4142 * \param node Parent node.
4143 * \param ds Data source.
4144 * \param itemFolder Folder to add.
4145 * \param otype Object type to display.
4146 * \return Inserted node for the folder.
4148 static GtkCTreeNode *addressbook_node_add_folder(
4149 GtkCTreeNode *node, AddressDataSource *ds,
4150 ItemFolder *itemFolder, AddressObjectType otype )
4152 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4153 GtkCTreeNode *newNode = NULL;
4154 AdapterFolder *adapter;
4155 AddressTypeControlItem *atci = NULL;
4156 GList *listItems = NULL;
4158 ItemFolder *rootFolder;
4160 /* Only visible folders */
4161 if( itemFolder->isHidden ) return NULL;
4163 if( ds == NULL ) return NULL;
4164 if( node == NULL || itemFolder == NULL ) return NULL;
4166 /* Determine object type */
4167 atci = addrbookctl_lookup( otype );
4168 if( atci == NULL ) return NULL;
4170 rootFolder = addrindex_ds_get_root_folder( ds );
4171 if( itemFolder == rootFolder ) {
4175 adapter = g_new0( AdapterFolder, 1 );
4176 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4177 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4178 adapter->itemFolder = itemFolder;
4180 name = ADDRITEM_NAME(itemFolder);
4181 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4182 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4183 atci->treeLeaf, atci->treeExpand );
4185 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4186 addressbook_free_treenode );
4190 listItems = itemFolder->listFolder;
4191 while( listItems ) {
4192 ItemFolder *item = listItems->data;
4193 addressbook_node_add_folder( newNode, ds, item, otype );
4194 listItems = g_list_next( listItems );
4196 listItems = itemFolder->listGroup;
4197 while( listItems ) {
4198 ItemGroup *item = listItems->data;
4199 addressbook_node_add_group( newNode, ds, item );
4200 listItems = g_list_next( listItems );
4202 gtk_sctree_sort_node( ctree, node );
4206 void addressbook_export_to_file( void ) {
4207 if( _addressIndex_ ) {
4208 /* Save all new address book data */
4209 debug_print( "Saving address books...\n" );
4210 addrindex_save_all_books( _addressIndex_ );
4212 debug_print( "Exporting addressbook to file...\n" );
4213 addrindex_save_data( _addressIndex_ );
4214 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4215 addrindex_print_index( _addressIndex_, stdout );
4218 /* Notify address completion of new data */
4219 invalidate_address_completion();
4223 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4225 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4226 addressbook_lup_clicked(NULL, NULL);
4231 * Comparison using cell contents (text in first column). Used for sort
4232 * address index widget.
4234 static gint addressbook_treenode_compare_func(
4235 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4237 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
4238 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
4239 gchar *name1 = NULL, *name2 = NULL;
4240 if( cell1 ) name1 = cell1->u.text;
4241 if( cell2 ) name2 = cell2->u.text;
4242 if( ! name1 ) return ( name2 != NULL );
4243 if( ! name2 ) return -1;
4244 return g_utf8_collate( name1, name2 );
4247 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
4248 AdapterDSource *ads;
4249 AdapterInterface *adapter;
4250 GtkCTreeNode *newNode;
4252 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4253 if( adapter == NULL ) return;
4254 ads = addressbook_edit_book( _addressIndex_, NULL );
4256 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4258 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4259 addrbook.treeSelected = newNode;
4264 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
4265 AdapterDSource *ads;
4266 AdapterInterface *adapter;
4267 GtkCTreeNode *newNode;
4269 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4270 if( adapter == NULL ) return;
4271 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4273 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4275 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4276 addrbook.treeSelected = newNode;
4282 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
4283 AdapterDSource *ads;
4284 AdapterInterface *adapter;
4285 AddressInterface *iface;
4286 GtkCTreeNode *newNode;
4288 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4289 if( adapter == NULL ) return;
4290 iface = adapter->interface;
4291 if( ! iface->haveLibrary ) return;
4292 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4294 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4296 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4297 addrbook.treeSelected = newNode;
4304 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
4305 AdapterDSource *ads;
4306 AdapterInterface *adapter;
4307 AddressInterface *iface;
4308 GtkCTreeNode *newNode;
4310 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4311 if( adapter == NULL ) return;
4312 iface = adapter->interface;
4313 if( ! iface->haveLibrary ) return;
4314 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4316 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4318 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4319 addrbook.treeSelected = newNode;
4326 * Display address search status message.
4327 * \param queryType Query type.
4328 * \param status Status/Error code.
4330 static void addressbook_search_message( gint queryType, gint sts ) {
4332 *addressbook_msgbuf = '\0';
4334 if( sts != MGU_SUCCESS ) {
4335 if( queryType == ADDRQUERY_LDAP ) {
4337 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4342 g_snprintf( addressbook_msgbuf,
4343 sizeof(addressbook_msgbuf), "%s", desc );
4344 addressbook_status_show( addressbook_msgbuf );
4347 addressbook_status_show( "" );
4352 * Refresh addressbook by forcing refresh of current selected object in
4355 static void addressbook_refresh_current( void ) {
4359 ctree = GTK_CTREE(addrbook.ctree);
4360 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4361 if( obj == NULL ) return;
4362 addressbook_set_clist( obj, TRUE );
4366 * Message that is displayed whilst a query is executing in a background
4369 static gchar *_tempMessage_ = N_( "Busy searching..." );
4372 * Address search idle function. This function is called during UI idle time
4373 * while a search is in progress.
4375 * \param data Idler data.
4377 static void addressbook_search_idle( gpointer data ) {
4381 queryID = GPOINTER_TO_INT( data );
4382 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4387 * Search completion callback function. This removes the query from the idle
4390 * \param sender Sender of query.
4391 * \param queryID Query ID of search request.
4392 * \param status Search status.
4393 * \param data Query data.
4395 static void addressbook_search_callback_end(
4396 gpointer sender, gint queryID, gint status, gpointer data )
4400 AddrQueryObject *aqo;
4402 /* Remove idler function */
4403 ptrQID = GINT_TO_POINTER( queryID );
4405 g_idle_remove_by_data( ptrQID );
4408 /* Refresh addressbook contents */
4409 addressbook_refresh_current();
4410 req = qrymgr_find_request( queryID );
4412 aqo = ( AddrQueryObject * ) req->queryList->data;
4413 addressbook_search_message( aqo->queryType, status );
4416 /* Stop the search */
4417 addrindex_stop_search( queryID );
4423 * \param ds Data source to search.
4424 * \param searchTerm String to lookup.
4425 * \param pNode Parent data source node.
4427 static void addressbook_perform_search(
4428 AddressDataSource *ds, gchar *searchTerm,
4429 GtkCTreeNode *pNode )
4431 AddrBookBase *adbase;
4432 AddressCache *cache;
4438 AddressObjectType aoType = ADDR_NONE;
4442 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4444 if( ds && ds->type == ADDR_IF_LDAP ) {
4446 aoType = ADDR_LDAP_QUERY;
4452 /* Get reference to address cache */
4453 adbase = ( AddrBookBase * ) ds->rawDataSource;
4454 cache = adbase->addressCache;
4456 /* Create a folder for the search results */
4457 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4458 folder = addressbook_setup_subf(ds, name, pNode);
4461 /* Setup the search */
4462 queryID = addrindex_setup_explicit_search(
4463 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4464 if( queryID == 0 ) return;
4466 /* Set up idler function */
4467 idleID = g_idle_add(
4468 ( GtkFunction ) addressbook_search_idle,
4469 GINT_TO_POINTER( queryID ) );
4471 /* Start search, sit back and wait for something to happen */
4472 addrindex_start_search( queryID );
4474 addressbook_status_show( _tempMessage_ );
4478 * Lookup button handler. Address search is only performed against
4479 * address interfaces for external queries.
4481 * \param button Lookup button widget.
4482 * \param data Data object.
4484 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4487 AddressDataSource *ds;
4488 AddressInterface *iface;
4490 GtkCTreeNode *node, *parentNode;
4492 node = addrbook.treeSelected;
4493 if( ! node ) return;
4494 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4496 ctree = GTK_CTREE(addrbook.ctree);
4497 obj = gtk_ctree_node_get_row_data( ctree, node );
4498 if( obj == NULL ) return;
4500 ds = addressbook_find_datasource( node );
4501 if( ds == NULL ) return;
4503 /* We must have a datasource that is an external interface */
4504 iface = ds->interface;
4505 if( ! iface->haveLibrary ) return;
4506 if( ! iface->externalQuery ) return;
4509 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4510 g_strchomp( searchTerm );
4512 if( obj->type == ADDR_ITEM_FOLDER ) {
4513 parentNode = GTK_CTREE_ROW(node)->parent;
4518 addressbook_perform_search( ds, searchTerm, parentNode );
4520 gtk_widget_grab_focus( addrbook.entry );
4522 g_free( searchTerm );
4525 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4526 addressbook_close();
4531 * Browse address entry for highlighted entry.
4533 static void addressbook_browse_entry_cb(void)
4535 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4537 AddressDataSource *ds;
4538 AddressInterface *iface;
4542 if(addrbook.listSelected == NULL)
4545 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4549 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4553 iface = ds->interface;
4554 if(! iface->haveLibrary )
4558 if (obj->type == ADDR_ITEM_EMAIL) {
4559 email = ( ItemEMail * ) obj;
4563 person = (ItemPerson *) ADDRITEM_PARENT(email);
4565 else if (obj->type == ADDR_ITEM_PERSON) {
4566 person = (ItemPerson *) obj;
4573 if( iface && iface->type == ADDR_IF_LDAP ) {
4574 browseldap_entry(ds, person->externalID);
4579 /* **********************************************************************
4580 * Build lookup tables.
4581 * ***********************************************************************
4585 * Remap object types.
4586 * Enter: abType AddressObjectType (used in tree node).
4587 * Return: ItemObjectType (used in address cache data).
4589 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4590 ItemObjectType ioType;
4593 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4594 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4595 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4596 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4597 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4598 default: ioType = ITEMTYPE_NONE; break;
4604 * Build table that controls the rendering of object types.
4606 static void addrbookctl_build_map( GtkWidget *window ) {
4607 AddressTypeControlItem *atci;
4610 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4611 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4612 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4613 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4614 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4615 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4616 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4617 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4618 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4619 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4621 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4622 _addressBookTypeList_ = NULL;
4625 atci = g_new0( AddressTypeControlItem, 1 );
4626 atci->objectType = ADDR_INTERFACE;
4627 atci->interfaceType = ADDR_IF_NONE;
4628 atci->showInTree = TRUE;
4629 atci->treeExpand = TRUE;
4630 atci->treeLeaf = FALSE;
4631 atci->displayName = _( "Interface" );
4632 atci->iconXpm = folderxpm;
4633 atci->maskXpm = folderxpmmask;
4634 atci->iconXpmOpen = folderopenxpm;
4635 atci->maskXpmOpen = folderopenxpmmask;
4636 atci->menuCommand = NULL;
4637 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4638 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4641 atci = g_new0( AddressTypeControlItem, 1 );
4642 atci->objectType = ADDR_BOOK;
4643 atci->interfaceType = ADDR_IF_BOOK;
4644 atci->showInTree = TRUE;
4645 atci->treeExpand = TRUE;
4646 atci->treeLeaf = FALSE;
4647 atci->displayName = _( "Address Book" );
4648 atci->iconXpm = bookxpm;
4649 atci->maskXpm = bookxpmmask;
4650 atci->iconXpmOpen = bookxpm;
4651 atci->maskXpmOpen = bookxpmmask;
4652 atci->menuCommand = "/Book/New Book";
4653 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4654 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4657 atci = g_new0( AddressTypeControlItem, 1 );
4658 atci->objectType = ADDR_ITEM_PERSON;
4659 atci->interfaceType = ADDR_IF_NONE;
4660 atci->showInTree = FALSE;
4661 atci->treeExpand = FALSE;
4662 atci->treeLeaf = FALSE;
4663 atci->displayName = _( "Person" );
4664 atci->iconXpm = NULL;
4665 atci->maskXpm = NULL;
4666 atci->iconXpmOpen = NULL;
4667 atci->maskXpmOpen = NULL;
4668 atci->menuCommand = NULL;
4669 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4670 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4673 atci = g_new0( AddressTypeControlItem, 1 );
4674 atci->objectType = ADDR_ITEM_EMAIL;
4675 atci->interfaceType = ADDR_IF_NONE;
4676 atci->showInTree = FALSE;
4677 atci->treeExpand = FALSE;
4678 atci->treeLeaf = TRUE;
4679 atci->displayName = _( "Email Address" );
4680 atci->iconXpm = addressxpm;
4681 atci->maskXpm = addressxpmmask;
4682 atci->iconXpmOpen = addressxpm;
4683 atci->maskXpmOpen = addressxpmmask;
4684 atci->menuCommand = NULL;
4685 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4686 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4689 atci = g_new0( AddressTypeControlItem, 1 );
4690 atci->objectType = ADDR_ITEM_GROUP;
4691 atci->interfaceType = ADDR_IF_BOOK;
4692 atci->showInTree = TRUE;
4693 atci->treeExpand = FALSE;
4694 atci->treeLeaf = FALSE;
4695 atci->displayName = _( "Group" );
4696 atci->iconXpm = groupxpm;
4697 atci->maskXpm = groupxpmmask;
4698 atci->iconXpmOpen = groupxpm;
4699 atci->maskXpmOpen = groupxpmmask;
4700 atci->menuCommand = NULL;
4701 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4702 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4705 atci = g_new0( AddressTypeControlItem, 1 );
4706 atci->objectType = ADDR_ITEM_FOLDER;
4707 atci->interfaceType = ADDR_IF_BOOK;
4708 atci->showInTree = TRUE;
4709 atci->treeExpand = FALSE;
4710 atci->treeLeaf = FALSE;
4711 atci->displayName = _( "Folder" );
4712 atci->iconXpm = folderxpm;
4713 atci->maskXpm = folderxpmmask;
4714 atci->iconXpmOpen = folderopenxpm;
4715 atci->maskXpmOpen = folderopenxpmmask;
4716 atci->menuCommand = NULL;
4717 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4718 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4721 atci = g_new0( AddressTypeControlItem, 1 );
4722 atci->objectType = ADDR_VCARD;
4723 atci->interfaceType = ADDR_IF_VCARD;
4724 atci->showInTree = TRUE;
4725 atci->treeExpand = TRUE;
4726 atci->treeLeaf = TRUE;
4727 atci->displayName = _( "vCard" );
4728 atci->iconXpm = vcardxpm;
4729 atci->maskXpm = vcardxpmmask;
4730 atci->iconXpmOpen = vcardxpm;
4731 atci->maskXpmOpen = vcardxpmmask;
4732 atci->menuCommand = "/Book/New vCard";
4733 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4734 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4737 atci = g_new0( AddressTypeControlItem, 1 );
4738 atci->objectType = ADDR_JPILOT;
4739 atci->interfaceType = ADDR_IF_JPILOT;
4740 atci->showInTree = TRUE;
4741 atci->treeExpand = TRUE;
4742 atci->treeLeaf = FALSE;
4743 atci->displayName = _( "JPilot" );
4744 atci->iconXpm = jpilotxpm;
4745 atci->maskXpm = jpilotxpmmask;
4746 atci->iconXpmOpen = jpilotxpm;
4747 atci->maskXpmOpen = jpilotxpmmask;
4748 atci->menuCommand = "/Book/New JPilot";
4749 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4750 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4753 atci = g_new0( AddressTypeControlItem, 1 );
4754 atci->objectType = ADDR_CATEGORY;
4755 atci->interfaceType = ADDR_IF_JPILOT;
4756 atci->showInTree = TRUE;
4757 atci->treeExpand = TRUE;
4758 atci->treeLeaf = TRUE;
4759 atci->displayName = _( "JPilot" );
4760 atci->iconXpm = categoryxpm;
4761 atci->maskXpm = categoryxpmmask;
4762 atci->iconXpmOpen = categoryxpm;
4763 atci->maskXpmOpen = categoryxpmmask;
4764 atci->menuCommand = NULL;
4765 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4766 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4769 atci = g_new0( AddressTypeControlItem, 1 );
4770 atci->objectType = ADDR_LDAP;
4771 atci->interfaceType = ADDR_IF_LDAP;
4772 atci->showInTree = TRUE;
4773 atci->treeExpand = TRUE;
4774 atci->treeLeaf = FALSE;
4775 atci->displayName = _( "LDAP servers" );
4776 atci->iconXpm = ldapxpm;
4777 atci->maskXpm = ldapxpmmask;
4778 atci->iconXpmOpen = ldapxpm;
4779 atci->maskXpmOpen = ldapxpmmask;
4780 atci->menuCommand = "/Book/New LDAP Server";
4781 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4782 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4785 atci = g_new0( AddressTypeControlItem, 1 );
4786 atci->objectType = ADDR_LDAP_QUERY;
4787 atci->interfaceType = ADDR_IF_LDAP;
4788 atci->showInTree = TRUE;
4789 atci->treeExpand = FALSE;
4790 atci->treeLeaf = TRUE;
4791 atci->displayName = _( "LDAP Query" );
4792 atci->iconXpm = addrsearchxpm;
4793 atci->maskXpm = addrsearchxpmmask;
4794 atci->iconXpmOpen = addrsearchxpm;
4795 atci->maskXpmOpen = addrsearchxpmmask;
4796 atci->menuCommand = NULL;
4797 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4798 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4803 * Search for specified object type.
4805 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4807 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4811 * Search for specified interface type.
4813 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4814 GList *node = _addressBookTypeList_;
4816 AddressTypeControlItem *atci = node->data;
4817 if( atci->interfaceType == ifType ) return atci;
4818 node = g_list_next( node );
4823 static void addrbookctl_free_address( AddressObject *obj ) {
4824 g_free( obj->name );
4825 obj->type = ADDR_NONE;
4829 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4830 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4831 adapter->interface = NULL;
4832 adapter->interfaceType = ADDR_IF_NONE;
4833 adapter->atci = NULL;
4834 adapter->enabled = FALSE;
4835 adapter->haveLibrary = FALSE;
4836 adapter->treeNode = NULL;
4840 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4841 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4842 adapter->dataSource = NULL;
4843 adapter->subType = ADDR_NONE;
4847 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4848 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4849 adapter->itemFolder = NULL;
4853 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4854 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4855 adapter->itemGroup = NULL;
4860 * Build GUI interface list.
4862 static void addrbookctl_build_iflist( void ) {
4863 AddressTypeControlItem *atci;
4864 AdapterInterface *adapter;
4867 if( _addressIndex_ == NULL ) {
4868 _addressIndex_ = addrindex_create_index();
4869 if( _clipBoard_ == NULL ) {
4870 _clipBoard_ = addrclip_create();
4872 addrclip_set_index( _clipBoard_, _addressIndex_ );
4874 _addressInterfaceList_ = NULL;
4875 list = addrindex_get_interface_list( _addressIndex_ );
4877 AddressInterface *interface = list->data;
4878 atci = addrbookctl_lookup_iface( interface->type );
4880 adapter = g_new0( AdapterInterface, 1 );
4881 adapter->interfaceType = interface->type;
4882 adapter->atci = atci;
4883 adapter->interface = interface;
4884 adapter->treeNode = NULL;
4885 adapter->enabled = TRUE;
4886 adapter->haveLibrary = interface->haveLibrary;
4887 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4888 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4889 _addressInterfaceList_ =
4890 g_list_append( _addressInterfaceList_, adapter );
4892 list = g_list_next( list );
4897 * Find GUI interface type specified interface type.
4898 * \param ifType Interface type.
4899 * \return Interface item, or NULL if not found.
4901 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4902 GList *node = _addressInterfaceList_;
4904 AdapterInterface *adapter = node->data;
4905 if( adapter->interfaceType == ifType ) return adapter;
4906 node = g_list_next( node );
4912 * Build interface list selection.
4914 static void addrbookctl_build_ifselect( void ) {
4915 GList *newList = NULL;
4920 gchar *endptr = NULL;
4922 AdapterInterface *adapter;
4924 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4927 splitStr = g_strsplit( selectStr, ",", -1 );
4928 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
4930 /* g_print( "%d : %s\n", i, splitStr[i] ); */
4931 ifType = strtol( splitStr[i], &endptr, 10 );
4934 if( strcmp( endptr, "/n" ) == 0 ) {
4938 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
4939 adapter = addrbookctl_find_interface( ifType );
4941 newList = g_list_append( newList, adapter );
4948 /* g_print( "i=%d\n", i ); */
4949 g_strfreev( splitStr );
4950 g_free( selectStr );
4952 /* Replace existing list */
4953 mgu_clear_list( _addressIFaceSelection_ );
4954 g_list_free( _addressIFaceSelection_ );
4955 _addressIFaceSelection_ = newList;
4959 /* ***********************************************************************
4960 * Add sender to address book.
4961 * ***********************************************************************
4965 * This function is used by the Add sender to address book function.
4967 gboolean addressbook_add_contact(
4968 const gchar *name, const gchar *address, const gchar *remarks,
4969 GdkPixbuf *picture )
4971 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
4972 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
4973 debug_print( "addressbook_add_contact - added\n" );
4974 addressbook_refresh();
4979 /* ***********************************************************************
4980 * Book/folder selection.
4981 * ***********************************************************************
4985 * This function is used by the matcher dialog to select a book/folder.
4987 gchar *addressbook_folder_selection( const gchar *folderpath)
4989 AddressBookFile *book = NULL;
4990 ItemFolder *folder = NULL;
4993 g_return_val_if_fail( folderpath != NULL, NULL);
4995 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
4997 if ( folder != NULL) {
4999 gchar *oldtmp = NULL;
5000 AddrItemObject *obj = NULL;
5002 /* walk thru folder->parent to build the full folder path */
5003 /* TODO: wwp: optimize this */
5005 tmp = g_strdup(obj->uid);
5006 while ( obj->parent ) {
5008 if ( obj->name != NULL ) {
5009 oldtmp = g_strdup(tmp);
5011 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5015 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5018 path = g_strdup_printf("%s", book->fileName);
5020 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5026 /* ***********************************************************************
5027 * Book/folder checking.
5028 * ***********************************************************************
5031 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5033 FolderInfo *fi = g_new0( FolderInfo, 1 );
5035 fi->folder = folder;
5039 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5040 FolderInfo *fiParent, FolderPathMatch *match )
5046 FolderPathMatch *nextmatch = NULL;
5051 list = parentFolder->listFolder;
5053 folder = list->data;
5054 fName = g_strdup( ADDRITEM_NAME(folder) );
5056 /* match folder name, match pointer will be set to NULL if next recursive call
5057 doesn't need to match subfolder name */
5058 if ( match != NULL &&
5059 match->matched == FALSE ) {
5060 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5061 /* folder name matches, prepare next subfolder match */
5062 debug_print("matched folder name '%s'\n", fName);
5064 if ( match->folder_path[match->index] == NULL ) {
5065 /* we've matched all elements */
5066 match->matched = TRUE;
5067 match->folder = folder;
5068 debug_print("book/folder path matched!\n");
5070 /* keep on matching */
5078 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5079 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5081 list = g_list_next( list );
5086 * This function is used by to check if a matcher book/folder path corresponds to an
5087 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5088 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5089 if book AND folder are NULL this means that folderpath was empty or Any.
5090 If folderpath is a simple book name (without folder), book will not be NULL and folder
5091 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5094 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5095 AddressDataSource **book,
5096 ItemFolder **folder )
5098 AddressDataSource *ds;
5099 GList *list, *nodeDS;
5100 ItemFolder *rootFolder;
5101 AddressBookFile *abf;
5103 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5110 if ( folderpath == NULL )
5113 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
5116 /* split the folder path we've received, we'll try to match this path, subpath by
5117 subpath against the book/folder structure in order */
5118 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5119 if (!folder_path_match.folder_path)
5122 list = addrindex_get_interface_list( _addressIndex_ );
5123 while ( list && !folder_path_match.matched ) {
5124 AddressInterface *interface = list->data;
5125 if ( interface && interface->type == ADDR_IF_BOOK ) {
5126 nodeDS = interface->listSource;
5127 while ( nodeDS && !folder_path_match.matched ) {
5130 /* Read address book */
5131 if( ! addrindex_ds_get_read_flag( ds ) ) {
5132 addrindex_ds_read_data( ds );
5135 /* Add node for address book */
5136 abf = ds->rawDataSource;
5138 /* match book name */
5139 if ( abf && abf->fileName &&
5140 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5142 debug_print("matched book name '%s'\n", abf->fileName);
5143 folder_path_match.book = ds;
5145 if ( folder_path_match.folder_path[1] == NULL ) {
5146 /* no folder part to match */
5148 folder_path_match.matched = TRUE;
5149 folder_path_match.folder = NULL;
5150 debug_print("book path matched!\n");
5153 /* match folder part */
5155 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5156 rootFolder = addrindex_ds_get_root_folder( ds );
5158 /* prepare for recursive call */
5159 folder_path_match.index = 1;
5160 /* this call will set folder_path_match.matched and folder_path_match.folder */
5161 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5166 nodeDS = g_list_next( nodeDS );
5169 list = g_list_next( list );
5172 g_strfreev( folder_path_match.folder_path );
5175 *book = folder_path_match.book;
5177 *folder = folder_path_match.folder;
5178 return folder_path_match.matched;
5182 /* **********************************************************************
5184 * ***********************************************************************
5190 static void addressbook_import_ldif_cb( void ) {
5191 AddressDataSource *ds = NULL;
5192 AdapterDSource *ads = NULL;
5193 AddressBookFile *abf = NULL;
5194 AdapterInterface *adapter;
5195 GtkCTreeNode *newNode;
5197 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5199 if( adapter->treeNode ) {
5200 abf = addressbook_imp_ldif( _addressIndex_ );
5202 ds = addrindex_index_add_datasource(
5203 _addressIndex_, ADDR_IF_BOOK, abf );
5204 ads = addressbook_create_ds_adapter(
5205 ds, ADDR_BOOK, NULL );
5206 addressbook_ads_set_name(
5207 ads, addrbook_get_name( abf ) );
5208 newNode = addressbook_add_object(
5210 ADDRESS_OBJECT(ads) );
5212 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5214 addrbook.treeSelected = newNode;
5217 /* Notify address completion */
5218 invalidate_address_completion();
5227 static void addressbook_import_mutt_cb( void ) {
5228 AddressDataSource *ds = NULL;
5229 AdapterDSource *ads = NULL;
5230 AddressBookFile *abf = NULL;
5231 AdapterInterface *adapter;
5232 GtkCTreeNode *newNode;
5234 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5236 if( adapter->treeNode ) {
5237 abf = addressbook_imp_mutt( _addressIndex_ );
5239 ds = addrindex_index_add_datasource(
5240 _addressIndex_, ADDR_IF_BOOK, abf );
5241 ads = addressbook_create_ds_adapter(
5242 ds, ADDR_BOOK, NULL );
5243 addressbook_ads_set_name(
5244 ads, addrbook_get_name( abf ) );
5245 newNode = addressbook_add_object(
5247 ADDRESS_OBJECT(ads) );
5249 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5251 addrbook.treeSelected = newNode;
5254 /* Notify address completion */
5255 invalidate_address_completion();
5264 static void addressbook_import_pine_cb( void ) {
5265 AddressDataSource *ds = NULL;
5266 AdapterDSource *ads = NULL;
5267 AddressBookFile *abf = NULL;
5268 AdapterInterface *adapter;
5269 GtkCTreeNode *newNode;
5271 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5273 if( adapter->treeNode ) {
5274 abf = addressbook_imp_pine( _addressIndex_ );
5276 ds = addrindex_index_add_datasource(
5277 _addressIndex_, ADDR_IF_BOOK, abf );
5278 ads = addressbook_create_ds_adapter(
5279 ds, ADDR_BOOK, NULL );
5280 addressbook_ads_set_name(
5281 ads, addrbook_get_name( abf ) );
5282 newNode = addressbook_add_object(
5284 ADDRESS_OBJECT(ads) );
5286 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5288 addrbook.treeSelected = newNode;
5291 /* Notify address completion */
5292 invalidate_address_completion();
5299 * Harvest addresses.
5300 * \param folderItem Folder to import.
5301 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5302 * \param msgList List of message numbers, or NULL to process folder.
5304 void addressbook_harvest(
5305 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5307 AddressDataSource *ds = NULL;
5308 AdapterDSource *ads = NULL;
5309 AddressBookFile *abf = NULL;
5310 AdapterInterface *adapter;
5311 GtkCTreeNode *newNode;
5313 abf = addrgather_dlg_execute(
5314 folderItem, _addressIndex_, sourceInd, msgList );
5316 ds = addrindex_index_add_datasource(
5317 _addressIndex_, ADDR_IF_BOOK, abf );
5319 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5321 if( adapter->treeNode ) {
5322 ads = addressbook_create_ds_adapter(
5323 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5324 newNode = addressbook_add_object(
5326 ADDRESS_OBJECT(ads) );
5330 /* Notify address completion */
5331 invalidate_address_completion();
5338 static void addressbook_export_html_cb( void ) {
5339 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5341 AddressDataSource *ds = NULL;
5342 AddrBookBase *adbase;
5343 AddressCache *cache;
5344 GtkCTreeNode *node = NULL;
5346 if( ! addrbook.treeSelected ) return;
5347 node = addrbook.treeSelected;
5348 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5349 obj = gtk_ctree_node_get_row_data( ctree, node );
5350 if( obj == NULL ) return;
5352 ds = addressbook_find_datasource( node );
5353 if( ds == NULL ) return;
5354 adbase = ( AddrBookBase * ) ds->rawDataSource;
5355 cache = adbase->addressCache;
5356 addressbook_exp_html( cache );
5362 static void addressbook_export_ldif_cb( void ) {
5363 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5365 AddressDataSource *ds = NULL;
5366 AddrBookBase *adbase;
5367 AddressCache *cache;
5368 GtkCTreeNode *node = NULL;
5370 if( ! addrbook.treeSelected ) return;
5371 node = addrbook.treeSelected;
5372 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5373 obj = gtk_ctree_node_get_row_data( ctree, node );
5374 if( obj == NULL ) return;
5376 ds = addressbook_find_datasource( node );
5377 if( ds == NULL ) return;
5378 adbase = ( AddrBookBase * ) ds->rawDataSource;
5379 cache = adbase->addressCache;
5380 addressbook_exp_ldif( cache );
5383 static void addressbook_find_duplicates_cb(void)
5385 addrduplicates_find(GTK_WINDOW(addrbook.window));
5388 static void addressbook_edit_custom_attr_cb(void)
5390 addressbook_custom_attr_edit();
5393 static void addressbook_start_drag(GtkWidget *widget, gint button,
5397 GdkDragContext *context;
5398 if (addressbook_target_list == NULL)
5399 addressbook_target_list = gtk_target_list_new(
5400 addressbook_drag_types, 1);
5401 context = gtk_drag_begin(widget, addressbook_target_list,
5402 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5403 gtk_drag_set_icon_default(context);
5406 static void addressbook_drag_data_get(GtkWidget *widget,
5407 GdkDragContext *drag_context,
5408 GtkSelectionData *selection_data,
5413 AddrItemObject *aio = NULL;
5414 AddressObject *pobj = NULL;
5415 AdapterDSource *ads = NULL;
5416 AddressDataSource *ds = NULL;
5419 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5421 if( pobj == NULL ) return;
5423 if( pobj->type == ADDR_DATASOURCE ) {
5424 ads = ADAPTER_DSOURCE(pobj);
5425 ds = ads->dataSource;
5426 } else if (pobj->type == ADDR_ITEM_GROUP) {
5431 else if( pobj->type != ADDR_INTERFACE ) {
5432 ds = addressbook_find_datasource( addrbook.treeSelected );
5438 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5439 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5440 GTK_CTREE_NODE(cur->data));
5441 while (aio && aio->type != ADDR_ITEM_PERSON) {
5446 if (aio && aio->type == ADDR_ITEM_PERSON) {
5447 if( ds && ds->interface && ds->interface->readOnly)
5448 gtk_selection_data_set(selection_data,
5449 selection_data->target, 8,
5450 (const guchar *)"Dummy_addr_copy", 15);
5452 gtk_selection_data_set(selection_data,
5453 selection_data->target, 8,
5454 (const guchar *)"Dummy_addr_move", 15);
5458 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5459 GdkDragContext *context,
5466 GtkCTreeNode *node = NULL;
5467 gboolean acceptable = FALSE;
5468 gint height = addrbook.ctree->allocation.height;
5469 gint total_height = addrbook.ctree->requisition.height;
5470 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5471 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5472 gfloat vpos = pos->value;
5474 if (gtk_clist_get_selection_info
5475 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5477 if (y > height - 24 && height + vpos < total_height) {
5478 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5479 gtk_adjustment_changed(pos);
5481 if (y < 24 && y > 0) {
5482 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5483 gtk_adjustment_changed(pos);
5485 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5488 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5489 if( obj->type == ADDR_ITEM_FOLDER
5490 || obj->type == ADDR_ITEM_GROUP)
5493 AdapterDSource *ads = NULL;
5494 AddressDataSource *ds = NULL;
5495 ads = ADAPTER_DSOURCE(obj);
5496 if (ads == NULL ){ return FALSE;}
5497 ds = ads->dataSource;
5498 if (ds == NULL ) { return FALSE;}
5506 g_signal_handlers_block_by_func
5508 G_CALLBACK(addressbook_tree_selected), NULL);
5509 gtk_sctree_select( GTK_SCTREE(widget), node);
5510 g_signal_handlers_unblock_by_func
5512 G_CALLBACK(addressbook_tree_selected), NULL);
5513 gdk_drag_status(context,
5514 (context->actions == GDK_ACTION_COPY ?
5515 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5517 gdk_drag_status(context, 0, time);
5522 static void addressbook_drag_leave_cb(GtkWidget *widget,
5523 GdkDragContext *context,
5527 if (addrbook.treeSelected) {
5528 g_signal_handlers_block_by_func
5530 G_CALLBACK(addressbook_tree_selected), NULL);
5531 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5532 g_signal_handlers_unblock_by_func
5534 G_CALLBACK(addressbook_tree_selected), NULL);
5539 static void addressbook_drag_received_cb(GtkWidget *widget,
5540 GdkDragContext *drag_context,
5543 GtkSelectionData *data,
5550 GtkCTreeNode *lastopened = addrbook.opened;
5552 if (!strncmp(data->data, "Dummy_addr", 10)) {
5553 if (gtk_clist_get_selection_info
5554 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5558 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5559 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5562 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5563 if (drag_context->action == GDK_ACTION_COPY ||
5564 !strcmp(data->data, "Dummy_addr_copy"))
5565 addressbook_clip_copy_cb();
5567 addressbook_clip_cut_cb();
5568 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5569 addressbook_clip_paste_cb();
5570 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5571 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5572 gtk_drag_finish(drag_context, TRUE, TRUE, time);