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);
1351 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1353 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1357 * Delete one or more objects from address list.
1359 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1361 GtkCTree *clist = GTK_CTREE(addrbook.clist);
1362 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
1363 AddressObject *pobj;
1364 AdapterDSource *ads = NULL;
1365 GtkCTreeNode *nodeList;
1368 AddressBookFile *abf = NULL;
1369 AddressDataSource *ds = NULL;
1370 AddressInterface *iface;
1371 AddrItemObject *aio;
1372 AddrSelectItem *item;
1374 gboolean refreshList = FALSE;
1376 pobj = gtk_ctree_node_get_row_data(ctree, addrbook.opened );
1377 g_return_if_fail(pobj != NULL);
1379 /* Test whether anything selected for deletion */
1380 nodeList = addrbook.listSelected;
1382 aio = gtk_ctree_node_get_row_data( clist, nodeList );
1383 if( aio == NULL) return;
1384 ds = addressbook_find_datasource( addrbook.treeSelected );
1385 if( ds == NULL ) return;
1387 /* Test for read only */
1388 iface = ds->interface;
1389 if( iface->readOnly ) {
1390 alertpanel( _("Delete address(es)"),
1391 _("This address data is readonly and cannot be deleted."),
1392 GTK_STOCK_CLOSE, NULL, NULL );
1396 /* Test whether Ok to proceed */
1398 if( pobj->type == ADDR_DATASOURCE ) {
1399 ads = ADAPTER_DSOURCE(pobj);
1400 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1402 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1405 else if( pobj->type == ADDR_ITEM_GROUP ) {
1408 if( ! procFlag ) return;
1409 abf = ds->rawDataSource;
1410 if( abf == NULL ) return;
1412 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
1413 g_signal_handlers_block_by_func
1414 (G_OBJECT(addrbook.clist),
1415 G_CALLBACK(addressbook_list_row_unselected), NULL);
1417 /* Process deletions */
1418 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1419 GList *groups = NULL, *persons = NULL, *emails = NULL;
1420 gboolean group_delete = TRUE;
1421 /* Items inside folders */
1422 list = addrselect_get_list( _addressSelect_ );
1423 /* Confirm deletion */
1427 node = g_list_next( node );
1428 aio = ( AddrItemObject * ) item->addressItem;
1429 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1430 group_delete = FALSE;
1435 aval = alertpanel( _("Delete group"),
1436 _("Really delete the group(s)?\n"
1437 "The addresses it contains will not be lost."),
1438 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1439 if( aval != G_ALERTALTERNATE ) {
1443 aval = alertpanel( _("Delete address(es)"),
1444 _("Really delete the address(es)?"),
1445 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1446 if( aval != G_ALERTALTERNATE ) {
1451 /* first, set lists of groups and persons to remove */
1455 node = g_list_next( node );
1456 aio = ( AddrItemObject * ) item->addressItem;
1459 if( aio->type == ADDR_ITEM_GROUP ) {
1460 groups = g_list_prepend(groups, item);
1462 else if( aio->type == ADDR_ITEM_PERSON ) {
1463 persons = g_list_prepend(persons, item);
1466 /* then set list of emails to remove *if* they're not children of
1467 * persons to remove */
1471 node = g_list_next( node );
1472 aio = ( AddrItemObject * ) item->addressItem;
1475 if( aio->type == ADDR_ITEM_EMAIL ) {
1476 ItemEMail *sitem = ( ItemEMail * ) aio;
1477 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1478 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1479 emails = g_list_prepend(emails, item);
1481 /* else, the email will be removed via the parent person */
1484 /* then delete groups */
1488 node = g_list_next( node );
1489 aio = ( AddrItemObject * ) item->addressItem;
1492 if( aio->type == ADDR_ITEM_GROUP ) {
1493 ItemGroup *item = ( ItemGroup * ) aio;
1494 GtkCTreeNode *nd = NULL;
1495 nd = addressbook_find_group_node( addrbook.opened, item );
1496 item = addrbook_remove_group( abf, item );
1498 addritem_free_item_group( item );
1500 /* Remove group from parent node */
1501 gtk_ctree_remove_node( ctree, nd );
1505 /* then delete persons */
1509 node = g_list_next( node );
1510 aio = ( AddrItemObject * ) item->addressItem;
1513 if( aio->type == ADDR_ITEM_PERSON ) {
1514 ItemPerson *item = ( ItemPerson * ) aio;
1515 item->status = DELETE_ENTRY;
1516 addressbook_folder_remove_one_person( clist, item );
1517 if (pobj->type == ADDR_ITEM_FOLDER)
1518 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1519 item = addrbook_remove_person( abf, item );
1521 if (ds && ds->type == ADDR_IF_LDAP) {
1522 LdapServer *server = ds->rawDataSource;
1523 ldapsvr_set_modified(server, TRUE);
1524 ldapsvr_update_book(server, item);
1528 gchar *filename = addritem_person_get_picture(item);
1529 if (filename && is_file_exist(filename))
1530 claws_unlink(filename);
1532 addritem_free_item_person( item );
1536 /* then delete emails */
1540 node = g_list_next( node );
1541 aio = ( AddrItemObject * ) item->addressItem;
1545 if( aio->type == ADDR_ITEM_EMAIL ) {
1546 ItemEMail *sitem = ( ItemEMail * ) aio;
1547 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1548 sitem = addrbook_person_remove_email( abf, person, sitem );
1550 addrcache_remove_email(abf->addressCache, sitem);
1551 addritem_free_item_email( sitem );
1553 addressbook_folder_refresh_one_person( clist, person );
1556 g_list_free( groups );
1557 g_list_free( persons );
1558 g_list_free( emails );
1559 g_list_free( list );
1560 addressbook_list_select_clear();
1562 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1563 addressbook_set_clist(
1564 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1568 addrbook_set_dirty(abf, TRUE);
1569 addressbook_export_to_file();
1570 addressbook_list_menu_setup();
1573 else if( pobj->type == ADDR_ITEM_GROUP ) {
1574 /* Items inside groups */
1575 list = addrselect_get_list( _addressSelect_ );
1579 node = g_list_next( node );
1580 aio = ( AddrItemObject * ) item->addressItem;
1581 if( aio->type == ADDR_ITEM_EMAIL ) {
1582 ItemEMail *item = ( ItemEMail * ) aio;
1583 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1584 item = addrbook_person_remove_email( abf, person, item );
1586 addritem_free_item_email( item );
1590 g_list_free( list );
1591 addressbook_list_select_clear();
1592 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1593 addressbook_set_clist(
1594 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
1598 addrbook_set_dirty(abf, TRUE);
1599 addressbook_export_to_file();
1600 addressbook_list_menu_setup();
1604 gtk_ctree_node_set_row_data( clist, nodeList, NULL );
1605 gtk_ctree_remove_node( clist, nodeList );
1607 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
1608 g_signal_handlers_unblock_by_func
1609 (G_OBJECT(addrbook.clist),
1610 G_CALLBACK(addressbook_list_row_unselected), NULL);
1613 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1615 addressbook_new_address_cb( NULL, 0, NULL );
1618 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1621 gchar *address = NULL;
1623 if( aio->type == ADDR_ITEM_EMAIL ) {
1624 ItemPerson *person = NULL;
1625 ItemEMail *email = ( ItemEMail * ) aio;
1627 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1628 if( email->address ) {
1629 if( ADDRITEM_NAME(email) ) {
1630 name = ADDRITEM_NAME(email);
1631 if( *name == '\0' ) {
1632 name = ADDRITEM_NAME(person);
1635 else if( ADDRITEM_NAME(person) ) {
1636 name = ADDRITEM_NAME(person);
1639 buf = g_strdup( email->address );
1641 address = email->address;
1644 else if( aio->type == ADDR_ITEM_PERSON ) {
1645 ItemPerson *person = ( ItemPerson * ) aio;
1646 GList *node = person->listEMail;
1648 name = ADDRITEM_NAME(person);
1650 ItemEMail *email = ( ItemEMail * ) node->data;
1651 address = email->address;
1655 if( name && name[0] != '\0' ) {
1656 if( strchr_with_skip_quote( name, '"', ',' ) )
1657 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1659 buf = g_strdup_printf( "%s <%s>", name, address );
1662 buf = g_strdup( address );
1669 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1673 AddrSelectItem *item;
1674 AddrItemObject *aio;
1677 compose = addrbook.target_compose;
1678 if( ! compose ) return;
1680 /* Nothing selected, but maybe there is something in text entry */
1681 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1683 compose_entry_append(
1684 compose, addr, (ComposeEntryType)data );
1687 /* Select from address list */
1688 list = addrselect_get_list( _addressSelect_ );
1693 node = g_list_next( node );
1694 aio = item->addressItem;
1695 if( aio->type == ADDR_ITEM_PERSON ||
1696 aio->type == ADDR_ITEM_EMAIL ) {
1697 addr = addressbook_format_address( aio );
1698 compose_entry_append(
1699 compose, addr, (ComposeEntryType) data );
1702 else if( aio->type == ADDR_ITEM_GROUP ) {
1703 ItemGroup *group = ( ItemGroup * ) aio;
1704 GList *nodeMail = group->listEMail;
1706 ItemEMail *email = nodeMail->data;
1708 addr = addressbook_format_address(
1709 ( AddrItemObject * ) email );
1710 compose_entry_append(
1711 compose, addr, (ComposeEntryType) data );
1713 nodeMail = g_list_next( nodeMail );
1718 AddressObject *obj = NULL;
1720 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1722 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1723 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1724 GList *nodeMail = itemGroup->listEMail;
1726 ItemEMail *email = nodeMail->data;
1728 addr = addressbook_format_address(
1729 ( AddrItemObject * ) email );
1730 compose_entry_append(
1731 compose, addr, (ComposeEntryType) data );
1733 nodeMail = g_list_next( nodeMail );
1737 g_list_free( list );
1740 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1741 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", sensitive );
1742 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", sensitive );
1743 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", sensitive );
1745 menu_set_sensitive( addrbook.menu_factory, "/Address/Select all", TRUE );
1746 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", sensitive );
1747 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", sensitive );
1748 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", sensitive );
1750 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", sensitive );
1751 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", sensitive );
1752 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", sensitive );
1753 gtk_widget_set_sensitive( addrbook.reg_btn, sensitive );
1754 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1755 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1758 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCTreeNode *node ) {
1759 gboolean canEdit = FALSE;
1760 gboolean canDelete = TRUE;
1761 gboolean canAdd = FALSE;
1762 gboolean canEditTr = TRUE;
1763 gboolean editAddress = FALSE;
1764 gboolean canExport = TRUE;
1765 AddressTypeControlItem *atci = NULL;
1766 AddressDataSource *ds = NULL;
1767 AddressInterface *iface = NULL;
1769 if( obj == NULL ) return;
1770 if( obj->type == ADDR_INTERFACE ) {
1771 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1772 iface = adapter->interface;
1774 if( iface->haveLibrary ) {
1775 /* Enable appropriate File / New command */
1776 atci = adapter->atci;
1777 menu_set_sensitive( addrbook.menu_factory, atci->menuCommand, TRUE );
1780 canEditTr = canExport = FALSE;
1782 else if( obj->type == ADDR_DATASOURCE ) {
1783 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1784 ds = ads->dataSource;
1785 iface = ds->interface;
1786 if( ! iface->readOnly ) {
1787 canAdd = canEdit = editAddress = canDelete = TRUE;
1789 if( ! iface->haveLibrary ) {
1790 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1793 else if( obj->type == ADDR_ITEM_FOLDER ) {
1794 ds = addressbook_find_datasource( addrbook.treeSelected );
1796 iface = ds->interface;
1797 if( iface->readOnly ) {
1802 canAdd = editAddress = TRUE;
1806 else if( obj->type == ADDR_ITEM_GROUP ) {
1807 ds = addressbook_find_datasource( addrbook.treeSelected );
1809 iface = ds->interface;
1810 if( ! iface->readOnly ) {
1816 if( addrbook.listSelected == NULL )
1820 menu_set_sensitive( addrbook.menu_factory, "/Address/New Address", editAddress );
1821 menu_set_sensitive( addrbook.menu_factory, "/Address/New Group", canAdd );
1822 menu_set_sensitive( addrbook.menu_factory, "/Book/New Folder", canAdd );
1823 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1826 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
1827 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
1828 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1829 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1831 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEditTr );
1832 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEditTr );
1835 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export HTML...", canExport );
1836 menu_set_sensitive( addrbook.menu_factory, "/Tools/Export LDIF...", canExport );
1840 * Address book tree callback function that responds to selection of tree
1843 * \param ctree Tree widget.
1844 * \param node Node that was selected.
1845 * \param column Column number where selected occurred.
1846 * \param data Pointer to user data.
1848 static void addressbook_tree_selected(GtkCTree *ctree, GtkCTreeNode *node,
1849 gint column, gpointer data)
1851 AddressObject *obj = NULL;
1852 AdapterDSource *ads = NULL;
1853 AddressDataSource *ds = NULL;
1854 ItemFolder *rootFolder = NULL;
1855 AddressObjectType aot;
1857 addrbook.treeSelected = node;
1858 addrbook.listSelected = NULL;
1859 addressbook_status_show( "" );
1860 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1862 if( node ) obj = gtk_ctree_node_get_row_data( ctree, node );
1864 addressbook_set_clist(NULL, TRUE);
1867 addrbook.opened = node;
1869 if( obj->type == ADDR_DATASOURCE ) {
1870 /* Read from file */
1871 static gboolean tVal = TRUE;
1873 ads = ADAPTER_DSOURCE(obj);
1874 if( ads == NULL ) return;
1875 ds = ads->dataSource;
1876 if( ds == NULL ) return;
1878 if( addrindex_ds_get_modify_flag( ds ) ) {
1879 addrindex_ds_read_data( ds );
1882 if( ! addrindex_ds_get_read_flag( ds ) ) {
1883 addrindex_ds_read_data( ds );
1885 addressbook_ds_show_message( ds );
1887 if( ! addrindex_ds_get_access_flag( ds ) ) {
1888 /* Remove existing folders and groups */
1889 gtk_clist_freeze( GTK_CLIST(ctree) );
1890 addressbook_tree_remove_children( ctree, node );
1891 gtk_clist_thaw( GTK_CLIST(ctree) );
1893 /* Load folders into the tree */
1894 rootFolder = addrindex_ds_get_root_folder( ds );
1895 if( ds && ds->type == ADDR_IF_JPILOT ) {
1896 aot = ADDR_CATEGORY;
1898 else if( ds && ds->type == ADDR_IF_LDAP ) {
1899 aot = ADDR_LDAP_QUERY;
1902 aot = ADDR_ITEM_FOLDER;
1904 addressbook_node_add_folder( node, ds, rootFolder, aot );
1905 addrindex_ds_set_access_flag( ds, &tVal );
1906 gtk_ctree_expand( ctree, node );
1909 addressbook_set_clist(NULL, TRUE);
1912 /* Update address list */
1913 g_signal_handlers_block_by_func
1915 G_CALLBACK(addressbook_tree_selected), NULL);
1916 addressbook_set_clist( obj, FALSE );
1917 g_signal_handlers_unblock_by_func
1919 G_CALLBACK(addressbook_tree_selected), NULL);
1920 if (!prefs_common.addressbook_use_editaddress_dialog)
1921 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1923 /* Setup main menu selections */
1924 addressbook_menubar_set_sensitive( FALSE );
1925 addressbook_menuitem_set_sensitive( obj, node );
1926 addressbook_list_select_clear();
1927 addressbook_list_menu_setup();
1932 * Setup address list popup menu items. Items are enabled or disabled as
1935 static void addressbook_list_menu_setup( void ) {
1936 GtkCTree *clist = NULL;
1937 AddressObject *pobj = NULL;
1938 AddressObject *obj = NULL;
1939 AdapterDSource *ads = NULL;
1940 AddressInterface *iface = NULL;
1941 AddressDataSource *ds = NULL;
1942 gboolean canEdit = FALSE;
1943 gboolean canDelete = FALSE;
1944 gboolean canCut = FALSE;
1945 gboolean canCopy = FALSE;
1946 gboolean canPaste = FALSE;
1947 gboolean canBrowse = FALSE;
1949 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
1950 if( pobj == NULL ) return;
1952 clist = GTK_CTREE(addrbook.clist);
1953 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
1954 if( obj == NULL ) canEdit = FALSE;
1956 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1957 menu_set_sensitive( addrbook.list_factory, "/Select all", TRUE );
1959 if( pobj->type == ADDR_DATASOURCE ) {
1960 /* Parent object is a data source */
1961 ads = ADAPTER_DSOURCE(pobj);
1962 ds = ads->dataSource;
1965 iface = ds->interface;
1968 if( ! iface->readOnly ) {
1969 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1970 if (iface->type != ADDR_IF_LDAP)
1971 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1972 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1975 canDelete = canEdit;
1978 else if( pobj->type != ADDR_INTERFACE ) {
1979 /* Parent object is not an interface */
1980 ds = addressbook_find_datasource( addrbook.treeSelected );
1983 iface = ds->interface;
1986 if( ! iface->readOnly ) {
1987 /* Folder or group */
1988 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
1989 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
1990 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
1991 if( obj ) canEdit = TRUE;
1994 if( pobj->type == ADDR_ITEM_FOLDER ) {
1995 if (iface->type != ADDR_IF_LDAP)
1996 menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
1997 if( obj ) canEdit = TRUE;
1999 canDelete = canEdit;
2001 if( iface->type == ADDR_IF_LDAP ) {
2002 if( obj ) canBrowse = TRUE;
2009 /* Enable cut and paste */
2010 if( ! addrclip_is_empty( _clipBoard_ ) )
2012 if( ! addrselect_test_empty( _addressSelect_ ) )
2014 /* Enable copy if something is selected */
2015 if( ! addrselect_test_empty( _addressSelect_ ) )
2019 /* Disable edit or browse if more than one row selected */
2020 if( GTK_CLIST(clist)->selection && GTK_CLIST(clist)->selection->next ) {
2025 /* Forbid write changes when read-only */
2026 if( iface && iface->readOnly ) {
2032 /* Now go finalize menu items */
2033 menu_set_sensitive( addrbook.list_factory, "/Edit", canEdit );
2034 menu_set_sensitive( addrbook.list_factory, "/Delete", canDelete );
2036 menu_set_sensitive( addrbook.list_factory, "/Cut", canCut );
2037 menu_set_sensitive( addrbook.list_factory, "/Copy", canCopy );
2038 menu_set_sensitive( addrbook.list_factory, "/Paste", canPaste );
2040 menu_set_sensitive( addrbook.list_factory, "/Mail To", canCopy );
2042 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2043 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2044 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2046 menu_set_sensitive( addrbook.menu_factory, "/Address/Edit", canEdit );
2047 menu_set_sensitive( addrbook.menu_factory, "/Address/Delete", canDelete );
2048 menu_set_sensitive( addrbook.menu_factory, "/Address/Mail To", canCopy );
2050 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2051 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2054 menu_set_sensitive( addrbook.list_factory, "/Browse Entry", canBrowse );
2058 static void addressbook_select_row_tree (GtkCTree *ctree,
2066 * Add list of items into tree node below specified tree node.
2067 * \param treeNode Tree node.
2068 * \param ds Data source.
2069 * \param listItems List of items.
2071 static void addressbook_treenode_add_list(
2072 GtkCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2078 AddrItemObject *aio;
2082 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2085 group = ( ItemGroup * ) aio;
2086 nn = addressbook_node_add_group( treeNode, ds, group );
2088 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2091 folder = ( ItemFolder * ) aio;
2092 nn = addressbook_node_add_folder(
2093 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2095 node = g_list_next( node );
2099 static void addressbook_select_all_cb( void ) {
2100 gtk_clist_select_all(GTK_CLIST(addrbook.clist));
2104 * Cut from address list widget.
2106 static void addressbook_clip_cut_cb( void ) {
2107 _clipBoard_->cutFlag = TRUE;
2108 addrclip_clear( _clipBoard_ );
2109 addrclip_add( _clipBoard_, _addressSelect_ );
2110 /* addrclip_list_show( _clipBoard_, stdout ); */
2114 * Copy from address list widget.
2116 static void addressbook_clip_copy_cb( void ) {
2117 _clipBoard_->cutFlag = FALSE;
2118 addrclip_clear( _clipBoard_ );
2119 addrclip_add( _clipBoard_, _addressSelect_ );
2120 /* addrclip_list_show( _clipBoard_, stdout ); */
2124 * Paste clipboard into address list widget.
2126 static void addressbook_clip_paste_cb( void ) {
2127 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2128 AddressObject *pobj = NULL;
2129 AddressDataSource *ds = NULL;
2130 AddressBookFile *abf = NULL;
2131 ItemFolder *folder = NULL;
2132 GList *folderGroup = NULL;
2134 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
2135 if( ds == NULL ) return;
2136 if( addrindex_ds_get_readonly( ds ) ) {
2137 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2141 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2143 if( pobj->type == ADDR_ITEM_FOLDER ) {
2144 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2146 else if( pobj->type == ADDR_ITEM_GROUP ) {
2147 alertpanel_error( _("Cannot paste into an address group.") );
2152 /* Get an address book */
2153 abf = addressbook_get_book_file();
2154 if( abf == NULL ) return;
2156 if( _clipBoard_->cutFlag ) {
2158 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2160 /* Remove all groups and folders in clipboard from tree node */
2161 addressbook_treenode_remove_item();
2163 /* Remove all "cut" items */
2164 addrclip_delete_item( _clipBoard_ );
2166 /* Clear clipboard - cut items??? */
2167 addrclip_clear( _clipBoard_ );
2171 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2174 /* addrclip_list_show( _clipBoard_, stdout ); */
2176 /* Update tree by inserting node for each folder or group */
2177 addressbook_treenode_add_list(
2178 addrbook.treeSelected, ds, folderGroup );
2179 gtk_ctree_expand( ctree, addrbook.treeSelected );
2180 g_list_free( folderGroup );
2184 /* Display items pasted */
2185 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2186 addressbook_set_clist(
2187 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2195 * Add current treenode object to clipboard. Note that widget only allows
2196 * one entry from the tree list to be selected.
2198 static void addressbook_treenode_to_clipboard( void ) {
2199 AddressObject *obj = NULL;
2200 AddressDataSource *ds = NULL;
2201 AddrSelectItem *item;
2202 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
2205 node = addrbook.treeSelected;
2206 if( node == NULL ) return;
2207 obj = gtk_ctree_node_get_row_data( ctree, node );
2208 if( obj == NULL ) return;
2210 ds = addressbook_find_datasource( node );
2211 if( ds == NULL ) return;
2214 if( obj->type == ADDR_ITEM_FOLDER ) {
2215 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2216 ItemFolder *folder = adapter->itemFolder;
2218 item = addrselect_create_node( obj );
2219 item->uid = g_strdup( ADDRITEM_ID(folder) );
2221 else if( obj->type == ADDR_ITEM_GROUP ) {
2222 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2223 ItemGroup *group = adapter->itemGroup;
2225 item = addrselect_create_node( obj );
2226 item->uid = g_strdup( ADDRITEM_ID(group) );
2228 else if( obj->type == ADDR_DATASOURCE ) {
2230 item = addrselect_create_node( obj );
2235 /* Clear existing list and add item into list */
2238 addressbook_list_select_clear();
2239 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2240 addrselect_list_add( _addressSelect_, item, cacheID );
2246 * Cut from tree widget.
2248 static void addressbook_treenode_cut_cb( void ) {
2249 _clipBoard_->cutFlag = TRUE;
2250 addressbook_treenode_to_clipboard();
2251 addrclip_clear( _clipBoard_ );
2252 addrclip_add( _clipBoard_, _addressSelect_ );
2253 /* addrclip_list_show( _clipBoard_, stdout ); */
2257 * Copy from tree widget.
2259 static void addressbook_treenode_copy_cb( void ) {
2260 _clipBoard_->cutFlag = FALSE;
2261 addressbook_treenode_to_clipboard();
2262 addrclip_clear( _clipBoard_ );
2263 addrclip_add( _clipBoard_, _addressSelect_ );
2264 /* addrclip_list_show( _clipBoard_, stdout ); */
2268 * Paste clipboard into address tree widget.
2270 static void addressbook_treenode_paste_cb( void ) {
2271 addressbook_clip_paste_cb();
2275 * Clear selected entries in clipboard.
2277 static void addressbook_list_select_clear( void ) {
2278 addrselect_list_clear( _addressSelect_ );
2282 * Add specified address item to selected address list.
2283 * \param aio Address item object.
2284 * \param ds Datasource.
2286 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2289 if( ds == NULL ) return;
2290 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2291 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2296 * Remove specified address item from selected address list.
2297 * \param aio Address item object.
2299 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2300 addrselect_list_remove( _addressSelect_, aio );
2304 * Invoke EMail compose window with addresses in selected address list.
2306 static void addressbook_mail_to_cb( void ) {
2309 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2310 listAddress = addrselect_build_list( _addressSelect_ );
2311 compose_new_with_list( NULL, listAddress );
2312 mgu_free_dlist( listAddress );
2317 static void addressbook_list_row_selected( GtkCTree *clist,
2322 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2323 AddrItemObject *aio = NULL;
2324 AddressObject *pobj = NULL;
2325 AdapterDSource *ads = NULL;
2326 AddressDataSource *ds = NULL;
2328 gtk_entry_set_text( entry, "" );
2329 addrbook.listSelected = node;
2331 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
2332 if( pobj == NULL ) return;
2334 if( pobj->type == ADDR_DATASOURCE ) {
2335 ads = ADAPTER_DSOURCE(pobj);
2336 ds = ads->dataSource;
2338 else if( pobj->type != ADDR_INTERFACE ) {
2339 ds = addressbook_find_datasource( addrbook.treeSelected );
2342 aio = gtk_ctree_node_get_row_data( clist, node );
2344 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2345 addressbook_list_select_add( aio, ds );
2348 addressbook_list_menu_setup();
2350 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2351 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2353 if (obj && obj->type != ADDR_ITEM_GROUP)
2354 addressbook_edit_address(NULL, 0, NULL, FALSE);
2358 static void addressbook_list_row_unselected( GtkCTree *ctree,
2363 AddrItemObject *aio;
2365 aio = gtk_ctree_node_get_row_data( ctree, node );
2367 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2368 addressbook_list_select_remove( aio );
2371 if (!prefs_common.addressbook_use_editaddress_dialog)
2372 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2375 /* from gdkevents.c */
2376 #define DOUBLE_CLICK_TIME 250
2378 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2379 GdkEventButton *event,
2382 static guint32 lasttime = 0;
2383 if( ! event ) return FALSE;
2385 addressbook_list_menu_setup();
2387 if( event->button == 3 ) {
2388 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2389 event->button, event->time );
2390 } else if (event->button == 1) {
2391 if (event->time - lasttime < DOUBLE_CLICK_TIME) {
2392 if (prefs_common.add_address_by_click &&
2393 addrbook.target_compose)
2394 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2396 if (prefs_common.addressbook_use_editaddress_dialog)
2397 addressbook_edit_address_cb(NULL, 0, NULL);
2399 GtkCTree *clist = GTK_CTREE(addrbook.clist);
2400 AddressObject *obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
2401 if( obj && obj->type == ADDR_ITEM_GROUP )
2402 addressbook_edit_address_cb(NULL, 0, NULL);
2407 lasttime = event->time;
2413 static gboolean addressbook_list_button_released(GtkWidget *widget,
2414 GdkEventButton *event,
2420 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2421 GdkEventButton *event,
2424 GtkCList *clist = GTK_CLIST(ctree);
2426 AddressObject *obj = NULL;
2427 AdapterDSource *ads = NULL;
2428 AddressInterface *iface = NULL;
2429 AddressDataSource *ds = NULL;
2430 gboolean canEdit = FALSE;
2431 gboolean canDelete = FALSE;
2432 gboolean canCut = FALSE;
2433 gboolean canCopy = FALSE;
2434 gboolean canPaste = FALSE;
2435 gboolean canTreeCut = FALSE;
2436 gboolean canTreeCopy = FALSE;
2437 gboolean canTreePaste = FALSE;
2438 gboolean canLookup = FALSE;
2439 GtkCTreeNode *node = NULL;
2441 if( ! event ) return FALSE;
2442 addressbook_menubar_set_sensitive( FALSE );
2444 if( gtk_clist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2445 gtkut_clist_set_focus_row(clist, row);
2446 obj = gtk_clist_get_row_data( clist, row );
2449 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2451 if( obj == NULL ) return FALSE;
2452 node = gtk_ctree_node_nth(GTK_CTREE(clist), row);
2454 if( ! addrclip_is_empty( _clipBoard_ ) ) {
2455 canTreePaste = TRUE;
2457 if (obj->type == ADDR_INTERFACE) {
2458 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2461 iface = adapter->interface;
2464 if( !iface->readOnly ) {
2465 menu_set_sensitive( addrbook.tree_factory, "/New Book", TRUE );
2466 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2468 if( iface->externalQuery ) canLookup = TRUE;
2470 if (obj->type == ADDR_DATASOURCE) {
2471 ads = ADAPTER_DSOURCE(obj);
2472 ds = ads->dataSource;
2475 iface = ds->interface;
2478 if( !iface->readOnly ) {
2480 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2481 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2482 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2486 if( iface->externalQuery ) canLookup = TRUE;
2488 else if (obj->type == ADDR_ITEM_FOLDER) {
2489 ds = addressbook_find_datasource( node );
2492 iface = ds->interface;
2495 if( !iface->readOnly ) {
2499 menu_set_sensitive( addrbook.tree_factory, "/New Folder", TRUE );
2500 menu_set_sensitive( addrbook.tree_factory, "/New Group", TRUE );
2501 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2505 if( iface->externalQuery ) {
2506 /* Enable deletion of LDAP folder */
2511 else if (obj->type == ADDR_ITEM_GROUP) {
2512 ds = addressbook_find_datasource( node );
2515 iface = ds->interface;
2518 if( ! iface->readOnly ) {
2521 menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
2522 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2527 if( ! addrselect_test_empty( _addressSelect_ ) )
2530 if( ! addrselect_test_empty( _addressSelect_ ) )
2532 if( ! addrclip_is_empty( _clipBoard_ ) )
2535 /* Forbid write changes when read-only */
2536 if( iface && iface->readOnly ) {
2538 canTreePaste = FALSE;
2546 menu_set_sensitive( addrbook.tree_factory, "/Edit", canEdit );
2547 menu_set_sensitive( addrbook.tree_factory, "/Delete", canDelete );
2548 menu_set_sensitive( addrbook.tree_factory, "/Cut", canTreeCut );
2549 menu_set_sensitive( addrbook.tree_factory, "/Copy", canTreeCopy );
2550 menu_set_sensitive( addrbook.tree_factory, "/Paste", canTreePaste );
2552 menu_set_sensitive( addrbook.menu_factory, "/Book/Edit book", canEdit );
2553 menu_set_sensitive( addrbook.menu_factory, "/Book/Delete book", canEdit );
2554 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", canCut );
2555 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", canCopy );
2556 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", canPaste );
2558 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2559 addrbook.target_compose != NULL);
2561 if( event->button == 3 ) {
2562 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2563 event->button, event->time);
2569 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2570 GdkEventButton *event,
2573 gtkut_ctree_set_focus_row(GTK_CTREE(addrbook.ctree), addrbook.opened);
2577 static void addressbook_new_folder_cb(gpointer data, guint action,
2580 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2581 AddressObject *obj = NULL;
2582 AddressDataSource *ds = NULL;
2583 AddressBookFile *abf = NULL;
2584 ItemFolder *parentFolder = NULL;
2585 ItemFolder *folder = NULL;
2587 if( ! addrbook.treeSelected ) return;
2588 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
2589 if( obj == NULL ) return;
2590 ds = addressbook_find_datasource( addrbook.treeSelected );
2591 if( ds == NULL ) return;
2593 if( obj->type == ADDR_DATASOURCE ) {
2594 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2596 else if( obj->type == ADDR_ITEM_FOLDER ) {
2597 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2603 abf = ds->rawDataSource;
2604 if( abf == NULL ) return;
2605 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2608 nn = addressbook_node_add_folder(
2609 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2610 gtk_ctree_expand( ctree, addrbook.treeSelected );
2611 if( addrbook.treeSelected == addrbook.opened )
2612 addressbook_set_clist(obj, TRUE);
2617 static void addressbook_new_group_cb(gpointer data, guint action,
2620 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2621 AddressObject *obj = NULL;
2622 AddressDataSource *ds = NULL;
2623 AddressBookFile *abf = NULL;
2624 ItemFolder *parentFolder = NULL;
2625 ItemGroup *group = NULL;
2627 if( ! addrbook.treeSelected ) return;
2628 obj = gtk_ctree_node_get_row_data(ctree, addrbook.treeSelected);
2629 if( obj == NULL ) return;
2630 ds = addressbook_find_datasource( addrbook.treeSelected );
2631 if( ds == NULL ) return;
2633 if( obj->type == ADDR_DATASOURCE ) {
2634 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2636 else if( obj->type == ADDR_ITEM_FOLDER ) {
2637 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2643 abf = ds->rawDataSource;
2644 if( abf == NULL ) return;
2645 group = addressbook_edit_group( abf, parentFolder, NULL );
2648 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2649 gtk_ctree_expand( ctree, addrbook.treeSelected );
2650 if( addrbook.treeSelected == addrbook.opened )
2651 addressbook_set_clist(obj, TRUE);
2656 static void addressbook_change_node_name(GtkCTreeNode *node, const gchar *name)
2658 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2661 GdkPixmap *pix_cl, *pix_op;
2662 GdkBitmap *mask_cl, *mask_op;
2663 gboolean is_leaf, expanded;
2665 gtk_ctree_get_node_info(ctree, node, text, &spacing,
2666 &pix_cl, &mask_cl, &pix_op, &mask_op,
2667 &is_leaf, &expanded);
2668 gtk_sctree_set_node_info(ctree, node, name, spacing,
2669 pix_cl, mask_cl, pix_op, mask_op,
2675 * \param obj Address object to edit.
2676 * \param node Node in tree.
2677 * \return New name of data source.
2679 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCTreeNode *node ) {
2680 gchar *newName = NULL;
2681 AddressDataSource *ds = NULL;
2682 AddressInterface *iface = NULL;
2683 AdapterDSource *ads = NULL;
2685 ds = addressbook_find_datasource( node );
2686 if( ds == NULL ) return NULL;
2687 iface = ds->interface;
2688 if( ! iface->haveLibrary ) return NULL;
2690 /* Read data from data source */
2691 if( addrindex_ds_get_modify_flag( ds ) ) {
2692 addrindex_ds_read_data( ds );
2695 if( ! addrindex_ds_get_read_flag( ds ) ) {
2696 addrindex_ds_read_data( ds );
2700 ads = ADAPTER_DSOURCE(obj);
2701 if( ads->subType == ADDR_BOOK ) {
2702 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2704 else if( ads->subType == ADDR_VCARD ) {
2705 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2708 else if( ads->subType == ADDR_JPILOT ) {
2709 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2713 else if( ads->subType == ADDR_LDAP ) {
2714 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2720 newName = obj->name;
2725 * Edit an object that is in the address tree area.
2727 static void addressbook_treenode_edit_cb(gpointer data, guint action,
2730 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2732 AddressDataSource *ds = NULL;
2733 AddressBookFile *abf = NULL;
2734 GtkCTreeNode *node = NULL, *parentNode = NULL;
2737 if( ! addrbook.treeSelected ) return;
2738 node = addrbook.treeSelected;
2739 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2740 obj = gtk_ctree_node_get_row_data( ctree, node );
2741 if( obj == NULL ) return;
2742 parentNode = GTK_CTREE_ROW(node)->parent;
2744 ds = addressbook_find_datasource( node );
2745 if( ds == NULL ) return;
2747 if( obj->type == ADDR_DATASOURCE ) {
2748 name = addressbook_edit_datasource( obj, node );
2749 if( name == NULL ) return;
2752 abf = ds->rawDataSource;
2753 if( abf == NULL ) return;
2754 if( obj->type == ADDR_ITEM_FOLDER ) {
2755 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2756 ItemFolder *item = adapter->itemFolder;
2757 ItemFolder *parentFolder = NULL;
2758 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2759 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2760 name = ADDRITEM_NAME(item);
2762 else if( obj->type == ADDR_ITEM_GROUP ) {
2763 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2764 ItemGroup *item = adapter->itemGroup;
2765 ItemFolder *parentFolder = NULL;
2766 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2767 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2768 name = ADDRITEM_NAME(item);
2771 if( name && parentNode ) {
2772 /* Update node in tree view */
2773 addressbook_change_node_name( node, name );
2774 gtk_sctree_sort_node(ctree, parentNode);
2775 gtk_ctree_expand( ctree, node );
2776 gtk_sctree_select( GTK_SCTREE( ctree), node );
2783 ADDRTREE_DEL_FOLDER_ONLY,
2784 ADDRTREE_DEL_FOLDER_ADDR
2788 * Delete an item from the tree widget.
2789 * \param data Data passed in.
2790 * \param action Action.
2791 * \param widget Widget issuing callback.
2793 static void addressbook_treenode_delete_cb(
2794 gpointer data, guint action, GtkWidget *widget )
2796 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
2797 GtkCTreeNode *node = NULL;
2801 AddrBookBase *adbase;
2802 AddressCache *cache;
2803 AdapterDSource *ads = NULL;
2804 AddressInterface *iface = NULL;
2805 AddressDataSource *ds = NULL;
2806 gboolean remFlag = FALSE;
2807 TreeItemDelType delType;
2809 if( ! addrbook.treeSelected ) return;
2810 node = addrbook.treeSelected;
2811 if( GTK_CTREE_ROW(node)->level == 1 ) return;
2813 obj = gtk_ctree_node_get_row_data( ctree, node );
2814 g_return_if_fail(obj != NULL);
2816 if( obj->type == ADDR_DATASOURCE ) {
2817 ads = ADAPTER_DSOURCE(obj);
2818 if( ads == NULL ) return;
2819 ds = ads->dataSource;
2820 if( ds == NULL ) return;
2823 /* Must be folder or something else */
2824 ds = addressbook_find_datasource( node );
2825 if( ds == NULL ) return;
2827 /* Only allow deletion from non-readOnly */
2828 iface = ds->interface;
2829 if( iface->readOnly ) {
2830 /* Allow deletion of query results */
2831 if( ! iface->externalQuery ) return;
2835 /* Confirm deletion */
2836 delType = ADDRTREE_DEL_NONE;
2837 if( obj->type == ADDR_ITEM_FOLDER ) {
2838 if( iface->externalQuery ) {
2839 message = g_strdup_printf( _(
2840 "Do you want to delete the query " \
2841 "results and addresses in '%s' ?" ),
2843 aval = alertpanel( _("Delete"), message,
2844 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2846 if( aval == G_ALERTALTERNATE ) {
2847 delType = ADDRTREE_DEL_FOLDER_ADDR;
2851 message = g_strdup_printf
2852 ( _( "Do you want to delete '%s' ?"
2853 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2855 aval = alertpanel( _("Delete folder"), message,
2856 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2858 if( aval == G_ALERTALTERNATE ) {
2859 delType = ADDRTREE_DEL_FOLDER_ONLY;
2861 else if( aval == G_ALERTOTHER ) {
2862 delType = ADDRTREE_DEL_FOLDER_ADDR;
2866 else if( obj->type == ADDR_ITEM_GROUP ) {
2867 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2868 "The addresses it contains will not be lost."), obj->name);
2869 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2870 "+" GTK_STOCK_DELETE, NULL);
2872 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2874 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2875 "The addresses it contains will be lost."), obj->name);
2876 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2877 "+" GTK_STOCK_DELETE, NULL);
2879 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2881 if( delType == ADDRTREE_DEL_NONE ) return;
2883 /* Proceed with deletion */
2884 if( obj->type == ADDR_DATASOURCE ) {
2885 /* Remove node from tree */
2886 gtk_ctree_remove_node( ctree, node );
2888 /* Remove data source. */
2889 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2890 addrindex_free_datasource( ds );
2895 /* Get reference to cache */
2896 adbase = ( AddrBookBase * ) ds->rawDataSource;
2897 if( adbase == NULL ) return;
2898 cache = adbase->addressCache;
2900 /* Remove query results folder */
2901 if( iface->externalQuery ) {
2902 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2903 ItemFolder *folder = adapter->itemFolder;
2905 adapter->itemFolder = NULL;
2907 g_print( "remove folder for ::%s::\n", obj->name );
2908 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2909 g_print( "-------------- remove results\n" );
2911 addrindex_remove_results( ds, folder );
2912 /* g_print( "-------------- remove node\n" ); */
2913 gtk_ctree_remove_node( ctree, node );
2917 /* Code below is valid for regular address book deletion */
2918 if( obj->type == ADDR_ITEM_FOLDER ) {
2919 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2920 ItemFolder *item = adapter->itemFolder;
2922 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2923 /* Remove folder only */
2924 item = addrcache_remove_folder( cache, item );
2926 addritem_free_item_folder( item );
2927 addressbook_move_nodes_up( ctree, node );
2931 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
2932 /* Remove folder and addresses */
2933 item = addrcache_remove_folder_delete( cache, item );
2935 addritem_free_item_folder( item );
2940 else if( obj->type == ADDR_ITEM_GROUP ) {
2941 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2942 ItemGroup *item = adapter->itemGroup;
2944 item = addrcache_remove_group( cache, item );
2946 addritem_free_item_group( item );
2953 gtk_ctree_remove_node(ctree, node );
2957 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
2959 if( person && addrbook.treeSelected == addrbook.opened ) {
2960 person->status = ADD_ENTRY;
2961 gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
2962 addressbook_folder_refresh_one_person(
2963 GTK_CTREE(addrbook.clist), person );
2965 addressbook_address_list_set_focus();
2968 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
2970 if( person && addrbook.treeSelected == addrbook.opened) {
2971 person->status = ADD_ENTRY;
2972 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
2973 addressbook_set_clist(
2974 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
2978 addressbook_address_list_set_focus();
2982 * Label (a format string) that is used to name each folder.
2984 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
2987 * Search ctree widget callback function.
2988 * \param pA Pointer to node.
2989 * \param pB Pointer to data item being sought.
2990 * \return Zero (0) if folder found.
2992 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
2995 aoA = ( AddressObject * ) pA;
2996 if( aoA->type == ADDR_ITEM_FOLDER ) {
2997 ItemFolder *folder, *fld;
2999 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3000 folder = ( ItemFolder * ) pB;
3001 if( fld == folder ) return 0; /* Found folder */
3006 static ItemFolder * addressbook_setup_subf(
3007 AddressDataSource *ds, gchar *title,
3008 GtkCTreeNode *pNode )
3010 AddrBookBase *adbase;
3011 AddressCache *cache;
3014 GtkCTreeNode *nNode;
3016 AddressObjectType aoType = ADDR_NONE;
3019 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3021 if( ds && ds->type == ADDR_IF_LDAP ) {
3023 aoType = ADDR_LDAP_QUERY;
3030 ctree = GTK_CTREE(addrbook.ctree);
3031 /* Get reference to address cache */
3032 adbase = ( AddrBookBase * ) ds->rawDataSource;
3033 cache = adbase->addressCache;
3035 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3036 GList *cur = children;
3037 for (; cur; cur = cur->next) {
3038 ItemFolder *child = (ItemFolder *) cur->data;
3039 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3040 nNode = gtk_ctree_find_by_row_data_custom(
3042 addressbook_treenode_find_folder_cb );
3044 addrindex_remove_results( ds, child );
3045 while( child->listPerson ) {
3046 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3047 item = addrcache_remove_person( cache, item );
3049 addritem_free_item_person( item );
3053 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3054 addrbook.treeSelected = nNode;
3061 /* Create a folder */
3062 folder = addrcache_add_new_folder( cache, NULL );
3063 name = g_strdup_printf( "%s", title );
3064 addritem_folder_set_name( folder, name );
3065 addritem_folder_set_remarks( folder, "" );
3068 /* Now let's see the folder */
3069 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3070 gtk_ctree_expand( ctree, pNode );
3072 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3073 addrbook.treeSelected = nNode;
3079 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3080 AddressObject *pobj = NULL;
3081 AddressDataSource *ds = NULL;
3082 AddressBookFile *abf = NULL;
3083 debug_print("adding address\n");
3084 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3085 if( pobj == NULL ) {
3086 debug_print("no row data\n");
3089 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3091 debug_print("no datasource\n");
3095 abf = ds->rawDataSource;
3097 g_print("no addressbook file\n");
3101 if( pobj->type == ADDR_DATASOURCE ) {
3102 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3103 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3105 ItemFolder *folder = NULL;
3107 if (abf && abf->type == ADDR_IF_LDAP) {
3108 GtkCTreeNode *parentNode;
3109 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3110 if( ds == NULL ) return;
3112 /* We must have a datasource that is an external interface */
3113 if( ! ds->interface->haveLibrary ) return;
3114 if( ! ds->interface->externalQuery ) return;
3116 if( pobj->type == ADDR_ITEM_FOLDER ) {
3117 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3120 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3122 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3124 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3125 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3126 abf = ds->rawDataSource;
3129 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3130 addrbook.editaddress_vbox,
3131 addressbook_new_address_from_book_post_cb,
3134 if (abf && abf->type == ADDR_IF_LDAP) {
3135 LdapServer *server = ds->rawDataSource;
3136 ldapsvr_set_modified(server, TRUE);
3137 ldapsvr_update_book(server, NULL);
3138 if (server->retVal != LDAPRC_SUCCESS) {
3139 alertpanel( _("Add address(es)"),
3140 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3141 GTK_STOCK_CLOSE, NULL, NULL );
3142 server->retVal = LDAPRC_SUCCESS;
3147 if (prefs_common.addressbook_use_editaddress_dialog)
3148 addressbook_new_address_from_book_post_cb( person );
3151 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3153 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3156 if (abf && abf->type == ADDR_IF_LDAP) {
3157 GtkCTreeNode *parentNode;
3158 ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
3159 if( ds == NULL ) return;
3161 /* We must have a datasource that is an external interface */
3162 if( ! ds->interface->haveLibrary ) return;
3163 if( ! ds->interface->externalQuery ) return;
3165 if( pobj->type == ADDR_ITEM_FOLDER ) {
3166 parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
3169 parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
3171 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3174 pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
3175 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3176 abf = ds->rawDataSource;
3179 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3180 addrbook.editaddress_vbox,
3181 addressbook_new_address_from_folder_post_cb,
3184 if (abf && abf->type == ADDR_IF_LDAP) {
3185 LdapServer *server = ds->rawDataSource;
3186 ldapsvr_set_modified(server, TRUE);
3187 ldapsvr_update_book(server, NULL);
3188 if (server->retVal != LDAPRC_SUCCESS) {
3189 alertpanel( _("Add address(es)"),
3190 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3191 GTK_STOCK_CLOSE, NULL, NULL );
3196 if (prefs_common.addressbook_use_editaddress_dialog)
3197 addressbook_new_address_from_folder_post_cb( person );
3199 else if( pobj->type == ADDR_ITEM_GROUP ) {
3200 /* New address in group */
3201 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3202 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3203 if (addrbook.treeSelected == addrbook.opened) {
3204 /* Change node name in tree. */
3205 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3206 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3207 addressbook_set_clist(
3208 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3216 * Search for specified child group node in address index tree.
3217 * \param parent Parent node.
3218 * \param group Group to find.
3220 static GtkCTreeNode *addressbook_find_group_node( GtkCTreeNode *parent, ItemGroup *group ) {
3221 GtkCTreeNode *node = NULL;
3222 GtkCTreeRow *currRow;
3224 currRow = GTK_CTREE_ROW( parent );
3226 node = currRow->children;
3230 obj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3231 if( obj->type == ADDR_ITEM_GROUP ) {
3232 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3233 if( g == group ) return node;
3235 currRow = GTK_CTREE_ROW(node);
3236 node = currRow->sibling;
3242 static AddressBookFile *addressbook_get_book_file() {
3243 AddressBookFile *abf = NULL;
3244 AddressDataSource *ds = NULL;
3246 ds = addressbook_find_datasource( addrbook.treeSelected );
3247 if( ds == NULL ) return NULL;
3248 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3252 static void addressbook_tree_remove_children( GtkCTree *ctree, GtkCTreeNode *parent ) {
3256 /* Remove existing folders and groups */
3257 row = GTK_CTREE_ROW( parent );
3259 while( (node = row->children) ) {
3260 gtk_ctree_remove_node( ctree, node );
3265 static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
3266 GtkCTreeNode *parent, *child;
3267 GtkCTreeRow *currRow;
3268 currRow = GTK_CTREE_ROW( node );
3270 parent = currRow->parent;
3271 while( (child = currRow->children) ) {
3272 gtk_ctree_move( ctree, child, parent, node );
3274 gtk_sctree_sort_node( ctree, parent );
3278 static void addressbook_edit_address_post_cb( ItemPerson *person )
3282 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3283 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3285 addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
3286 invalidate_address_completion();
3288 addressbook_address_list_set_focus();
3291 void addressbook_address_list_set_focus( void )
3293 if (!prefs_common.addressbook_use_editaddress_dialog) {
3294 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3295 addressbook_list_menu_setup();
3299 void addressbook_address_list_disable_some_actions(void)
3301 /* disable address copy/pasting when editing contact's detail (embedded form) */
3302 menu_set_sensitive( addrbook.menu_factory, "/Address/Cut", FALSE );
3303 menu_set_sensitive( addrbook.menu_factory, "/Address/Copy", FALSE );
3304 menu_set_sensitive( addrbook.menu_factory, "/Address/Paste", FALSE );
3307 static void addressbook_edit_address_cb( gpointer data, guint action, GtkWidget *widget ) {
3308 addressbook_edit_address(data, action, widget, TRUE);
3311 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3312 gboolean force_focus ) {
3313 GtkCTree *clist = GTK_CTREE(addrbook.clist);
3315 AddressObject *obj = NULL, *pobj = NULL;
3316 AddressDataSource *ds = NULL;
3317 GtkCTreeNode *node = NULL, *parentNode = NULL;
3319 AddressBookFile *abf = NULL;
3321 if( addrbook.listSelected == NULL ) return;
3322 obj = gtk_ctree_node_get_row_data( clist, addrbook.listSelected );
3323 g_return_if_fail(obj != NULL);
3325 ctree = GTK_CTREE( addrbook.ctree );
3326 pobj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
3327 node = gtk_ctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3329 ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
3330 if( ds == NULL ) return;
3332 abf = addressbook_get_book_file();
3334 if( obj->type == ADDR_ITEM_EMAIL ) {
3335 ItemEMail *email = ( ItemEMail * ) obj;
3336 if( email == NULL ) return;
3337 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3338 /* Edit parent group */
3339 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3340 ItemGroup *itemGrp = adapter->itemGroup;
3341 if( abf == NULL ) return;
3342 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3343 name = ADDRITEM_NAME(itemGrp);
3344 node = addrbook.treeSelected;
3345 parentNode = GTK_CTREE_ROW(node)->parent;
3348 /* Edit person - email page */
3350 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3351 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3352 addressbook_edit_address_post_cb,
3353 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3356 if (abf && abf->type == ADDR_IF_LDAP) {
3357 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3358 person->status = UPDATE_ENTRY;
3361 if (prefs_common.addressbook_use_editaddress_dialog)
3362 addressbook_edit_address_post_cb( person );
3367 else if( obj->type == ADDR_ITEM_PERSON ) {
3368 /* Edit person - basic page */
3369 ItemPerson *person = ( ItemPerson * ) obj;
3370 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3371 addressbook_edit_address_post_cb,
3372 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3375 if (abf && abf->type == ADDR_IF_LDAP) {
3376 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3377 person->status = UPDATE_ENTRY;
3380 if (prefs_common.addressbook_use_editaddress_dialog)
3381 addressbook_edit_address_post_cb( person );
3385 else if( obj->type == ADDR_ITEM_GROUP ) {
3386 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3387 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3388 parentNode = addrbook.treeSelected;
3389 node = addressbook_find_group_node( parentNode, itemGrp );
3390 name = ADDRITEM_NAME(itemGrp);
3391 invalidate_address_completion();
3397 /* Update tree node with node name */
3398 if( node == NULL ) return;
3399 addressbook_change_node_name( node, name );
3400 gtk_sctree_sort_node( ctree, parentNode );
3401 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3402 addressbook_set_clist(
3403 gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
3408 static void addressbook_delete_address_cb(gpointer data, guint action,
3411 addressbook_del_clicked(NULL, NULL);
3414 static void close_cb(gpointer data, guint action, GtkWidget *widget)
3416 addressbook_close();
3419 static void addressbook_file_save_cb( gpointer data, guint action, GtkWidget *widget ) {
3420 addressbook_export_to_file();
3423 static void addressbook_person_expand_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3425 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3426 if( person ) addritem_person_set_opened( person, TRUE );
3430 static void addressbook_person_collapse_node( GtkCTree *ctree, GList *node, gpointer *data ) {
3432 ItemPerson *person = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
3433 if( person ) addritem_person_set_opened( person, FALSE );
3437 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3439 gchar *eMailAlias = ADDRITEM_NAME(email);
3440 if( eMailAlias && *eMailAlias != '\0' ) {
3442 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3445 str = g_strdup( eMailAlias );
3451 static void addressbook_load_group( GtkCTree *clist, ItemGroup *itemGroup ) {
3452 GList *items = itemGroup->listEMail;
3453 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3454 for( ; items != NULL; items = g_list_next( items ) ) {
3455 GtkCTreeNode *nodeEMail = NULL;
3456 gchar *text[N_LIST_COLS];
3457 ItemEMail *email = items->data;
3461 if( ! email ) continue;
3463 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3464 str = addressbook_format_item_clist( person, email );
3466 text[COL_NAME] = addressbook_set_col_name_guard(str);
3469 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3471 text[COL_ADDRESS] = email->address;
3472 text[COL_REMARKS] = email->remarks;
3473 nodeEMail = gtk_sctree_insert_node(
3475 text, FOLDER_SPACING,
3476 atci->iconXpm, atci->maskXpm,
3477 atci->iconXpmOpen, atci->maskXpmOpen,
3479 gtk_ctree_node_set_row_data( clist, nodeEMail, email );
3485 gchar *addressbook_set_col_name_guard(gchar *value)
3487 gchar *ret = "<not set>";
3488 gchar *tmp = g_strdup(value);
3490 if (tmp !=NULL && *tmp != '\0')
3496 static void addressbook_folder_load_one_person(
3497 GtkCTree *clist, ItemPerson *person,
3498 AddressTypeControlItem *atci,
3499 AddressTypeControlItem *atciMail )
3501 GtkCTreeNode *nodePerson = NULL;
3502 GtkCTreeNode *nodeEMail = NULL;
3503 gchar *text[N_LIST_COLS];
3504 gboolean flgFirst = TRUE, haveAddr = FALSE;
3507 AddressBookFile *abf = addressbook_get_book_file();
3510 if( person == NULL ) return;
3512 text[COL_NAME] = "";
3513 node = person->listEMail;
3515 ItemEMail *email = node->data;
3516 gchar *eMailAddr = NULL;
3517 node = g_list_next( node );
3519 text[COL_ADDRESS] = email->address;
3520 text[COL_REMARKS] = email->remarks;
3521 eMailAddr = ADDRITEM_NAME(email);
3522 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3524 /* First email belongs with person */
3525 gchar *str = addressbook_format_item_clist( person, email );
3527 text[COL_NAME] = addressbook_set_col_name_guard(str);
3530 else if( abf && abf->type == ADDR_IF_LDAP &&
3531 person && person->nickName ) {
3532 if (person->nickName) {
3533 if (strcmp(person->nickName, "") != 0) {
3534 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3537 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3543 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3545 nodePerson = gtk_sctree_insert_node(
3547 text, FOLDER_SPACING,
3548 atci->iconXpm, atci->maskXpm,
3549 atci->iconXpmOpen, atci->maskXpmOpen,
3550 FALSE, person->isOpened );
3553 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3556 /* Subsequent email is a child node of person */
3557 text[COL_NAME] = ADDRITEM_NAME(email);
3558 nodeEMail = gtk_sctree_insert_node(
3559 clist, nodePerson, NULL,
3560 text, FOLDER_SPACING,
3561 atciMail->iconXpm, atciMail->maskXpm,
3562 atciMail->iconXpmOpen, atciMail->maskXpmOpen,
3564 gtk_ctree_node_set_row_data(clist, nodeEMail, email );
3570 /* Have name without EMail */
3571 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3572 text[COL_ADDRESS] = "";
3573 text[COL_REMARKS] = "";
3574 nodePerson = gtk_sctree_insert_node(
3576 text, FOLDER_SPACING,
3577 atci->iconXpm, atci->maskXpm,
3578 atci->iconXpmOpen, atci->maskXpmOpen,
3579 FALSE, person->isOpened );
3580 gtk_ctree_node_set_row_data(clist, nodePerson, person );
3585 static void addressbook_folder_load_person( GtkCTree *clist, ItemFolder *itemFolder ) {
3587 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3588 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3590 if( atci == NULL ) return;
3591 if( atciMail == NULL ) return;
3593 /* Load email addresses */
3594 items = addritem_folder_get_person_list( itemFolder );
3595 for( ; items != NULL; items = g_list_next( items ) ) {
3596 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3598 /* Free up the list */
3599 mgu_clear_list( items );
3600 g_list_free( items );
3603 static void addressbook_folder_remove_node( GtkCTree *clist, GtkCTreeNode *node ) {
3604 addrbook.listSelected = NULL;
3605 gtk_ctree_remove_node( clist, node );
3606 addressbook_menubar_set_sensitive( FALSE );
3607 addressbook_menuitem_set_sensitive(
3608 gtk_ctree_node_get_row_data(
3609 GTK_CTREE(clist), addrbook.treeSelected ),
3610 addrbook.treeSelected );
3613 static void addressbook_folder_refresh_one_person( GtkCTree *clist, ItemPerson *person ) {
3614 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3615 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3617 if( atci == NULL ) return;
3618 if( atciMail == NULL ) return;
3619 if( person == NULL ) return;
3620 /* unload the person */
3622 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3624 addressbook_folder_remove_node( clist, node );
3625 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3626 gtk_sctree_sort_node( clist, NULL );
3627 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3629 gtk_sctree_select( GTK_SCTREE(clist), node );
3630 if (!gtk_ctree_node_is_visible( clist, node ) )
3631 gtk_ctree_node_moveto( clist, node, 0, 0, 0 );
3635 static void addressbook_folder_remove_one_person( GtkCTree *clist, ItemPerson *person ) {
3639 if( person == NULL ) return;
3640 node = gtk_ctree_find_by_row_data( clist, NULL, person );
3641 row = gtk_clist_find_row_from_data( GTK_CLIST(clist), person );
3643 addressbook_folder_remove_node( clist, node );
3647 static void addressbook_folder_load_group( GtkCTree *clist, ItemFolder *itemFolder ) {
3649 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3651 /* Load any groups */
3652 if( ! atci ) return;
3653 items = addritem_folder_get_group_list( itemFolder );
3654 for( ; items != NULL; items = g_list_next( items ) ) {
3655 GtkCTreeNode *nodeGroup = NULL;
3656 gchar *text[N_LIST_COLS];
3657 ItemGroup *group = items->data;
3658 if( group == NULL ) continue;
3659 text[COL_NAME] = ADDRITEM_NAME(group);
3660 text[COL_ADDRESS] = "";
3661 text[COL_REMARKS] = "";
3662 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3663 text, FOLDER_SPACING,
3664 atci->iconXpm, atci->maskXpm,
3665 atci->iconXpmOpen, atci->maskXpmOpen,
3667 gtk_ctree_node_set_row_data(clist, nodeGroup, group );
3668 gtk_sctree_sort_node(clist, NULL);
3670 /* Free up the list */
3671 mgu_clear_list( items );
3672 g_list_free( items );
3676 * Search ctree widget callback function.
3677 * \param pA Pointer to node.
3678 * \param pB Pointer to data item being sought.
3679 * \return Zero (0) if group found.
3681 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3684 aoA = ( AddressObject * ) pA;
3685 if( aoA->type == ADDR_ITEM_GROUP ) {
3686 ItemGroup *group, *grp;
3688 grp = ADAPTER_GROUP(aoA)->itemGroup;
3689 group = ( ItemGroup * ) pB;
3690 if( grp == group ) return 0; /* Found group */
3696 * Remove folder and group nodes from tree widget for items contained ("cut")
3699 static void addressbook_treenode_remove_item( void ) {
3701 AddrSelectItem *cutItem;
3702 AddressCache *cache;
3703 AddrItemObject *aio;
3704 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3707 node = _clipBoard_->objectList;
3709 cutItem = node->data;
3710 node = g_list_next( node );
3711 cache = addrindex_get_cache(
3712 _clipBoard_->addressIndex, cutItem->cacheID );
3713 if( cache == NULL ) continue;
3714 aio = addrcache_get_object( cache, cutItem->uid );
3717 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3720 folder = ( ItemFolder * ) aio;
3721 tn = gtk_ctree_find_by_row_data_custom(
3722 ctree, NULL, folder,
3723 addressbook_treenode_find_folder_cb );
3725 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3728 group = ( ItemGroup * ) aio;
3729 tn = gtk_ctree_find_by_row_data_custom(
3731 addressbook_treenode_find_group_cb );
3735 /* Free up adapter and remove node. */
3736 gtk_ctree_remove_node( ctree, tn );
3743 * Find parent datasource for specified tree node.
3744 * \param node Node to test.
3745 * \return Data source, or NULL if not found.
3747 static AddressDataSource *addressbook_find_datasource( GtkCTreeNode *node ) {
3748 AddressDataSource *ds = NULL;
3751 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3754 if( GTK_CTREE_ROW(node)->level < 2 ) return NULL;
3755 ao = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), node );
3757 /* g_print( "ao->type = %d\n", ao->type ); */
3758 if( ao->type == ADDR_DATASOURCE ) {
3759 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3760 /* g_print( "found it\n" ); */
3761 ds = ads->dataSource;
3765 node = GTK_CTREE_ROW(node)->parent;
3771 * Load address list widget with children of specified object.
3772 * \param obj Parent object to be loaded.
3774 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3775 GtkCTree *ctreelist = GTK_CTREE(addrbook.clist);
3776 GtkCList *clist = GTK_CLIST(addrbook.clist);
3777 AddressDataSource *ds = NULL;
3778 AdapterDSource *ads = NULL;
3779 static AddressObject *last_obj = NULL;
3781 if (addrbook.clist == NULL) {
3784 if (obj == last_obj && !refresh)
3789 gtk_clist_clear(clist);
3793 if( obj->type == ADDR_INTERFACE ) {
3794 /* g_print( "set_clist: loading datasource...\n" ); */
3795 /* addressbook_node_load_datasource( GTK_CTREE(clist), obj ); */
3799 gtk_clist_freeze(clist);
3800 gtk_clist_clear(clist);
3802 if( obj->type == ADDR_DATASOURCE ) {
3803 ads = ADAPTER_DSOURCE(obj);
3804 ds = ADAPTER_DSOURCE(obj)->dataSource;
3806 /* Load root folder */
3807 ItemFolder *rootFolder = NULL;
3808 rootFolder = addrindex_ds_get_root_folder( ds );
3809 addressbook_folder_load_person(
3810 ctreelist, addrindex_ds_get_root_folder( ds ) );
3811 addressbook_folder_load_group(
3812 ctreelist, addrindex_ds_get_root_folder( ds ) );
3816 if( obj->type == ADDR_ITEM_GROUP ) {
3818 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3819 addressbook_load_group( ctreelist, itemGroup );
3821 else if( obj->type == ADDR_ITEM_FOLDER ) {
3823 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3824 addressbook_folder_load_person( ctreelist, itemFolder );
3825 addressbook_folder_load_group( ctreelist, itemFolder );
3828 gtk_sctree_sort_recursive(GTK_CTREE(clist), NULL);
3829 clist->focus_row = -1;
3830 gtk_clist_thaw(clist);
3834 * Call back function to free adaptor. Call back is setup by function
3835 * gtk_ctree_node_set_row_data_full() when node is populated. This function is
3836 * called when the address book tree widget node is removed by calling
3837 * function gtk_ctree_remove_node().
3839 * \param data Tree node's row data.
3841 static void addressbook_free_treenode( gpointer data ) {
3844 ao = ( AddressObject * ) data;
3845 if( ao == NULL ) return;
3846 if( ao->type == ADDR_INTERFACE ) {
3847 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3848 addrbookctl_free_interface( ai );
3850 else if( ao->type == ADDR_DATASOURCE ) {
3851 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3852 addrbookctl_free_datasource( ads );
3854 else if( ao->type == ADDR_ITEM_FOLDER ) {
3855 AdapterFolder *af = ADAPTER_FOLDER(ao);
3856 addrbookctl_free_folder( af );
3858 else if( ao->type == ADDR_ITEM_GROUP ) {
3859 AdapterGroup *ag = ADAPTER_GROUP(ao);
3860 addrbookctl_free_group( ag );
3865 * Create new adaptor for specified data source.
3867 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3868 AddressObjectType otype, gchar *name )
3870 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3871 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3872 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3873 adapter->dataSource = ds;
3874 adapter->subType = otype;
3878 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3879 ADDRESS_OBJECT_NAME(adapter) =
3880 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3884 * Load tree from address index with the initial data.
3886 static void addressbook_load_tree( void ) {
3887 GtkCTree *ctree = GTK_CTREE( addrbook.ctree );
3888 GList *nodeIf, *nodeDS;
3889 AdapterInterface *adapter;
3890 AddressInterface *iface;
3891 AddressTypeControlItem *atci;
3892 AddressDataSource *ds;
3893 AdapterDSource *ads;
3894 GtkCTreeNode *node, *newNode;
3897 nodeIf = _addressInterfaceList_;
3899 adapter = nodeIf->data;
3900 node = adapter->treeNode;
3901 iface = adapter->interface;
3902 atci = adapter->atci;
3904 if( iface->useInterface ) {
3905 /* Load data sources below interface node */
3906 nodeDS = iface->listSource;
3910 name = addrindex_ds_get_name( ds );
3911 ads = addressbook_create_ds_adapter(
3912 ds, atci->objectType, name );
3913 newNode = addressbook_add_object(
3914 node, ADDRESS_OBJECT(ads) );
3915 nodeDS = g_list_next( nodeDS );
3917 gtk_ctree_expand( ctree, node );
3920 nodeIf = g_list_next( nodeIf );
3925 * Convert the old address book to new format.
3927 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
3928 gboolean retVal = FALSE;
3929 gboolean errFlag = TRUE;
3932 /* Read old address book, performing conversion */
3933 debug_print( "Reading and converting old address book...\n" );
3934 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
3935 addrindex_read_data( addrIndex );
3936 if( addrIndex->retVal == MGU_NO_FILE ) {
3937 /* We do not have a file - new user */
3938 debug_print( "New user... create new books...\n" );
3939 addrindex_create_new_books( addrIndex );
3940 if( addrIndex->retVal == MGU_SUCCESS ) {
3941 /* Save index file */
3942 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3943 addrindex_save_data( addrIndex );
3944 if( addrIndex->retVal == MGU_SUCCESS ) {
3949 msg = _( "New user, could not save index file." );
3953 msg = _( "New user, could not save address book files." );
3957 /* We have an old file */
3958 if( addrIndex->wasConverted ) {
3959 /* Converted successfully - save address index */
3960 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3961 addrindex_save_data( addrIndex );
3962 if( addrIndex->retVal == MGU_SUCCESS ) {
3963 msg = _( "Old address book converted successfully." );
3968 msg = _("Old address book converted,\n"
3969 "could not save new address index file." );
3973 /* File conversion failed - just create new books */
3974 debug_print( "File conversion failed... just create new books...\n" );
3975 addrindex_create_new_books( addrIndex );
3976 if( addrIndex->retVal == MGU_SUCCESS ) {
3978 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
3979 addrindex_save_data( addrIndex );
3980 if( addrIndex->retVal == MGU_SUCCESS ) {
3981 msg = _("Could not convert address book,\n"
3982 "but created empty new address book files." );
3987 msg = _("Could not convert address book,\n"
3988 "could not save new address index file." );
3992 msg = _("Could not convert address book\n"
3993 "and could not create new address book files." );
3998 debug_print( "Error\n%s\n", msg );
3999 alertpanel_full(_("Addressbook conversion error"), msg,
4000 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4001 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4004 debug_print( "Warning\n%s\n", msg );
4005 alertpanel_full(_("Addressbook conversion error"), msg,
4006 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4007 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4013 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4017 gboolean failed = FALSE;
4019 if( ( dp = opendir( origdir ) ) == NULL ) {
4023 while( ( d = readdir( dp ) ) != NULL ) {
4024 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4027 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4029 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4031 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4044 /* all copies succeeded, we can remove source files */
4045 if( ( dp = opendir( origdir ) ) == NULL ) {
4048 while( ( d = readdir( dp ) ) != NULL ) {
4049 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4052 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4054 claws_unlink(orig_file);
4064 void addressbook_read_file( void ) {
4065 AddressIndex *addrIndex = NULL;
4066 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4068 debug_print( "Reading address index...\n" );
4069 if( _addressIndex_ ) {
4070 debug_print( "address book already read!!!\n" );
4074 addrIndex = addrindex_create_index();
4075 addrindex_initialize();
4077 /* Use new address book index. */
4079 if ( !is_dir_exist(indexdir) ) {
4080 if ( make_dir(indexdir) < 0 ) {
4081 addrindex_set_file_path( addrIndex, get_rc_dir() );
4082 g_warning( "couldn't create dir %s\n", indexdir);
4084 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4085 remove_dir_recursive(indexdir);
4086 addrindex_set_file_path( addrIndex, get_rc_dir() );
4087 g_error("couldn't migrate dir %s", indexdir);
4089 addrindex_set_file_path( addrIndex, indexdir);
4093 addrindex_set_file_path( addrIndex, indexdir);
4096 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4097 addrindex_read_data( addrIndex );
4098 if( addrIndex->retVal == MGU_NO_FILE ) {
4099 /* Conversion required */
4100 debug_print( "Converting...\n" );
4101 if( addressbook_convert( addrIndex ) ) {
4102 _addressIndex_ = addrIndex;
4105 else if( addrIndex->retVal == MGU_SUCCESS ) {
4106 _addressIndex_ = addrIndex;
4109 /* Error reading address book */
4110 debug_print( "Could not read address index.\n" );
4111 addrindex_print_index( addrIndex, stdout );
4112 alertpanel_full(_("Addressbook Error"),
4113 _("Could not read address index"),
4114 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4115 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4117 debug_print( "done.\n" );
4121 * Add object into the address index tree widget.
4122 * Enter: node Parent node.
4123 * obj Object to add.
4124 * Return: Node that was added, or NULL if object not added.
4126 static GtkCTreeNode *addressbook_add_object(GtkCTreeNode *node,
4129 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4130 GtkCTreeNode *added;
4131 AddressObject *pobj;
4132 AddressObjectType otype;
4133 AddressTypeControlItem *atci = NULL;
4135 g_return_val_if_fail(node != NULL, NULL);
4136 g_return_val_if_fail(obj != NULL, NULL);
4138 pobj = gtk_ctree_node_get_row_data(ctree, node);
4139 g_return_val_if_fail(pobj != NULL, NULL);
4141 /* Determine object type to be displayed */
4142 if( obj->type == ADDR_DATASOURCE ) {
4143 otype = ADAPTER_DSOURCE(obj)->subType;
4149 /* Handle any special conditions. */
4151 atci = addrbookctl_lookup( otype );
4153 if( atci->showInTree ) {
4154 /* Add object to tree */
4157 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4158 atci->iconXpm, atci->maskXpm, atci->iconXpmOpen, atci->maskXpmOpen,
4159 atci->treeLeaf, atci->treeExpand );
4160 gtk_ctree_node_set_row_data_full( ctree, added, obj,
4161 addressbook_free_treenode );
4165 gtk_sctree_sort_node(ctree, node);
4171 * Add group into the address index tree.
4172 * \param node Parent node.
4173 * \param ds Data source.
4174 * \param itemGroup Group to add.
4175 * \return Inserted node.
4177 static GtkCTreeNode *addressbook_node_add_group(
4178 GtkCTreeNode *node, AddressDataSource *ds,
4179 ItemGroup *itemGroup )
4181 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4182 GtkCTreeNode *newNode;
4183 AdapterGroup *adapter;
4184 AddressTypeControlItem *atci = NULL;
4187 if( ds == NULL ) return NULL;
4188 if( node == NULL || itemGroup == NULL ) return NULL;
4190 name = &itemGroup->obj.name;
4192 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4194 adapter = g_new0( AdapterGroup, 1 );
4195 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4196 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4197 adapter->itemGroup = itemGroup;
4199 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4200 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4201 atci->treeLeaf, atci->treeExpand );
4202 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4203 addressbook_free_treenode );
4204 gtk_sctree_sort_node( ctree, node );
4209 * Add folder into the address index tree. Only visible folders are loaded into
4210 * the address index tree. Note that the root folder is not inserted into the
4213 * \param node Parent node.
4214 * \param ds Data source.
4215 * \param itemFolder Folder to add.
4216 * \param otype Object type to display.
4217 * \return Inserted node for the folder.
4219 static GtkCTreeNode *addressbook_node_add_folder(
4220 GtkCTreeNode *node, AddressDataSource *ds,
4221 ItemFolder *itemFolder, AddressObjectType otype )
4223 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
4224 GtkCTreeNode *newNode = NULL;
4225 AdapterFolder *adapter;
4226 AddressTypeControlItem *atci = NULL;
4227 GList *listItems = NULL;
4229 ItemFolder *rootFolder;
4231 /* Only visible folders */
4232 if( itemFolder->isHidden ) return NULL;
4234 if( ds == NULL ) return NULL;
4235 if( node == NULL || itemFolder == NULL ) return NULL;
4237 /* Determine object type */
4238 atci = addrbookctl_lookup( otype );
4239 if( atci == NULL ) return NULL;
4241 rootFolder = addrindex_ds_get_root_folder( ds );
4242 if( itemFolder == rootFolder ) {
4246 adapter = g_new0( AdapterFolder, 1 );
4247 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4248 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4249 adapter->itemFolder = itemFolder;
4251 name = ADDRITEM_NAME(itemFolder);
4252 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4253 atci->iconXpm, atci->maskXpm, atci->iconXpm, atci->maskXpm,
4254 atci->treeLeaf, atci->treeExpand );
4256 gtk_ctree_node_set_row_data_full( ctree, newNode, adapter,
4257 addressbook_free_treenode );
4261 listItems = itemFolder->listFolder;
4262 while( listItems ) {
4263 ItemFolder *item = listItems->data;
4264 addressbook_node_add_folder( newNode, ds, item, otype );
4265 listItems = g_list_next( listItems );
4267 listItems = itemFolder->listGroup;
4268 while( listItems ) {
4269 ItemGroup *item = listItems->data;
4270 addressbook_node_add_group( newNode, ds, item );
4271 listItems = g_list_next( listItems );
4273 gtk_sctree_sort_node( ctree, node );
4277 void addressbook_export_to_file( void ) {
4278 if( _addressIndex_ ) {
4279 /* Save all new address book data */
4280 debug_print( "Saving address books...\n" );
4281 addrindex_save_all_books( _addressIndex_ );
4283 debug_print( "Exporting addressbook to file...\n" );
4284 addrindex_save_data( _addressIndex_ );
4285 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4286 addrindex_print_index( _addressIndex_, stdout );
4289 /* Notify address completion of new data */
4290 invalidate_address_completion();
4294 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4296 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4297 addressbook_lup_clicked(NULL, NULL);
4302 * Comparison using cell contents (text in first column). Used for sort
4303 * address index widget.
4305 static gint addressbook_treenode_compare_func(
4306 GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4308 GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
4309 GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
4310 gchar *name1 = NULL, *name2 = NULL;
4311 if( cell1 ) name1 = cell1->u.text;
4312 if( cell2 ) name2 = cell2->u.text;
4313 if( ! name1 ) return ( name2 != NULL );
4314 if( ! name2 ) return -1;
4315 return g_utf8_collate( name1, name2 );
4318 static void addressbook_new_book_cb( gpointer data, guint action, GtkWidget *widget ) {
4319 AdapterDSource *ads;
4320 AdapterInterface *adapter;
4321 GtkCTreeNode *newNode;
4323 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4324 if( adapter == NULL ) return;
4325 ads = addressbook_edit_book( _addressIndex_, NULL );
4327 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4329 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4330 addrbook.treeSelected = newNode;
4335 static void addressbook_new_vcard_cb( gpointer data, guint action, GtkWidget *widget ) {
4336 AdapterDSource *ads;
4337 AdapterInterface *adapter;
4338 GtkCTreeNode *newNode;
4340 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4341 if( adapter == NULL ) return;
4342 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4344 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4346 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4347 addrbook.treeSelected = newNode;
4353 static void addressbook_new_jpilot_cb( gpointer data, guint action, GtkWidget *widget ) {
4354 AdapterDSource *ads;
4355 AdapterInterface *adapter;
4356 AddressInterface *iface;
4357 GtkCTreeNode *newNode;
4359 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4360 if( adapter == NULL ) return;
4361 iface = adapter->interface;
4362 if( ! iface->haveLibrary ) return;
4363 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4365 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4367 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4368 addrbook.treeSelected = newNode;
4375 static void addressbook_new_ldap_cb( gpointer data, guint action, GtkWidget *widget ) {
4376 AdapterDSource *ads;
4377 AdapterInterface *adapter;
4378 AddressInterface *iface;
4379 GtkCTreeNode *newNode;
4381 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4382 if( adapter == NULL ) return;
4383 iface = adapter->interface;
4384 if( ! iface->haveLibrary ) return;
4385 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4387 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4389 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4390 addrbook.treeSelected = newNode;
4397 * Display address search status message.
4398 * \param queryType Query type.
4399 * \param status Status/Error code.
4401 static void addressbook_search_message( gint queryType, gint sts ) {
4403 *addressbook_msgbuf = '\0';
4405 if( sts != MGU_SUCCESS ) {
4406 if( queryType == ADDRQUERY_LDAP ) {
4408 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4413 g_snprintf( addressbook_msgbuf,
4414 sizeof(addressbook_msgbuf), "%s", desc );
4415 addressbook_status_show( addressbook_msgbuf );
4418 addressbook_status_show( "" );
4423 * Refresh addressbook by forcing refresh of current selected object in
4426 static void addressbook_refresh_current( void ) {
4430 ctree = GTK_CTREE(addrbook.ctree);
4431 obj = gtk_ctree_node_get_row_data( ctree, addrbook.treeSelected );
4432 if( obj == NULL ) return;
4433 addressbook_set_clist( obj, TRUE );
4437 * Message that is displayed whilst a query is executing in a background
4440 static gchar *_tempMessage_ = N_( "Busy searching..." );
4443 * Address search idle function. This function is called during UI idle time
4444 * while a search is in progress.
4446 * \param data Idler data.
4448 static void addressbook_search_idle( gpointer data ) {
4452 queryID = GPOINTER_TO_INT( data );
4453 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4458 * Search completion callback function. This removes the query from the idle
4461 * \param sender Sender of query.
4462 * \param queryID Query ID of search request.
4463 * \param status Search status.
4464 * \param data Query data.
4466 static void addressbook_search_callback_end(
4467 gpointer sender, gint queryID, gint status, gpointer data )
4471 AddrQueryObject *aqo;
4473 /* Remove idler function */
4474 ptrQID = GINT_TO_POINTER( queryID );
4476 g_idle_remove_by_data( ptrQID );
4479 /* Refresh addressbook contents */
4480 addressbook_refresh_current();
4481 req = qrymgr_find_request( queryID );
4483 aqo = ( AddrQueryObject * ) req->queryList->data;
4484 addressbook_search_message( aqo->queryType, status );
4487 /* Stop the search */
4488 addrindex_stop_search( queryID );
4494 * \param ds Data source to search.
4495 * \param searchTerm String to lookup.
4496 * \param pNode Parent data source node.
4498 static void addressbook_perform_search(
4499 AddressDataSource *ds, gchar *searchTerm,
4500 GtkCTreeNode *pNode )
4502 AddrBookBase *adbase;
4503 AddressCache *cache;
4509 AddressObjectType aoType = ADDR_NONE;
4513 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4515 if( ds && ds->type == ADDR_IF_LDAP ) {
4517 aoType = ADDR_LDAP_QUERY;
4523 /* Get reference to address cache */
4524 adbase = ( AddrBookBase * ) ds->rawDataSource;
4525 cache = adbase->addressCache;
4527 /* Create a folder for the search results */
4528 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4529 folder = addressbook_setup_subf(ds, name, pNode);
4532 /* Setup the search */
4533 queryID = addrindex_setup_explicit_search(
4534 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4535 if( queryID == 0 ) return;
4537 /* Set up idler function */
4538 idleID = g_idle_add(
4539 ( GtkFunction ) addressbook_search_idle,
4540 GINT_TO_POINTER( queryID ) );
4542 /* Start search, sit back and wait for something to happen */
4543 addrindex_start_search( queryID );
4545 addressbook_status_show( _tempMessage_ );
4549 * Lookup button handler. Address search is only performed against
4550 * address interfaces for external queries.
4552 * \param button Lookup button widget.
4553 * \param data Data object.
4555 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4558 AddressDataSource *ds;
4559 AddressInterface *iface;
4561 GtkCTreeNode *node, *parentNode;
4563 node = addrbook.treeSelected;
4564 if( ! node ) return;
4565 if( GTK_CTREE_ROW(node)->level == 1 ) return;
4567 ctree = GTK_CTREE(addrbook.ctree);
4568 obj = gtk_ctree_node_get_row_data( ctree, node );
4569 if( obj == NULL ) return;
4571 ds = addressbook_find_datasource( node );
4572 if( ds == NULL ) return;
4574 /* We must have a datasource that is an external interface */
4575 iface = ds->interface;
4576 if( ! iface->haveLibrary ) return;
4577 if( ! iface->externalQuery ) return;
4580 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4581 g_strchomp( searchTerm );
4583 if( obj->type == ADDR_ITEM_FOLDER ) {
4584 parentNode = GTK_CTREE_ROW(node)->parent;
4589 addressbook_perform_search( ds, searchTerm, parentNode );
4591 gtk_widget_grab_focus( addrbook.entry );
4593 g_free( searchTerm );
4596 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4597 addressbook_close();
4602 * Browse address entry for highlighted entry.
4604 static void addressbook_browse_entry_cb(void)
4606 GtkCTree *clist = GTK_CTREE(addrbook.clist);
4608 AddressDataSource *ds;
4609 AddressInterface *iface;
4613 if(addrbook.listSelected == NULL)
4616 obj = gtk_ctree_node_get_row_data(clist, addrbook.listSelected);
4620 ds = addressbook_find_datasource(GTK_CTREE_NODE(addrbook.treeSelected));
4624 iface = ds->interface;
4625 if(! iface->haveLibrary )
4629 if (obj->type == ADDR_ITEM_EMAIL) {
4630 email = ( ItemEMail * ) obj;
4634 person = (ItemPerson *) ADDRITEM_PARENT(email);
4636 else if (obj->type == ADDR_ITEM_PERSON) {
4637 person = (ItemPerson *) obj;
4644 if( iface && iface->type == ADDR_IF_LDAP ) {
4645 browseldap_entry(ds, person->externalID);
4650 /* **********************************************************************
4651 * Build lookup tables.
4652 * ***********************************************************************
4656 * Remap object types.
4657 * Enter: abType AddressObjectType (used in tree node).
4658 * Return: ItemObjectType (used in address cache data).
4660 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4661 ItemObjectType ioType;
4664 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4665 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4666 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4667 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4668 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4669 default: ioType = ITEMTYPE_NONE; break;
4675 * Build table that controls the rendering of object types.
4677 static void addrbookctl_build_map( GtkWidget *window ) {
4678 AddressTypeControlItem *atci;
4681 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
4682 stock_pixmap_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
4683 stock_pixmap_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm, &groupxpmmask);
4684 stock_pixmap_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm, &vcardxpmmask);
4685 stock_pixmap_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm, &bookxpmmask);
4686 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm, &addressxpmmask);
4687 stock_pixmap_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm, &jpilotxpmmask);
4688 stock_pixmap_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm, &categoryxpmmask);
4689 stock_pixmap_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm, &ldapxpmmask);
4690 stock_pixmap_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm, &addrsearchxpmmask);
4692 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4693 _addressBookTypeList_ = NULL;
4696 atci = g_new0( AddressTypeControlItem, 1 );
4697 atci->objectType = ADDR_INTERFACE;
4698 atci->interfaceType = ADDR_IF_NONE;
4699 atci->showInTree = TRUE;
4700 atci->treeExpand = TRUE;
4701 atci->treeLeaf = FALSE;
4702 atci->displayName = _( "Interface" );
4703 atci->iconXpm = folderxpm;
4704 atci->maskXpm = folderxpmmask;
4705 atci->iconXpmOpen = folderopenxpm;
4706 atci->maskXpmOpen = folderopenxpmmask;
4707 atci->menuCommand = NULL;
4708 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4709 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4712 atci = g_new0( AddressTypeControlItem, 1 );
4713 atci->objectType = ADDR_BOOK;
4714 atci->interfaceType = ADDR_IF_BOOK;
4715 atci->showInTree = TRUE;
4716 atci->treeExpand = TRUE;
4717 atci->treeLeaf = FALSE;
4718 atci->displayName = _( "Address Book" );
4719 atci->iconXpm = bookxpm;
4720 atci->maskXpm = bookxpmmask;
4721 atci->iconXpmOpen = bookxpm;
4722 atci->maskXpmOpen = bookxpmmask;
4723 atci->menuCommand = "/Book/New Book";
4724 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4725 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4728 atci = g_new0( AddressTypeControlItem, 1 );
4729 atci->objectType = ADDR_ITEM_PERSON;
4730 atci->interfaceType = ADDR_IF_NONE;
4731 atci->showInTree = FALSE;
4732 atci->treeExpand = FALSE;
4733 atci->treeLeaf = FALSE;
4734 atci->displayName = _( "Person" );
4735 atci->iconXpm = NULL;
4736 atci->maskXpm = NULL;
4737 atci->iconXpmOpen = NULL;
4738 atci->maskXpmOpen = NULL;
4739 atci->menuCommand = NULL;
4740 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4741 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4744 atci = g_new0( AddressTypeControlItem, 1 );
4745 atci->objectType = ADDR_ITEM_EMAIL;
4746 atci->interfaceType = ADDR_IF_NONE;
4747 atci->showInTree = FALSE;
4748 atci->treeExpand = FALSE;
4749 atci->treeLeaf = TRUE;
4750 atci->displayName = _( "Email Address" );
4751 atci->iconXpm = addressxpm;
4752 atci->maskXpm = addressxpmmask;
4753 atci->iconXpmOpen = addressxpm;
4754 atci->maskXpmOpen = addressxpmmask;
4755 atci->menuCommand = NULL;
4756 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4757 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4760 atci = g_new0( AddressTypeControlItem, 1 );
4761 atci->objectType = ADDR_ITEM_GROUP;
4762 atci->interfaceType = ADDR_IF_BOOK;
4763 atci->showInTree = TRUE;
4764 atci->treeExpand = FALSE;
4765 atci->treeLeaf = FALSE;
4766 atci->displayName = _( "Group" );
4767 atci->iconXpm = groupxpm;
4768 atci->maskXpm = groupxpmmask;
4769 atci->iconXpmOpen = groupxpm;
4770 atci->maskXpmOpen = groupxpmmask;
4771 atci->menuCommand = NULL;
4772 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4773 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4776 atci = g_new0( AddressTypeControlItem, 1 );
4777 atci->objectType = ADDR_ITEM_FOLDER;
4778 atci->interfaceType = ADDR_IF_BOOK;
4779 atci->showInTree = TRUE;
4780 atci->treeExpand = FALSE;
4781 atci->treeLeaf = FALSE;
4782 atci->displayName = _( "Folder" );
4783 atci->iconXpm = folderxpm;
4784 atci->maskXpm = folderxpmmask;
4785 atci->iconXpmOpen = folderopenxpm;
4786 atci->maskXpmOpen = folderopenxpmmask;
4787 atci->menuCommand = NULL;
4788 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4789 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4792 atci = g_new0( AddressTypeControlItem, 1 );
4793 atci->objectType = ADDR_VCARD;
4794 atci->interfaceType = ADDR_IF_VCARD;
4795 atci->showInTree = TRUE;
4796 atci->treeExpand = TRUE;
4797 atci->treeLeaf = TRUE;
4798 atci->displayName = _( "vCard" );
4799 atci->iconXpm = vcardxpm;
4800 atci->maskXpm = vcardxpmmask;
4801 atci->iconXpmOpen = vcardxpm;
4802 atci->maskXpmOpen = vcardxpmmask;
4803 atci->menuCommand = "/Book/New vCard";
4804 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4805 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4808 atci = g_new0( AddressTypeControlItem, 1 );
4809 atci->objectType = ADDR_JPILOT;
4810 atci->interfaceType = ADDR_IF_JPILOT;
4811 atci->showInTree = TRUE;
4812 atci->treeExpand = TRUE;
4813 atci->treeLeaf = FALSE;
4814 atci->displayName = _( "JPilot" );
4815 atci->iconXpm = jpilotxpm;
4816 atci->maskXpm = jpilotxpmmask;
4817 atci->iconXpmOpen = jpilotxpm;
4818 atci->maskXpmOpen = jpilotxpmmask;
4819 atci->menuCommand = "/Book/New JPilot";
4820 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4821 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4824 atci = g_new0( AddressTypeControlItem, 1 );
4825 atci->objectType = ADDR_CATEGORY;
4826 atci->interfaceType = ADDR_IF_JPILOT;
4827 atci->showInTree = TRUE;
4828 atci->treeExpand = TRUE;
4829 atci->treeLeaf = TRUE;
4830 atci->displayName = _( "JPilot" );
4831 atci->iconXpm = categoryxpm;
4832 atci->maskXpm = categoryxpmmask;
4833 atci->iconXpmOpen = categoryxpm;
4834 atci->maskXpmOpen = categoryxpmmask;
4835 atci->menuCommand = NULL;
4836 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4837 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4840 atci = g_new0( AddressTypeControlItem, 1 );
4841 atci->objectType = ADDR_LDAP;
4842 atci->interfaceType = ADDR_IF_LDAP;
4843 atci->showInTree = TRUE;
4844 atci->treeExpand = TRUE;
4845 atci->treeLeaf = FALSE;
4846 atci->displayName = _( "LDAP servers" );
4847 atci->iconXpm = ldapxpm;
4848 atci->maskXpm = ldapxpmmask;
4849 atci->iconXpmOpen = ldapxpm;
4850 atci->maskXpmOpen = ldapxpmmask;
4851 atci->menuCommand = "/Book/New LDAP Server";
4852 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4853 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4856 atci = g_new0( AddressTypeControlItem, 1 );
4857 atci->objectType = ADDR_LDAP_QUERY;
4858 atci->interfaceType = ADDR_IF_LDAP;
4859 atci->showInTree = TRUE;
4860 atci->treeExpand = FALSE;
4861 atci->treeLeaf = TRUE;
4862 atci->displayName = _( "LDAP Query" );
4863 atci->iconXpm = addrsearchxpm;
4864 atci->maskXpm = addrsearchxpmmask;
4865 atci->iconXpmOpen = addrsearchxpm;
4866 atci->maskXpmOpen = addrsearchxpmmask;
4867 atci->menuCommand = NULL;
4868 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4869 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4874 * Search for specified object type.
4876 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4878 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4882 * Search for specified interface type.
4884 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4885 GList *node = _addressBookTypeList_;
4887 AddressTypeControlItem *atci = node->data;
4888 if( atci->interfaceType == ifType ) return atci;
4889 node = g_list_next( node );
4894 static void addrbookctl_free_address( AddressObject *obj ) {
4895 g_free( obj->name );
4896 obj->type = ADDR_NONE;
4900 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4901 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4902 adapter->interface = NULL;
4903 adapter->interfaceType = ADDR_IF_NONE;
4904 adapter->atci = NULL;
4905 adapter->enabled = FALSE;
4906 adapter->haveLibrary = FALSE;
4907 adapter->treeNode = NULL;
4911 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4912 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4913 adapter->dataSource = NULL;
4914 adapter->subType = ADDR_NONE;
4918 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4919 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4920 adapter->itemFolder = NULL;
4924 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4925 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4926 adapter->itemGroup = NULL;
4931 * Build GUI interface list.
4933 static void addrbookctl_build_iflist( void ) {
4934 AddressTypeControlItem *atci;
4935 AdapterInterface *adapter;
4938 if( _addressIndex_ == NULL ) {
4939 _addressIndex_ = addrindex_create_index();
4940 if( _clipBoard_ == NULL ) {
4941 _clipBoard_ = addrclip_create();
4943 addrclip_set_index( _clipBoard_, _addressIndex_ );
4945 _addressInterfaceList_ = NULL;
4946 list = addrindex_get_interface_list( _addressIndex_ );
4948 AddressInterface *interface = list->data;
4949 atci = addrbookctl_lookup_iface( interface->type );
4951 adapter = g_new0( AdapterInterface, 1 );
4952 adapter->interfaceType = interface->type;
4953 adapter->atci = atci;
4954 adapter->interface = interface;
4955 adapter->treeNode = NULL;
4956 adapter->enabled = TRUE;
4957 adapter->haveLibrary = interface->haveLibrary;
4958 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
4959 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
4960 _addressInterfaceList_ =
4961 g_list_append( _addressInterfaceList_, adapter );
4963 list = g_list_next( list );
4968 * Find GUI interface type specified interface type.
4969 * \param ifType Interface type.
4970 * \return Interface item, or NULL if not found.
4972 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
4973 GList *node = _addressInterfaceList_;
4975 AdapterInterface *adapter = node->data;
4976 if( adapter->interfaceType == ifType ) return adapter;
4977 node = g_list_next( node );
4983 * Build interface list selection.
4985 static void addrbookctl_build_ifselect( void ) {
4986 GList *newList = NULL;
4991 gchar *endptr = NULL;
4993 AdapterInterface *adapter;
4995 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
4998 splitStr = g_strsplit( selectStr, ",", -1 );
4999 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5001 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5002 ifType = strtol( splitStr[i], &endptr, 10 );
5005 if( strcmp( endptr, "/n" ) == 0 ) {
5009 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5010 adapter = addrbookctl_find_interface( ifType );
5012 newList = g_list_append( newList, adapter );
5019 /* g_print( "i=%d\n", i ); */
5020 g_strfreev( splitStr );
5021 g_free( selectStr );
5023 /* Replace existing list */
5024 mgu_clear_list( _addressIFaceSelection_ );
5025 g_list_free( _addressIFaceSelection_ );
5026 _addressIFaceSelection_ = newList;
5030 /* ***********************************************************************
5031 * Add sender to address book.
5032 * ***********************************************************************
5036 * This function is used by the Add sender to address book function.
5038 gboolean addressbook_add_contact(
5039 const gchar *name, const gchar *address, const gchar *remarks,
5040 GdkPixbuf *picture )
5042 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5043 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5044 debug_print( "addressbook_add_contact - added\n" );
5045 addressbook_refresh();
5050 /* ***********************************************************************
5051 * Book/folder selection.
5052 * ***********************************************************************
5056 * This function is used by the matcher dialog to select a book/folder.
5058 gchar *addressbook_folder_selection( const gchar *folderpath)
5060 AddressBookFile *book = NULL;
5061 ItemFolder *folder = NULL;
5064 g_return_val_if_fail( folderpath != NULL, NULL);
5066 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5068 if ( folder != NULL) {
5070 gchar *oldtmp = NULL;
5071 AddrItemObject *obj = NULL;
5073 /* walk thru folder->parent to build the full folder path */
5074 /* TODO: wwp: optimize this */
5076 tmp = g_strdup(obj->uid);
5077 while ( obj->parent ) {
5079 if ( obj->name != NULL ) {
5080 oldtmp = g_strdup(tmp);
5082 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5086 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5089 path = g_strdup_printf("%s", book->fileName);
5091 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5097 /* ***********************************************************************
5098 * Book/folder checking.
5099 * ***********************************************************************
5102 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5104 FolderInfo *fi = g_new0( FolderInfo, 1 );
5106 fi->folder = folder;
5110 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5111 FolderInfo *fiParent, FolderPathMatch *match )
5117 FolderPathMatch *nextmatch = NULL;
5122 list = parentFolder->listFolder;
5124 folder = list->data;
5125 fName = g_strdup( ADDRITEM_NAME(folder) );
5127 /* match folder name, match pointer will be set to NULL if next recursive call
5128 doesn't need to match subfolder name */
5129 if ( match != NULL &&
5130 match->matched == FALSE ) {
5131 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5132 /* folder name matches, prepare next subfolder match */
5133 debug_print("matched folder name '%s'\n", fName);
5135 if ( match->folder_path[match->index] == NULL ) {
5136 /* we've matched all elements */
5137 match->matched = TRUE;
5138 match->folder = folder;
5139 debug_print("book/folder path matched!\n");
5141 /* keep on matching */
5149 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5150 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5152 list = g_list_next( list );
5157 * This function is used by to check if a matcher book/folder path corresponds to an
5158 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5159 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5160 if book AND folder are NULL this means that folderpath was empty or Any.
5161 If folderpath is a simple book name (without folder), book will not be NULL and folder
5162 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5165 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5166 AddressDataSource **book,
5167 ItemFolder **folder )
5169 AddressDataSource *ds;
5170 GList *list, *nodeDS;
5171 ItemFolder *rootFolder;
5172 AddressBookFile *abf;
5174 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5181 if ( folderpath == NULL )
5184 if ( strcasecmp(folderpath, _("Any")) == 0 || *folderpath == '\0' )
5187 /* split the folder path we've received, we'll try to match this path, subpath by
5188 subpath against the book/folder structure in order */
5189 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5190 if (!folder_path_match.folder_path)
5193 list = addrindex_get_interface_list( _addressIndex_ );
5194 while ( list && !folder_path_match.matched ) {
5195 AddressInterface *interface = list->data;
5196 if ( interface && interface->type == ADDR_IF_BOOK ) {
5197 nodeDS = interface->listSource;
5198 while ( nodeDS && !folder_path_match.matched ) {
5201 /* Read address book */
5202 if( ! addrindex_ds_get_read_flag( ds ) ) {
5203 addrindex_ds_read_data( ds );
5206 /* Add node for address book */
5207 abf = ds->rawDataSource;
5209 /* match book name */
5210 if ( abf && abf->fileName &&
5211 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5213 debug_print("matched book name '%s'\n", abf->fileName);
5214 folder_path_match.book = ds;
5216 if ( folder_path_match.folder_path[1] == NULL ) {
5217 /* no folder part to match */
5219 folder_path_match.matched = TRUE;
5220 folder_path_match.folder = NULL;
5221 debug_print("book path matched!\n");
5224 /* match folder part */
5226 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5227 rootFolder = addrindex_ds_get_root_folder( ds );
5229 /* prepare for recursive call */
5230 folder_path_match.index = 1;
5231 /* this call will set folder_path_match.matched and folder_path_match.folder */
5232 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5237 nodeDS = g_list_next( nodeDS );
5240 list = g_list_next( list );
5243 g_strfreev( folder_path_match.folder_path );
5246 *book = folder_path_match.book;
5248 *folder = folder_path_match.folder;
5249 return folder_path_match.matched;
5253 /* **********************************************************************
5255 * ***********************************************************************
5261 static void addressbook_import_ldif_cb( void ) {
5262 AddressDataSource *ds = NULL;
5263 AdapterDSource *ads = NULL;
5264 AddressBookFile *abf = NULL;
5265 AdapterInterface *adapter;
5266 GtkCTreeNode *newNode;
5268 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5270 if( adapter->treeNode ) {
5271 abf = addressbook_imp_ldif( _addressIndex_ );
5273 ds = addrindex_index_add_datasource(
5274 _addressIndex_, ADDR_IF_BOOK, abf );
5275 ads = addressbook_create_ds_adapter(
5276 ds, ADDR_BOOK, NULL );
5277 addressbook_ads_set_name(
5278 ads, addrbook_get_name( abf ) );
5279 newNode = addressbook_add_object(
5281 ADDRESS_OBJECT(ads) );
5283 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5285 addrbook.treeSelected = newNode;
5288 /* Notify address completion */
5289 invalidate_address_completion();
5298 static void addressbook_import_mutt_cb( void ) {
5299 AddressDataSource *ds = NULL;
5300 AdapterDSource *ads = NULL;
5301 AddressBookFile *abf = NULL;
5302 AdapterInterface *adapter;
5303 GtkCTreeNode *newNode;
5305 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5307 if( adapter->treeNode ) {
5308 abf = addressbook_imp_mutt( _addressIndex_ );
5310 ds = addrindex_index_add_datasource(
5311 _addressIndex_, ADDR_IF_BOOK, abf );
5312 ads = addressbook_create_ds_adapter(
5313 ds, ADDR_BOOK, NULL );
5314 addressbook_ads_set_name(
5315 ads, addrbook_get_name( abf ) );
5316 newNode = addressbook_add_object(
5318 ADDRESS_OBJECT(ads) );
5320 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5322 addrbook.treeSelected = newNode;
5325 /* Notify address completion */
5326 invalidate_address_completion();
5335 static void addressbook_import_pine_cb( void ) {
5336 AddressDataSource *ds = NULL;
5337 AdapterDSource *ads = NULL;
5338 AddressBookFile *abf = NULL;
5339 AdapterInterface *adapter;
5340 GtkCTreeNode *newNode;
5342 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5344 if( adapter->treeNode ) {
5345 abf = addressbook_imp_pine( _addressIndex_ );
5347 ds = addrindex_index_add_datasource(
5348 _addressIndex_, ADDR_IF_BOOK, abf );
5349 ads = addressbook_create_ds_adapter(
5350 ds, ADDR_BOOK, NULL );
5351 addressbook_ads_set_name(
5352 ads, addrbook_get_name( abf ) );
5353 newNode = addressbook_add_object(
5355 ADDRESS_OBJECT(ads) );
5357 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5359 addrbook.treeSelected = newNode;
5362 /* Notify address completion */
5363 invalidate_address_completion();
5370 * Harvest addresses.
5371 * \param folderItem Folder to import.
5372 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5373 * \param msgList List of message numbers, or NULL to process folder.
5375 void addressbook_harvest(
5376 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5378 AddressDataSource *ds = NULL;
5379 AdapterDSource *ads = NULL;
5380 AddressBookFile *abf = NULL;
5381 AdapterInterface *adapter;
5382 GtkCTreeNode *newNode;
5384 abf = addrgather_dlg_execute(
5385 folderItem, _addressIndex_, sourceInd, msgList );
5387 ds = addrindex_index_add_datasource(
5388 _addressIndex_, ADDR_IF_BOOK, abf );
5390 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5392 if( adapter->treeNode ) {
5393 ads = addressbook_create_ds_adapter(
5394 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5395 newNode = addressbook_add_object(
5397 ADDRESS_OBJECT(ads) );
5401 /* Notify address completion */
5402 invalidate_address_completion();
5409 static void addressbook_export_html_cb( void ) {
5410 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5412 AddressDataSource *ds = NULL;
5413 AddrBookBase *adbase;
5414 AddressCache *cache;
5415 GtkCTreeNode *node = NULL;
5417 if( ! addrbook.treeSelected ) return;
5418 node = addrbook.treeSelected;
5419 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5420 obj = gtk_ctree_node_get_row_data( ctree, node );
5421 if( obj == NULL ) return;
5423 ds = addressbook_find_datasource( node );
5424 if( ds == NULL ) return;
5425 adbase = ( AddrBookBase * ) ds->rawDataSource;
5426 cache = adbase->addressCache;
5427 addressbook_exp_html( cache );
5433 static void addressbook_export_ldif_cb( void ) {
5434 GtkCTree *ctree = GTK_CTREE(addrbook.ctree);
5436 AddressDataSource *ds = NULL;
5437 AddrBookBase *adbase;
5438 AddressCache *cache;
5439 GtkCTreeNode *node = NULL;
5441 if( ! addrbook.treeSelected ) return;
5442 node = addrbook.treeSelected;
5443 if( GTK_CTREE_ROW(node)->level == 1 ) return;
5444 obj = gtk_ctree_node_get_row_data( ctree, node );
5445 if( obj == NULL ) return;
5447 ds = addressbook_find_datasource( node );
5448 if( ds == NULL ) return;
5449 adbase = ( AddrBookBase * ) ds->rawDataSource;
5450 cache = adbase->addressCache;
5451 addressbook_exp_ldif( cache );
5454 static void addressbook_find_duplicates_cb(void)
5456 addrduplicates_find(GTK_WINDOW(addrbook.window));
5459 static void addressbook_edit_custom_attr_cb(void)
5461 addressbook_custom_attr_edit();
5464 static void addressbook_start_drag(GtkWidget *widget, gint button,
5468 GdkDragContext *context;
5469 if (addressbook_target_list == NULL)
5470 addressbook_target_list = gtk_target_list_new(
5471 addressbook_drag_types, 1);
5472 context = gtk_drag_begin(widget, addressbook_target_list,
5473 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5474 gtk_drag_set_icon_default(context);
5477 static void addressbook_drag_data_get(GtkWidget *widget,
5478 GdkDragContext *drag_context,
5479 GtkSelectionData *selection_data,
5484 AddrItemObject *aio = NULL;
5485 AddressObject *pobj = NULL;
5486 AdapterDSource *ads = NULL;
5487 AddressDataSource *ds = NULL;
5490 pobj = gtk_ctree_node_get_row_data( GTK_CTREE(addrbook.ctree), addrbook.treeSelected );
5492 if( pobj == NULL ) return;
5494 if( pobj->type == ADDR_DATASOURCE ) {
5495 ads = ADAPTER_DSOURCE(pobj);
5496 ds = ads->dataSource;
5497 } else if (pobj->type == ADDR_ITEM_GROUP) {
5502 else if( pobj->type != ADDR_INTERFACE ) {
5503 ds = addressbook_find_datasource( addrbook.treeSelected );
5509 for(cur = GTK_CLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5510 aio = (AddrItemObject *)gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.clist),
5511 GTK_CTREE_NODE(cur->data));
5512 while (aio && aio->type != ADDR_ITEM_PERSON) {
5517 if (aio && aio->type == ADDR_ITEM_PERSON) {
5518 if( ds && ds->interface && ds->interface->readOnly)
5519 gtk_selection_data_set(selection_data,
5520 selection_data->target, 8,
5521 (const guchar *)"Dummy_addr_copy", 15);
5523 gtk_selection_data_set(selection_data,
5524 selection_data->target, 8,
5525 (const guchar *)"Dummy_addr_move", 15);
5529 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5530 GdkDragContext *context,
5537 GtkCTreeNode *node = NULL;
5538 gboolean acceptable = FALSE;
5539 gint height = addrbook.ctree->allocation.height;
5540 gint total_height = addrbook.ctree->requisition.height;
5541 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5542 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5543 gfloat vpos = pos->value;
5545 if (gtk_clist_get_selection_info
5546 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
5548 if (y > height - 24 && height + vpos < total_height) {
5549 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5550 gtk_adjustment_changed(pos);
5552 if (y < 24 && y > 0) {
5553 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5554 gtk_adjustment_changed(pos);
5556 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5559 AddressObject *obj = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node );
5560 if( obj->type == ADDR_ITEM_FOLDER
5561 || obj->type == ADDR_ITEM_GROUP)
5564 AdapterDSource *ads = NULL;
5565 AddressDataSource *ds = NULL;
5566 ads = ADAPTER_DSOURCE(obj);
5567 if (ads == NULL ){ return FALSE;}
5568 ds = ads->dataSource;
5569 if (ds == NULL ) { return FALSE;}
5577 g_signal_handlers_block_by_func
5579 G_CALLBACK(addressbook_tree_selected), NULL);
5580 gtk_sctree_select( GTK_SCTREE(widget), node);
5581 g_signal_handlers_unblock_by_func
5583 G_CALLBACK(addressbook_tree_selected), NULL);
5584 gdk_drag_status(context,
5585 (context->actions == GDK_ACTION_COPY ?
5586 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5588 gdk_drag_status(context, 0, time);
5593 static void addressbook_drag_leave_cb(GtkWidget *widget,
5594 GdkDragContext *context,
5598 if (addrbook.treeSelected) {
5599 g_signal_handlers_block_by_func
5601 G_CALLBACK(addressbook_tree_selected), NULL);
5602 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5603 g_signal_handlers_unblock_by_func
5605 G_CALLBACK(addressbook_tree_selected), NULL);
5610 static void addressbook_drag_received_cb(GtkWidget *widget,
5611 GdkDragContext *drag_context,
5614 GtkSelectionData *data,
5621 GtkCTreeNode *lastopened = addrbook.opened;
5623 if (!strncmp(data->data, "Dummy_addr", 10)) {
5624 if (gtk_clist_get_selection_info
5625 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5629 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
5630 if( !node || !gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), node))
5633 gtk_clist_freeze(GTK_CLIST(addrbook.clist));
5634 if (drag_context->action == GDK_ACTION_COPY ||
5635 !strcmp(data->data, "Dummy_addr_copy"))
5636 addressbook_clip_copy_cb();
5638 addressbook_clip_cut_cb();
5639 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5640 addressbook_clip_paste_cb();
5641 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5642 gtk_clist_thaw(GTK_CLIST(addrbook.clist));
5643 gtk_drag_finish(drag_context, TRUE, TRUE, time);