2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2013 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/>.
22 #include "claws-features.h"
28 #include <glib/gi18n.h>
29 #include <gdk/gdkkeysyms.h>
33 #include <sys/types.h>
37 #include "addressbook.h"
38 #include "manage_window.h"
39 #include "prefs_common.h"
40 #include "alertpanel.h"
41 #include "inputdialog.h"
43 #include "stock_pixmap.h"
45 #include "prefs_gtk.h"
51 #include "addr_compl.h"
54 #include "addressitem.h"
56 #include "addrcache.h"
58 #include "addrindex.h"
59 #include "addressadd.h"
60 #include "addrduplicates.h"
61 #include "addressbook_foldersel.h"
63 #include "editvcard.h"
64 #include "editgroup.h"
65 #include "editaddress.h"
67 #include "importldif.h"
68 #include "importmutt.h"
69 #include "importpine.h"
74 #include "editjpilot.h"
79 #include "ldapserver.h"
81 #include "ldapupdate.h"
83 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
86 #include "addrquery.h"
87 #include "addrselect.h"
89 #include "addrgather.h"
90 #include "adbookbase.h"
91 #include "exphtmldlg.h"
92 #include "expldifdlg.h"
93 #include "browseldap.h"
94 #include "addrcustomattr.h"
102 } AddressIndexColumns;
110 } AddressListColumns;
113 AddressBookFile *book;
121 AddressDataSource *book;
125 static gchar *list_titles[] = { N_("Name"),
129 #define COL_NAME_WIDTH 164
130 #define COL_ADDRESS_WIDTH 156
132 #define COL_FOLDER_WIDTH 170
133 #define ADDRESSBOOK_WIDTH 640
134 #define ADDRESSBOOK_HEIGHT 360
136 #define ADDRESSBOOK_MSGBUF_SIZE 2048
138 static GdkPixbuf *folderxpm = NULL;
139 static GdkPixbuf *folderopenxpm = NULL;
140 static GdkPixbuf *groupxpm = NULL;
141 static GdkPixbuf *interfacexpm = NULL;
142 static GdkPixbuf *bookxpm = NULL;
143 static GdkPixbuf *addressxpm = NULL;
144 static GdkPixbuf *vcardxpm = NULL;
145 static GdkPixbuf *jpilotxpm = NULL;
146 static GdkPixbuf *categoryxpm = NULL;
147 static GdkPixbuf *ldapxpm = NULL;
148 static GdkPixbuf *addrsearchxpm = NULL;
151 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
153 /* Address list selection */
154 static AddrSelectList *_addressSelect_ = NULL;
155 static AddressClipboard *_clipBoard_ = NULL;
157 /* Address index file and interfaces */
158 static AddressIndex *_addressIndex_ = NULL;
159 static GList *_addressInterfaceList_ = NULL;
160 static GList *_addressIFaceSelection_ = NULL;
161 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
163 static AddressBook_win addrbook;
165 static GHashTable *_addressBookTypeHash_ = NULL;
166 static GList *_addressBookTypeList_ = NULL;
168 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
169 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
170 static void addressbook_edit_address_post_cb( ItemPerson *person );
172 static void addressbook_create (void);
173 static gint addressbook_close (void);
175 static gboolean address_index_has_focus = FALSE;
176 static gboolean address_list_has_focus = FALSE;
178 /* callback functions */
179 static void addressbook_del_clicked (GtkButton *button,
181 static void addressbook_reg_clicked (GtkButton *button,
183 static void addressbook_to_clicked (GtkButton *button,
185 static void addressbook_lup_clicked (GtkButton *button,
187 static void addressbook_close_clicked (GtkButton *button,
190 static void addressbook_tree_selected (GtkCMCTree *ctree,
191 GtkCMCTreeNode *node,
194 static void addressbook_select_row_tree (GtkCMCTree *ctree,
195 GtkCMCTreeNode *node,
198 static void addressbook_list_row_selected (GtkCMCTree *clist,
199 GtkCMCTreeNode *node,
202 static void addressbook_list_row_unselected (GtkCMCTree *clist,
203 GtkCMCTreeNode *node,
206 static void addressbook_person_expand_node (GtkCMCTree *ctree,
209 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
213 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
214 GdkEventButton *event,
216 static gboolean addressbook_list_button_released(GtkWidget *widget,
217 GdkEventButton *event,
219 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
220 GdkEventButton *event,
222 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
223 GdkEventButton *event,
226 static void addressbook_new_folder_cb (GtkAction *action,
228 static void addressbook_new_group_cb (GtkAction *action,
230 static void addressbook_treenode_edit_cb (GtkAction *action,
232 static void addressbook_treenode_delete_cb (GtkAction *action,
235 static void addressbook_change_node_name (GtkCMCTreeNode *node,
238 static void addressbook_new_address_cb (GtkAction *action,
240 static void addressbook_edit_address_cb (GtkAction *action,
242 static void addressbook_delete_address_cb (GtkAction *action,
245 static void close_cb (GtkAction *action,
247 static void addressbook_file_save_cb (GtkAction *action,
250 /* Data source edit stuff */
251 static void addressbook_new_book_cb (GtkAction *action,
253 static void addressbook_new_vcard_cb (GtkAction *action,
257 static void addressbook_new_jpilot_cb (GtkAction *action,
262 static void addressbook_new_ldap_cb (GtkAction *action,
266 static void addressbook_set_clist (AddressObject *obj,
269 static void addressbook_load_tree (void);
270 void addressbook_read_file (void);
272 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
274 static void addressbook_treenode_remove_item ( void );
276 static AddressDataSource *addressbook_find_datasource
277 (GtkCMCTreeNode *node );
279 static AddressBookFile *addressbook_get_book_file(void);
281 static GtkCMCTreeNode *addressbook_node_add_folder
282 (GtkCMCTreeNode *node,
283 AddressDataSource *ds,
284 ItemFolder *itemFolder,
285 AddressObjectType otype);
286 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
287 AddressDataSource *ds,
288 ItemGroup *itemGroup);
289 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
290 GtkCMCTreeNode *parent);
291 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
292 GtkCMCTreeNode *node);
293 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
295 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
298 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
301 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
303 AddressTypeControlItem *atci,
304 AddressTypeControlItem *atciMail);
305 static void addressbook_folder_refresh_one_person(GtkCMCTree *clist,
307 static void addressbook_folder_remove_one_person(GtkCMCTree *clist,
309 static void addressbook_folder_remove_node (GtkCMCTree *clist,
310 GtkCMCTreeNode *node);
312 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
313 gboolean force_focus );
315 /* LUT's and IF stuff */
316 static void addressbook_free_treenode ( gpointer data );
317 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
318 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
320 static void addrbookctl_build_map (GtkWidget *window);
321 static void addrbookctl_build_iflist (void);
322 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
323 static void addrbookctl_build_ifselect (void);
325 static void addrbookctl_free_interface (AdapterInterface *adapter);
326 static void addrbookctl_free_datasource (AdapterDSource *adapter);
327 static void addrbookctl_free_folder (AdapterFolder *adapter);
328 static void addrbookctl_free_group (AdapterGroup *adapter);
330 static void addressbook_list_select_clear ( void );
331 static void addressbook_list_select_add ( AddrItemObject *aio,
332 AddressDataSource *ds );
333 static void addressbook_list_select_remove ( AddrItemObject *aio );
335 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
336 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
337 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
338 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
339 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
340 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
341 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
342 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
343 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
344 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
345 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
346 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
347 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
348 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
350 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
353 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
355 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
357 static void addressbook_start_drag(GtkWidget *widget, gint button,
360 static void addressbook_drag_data_get(GtkWidget *widget,
361 GdkDragContext *drag_context,
362 GtkSelectionData *selection_data,
366 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
367 GdkDragContext *context,
372 static void addressbook_drag_leave_cb(GtkWidget *widget,
373 GdkDragContext *context,
376 static void addressbook_drag_received_cb(GtkWidget *widget,
377 GdkDragContext *drag_context,
380 GtkSelectionData *data,
384 static void addressbook_list_menu_setup( void );
386 static GtkTargetEntry addressbook_drag_types[] =
388 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
391 static GtkTargetList *addressbook_target_list = NULL;
393 static void about_show_cb(GtkAction *action, gpointer data)
398 static GtkActionEntry addressbook_entries[] =
400 {"Menu", NULL, "Menu" },
402 {"Book", NULL, N_("_Book") },
403 {"Address", NULL, N_("_Edit") },
404 {"Tools", NULL, N_("_Tools") },
405 {"Help", NULL, N_("_Help") },
408 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
409 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
410 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
414 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
417 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
419 {"Book/---", NULL, "---", NULL, NULL, NULL },
421 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
422 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
423 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
424 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
425 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
428 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
429 {"Address/---", NULL, "---", NULL, NULL, NULL },
430 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
431 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
432 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
433 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
434 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
435 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
436 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
437 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
438 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
439 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
440 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
444 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
445 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
446 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
447 {"Tools/---", NULL, "---", NULL, NULL, NULL },
448 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
449 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
450 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
451 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
452 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
455 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
459 static GtkActionEntry addressbook_tree_popup_entries[] =
461 {"ABTreePopup", NULL, "ABTreePopup" },
462 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
463 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
464 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
465 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
466 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
467 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
468 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
469 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
470 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
471 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
474 static GtkActionEntry addressbook_list_popup_entries[] =
476 {"ABListPopup", NULL, "ABListPopup" },
477 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
478 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
479 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
480 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
481 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
482 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
483 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
484 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
485 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
486 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
487 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
488 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
489 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
491 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
496 * Structure of error message table.
498 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
499 struct _ErrMsgTableEntry {
504 static gchar *_errMsgUnknown_ = N_( "Unknown" );
507 * Lookup table of error messages for general errors. Note that a NULL
508 * description signifies the end of the table.
510 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
511 { MGU_SUCCESS, N_("Success") },
512 { MGU_BAD_ARGS, N_("Bad arguments") },
513 { MGU_NO_FILE, N_("File not specified") },
514 { MGU_OPEN_FILE, N_("Error opening file") },
515 { MGU_ERROR_READ, N_("Error reading file") },
516 { MGU_EOF, N_("End of file encountered") },
517 { MGU_OO_MEMORY, N_("Error allocating memory") },
518 { MGU_BAD_FORMAT, N_("Bad file format") },
519 { MGU_ERROR_WRITE, N_("Error writing to file") },
520 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
521 { MGU_NO_PATH, N_("No path specified") },
527 * Lookup table of error messages for LDAP errors.
529 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
530 { LDAPRC_SUCCESS, N_("Success") },
531 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
532 { LDAPRC_INIT, N_("Error initializing LDAP") },
533 { LDAPRC_BIND, N_("Error binding to LDAP server") },
534 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
535 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
536 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
537 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
538 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
539 { LDAPRC_TLS, N_("Error starting TLS connection") },
540 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
541 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
542 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
543 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
549 * Lookup message for specified error code.
550 * \param lut Lookup table.
551 * \param code Code to lookup.
552 * \return Description associated to code.
554 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
556 ErrMsgTableEntry entry;
559 for( i = 0; ; i++ ) {
561 if( entry.description == NULL ) break;
562 if( entry.code == code ) {
563 desc = entry.description;
568 desc = _errMsgUnknown_;
573 static gboolean lastCanLookup = FALSE;
575 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
577 if (add_and_delete) {
578 gtk_widget_show(addrbook.edit_btn);
579 gtk_widget_show(addrbook.del_btn);
580 gtk_widget_show(addrbook.reg_btn);
582 gtk_widget_hide(addrbook.edit_btn);
583 gtk_widget_hide(addrbook.del_btn);
584 gtk_widget_hide(addrbook.reg_btn);
588 gtk_widget_show(addrbook.lup_btn);
589 gtk_widget_show(addrbook.entry);
590 gtk_widget_show(addrbook.label);
592 gtk_widget_hide(addrbook.lup_btn);
593 gtk_widget_hide(addrbook.entry);
594 gtk_widget_hide(addrbook.label);
597 lastCanLookup = lookup;
600 gtk_widget_show(addrbook.to_btn);
601 gtk_widget_show(addrbook.cc_btn);
602 gtk_widget_show(addrbook.bcc_btn);
604 gtk_widget_hide(addrbook.to_btn);
605 gtk_widget_hide(addrbook.cc_btn);
606 gtk_widget_hide(addrbook.bcc_btn);
610 void addressbook_open(Compose *target)
612 /* Initialize all static members */
613 if( _clipBoard_ == NULL ) {
614 _clipBoard_ = addrclip_create();
616 if( _addressIndex_ != NULL ) {
617 addrclip_set_index( _clipBoard_, _addressIndex_ );
619 if( _addressSelect_ == NULL ) {
620 _addressSelect_ = addrselect_list_create();
622 if (!addrbook.window) {
623 addressbook_read_file();
624 addressbook_create();
625 addressbook_load_tree();
626 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
627 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
630 gtk_widget_hide(addrbook.window);
633 gtk_widget_show_all(addrbook.window);
635 if (!prefs_common.addressbook_use_editaddress_dialog)
636 addressbook_edit_person_widgetset_hide();
638 address_completion_start(addrbook.window);
640 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
641 addressbook_set_target_compose(target);
645 * Destroy addressbook.
647 void addressbook_destroy( void ) {
648 /* Free up address stuff */
649 if( _addressSelect_ != NULL ) {
650 addrselect_list_free( _addressSelect_ );
652 if( _clipBoard_ != NULL ) {
653 addrclip_free( _clipBoard_ );
655 if( _addressIndex_ != NULL ) {
656 addrindex_free_index( _addressIndex_ );
657 addrindex_teardown();
659 _addressSelect_ = NULL;
661 _addressIndex_ = NULL;
664 void addressbook_set_target_compose(Compose *target)
666 addrbook.target_compose = target;
669 Compose *addressbook_get_target_compose(void)
671 return addrbook.target_compose;
675 * Refresh addressbook and save to file(s).
677 void addressbook_refresh( void )
679 if (addrbook.window) {
680 if (addrbook.treeSelected) {
681 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
682 addrbook.treeSelected);
683 addressbook_set_clist(
684 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
685 addrbook.treeSelected),
690 addressbook_export_to_file();
693 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
695 if (event && event->keyval == GDK_KEY_Escape)
697 else if (event && event->keyval == GDK_KEY_Delete) {
698 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
699 if ( /* address_index_has_focus || */ address_list_has_focus )
700 addressbook_del_clicked(NULL, NULL);
706 *\brief Save Gtk object size to prefs dataset
708 static void addressbook_size_allocate_cb(GtkWidget *widget,
709 GtkAllocation *allocation)
711 cm_return_if_fail(allocation != NULL);
713 prefs_common.addressbookwin_width = allocation->width;
714 prefs_common.addressbookwin_height = allocation->height;
717 static gint sort_column_number = 0;
718 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
720 static gint list_case_sort(
721 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
723 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
724 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
725 gchar *name1 = NULL, *name2 = NULL;
726 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
727 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
729 if( aio1->type == aio2->type ) {
731 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
733 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
734 if( ! name1 ) return ( name2 != NULL );
735 if( ! name2 ) return -1;
736 return g_utf8_collate( name1, name2 );
738 /* Order groups before person */
739 if( aio1->type == ITEMTYPE_GROUP ) {
740 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
741 } else if( aio2->type == ITEMTYPE_GROUP ) {
742 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
748 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
749 const GtkSortType sort_type)
752 GtkWidget *hbox, *label, *arrow;
754 sort_column_number = col;
755 sort_column_type = sort_type;
756 gtk_cmclist_set_compare_func(clist, list_case_sort);
757 gtk_cmclist_set_sort_type(clist, sort_type);
758 gtk_cmclist_set_sort_column(clist, col);
760 gtk_cmclist_freeze(clist);
761 gtk_cmclist_sort(clist);
763 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
764 hbox = gtk_hbox_new(FALSE, 4);
765 label = gtk_label_new(gettext(list_titles[pos]));
766 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
769 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
770 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
771 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
774 gtk_widget_show_all(hbox);
775 gtk_cmclist_set_column_widget(clist, pos, hbox);
778 gtk_cmclist_thaw(clist);
781 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
783 static GtkSortType sort_type = GTK_SORT_ASCENDING;
785 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
787 addressbook_sort_list(clist, COL_NAME, sort_type);
790 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
792 static GtkSortType sort_type = GTK_SORT_ASCENDING;
794 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
796 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
799 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
801 static GtkSortType sort_type = GTK_SORT_ASCENDING;
803 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
805 addressbook_sort_list(clist, COL_REMARKS, sort_type);
808 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
811 address_index_has_focus = TRUE;
815 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
818 address_index_has_focus = FALSE;
819 if (!prefs_common.addressbook_use_editaddress_dialog
820 && !address_list_has_focus)
821 addressbook_address_list_disable_some_actions();
825 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
828 address_list_has_focus = TRUE;
832 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
835 address_list_has_focus = FALSE;
836 if (!prefs_common.addressbook_use_editaddress_dialog
837 && !address_index_has_focus)
838 addressbook_address_list_disable_some_actions();
842 /* save hpane and vpane's handle position when it moves */
843 static void addressbook_pane_save_position(void)
846 prefs_common.addressbook_hpaned_pos =
847 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
849 prefs_common.addressbook_vpaned_pos =
850 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
854 * Create the address book widgets. The address book contains two CTree widgets: the
855 * address index tree on the left and the address list on the right.
857 * The address index tree displays a hierarchy of interfaces and groups. Each node in
858 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
859 * data sources and folder objects.
861 * The address list displays group, person and email objects. These items are linked
862 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
865 * In the tradition of MVC architecture, the data stores have been separated from the
866 * GUI components. The addrindex.c file provides the interface to all data stores.
868 static void addressbook_create(void)
874 GtkWidget *ctree_swin;
876 GtkWidget *editaddress_vbox;
877 GtkWidget *clist_vbox;
878 GtkWidget *clist_swin;
885 GtkWidget *statusbar;
896 GtkWidget *close_btn;
897 GtkWidget *tree_popup;
898 GtkWidget *list_popup;
900 GtkUIManager *ui_manager;
901 GtkActionGroup *action_group;
902 gchar *index_titles[N_INDEX_COLS];
906 static GdkGeometry geometry;
908 debug_print("Creating addressbook window...\n");
910 index_titles[COL_SOURCES] = _("Sources");
912 /* Address book window */
913 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
914 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
915 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
916 gtk_widget_realize(window);
918 g_signal_connect(G_OBJECT(window), "delete_event",
919 G_CALLBACK(addressbook_close), NULL);
920 g_signal_connect(G_OBJECT(window), "size_allocate",
921 G_CALLBACK(addressbook_size_allocate_cb), NULL);
922 g_signal_connect(G_OBJECT(window), "key_press_event",
923 G_CALLBACK(key_pressed), NULL);
924 MANAGE_WINDOW_SIGNALS_CONNECT(window);
926 vbox = gtk_vbox_new(FALSE, 0);
927 gtk_container_add(GTK_CONTAINER(window), vbox);
930 ui_manager = gtk_ui_manager_new();
931 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
932 G_N_ELEMENTS(addressbook_entries), NULL);
933 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
934 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
935 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
936 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
938 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
940 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
941 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
942 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
950 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
955 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
957 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
991 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
993 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
995 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
996 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
997 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
999 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1000 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1001 GTK_POLICY_AUTOMATIC,
1002 GTK_POLICY_AUTOMATIC);
1003 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1006 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1007 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1009 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1010 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1011 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1012 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1013 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1014 GTK_CMCTREE_EXPANDER_TRIANGLE);
1015 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1016 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1017 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1018 addressbook_treenode_compare_func);
1020 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1021 G_CALLBACK(addressbook_tree_selected), NULL);
1022 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1023 G_CALLBACK(addressbook_tree_button_pressed),
1025 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1026 G_CALLBACK(addressbook_tree_button_released),
1029 g_signal_connect(G_OBJECT(ctree), "select_row",
1030 G_CALLBACK(addressbook_select_row_tree), NULL);
1032 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1033 addressbook_drag_types, 1,
1034 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1035 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1036 G_CALLBACK(addressbook_drag_motion_cb),
1038 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1039 G_CALLBACK(addressbook_drag_leave_cb),
1041 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1042 G_CALLBACK(addressbook_drag_received_cb),
1044 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1045 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1046 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1047 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1049 clist_vbox = gtk_vbox_new(FALSE, 4);
1051 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1052 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1053 GTK_POLICY_AUTOMATIC,
1054 GTK_POLICY_AUTOMATIC);
1055 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1058 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1059 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1060 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1061 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1062 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1063 GTK_CMCTREE_EXPANDER_TRIANGLE);
1064 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1065 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1066 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1068 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1070 gtk_widget_set_size_request(clist, -1, 80);
1072 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1073 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1074 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1075 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1076 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1077 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1078 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1079 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1080 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1081 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1082 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1084 for (i = 0; i < N_LIST_COLS; i++)
1085 gtkut_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1088 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1089 G_CALLBACK(addressbook_list_row_selected), NULL);
1090 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1091 G_CALLBACK(addressbook_list_row_unselected), NULL);
1092 g_signal_connect(G_OBJECT(clist), "button_press_event",
1093 G_CALLBACK(addressbook_list_button_pressed),
1095 g_signal_connect(G_OBJECT(clist), "button_release_event",
1096 G_CALLBACK(addressbook_list_button_released),
1098 g_signal_connect(G_OBJECT(clist), "tree_expand",
1099 G_CALLBACK(addressbook_person_expand_node), NULL );
1100 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1101 G_CALLBACK(addressbook_person_collapse_node), NULL );
1102 g_signal_connect(G_OBJECT(clist), "start_drag",
1103 G_CALLBACK(addressbook_start_drag), NULL);
1104 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1105 G_CALLBACK(addressbook_drag_data_get), NULL);
1106 hbox = gtk_hbox_new(FALSE, 4);
1107 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1109 label = gtk_label_new(_("Lookup name:"));
1110 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1112 entry = gtk_entry_new();
1113 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1115 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1117 g_signal_connect(G_OBJECT(entry), "key_press_event",
1118 G_CALLBACK(addressbook_entry_key_pressed),
1121 if (!prefs_common.addressbook_use_editaddress_dialog) {
1122 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1123 vpaned = gtk_vpaned_new();
1124 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1125 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1128 editaddress_vbox = NULL;
1130 hpaned = gtk_hpaned_new();
1131 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1132 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1133 if (prefs_common.addressbook_use_editaddress_dialog)
1134 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1136 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1139 hsbox = gtk_hbox_new(FALSE, 0);
1140 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1141 statusbar = gtk_statusbar_new();
1142 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1145 hbbox = gtk_hbutton_box_new();
1146 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1147 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1148 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1149 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1151 gtkut_stock_button_add_help(hbbox, &help_btn);
1153 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1154 gtkut_widget_set_can_default(edit_btn, TRUE);
1155 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1156 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1157 gtkut_widget_set_can_default(del_btn, TRUE);
1158 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1159 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1160 gtkut_widget_set_can_default(reg_btn, TRUE);
1161 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1164 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1165 gtkut_widget_set_can_default(lup_btn, TRUE);
1166 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1168 g_signal_connect(G_OBJECT(help_btn), "clicked",
1169 G_CALLBACK(manual_open_with_anchor_cb),
1170 MANUAL_ANCHOR_ADDRBOOK);
1172 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1173 G_CALLBACK(addressbook_edit_clicked), NULL);
1174 g_signal_connect(G_OBJECT(del_btn), "clicked",
1175 G_CALLBACK(addressbook_del_clicked), NULL);
1176 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1177 G_CALLBACK(addressbook_reg_clicked), NULL);
1178 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1179 G_CALLBACK(addressbook_lup_clicked), NULL);
1181 to_btn = gtk_button_new_with_label
1182 (prefs_common_translated_header_name("To:"));
1183 gtkut_widget_set_can_default(to_btn, TRUE);
1184 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1185 cc_btn = gtk_button_new_with_label
1186 (prefs_common_translated_header_name("Cc:"));
1187 gtkut_widget_set_can_default(cc_btn, TRUE);
1188 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1189 bcc_btn = gtk_button_new_with_label
1190 (prefs_common_translated_header_name("Bcc:"));
1191 gtkut_widget_set_can_default(bcc_btn, TRUE);
1192 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1194 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1195 gtkut_widget_set_can_default(close_btn, TRUE);
1196 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1198 g_signal_connect(G_OBJECT(to_btn), "clicked",
1199 G_CALLBACK(addressbook_to_clicked),
1200 GINT_TO_POINTER(COMPOSE_TO));
1201 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1202 G_CALLBACK(addressbook_to_clicked),
1203 GINT_TO_POINTER(COMPOSE_CC));
1204 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1205 G_CALLBACK(addressbook_to_clicked),
1206 GINT_TO_POINTER(COMPOSE_BCC));
1207 g_signal_connect(G_OBJECT(close_btn), "clicked",
1208 G_CALLBACK(addressbook_close_clicked), NULL);
1210 /* Build icons for interface */
1212 /* Build control tables */
1213 addrbookctl_build_map(window);
1214 addrbookctl_build_iflist();
1215 addrbookctl_build_ifselect();
1217 addrbook.clist = NULL;
1219 /* Add each interface into the tree as a root level folder */
1220 nodeIf = _addressInterfaceList_;
1222 AdapterInterface *adapter = nodeIf->data;
1223 AddressInterface *iface = adapter->interface;
1224 nodeIf = g_list_next(nodeIf);
1226 if(iface->useInterface) {
1227 AddressTypeControlItem *atci = adapter->atci;
1228 text = atci->displayName;
1230 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1231 NULL, NULL, &text, FOLDER_SPACING,
1235 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1236 gtk_cmctree_node_set_row_data_full(
1237 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1238 addressbook_free_treenode );
1244 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1245 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1246 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1247 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1248 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1249 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1250 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1257 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1258 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1277 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1278 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1280 addrbook.window = window;
1281 addrbook.hpaned = hpaned;
1282 addrbook.vpaned = vpaned;
1283 addrbook.menubar = menubar;
1284 addrbook.ctree = ctree;
1287 addrbook.editaddress_vbox = editaddress_vbox;
1288 addrbook.clist = clist;
1289 addrbook.label = label;
1290 addrbook.entry = entry;
1291 addrbook.statusbar = statusbar;
1292 addrbook.status_cid = gtk_statusbar_get_context_id(
1293 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1295 addrbook.help_btn = help_btn;
1296 addrbook.edit_btn = edit_btn;
1297 addrbook.del_btn = del_btn;
1298 addrbook.reg_btn = reg_btn;
1299 addrbook.lup_btn = lup_btn;
1300 addrbook.to_btn = to_btn;
1301 addrbook.cc_btn = cc_btn;
1302 addrbook.bcc_btn = bcc_btn;
1304 addrbook.tree_popup = tree_popup;
1305 addrbook.list_popup = list_popup;
1306 addrbook.ui_manager = ui_manager;
1308 addrbook.listSelected = NULL;
1310 if (!geometry.min_height) {
1311 geometry.min_width = ADDRESSBOOK_WIDTH;
1312 geometry.min_height = ADDRESSBOOK_HEIGHT;
1315 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1317 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1318 prefs_common.addressbookwin_height);
1320 gtk_window_move(GTK_WINDOW(window), 48, 48);
1323 if (!prefs_common.addressbook_use_editaddress_dialog) {
1324 if (prefs_common.addressbook_vpaned_pos > 0)
1325 gtk_paned_set_position(GTK_PANED(vpaned),
1326 prefs_common.addressbook_vpaned_pos);
1328 if (prefs_common.addressbook_hpaned_pos > 0)
1329 gtk_paned_set_position(GTK_PANED(hpaned),
1330 prefs_common.addressbook_hpaned_pos);
1333 gtk_widget_show_all(window);
1337 * Close address book window and save to file(s).
1339 static gint addressbook_close( void ) {
1340 address_completion_end(addrbook.window);
1341 if (!prefs_common.addressbook_use_editaddress_dialog)
1342 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1344 addressbook_pane_save_position();
1346 gtk_widget_hide(addrbook.window);
1347 addressbook_export_to_file();
1352 * Display message in status line.
1353 * \param msg Message to display.
1355 static void addressbook_status_show( gchar *msg ) {
1356 if( addrbook.statusbar != NULL ) {
1358 GTK_STATUSBAR(addrbook.statusbar),
1359 addrbook.status_cid );
1362 GTK_STATUSBAR(addrbook.statusbar),
1363 addrbook.status_cid, msg );
1368 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1372 *addressbook_msgbuf = '\0';
1374 name = addrindex_ds_get_name( ds );
1375 retVal = addrindex_ds_get_status_code( ds );
1376 if( retVal == MGU_SUCCESS ) {
1377 g_snprintf( addressbook_msgbuf,
1378 sizeof(addressbook_msgbuf), "%s", name );
1381 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1382 g_snprintf( addressbook_msgbuf,
1383 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1386 addressbook_status_show( addressbook_msgbuf );
1389 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1391 addressbook_edit_address_cb(NULL, NULL);
1394 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1396 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1400 * Delete one or more objects from address list.
1402 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1404 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1405 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1406 AddressObject *pobj;
1407 AdapterDSource *ads = NULL;
1408 GtkCMCTreeNode *nodeList;
1411 AddressBookFile *abf = NULL;
1412 AddressDataSource *ds = NULL;
1413 AddressInterface *iface;
1414 AddrItemObject *aio;
1415 AddrSelectItem *item;
1417 gboolean refreshList = FALSE;
1419 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1420 cm_return_if_fail(pobj != NULL);
1422 /* Test whether anything selected for deletion */
1423 nodeList = addrbook.listSelected;
1425 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1426 if( aio == NULL) return;
1427 ds = addressbook_find_datasource( addrbook.treeSelected );
1428 if( ds == NULL ) return;
1430 /* Test for read only */
1431 iface = ds->interface;
1432 if( iface->readOnly ) {
1433 alertpanel( _("Delete address(es)"),
1434 _("This address data is readonly and cannot be deleted."),
1435 GTK_STOCK_CLOSE, NULL, NULL );
1439 /* Test whether Ok to proceed */
1441 if( pobj->type == ADDR_DATASOURCE ) {
1442 ads = ADAPTER_DSOURCE(pobj);
1443 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1445 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1448 else if( pobj->type == ADDR_ITEM_GROUP ) {
1451 if( ! procFlag ) return;
1452 abf = ds->rawDataSource;
1453 if( abf == NULL ) return;
1455 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1456 g_signal_handlers_block_by_func
1457 (G_OBJECT(addrbook.clist),
1458 G_CALLBACK(addressbook_list_row_unselected), NULL);
1460 /* Process deletions */
1461 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1462 GList *groups = NULL, *persons = NULL, *emails = NULL;
1463 gboolean group_delete = TRUE;
1464 /* Items inside folders */
1465 list = addrselect_get_list( _addressSelect_ );
1466 /* Confirm deletion */
1470 node = g_list_next( node );
1471 aio = ( AddrItemObject * ) item->addressItem;
1472 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1473 group_delete = FALSE;
1478 aval = alertpanel( _("Delete group"),
1479 _("Really delete the group(s)?\n"
1480 "The addresses it contains will not be lost."),
1481 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1482 if( aval != G_ALERTALTERNATE ) {
1486 aval = alertpanel( _("Delete address(es)"),
1487 _("Really delete the address(es)?"),
1488 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1489 if( aval != G_ALERTALTERNATE ) {
1494 /* first, set lists of groups and persons to remove */
1498 node = g_list_next( node );
1499 aio = ( AddrItemObject * ) item->addressItem;
1502 if( aio->type == ITEMTYPE_GROUP ) {
1503 groups = g_list_prepend(groups, item);
1505 else if( aio->type == ITEMTYPE_PERSON ) {
1506 persons = g_list_prepend(persons, item);
1509 /* then set list of emails to remove *if* they're not children of
1510 * persons to remove */
1514 node = g_list_next( node );
1515 aio = ( AddrItemObject * ) item->addressItem;
1518 if( aio->type == ITEMTYPE_EMAIL ) {
1519 ItemEMail *sitem = ( ItemEMail * ) aio;
1520 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1521 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1522 emails = g_list_prepend(emails, item);
1524 /* else, the email will be removed via the parent person */
1527 /* then delete groups */
1531 node = g_list_next( node );
1532 aio = ( AddrItemObject * ) item->addressItem;
1535 if( aio->type == ITEMTYPE_GROUP ) {
1536 ItemGroup *item = ( ItemGroup * ) aio;
1537 GtkCMCTreeNode *nd = NULL;
1538 nd = addressbook_find_group_node( addrbook.opened, item );
1539 item = addrbook_remove_group( abf, item );
1541 addritem_free_item_group( item );
1543 /* Remove group from parent node */
1544 gtk_cmctree_remove_node( ctree, nd );
1548 /* then delete persons */
1552 node = g_list_next( node );
1553 aio = ( AddrItemObject * ) item->addressItem;
1556 if( aio->type == ITEMTYPE_PERSON ) {
1557 ItemPerson *item = ( ItemPerson * ) aio;
1558 item->status = DELETE_ENTRY;
1559 addressbook_folder_remove_one_person( clist, item );
1560 if (pobj->type == ADDR_ITEM_FOLDER)
1561 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1562 item = addrbook_remove_person( abf, item );
1564 if (ds && ds->type == ADDR_IF_LDAP) {
1565 LdapServer *server = ds->rawDataSource;
1566 ldapsvr_set_modified(server, TRUE);
1567 ldapsvr_update_book(server, item);
1571 gchar *filename = addritem_person_get_picture(item);
1572 if (filename && is_file_exist(filename))
1573 claws_unlink(filename);
1575 addritem_free_item_person( item );
1579 /* then delete emails */
1583 node = g_list_next( node );
1584 aio = ( AddrItemObject * ) item->addressItem;
1588 if( aio->type == ITEMTYPE_EMAIL ) {
1589 ItemEMail *sitem = ( ItemEMail * ) aio;
1590 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1591 sitem = addrbook_person_remove_email( abf, person, sitem );
1593 addrcache_remove_email(abf->addressCache, sitem);
1594 addritem_free_item_email( sitem );
1596 addressbook_folder_refresh_one_person( clist, person );
1599 g_list_free( groups );
1600 g_list_free( persons );
1601 g_list_free( emails );
1602 g_list_free( list );
1603 addressbook_list_select_clear();
1605 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1606 addressbook_set_clist(
1607 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1611 addrbook_set_dirty(abf, TRUE);
1612 addressbook_export_to_file();
1613 addressbook_list_menu_setup();
1616 else if( pobj->type == ADDR_ITEM_GROUP ) {
1617 /* Items inside groups */
1618 list = addrselect_get_list( _addressSelect_ );
1622 node = g_list_next( node );
1623 aio = ( AddrItemObject * ) item->addressItem;
1624 if( aio->type == ITEMTYPE_EMAIL ) {
1625 ItemEMail *item = ( ItemEMail * ) aio;
1626 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1627 item = addrbook_person_remove_email( abf, person, item );
1629 addritem_free_item_email( item );
1633 g_list_free( list );
1634 addressbook_list_select_clear();
1635 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1636 addressbook_set_clist(
1637 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1641 addrbook_set_dirty(abf, TRUE);
1642 addressbook_export_to_file();
1643 addressbook_list_menu_setup();
1647 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1648 gtk_cmctree_remove_node( clist, nodeList );
1650 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1651 g_signal_handlers_unblock_by_func
1652 (G_OBJECT(addrbook.clist),
1653 G_CALLBACK(addressbook_list_row_unselected), NULL);
1656 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1658 addressbook_new_address_cb( NULL, NULL );
1661 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1664 gchar *address = NULL;
1666 if( aio->type == ITEMTYPE_EMAIL ) {
1667 ItemPerson *person = NULL;
1668 ItemEMail *email = ( ItemEMail * ) aio;
1670 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1671 if( email->address ) {
1672 if( ADDRITEM_NAME(email) ) {
1673 name = ADDRITEM_NAME(email);
1674 if( *name == '\0' ) {
1675 name = ADDRITEM_NAME(person);
1678 else if( ADDRITEM_NAME(person) ) {
1679 name = ADDRITEM_NAME(person);
1682 buf = g_strdup( email->address );
1684 address = email->address;
1687 else if( aio->type == ITEMTYPE_PERSON ) {
1688 ItemPerson *person = ( ItemPerson * ) aio;
1689 GList *node = person->listEMail;
1691 name = ADDRITEM_NAME(person);
1693 ItemEMail *email = ( ItemEMail * ) node->data;
1694 address = email->address;
1698 if( name && name[0] != '\0' ) {
1699 if( strchr_with_skip_quote( name, '"', ',' ) )
1700 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1702 buf = g_strdup_printf( "%s <%s>", name, address );
1705 buf = g_strdup( address );
1712 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1716 AddrSelectItem *item;
1717 AddrItemObject *aio;
1720 compose = addrbook.target_compose;
1721 if( ! compose ) return;
1723 /* Nothing selected, but maybe there is something in text entry */
1724 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1726 compose_entry_append(
1727 compose, addr, (ComposeEntryType)data , PREF_NONE);
1730 /* Select from address list */
1731 list = addrselect_get_list( _addressSelect_ );
1736 node = g_list_next( node );
1737 aio = item->addressItem;
1738 if( aio->type == ITEMTYPE_PERSON ||
1739 aio->type == ITEMTYPE_EMAIL ) {
1740 addr = addressbook_format_address( aio );
1741 compose_entry_append(
1742 compose, addr, (ComposeEntryType) data, PREF_NONE );
1745 else if( aio->type == ITEMTYPE_GROUP ) {
1746 ItemGroup *group = ( ItemGroup * ) aio;
1747 GList *nodeMail = group->listEMail;
1749 ItemEMail *email = nodeMail->data;
1751 addr = addressbook_format_address(
1752 ( AddrItemObject * ) email );
1753 compose_entry_append(
1754 compose, addr, (ComposeEntryType) data, PREF_NONE );
1756 nodeMail = g_list_next( nodeMail );
1761 AddressObject *obj = NULL;
1763 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1765 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1766 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1767 GList *nodeMail = itemGroup->listEMail;
1769 ItemEMail *email = nodeMail->data;
1771 addr = addressbook_format_address(
1772 ( AddrItemObject * ) email );
1773 compose_entry_append(
1774 compose, addr, (ComposeEntryType) data, PREF_NONE );
1776 nodeMail = g_list_next( nodeMail );
1780 g_list_free( list );
1783 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1784 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1785 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1786 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1788 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1796 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1797 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1800 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1801 gboolean canEdit = FALSE;
1802 gboolean canDelete = TRUE;
1803 gboolean canAdd = FALSE;
1804 gboolean canEditTr = TRUE;
1805 gboolean editAddress = FALSE;
1806 gboolean canExport = TRUE;
1807 AddressTypeControlItem *atci = NULL;
1808 AddressDataSource *ds = NULL;
1809 AddressInterface *iface = NULL;
1811 if( obj == NULL ) return;
1812 if( obj->type == ADDR_INTERFACE ) {
1813 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1814 iface = adapter->interface;
1816 if( iface->haveLibrary ) {
1817 /* Enable appropriate File / New command */
1818 atci = adapter->atci;
1819 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1822 canEditTr = canExport = FALSE;
1824 else if( obj->type == ADDR_DATASOURCE ) {
1825 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1826 ds = ads->dataSource;
1827 iface = ds->interface;
1828 if( ! iface->readOnly ) {
1829 canAdd = canEdit = editAddress = canDelete = TRUE;
1831 if( ! iface->haveLibrary ) {
1832 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1835 else if( obj->type == ADDR_ITEM_FOLDER ) {
1836 ds = addressbook_find_datasource( addrbook.treeSelected );
1838 iface = ds->interface;
1839 if( iface->readOnly ) {
1844 canAdd = editAddress = TRUE;
1848 else if( obj->type == ADDR_ITEM_GROUP ) {
1849 ds = addressbook_find_datasource( addrbook.treeSelected );
1851 iface = ds->interface;
1852 if( ! iface->readOnly ) {
1858 if( addrbook.listSelected == NULL )
1862 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1863 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1864 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1865 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1868 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1869 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1870 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1871 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1873 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1877 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1878 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1882 * Address book tree callback function that responds to selection of tree
1885 * \param ctree Tree widget.
1886 * \param node Node that was selected.
1887 * \param column Column number where selected occurred.
1888 * \param data Pointer to user data.
1890 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1891 gint column, gpointer data)
1893 AddressObject *obj = NULL;
1894 AdapterDSource *ads = NULL;
1895 AddressDataSource *ds = NULL;
1896 ItemFolder *rootFolder = NULL;
1897 AddressObjectType aot;
1899 addrbook.treeSelected = node;
1900 addrbook.listSelected = NULL;
1901 addressbook_status_show( "" );
1902 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1904 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1906 addressbook_set_clist(NULL, TRUE);
1909 addrbook.opened = node;
1911 if( obj->type == ADDR_DATASOURCE ) {
1912 /* Read from file */
1913 static gboolean tVal = TRUE;
1915 ads = ADAPTER_DSOURCE(obj);
1916 if( ads == NULL ) return;
1917 ds = ads->dataSource;
1918 if( ds == NULL ) return;
1920 if( addrindex_ds_get_modify_flag( ds ) ) {
1921 addrindex_ds_read_data( ds );
1924 if( ! addrindex_ds_get_read_flag( ds ) ) {
1925 addrindex_ds_read_data( ds );
1927 addressbook_ds_show_message( ds );
1929 if( ! addrindex_ds_get_access_flag( ds ) ) {
1930 /* Remove existing folders and groups */
1931 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1932 addressbook_tree_remove_children( ctree, node );
1933 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1935 /* Load folders into the tree */
1936 rootFolder = addrindex_ds_get_root_folder( ds );
1937 if( ds && ds->type == ADDR_IF_JPILOT ) {
1938 aot = ADDR_CATEGORY;
1940 else if( ds && ds->type == ADDR_IF_LDAP ) {
1941 aot = ADDR_LDAP_QUERY;
1944 aot = ADDR_ITEM_FOLDER;
1946 addressbook_node_add_folder( node, ds, rootFolder, aot );
1947 addrindex_ds_set_access_flag( ds, &tVal );
1948 gtk_cmctree_expand( ctree, node );
1951 addressbook_set_clist(NULL, TRUE);
1954 /* Update address list */
1955 g_signal_handlers_block_by_func
1957 G_CALLBACK(addressbook_tree_selected), NULL);
1958 addressbook_set_clist( obj, FALSE );
1959 g_signal_handlers_unblock_by_func
1961 G_CALLBACK(addressbook_tree_selected), NULL);
1962 if (!prefs_common.addressbook_use_editaddress_dialog)
1963 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1965 /* Setup main menu selections */
1966 addressbook_menubar_set_sensitive( FALSE );
1967 addressbook_menuitem_set_sensitive( obj, node );
1968 addressbook_list_select_clear();
1969 addressbook_list_menu_setup();
1974 * Setup address list popup menu items. Items are enabled or disabled as
1977 static void addressbook_list_menu_setup( void ) {
1978 GtkCMCTree *clist = NULL;
1979 AddressObject *pobj = NULL;
1980 AddressObject *obj = NULL;
1981 AdapterDSource *ads = NULL;
1982 AddressInterface *iface = NULL;
1983 AddressDataSource *ds = NULL;
1984 gboolean canEdit = FALSE;
1985 gboolean canDelete = FALSE;
1986 gboolean canCut = FALSE;
1987 gboolean canCopy = FALSE;
1988 gboolean canPaste = FALSE;
1989 gboolean canBrowse = FALSE;
1991 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1992 if( pobj == NULL ) return;
1994 clist = GTK_CMCTREE(addrbook.clist);
1995 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
1996 if( obj == NULL ) canEdit = FALSE;
1998 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1999 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2001 if( pobj->type == ADDR_DATASOURCE ) {
2002 /* Parent object is a data source */
2003 ads = ADAPTER_DSOURCE(pobj);
2004 ds = ads->dataSource;
2007 iface = ds->interface;
2010 if( ! iface->readOnly ) {
2011 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2012 if (iface->type != ADDR_IF_LDAP)
2013 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2014 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2017 canDelete = canEdit;
2020 else if( pobj->type != ADDR_INTERFACE ) {
2021 /* Parent object is not an interface */
2022 ds = addressbook_find_datasource( addrbook.treeSelected );
2025 iface = ds->interface;
2028 if( ! iface->readOnly ) {
2029 /* Folder or group */
2030 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2031 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2032 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2033 if( obj ) canEdit = TRUE;
2036 if( pobj->type == ADDR_ITEM_FOLDER ) {
2037 if (iface->type != ADDR_IF_LDAP)
2038 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2039 if( obj ) canEdit = TRUE;
2041 canDelete = canEdit;
2043 if( iface->type == ADDR_IF_LDAP ) {
2044 if( obj ) canBrowse = TRUE;
2051 /* Enable cut and paste */
2052 if( ! addrclip_is_empty( _clipBoard_ ) )
2054 if( ! addrselect_test_empty( _addressSelect_ ) )
2056 /* Enable copy if something is selected */
2057 if( ! addrselect_test_empty( _addressSelect_ ) )
2061 /* Disable edit or browse if more than one row selected */
2062 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2067 /* Forbid write changes when read-only */
2068 if( iface && iface->readOnly ) {
2074 /* Now go finalize menu items */
2075 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2076 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2078 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2079 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2080 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2082 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2084 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2085 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2086 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2088 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2089 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2090 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2092 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2093 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2095 if (addrbook.target_compose) {
2096 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2097 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2098 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2101 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2105 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2106 GtkCMCTreeNode *node,
2113 * Add list of items into tree node below specified tree node.
2114 * \param treeNode Tree node.
2115 * \param ds Data source.
2116 * \param listItems List of items.
2118 static void addressbook_treenode_add_list(
2119 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2125 AddrItemObject *aio;
2129 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2132 group = ( ItemGroup * ) aio;
2133 nn = addressbook_node_add_group( treeNode, ds, group );
2135 g_message("error adding addressbook group\n");
2138 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2141 folder = ( ItemFolder * ) aio;
2142 nn = addressbook_node_add_folder(
2143 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2145 g_message("error adding addressbook folder\n");
2148 node = g_list_next( node );
2152 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2153 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2157 * Cut from address list widget.
2159 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2160 _clipBoard_->cutFlag = TRUE;
2161 addrclip_clear( _clipBoard_ );
2162 addrclip_add( _clipBoard_, _addressSelect_ );
2163 /* addrclip_list_show( _clipBoard_, stdout ); */
2167 * Copy from address list widget.
2169 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2170 _clipBoard_->cutFlag = FALSE;
2171 addrclip_clear( _clipBoard_ );
2172 addrclip_add( _clipBoard_, _addressSelect_ );
2173 /* addrclip_list_show( _clipBoard_, stdout ); */
2177 * Paste clipboard into address list widget.
2179 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2180 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2181 AddressObject *pobj = NULL;
2182 AddressDataSource *ds = NULL;
2183 AddressBookFile *abf = NULL;
2184 ItemFolder *folder = NULL;
2185 GList *folderGroup = NULL;
2187 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2188 if( ds == NULL ) return;
2189 if( addrindex_ds_get_readonly( ds ) ) {
2190 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2194 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2196 if( pobj->type == ADDR_ITEM_FOLDER ) {
2197 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2199 else if( pobj->type == ADDR_ITEM_GROUP ) {
2200 alertpanel_error( _("Cannot paste into an address group.") );
2205 /* Get an address book */
2206 abf = addressbook_get_book_file();
2207 if( abf == NULL ) return;
2209 if( _clipBoard_->cutFlag ) {
2211 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2213 /* Remove all groups and folders in clipboard from tree node */
2214 addressbook_treenode_remove_item();
2216 /* Remove all "cut" items */
2217 addrclip_delete_item( _clipBoard_ );
2219 /* Clear clipboard - cut items??? */
2220 addrclip_clear( _clipBoard_ );
2224 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2227 /* addrclip_list_show( _clipBoard_, stdout ); */
2229 /* Update tree by inserting node for each folder or group */
2230 addressbook_treenode_add_list(
2231 addrbook.treeSelected, ds, folderGroup );
2232 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2233 g_list_free( folderGroup );
2237 /* Display items pasted */
2238 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2239 addressbook_set_clist(
2240 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2248 * Add current treenode object to clipboard. Note that widget only allows
2249 * one entry from the tree list to be selected.
2251 static void addressbook_treenode_to_clipboard( void ) {
2252 AddressObject *obj = NULL;
2253 AddressDataSource *ds = NULL;
2254 AddrSelectItem *item;
2255 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2256 GtkCMCTreeNode *node;
2258 node = addrbook.treeSelected;
2259 if( node == NULL ) return;
2260 obj = gtk_cmctree_node_get_row_data( ctree, node );
2261 if( obj == NULL ) return;
2263 ds = addressbook_find_datasource( node );
2264 if( ds == NULL ) return;
2267 if( obj->type == ADDR_ITEM_FOLDER ) {
2268 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2269 ItemFolder *folder = adapter->itemFolder;
2271 item = addrselect_create_node( obj );
2272 item->uid = g_strdup( ADDRITEM_ID(folder) );
2274 else if( obj->type == ADDR_ITEM_GROUP ) {
2275 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2276 ItemGroup *group = adapter->itemGroup;
2278 item = addrselect_create_node( obj );
2279 item->uid = g_strdup( ADDRITEM_ID(group) );
2281 else if( obj->type == ADDR_DATASOURCE ) {
2283 item = addrselect_create_node( obj );
2288 /* Clear existing list and add item into list */
2291 addressbook_list_select_clear();
2292 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2293 addrselect_list_add( _addressSelect_, item, cacheID );
2299 * Cut from tree widget.
2301 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2302 _clipBoard_->cutFlag = TRUE;
2303 addressbook_treenode_to_clipboard();
2304 addrclip_clear( _clipBoard_ );
2305 addrclip_add( _clipBoard_, _addressSelect_ );
2306 /* addrclip_list_show( _clipBoard_, stdout ); */
2310 * Copy from tree widget.
2312 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2313 _clipBoard_->cutFlag = FALSE;
2314 addressbook_treenode_to_clipboard();
2315 addrclip_clear( _clipBoard_ );
2316 addrclip_add( _clipBoard_, _addressSelect_ );
2317 /* addrclip_list_show( _clipBoard_, stdout ); */
2321 * Paste clipboard into address tree widget.
2323 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2324 addressbook_clip_paste_cb(NULL,NULL);
2328 * Clear selected entries in clipboard.
2330 static void addressbook_list_select_clear( void ) {
2331 addrselect_list_clear( _addressSelect_ );
2335 * Add specified address item to selected address list.
2336 * \param aio Address item object.
2337 * \param ds Datasource.
2339 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2342 if( ds == NULL ) return;
2343 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2344 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2349 * Remove specified address item from selected address list.
2350 * \param aio Address item object.
2352 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2353 addrselect_list_remove( _addressSelect_, aio );
2357 * Invoke EMail compose window with addresses in selected address list.
2359 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2362 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2363 listAddress = addrselect_build_list( _addressSelect_ );
2364 compose_new_with_list( NULL, listAddress );
2365 mgu_free_dlist( listAddress );
2370 static void addressbook_list_row_selected( GtkCMCTree *clist,
2371 GtkCMCTreeNode *node,
2375 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2376 AddrItemObject *aio = NULL;
2377 AddressObject *pobj = NULL;
2378 AdapterDSource *ads = NULL;
2379 AddressDataSource *ds = NULL;
2381 gtk_entry_set_text( entry, "" );
2382 addrbook.listSelected = node;
2384 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2385 if( pobj == NULL ) return;
2387 if( pobj->type == ADDR_DATASOURCE ) {
2388 ads = ADAPTER_DSOURCE(pobj);
2389 ds = ads->dataSource;
2391 else if( pobj->type != ADDR_INTERFACE ) {
2392 ds = addressbook_find_datasource( addrbook.treeSelected );
2395 aio = gtk_cmctree_node_get_row_data( clist, node );
2397 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2398 addressbook_list_select_add( aio, ds );
2401 addressbook_list_menu_setup();
2403 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2404 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2406 if (obj && obj->type != ADDR_ITEM_GROUP)
2407 addressbook_edit_address(NULL, 0, NULL, FALSE);
2411 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2412 GtkCMCTreeNode *node,
2416 AddrItemObject *aio;
2418 aio = gtk_cmctree_node_get_row_data( ctree, node );
2420 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2421 addressbook_list_select_remove( aio );
2424 if (!prefs_common.addressbook_use_editaddress_dialog)
2425 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2428 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2429 GdkEventButton *event,
2432 if( ! event ) return FALSE;
2434 addressbook_list_menu_setup();
2436 if( event->button == 3 ) {
2437 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2438 event->button, event->time );
2439 } else if (event->button == 1) {
2440 if (event->type == GDK_2BUTTON_PRESS) {
2441 if (prefs_common.add_address_by_click &&
2442 addrbook.target_compose)
2443 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2445 if (prefs_common.addressbook_use_editaddress_dialog)
2446 addressbook_edit_address_cb(NULL, NULL);
2448 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2449 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2450 if( obj && obj->type == ADDR_ITEM_GROUP )
2451 addressbook_edit_address_cb(NULL, NULL);
2459 static gboolean addressbook_list_button_released(GtkWidget *widget,
2460 GdkEventButton *event,
2466 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2467 GdkEventButton *event,
2470 GtkCMCList *clist = GTK_CMCLIST(ctree);
2472 AddressObject *obj = NULL;
2473 AdapterDSource *ads = NULL;
2474 AddressInterface *iface = NULL;
2475 AddressDataSource *ds = NULL;
2476 gboolean canEdit = FALSE;
2477 gboolean canDelete = FALSE;
2478 gboolean canCut = FALSE;
2479 gboolean canCopy = FALSE;
2480 gboolean canPaste = FALSE;
2481 gboolean canTreeCut = FALSE;
2482 gboolean canTreeCopy = FALSE;
2483 gboolean canTreePaste = FALSE;
2484 gboolean canLookup = FALSE;
2485 GtkCMCTreeNode *node = NULL;
2487 if( ! event ) return FALSE;
2488 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2490 if (event->button == 1) {
2491 if (event->type == GDK_2BUTTON_PRESS) {
2492 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2493 gtkut_clist_set_focus_row(clist, row);
2494 obj = gtk_cmclist_get_row_data( clist, row );
2499 if (obj->type == ADDR_ITEM_GROUP) {
2501 addressbook_treenode_edit_cb(NULL, NULL);
2503 /* expand pr collapse */
2504 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2505 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2511 addressbook_menubar_set_sensitive( FALSE );
2513 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2514 gtkut_clist_set_focus_row(clist, row);
2515 obj = gtk_cmclist_get_row_data( clist, row );
2518 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2522 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2524 if( ! addrclip_is_empty( _clipBoard_ ) )
2525 canTreePaste = TRUE;
2527 if (obj->type == ADDR_INTERFACE) {
2528 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2529 iface = adapter->interface;
2532 if( !iface->readOnly ) {
2533 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2534 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2536 if( iface->externalQuery )
2539 if (obj->type == ADDR_DATASOURCE) {
2540 ads = ADAPTER_DSOURCE(obj);
2541 ds = ads->dataSource;
2544 iface = ds->interface;
2547 if( !iface->readOnly ) {
2549 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2550 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2551 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2555 if( iface->externalQuery )
2558 else if (obj->type == ADDR_ITEM_FOLDER) {
2559 ds = addressbook_find_datasource( node );
2562 iface = ds->interface;
2565 if( !iface->readOnly ) {
2569 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2570 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2571 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2575 if( iface->externalQuery ) {
2576 /* Enable deletion of LDAP folder */
2581 else if (obj->type == ADDR_ITEM_GROUP) {
2582 ds = addressbook_find_datasource( node );
2585 iface = ds->interface;
2588 if( ! iface->readOnly ) {
2591 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2592 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2596 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2598 if( ! addrselect_test_empty( _addressSelect_ ) )
2600 if( ! addrclip_is_empty( _clipBoard_ ) )
2603 /* Forbid write changes when read-only */
2604 if( iface && iface->readOnly ) {
2606 canTreePaste = FALSE;
2614 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2615 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2616 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2617 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2618 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2620 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2621 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2622 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2623 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2624 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2626 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2627 addrbook.target_compose != NULL);
2629 if( event->button == 3 )
2630 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2631 event->button, event->time);
2636 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2637 GdkEventButton *event,
2640 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2644 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2646 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2647 AddressObject *obj = NULL;
2648 AddressDataSource *ds = NULL;
2649 AddressBookFile *abf = NULL;
2650 ItemFolder *parentFolder = NULL;
2651 ItemFolder *folder = NULL;
2653 if( ! addrbook.treeSelected ) return;
2654 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2655 if( obj == NULL ) return;
2656 ds = addressbook_find_datasource( addrbook.treeSelected );
2657 if( ds == NULL ) return;
2659 if( obj->type == ADDR_DATASOURCE ) {
2660 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2662 else if( obj->type == ADDR_ITEM_FOLDER ) {
2663 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2669 abf = ds->rawDataSource;
2670 if( abf == NULL ) return;
2671 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2674 nn = addressbook_node_add_folder(
2675 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2677 g_message("error adding addressbook folder\n");
2679 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2680 if( addrbook.treeSelected == addrbook.opened )
2681 addressbook_set_clist(obj, TRUE);
2685 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2687 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2688 AddressObject *obj = NULL;
2689 AddressDataSource *ds = NULL;
2690 AddressBookFile *abf = NULL;
2691 ItemFolder *parentFolder = NULL;
2692 ItemGroup *group = NULL;
2694 if( ! addrbook.treeSelected ) return;
2695 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2696 if( obj == NULL ) return;
2697 ds = addressbook_find_datasource( addrbook.treeSelected );
2698 if( ds == NULL ) return;
2700 if( obj->type == ADDR_DATASOURCE ) {
2701 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2703 else if( obj->type == ADDR_ITEM_FOLDER ) {
2704 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2710 abf = ds->rawDataSource;
2711 if( abf == NULL ) return;
2712 group = addressbook_edit_group( abf, parentFolder, NULL );
2715 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2717 g_message("error adding addressbook group\n");
2719 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2720 if( addrbook.treeSelected == addrbook.opened )
2721 addressbook_set_clist(obj, TRUE);
2725 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2727 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2730 GdkPixbuf *pix_cl, *pix_op;
2731 gboolean is_leaf, expanded;
2733 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2735 &is_leaf, &expanded);
2736 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2743 * \param obj Address object to edit.
2744 * \param node Node in tree.
2745 * \return New name of data source.
2747 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2748 gchar *newName = NULL;
2749 AddressDataSource *ds = NULL;
2750 AddressInterface *iface = NULL;
2751 AdapterDSource *ads = NULL;
2753 ds = addressbook_find_datasource( node );
2754 if( ds == NULL ) return NULL;
2755 iface = ds->interface;
2756 if( ! iface->haveLibrary ) return NULL;
2758 /* Read data from data source */
2759 if( addrindex_ds_get_modify_flag( ds ) ) {
2760 addrindex_ds_read_data( ds );
2763 if( ! addrindex_ds_get_read_flag( ds ) ) {
2764 addrindex_ds_read_data( ds );
2768 ads = ADAPTER_DSOURCE(obj);
2769 if( ads->subType == ADDR_BOOK ) {
2770 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2772 else if( ads->subType == ADDR_VCARD ) {
2773 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2776 else if( ads->subType == ADDR_JPILOT ) {
2777 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2781 else if( ads->subType == ADDR_LDAP ) {
2782 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2788 newName = obj->name;
2793 * Edit an object that is in the address tree area.
2795 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2797 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2799 AddressDataSource *ds = NULL;
2800 AddressBookFile *abf = NULL;
2801 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2804 if( ! addrbook.treeSelected ) return;
2805 node = addrbook.treeSelected;
2806 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2807 obj = gtk_cmctree_node_get_row_data( ctree, node );
2808 if( obj == NULL ) return;
2809 parentNode = GTK_CMCTREE_ROW(node)->parent;
2811 ds = addressbook_find_datasource( node );
2812 if( ds == NULL ) return;
2814 if( obj->type == ADDR_DATASOURCE ) {
2815 name = addressbook_edit_datasource( obj, node );
2816 if( name == NULL ) return;
2819 abf = ds->rawDataSource;
2820 if( abf == NULL ) return;
2821 if( obj->type == ADDR_ITEM_FOLDER ) {
2822 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2823 ItemFolder *item = adapter->itemFolder;
2824 ItemFolder *parentFolder = NULL;
2825 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2826 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2827 name = ADDRITEM_NAME(item);
2829 else if( obj->type == ADDR_ITEM_GROUP ) {
2830 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2831 ItemGroup *item = adapter->itemGroup;
2832 ItemFolder *parentFolder = NULL;
2833 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2834 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2835 name = ADDRITEM_NAME(item);
2838 if( name && parentNode ) {
2839 /* Update node in tree view */
2840 addressbook_change_node_name( node, name );
2841 gtk_sctree_sort_node(ctree, parentNode);
2842 gtk_cmctree_expand( ctree, node );
2843 gtk_sctree_select( GTK_SCTREE( ctree), node );
2850 ADDRTREE_DEL_FOLDER_ONLY,
2851 ADDRTREE_DEL_FOLDER_ADDR
2855 * Delete an item from the tree widget.
2856 * \param data Data passed in.
2857 * \param action Action.
2858 * \param widget Widget issuing callback.
2860 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2862 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2863 GtkCMCTreeNode *node = NULL;
2867 AddrBookBase *adbase;
2868 AddressCache *cache;
2869 AdapterDSource *ads = NULL;
2870 AddressInterface *iface = NULL;
2871 AddressDataSource *ds = NULL;
2872 gboolean remFlag = FALSE;
2873 TreeItemDelType delType;
2875 if( ! addrbook.treeSelected ) return;
2876 node = addrbook.treeSelected;
2877 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2879 obj = gtk_cmctree_node_get_row_data( ctree, node );
2880 cm_return_if_fail(obj != NULL);
2882 if( obj->type == ADDR_DATASOURCE ) {
2883 ads = ADAPTER_DSOURCE(obj);
2884 if( ads == NULL ) return;
2885 ds = ads->dataSource;
2886 if( ds == NULL ) return;
2889 /* Must be folder or something else */
2890 ds = addressbook_find_datasource( node );
2891 if( ds == NULL ) return;
2893 /* Only allow deletion from non-readOnly */
2894 iface = ds->interface;
2895 if( iface->readOnly ) {
2896 /* Allow deletion of query results */
2897 if( ! iface->externalQuery ) return;
2901 /* Confirm deletion */
2902 delType = ADDRTREE_DEL_NONE;
2903 if( obj->type == ADDR_ITEM_FOLDER ) {
2904 if( iface && iface->externalQuery ) {
2905 message = g_strdup_printf( _(
2906 "Do you want to delete the query " \
2907 "results and addresses in '%s'?" ),
2909 aval = alertpanel( _("Delete"), message,
2910 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2912 if( aval == G_ALERTALTERNATE ) {
2913 delType = ADDRTREE_DEL_FOLDER_ADDR;
2917 message = g_strdup_printf
2918 ( _( "Do you want to delete '%s'? "
2919 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2921 aval = alertpanel( _("Delete folder"), message,
2922 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2924 if( aval == G_ALERTALTERNATE ) {
2925 delType = ADDRTREE_DEL_FOLDER_ONLY;
2927 else if( aval == G_ALERTOTHER ) {
2928 delType = ADDRTREE_DEL_FOLDER_ADDR;
2932 else if( obj->type == ADDR_ITEM_GROUP ) {
2933 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2934 "The addresses it contains will not be lost."), obj->name);
2935 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2936 "+" GTK_STOCK_DELETE, NULL);
2938 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2940 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2941 "The addresses it contains will be lost."), obj->name);
2942 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2943 "+" GTK_STOCK_DELETE, NULL);
2945 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2947 if( delType == ADDRTREE_DEL_NONE ) return;
2949 /* Proceed with deletion */
2950 if( obj->type == ADDR_DATASOURCE ) {
2951 /* Remove node from tree */
2952 gtk_cmctree_remove_node( ctree, node );
2954 if (delType == ADDRTREE_DEL_DATA &&
2955 ds->interface && ds->interface->type == ADDR_IF_BOOK)
2956 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
2958 /* Remove data source. */
2959 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2960 addrindex_free_datasource( ds );
2965 /* Get reference to cache */
2966 adbase = ( AddrBookBase * ) ds->rawDataSource;
2967 if( adbase == NULL ) return;
2968 cache = adbase->addressCache;
2970 /* Remove query results folder */
2971 if( iface && iface->externalQuery ) {
2972 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2973 ItemFolder *folder = adapter->itemFolder;
2975 adapter->itemFolder = NULL;
2977 g_print( "remove folder for ::%s::\n", obj->name );
2978 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2979 g_print( "-------------- remove results\n" );
2981 addrindex_remove_results( ds, folder );
2982 /* g_print( "-------------- remove node\n" ); */
2983 gtk_cmctree_remove_node( ctree, node );
2987 /* Code below is valid for regular address book deletion */
2988 if( obj->type == ADDR_ITEM_FOLDER ) {
2989 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2990 ItemFolder *item = adapter->itemFolder;
2992 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2993 /* Remove folder only */
2994 item = addrcache_remove_folder( cache, item );
2996 addritem_free_item_folder( item );
2997 addressbook_move_nodes_up( ctree, node );
3001 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3002 /* Remove folder and addresses */
3003 item = addrcache_remove_folder_delete( cache, item );
3005 addritem_free_item_folder( item );
3010 else if( obj->type == ADDR_ITEM_GROUP ) {
3011 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3012 ItemGroup *item = adapter->itemGroup;
3014 item = addrcache_remove_group( cache, item );
3016 addritem_free_item_group( item );
3023 gtk_cmctree_remove_node(ctree, node );
3027 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3029 if( person && addrbook.treeSelected == addrbook.opened ) {
3030 person->status = ADD_ENTRY;
3031 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3032 addressbook_folder_refresh_one_person(
3033 GTK_CMCTREE(addrbook.clist), person );
3035 addressbook_address_list_set_focus();
3038 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3040 if( person && addrbook.treeSelected == addrbook.opened) {
3041 person->status = ADD_ENTRY;
3042 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3043 addressbook_set_clist(
3044 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3048 addressbook_address_list_set_focus();
3052 * Label (a format string) that is used to name each folder.
3054 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3057 * Search ctree widget callback function.
3058 * \param pA Pointer to node.
3059 * \param pB Pointer to data item being sought.
3060 * \return Zero (0) if folder found.
3062 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3065 aoA = ( AddressObject * ) pA;
3066 if( aoA->type == ADDR_ITEM_FOLDER ) {
3067 ItemFolder *folder, *fld;
3069 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3070 folder = ( ItemFolder * ) pB;
3071 if( fld == folder ) return 0; /* Found folder */
3076 static ItemFolder * addressbook_setup_subf(
3077 AddressDataSource *ds, gchar *title,
3078 GtkCMCTreeNode *pNode )
3080 AddrBookBase *adbase;
3081 AddressCache *cache;
3084 GtkCMCTreeNode *nNode;
3086 AddressObjectType aoType = ADDR_NONE;
3089 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3091 if( ds && ds->type == ADDR_IF_LDAP ) {
3093 aoType = ADDR_LDAP_QUERY;
3100 ctree = GTK_CMCTREE(addrbook.ctree);
3101 /* Get reference to address cache */
3102 adbase = ( AddrBookBase * ) ds->rawDataSource;
3103 cache = adbase->addressCache;
3105 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3106 GList *cur = children;
3107 for (; cur; cur = cur->next) {
3108 ItemFolder *child = (ItemFolder *) cur->data;
3109 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3110 nNode = gtk_cmctree_find_by_row_data_custom(
3112 addressbook_treenode_find_folder_cb );
3114 addrindex_remove_results( ds, child );
3115 while( child->listPerson ) {
3116 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3117 item = addrcache_remove_person( cache, item );
3119 addritem_free_item_person( item );
3123 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3124 addrbook.treeSelected = nNode;
3131 /* Create a folder */
3132 folder = addrcache_add_new_folder( cache, NULL );
3133 name = g_strdup_printf( "%s", title );
3134 addritem_folder_set_name( folder, name );
3135 addritem_folder_set_remarks( folder, "" );
3138 /* Now let's see the folder */
3139 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3140 gtk_cmctree_expand( ctree, pNode );
3142 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3143 addrbook.treeSelected = nNode;
3149 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3150 AddressObject *pobj = NULL;
3151 AddressDataSource *ds = NULL;
3152 AddressBookFile *abf = NULL;
3153 debug_print("adding address\n");
3154 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3155 if( pobj == NULL ) {
3156 debug_print("no row data\n");
3159 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3161 debug_print("no datasource\n");
3165 abf = ds->rawDataSource;
3167 g_print("no addressbook file\n");
3171 if( pobj->type == ADDR_DATASOURCE ) {
3172 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3173 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3175 ItemFolder *folder = NULL;
3177 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3178 GtkCMCTreeNode *parentNode;
3179 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3180 if( ds == NULL ) return;
3182 /* We must have a datasource that is an external interface */
3183 if( ! ds->interface->haveLibrary ) return;
3184 if( ! ds->interface->externalQuery ) return;
3186 if( pobj->type == ADDR_ITEM_FOLDER ) {
3187 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3190 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3192 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3194 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3195 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3197 abf = ds->rawDataSource;
3200 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3201 addrbook.editaddress_vbox,
3202 addressbook_new_address_from_book_post_cb,
3205 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3206 LdapServer *server = ds->rawDataSource;
3207 ldapsvr_set_modified(server, TRUE);
3208 ldapsvr_update_book(server, NULL);
3209 if (server->retVal != LDAPRC_SUCCESS) {
3210 alertpanel( _("Add address(es)"),
3211 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3212 GTK_STOCK_CLOSE, NULL, NULL );
3213 server->retVal = LDAPRC_SUCCESS;
3218 if (prefs_common.addressbook_use_editaddress_dialog)
3219 addressbook_new_address_from_book_post_cb( person );
3222 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3224 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3227 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3228 GtkCMCTreeNode *parentNode;
3229 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3230 if( ds == NULL ) return;
3232 /* We must have a datasource that is an external interface */
3233 if( ! ds->interface->haveLibrary ) return;
3234 if( ! ds->interface->externalQuery ) return;
3236 if( pobj->type == ADDR_ITEM_FOLDER ) {
3237 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3240 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3242 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3245 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3246 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3248 abf = ds->rawDataSource;
3251 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3252 addrbook.editaddress_vbox,
3253 addressbook_new_address_from_folder_post_cb,
3256 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3257 LdapServer *server = ds->rawDataSource;
3258 ldapsvr_set_modified(server, TRUE);
3259 ldapsvr_update_book(server, NULL);
3260 if (server->retVal != LDAPRC_SUCCESS) {
3261 alertpanel( _("Add address(es)"),
3262 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3263 GTK_STOCK_CLOSE, NULL, NULL );
3268 if (prefs_common.addressbook_use_editaddress_dialog)
3269 addressbook_new_address_from_folder_post_cb( person );
3271 else if( pobj->type == ADDR_ITEM_GROUP ) {
3272 /* New address in group */
3273 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3274 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3275 if (addrbook.treeSelected == addrbook.opened) {
3276 /* Change node name in tree. */
3277 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3278 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3279 addressbook_set_clist(
3280 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3288 * Search for specified child group node in address index tree.
3289 * \param parent Parent node.
3290 * \param group Group to find.
3292 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3293 GtkCMCTreeNode *node = NULL;
3294 GtkCMCTreeRow *currRow;
3296 currRow = GTK_CMCTREE_ROW( parent );
3298 node = currRow->children;
3302 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3303 if( obj->type == ADDR_ITEM_GROUP ) {
3304 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3305 if( g == group ) return node;
3307 currRow = GTK_CMCTREE_ROW(node);
3308 node = currRow->sibling;
3314 static AddressBookFile *addressbook_get_book_file() {
3315 AddressBookFile *abf = NULL;
3316 AddressDataSource *ds = NULL;
3318 ds = addressbook_find_datasource( addrbook.treeSelected );
3319 if( ds == NULL ) return NULL;
3320 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3324 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3325 GtkCMCTreeNode *node;
3328 /* Remove existing folders and groups */
3329 row = GTK_CMCTREE_ROW( parent );
3331 while( (node = row->children) ) {
3332 gtk_cmctree_remove_node( ctree, node );
3337 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3338 GtkCMCTreeNode *parent, *child;
3339 GtkCMCTreeRow *currRow;
3340 currRow = GTK_CMCTREE_ROW( node );
3342 parent = currRow->parent;
3343 while( (child = currRow->children) ) {
3344 gtk_cmctree_move( ctree, child, parent, node );
3346 gtk_sctree_sort_node( ctree, parent );
3350 static void addressbook_edit_address_post_cb( ItemPerson *person )
3354 AddressBookFile *abf = addressbook_get_book_file();
3356 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3357 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3358 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3361 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3362 invalidate_address_completion();
3364 addressbook_address_list_set_focus();
3367 void addressbook_address_list_set_focus( void )
3369 if (!prefs_common.addressbook_use_editaddress_dialog) {
3370 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3371 addressbook_list_menu_setup();
3375 void addressbook_address_list_disable_some_actions(void)
3377 /* disable address copy/pasting when editing contact's detail (embedded form) */
3378 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3379 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3380 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3383 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3384 addressbook_edit_address(data, 0, NULL, TRUE);
3387 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3388 gboolean force_focus ) {
3389 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3391 AddressObject *obj = NULL, *pobj = NULL;
3392 AddressDataSource *ds = NULL;
3393 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3395 AddressBookFile *abf = NULL;
3397 if( addrbook.listSelected == NULL ) return;
3398 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3399 cm_return_if_fail(obj != NULL);
3401 ctree = GTK_CMCTREE( addrbook.ctree );
3402 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3403 node = gtk_cmctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3405 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3406 if( ds == NULL ) return;
3408 abf = addressbook_get_book_file();
3410 if( obj->type == ADDR_ITEM_EMAIL ) {
3411 ItemEMail *email = ( ItemEMail * ) obj;
3412 if( email == NULL ) return;
3413 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3414 /* Edit parent group */
3415 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3416 ItemGroup *itemGrp = adapter->itemGroup;
3417 if( abf == NULL ) return;
3418 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3419 name = ADDRITEM_NAME(itemGrp);
3420 node = addrbook.treeSelected;
3421 parentNode = GTK_CMCTREE_ROW(node)->parent;
3424 /* Edit person - email page */
3426 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3427 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3428 addressbook_edit_address_post_cb,
3429 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3432 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3433 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3434 person->status = UPDATE_ENTRY;
3437 if (prefs_common.addressbook_use_editaddress_dialog)
3438 addressbook_edit_address_post_cb( person );
3443 else if( obj->type == ADDR_ITEM_PERSON ) {
3444 /* Edit person - basic page */
3445 ItemPerson *person = ( ItemPerson * ) obj;
3446 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3447 addressbook_edit_address_post_cb,
3448 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3451 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3452 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3453 person->status = UPDATE_ENTRY;
3456 if (prefs_common.addressbook_use_editaddress_dialog)
3457 addressbook_edit_address_post_cb( person );
3461 else if( obj->type == ADDR_ITEM_GROUP ) {
3462 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3463 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3464 parentNode = addrbook.treeSelected;
3465 node = addressbook_find_group_node( parentNode, itemGrp );
3466 name = ADDRITEM_NAME(itemGrp);
3467 invalidate_address_completion();
3473 /* Update tree node with node name */
3474 if( node == NULL ) return;
3475 addressbook_change_node_name( node, name );
3476 gtk_sctree_sort_node( ctree, parentNode );
3477 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3478 addressbook_set_clist(
3479 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3484 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3486 addressbook_del_clicked(NULL, NULL);
3489 static void close_cb(GtkAction *action, gpointer data)
3491 addressbook_close();
3494 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3495 addressbook_export_to_file();
3498 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3500 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3501 if( person ) addritem_person_set_opened( person, TRUE );
3505 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3507 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3508 if( person ) addritem_person_set_opened( person, FALSE );
3512 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3514 gchar *eMailAlias = ADDRITEM_NAME(email);
3515 if( eMailAlias && *eMailAlias != '\0' ) {
3517 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3520 str = g_strdup( eMailAlias );
3526 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3527 GList *items = itemGroup->listEMail;
3528 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3529 for( ; items != NULL; items = g_list_next( items ) ) {
3530 GtkCMCTreeNode *nodeEMail = NULL;
3531 gchar *text[N_LIST_COLS];
3532 ItemEMail *email = items->data;
3536 if( ! email ) continue;
3538 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3539 str = addressbook_format_item_clist( person, email );
3541 text[COL_NAME] = addressbook_set_col_name_guard(str);
3544 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3546 text[COL_ADDRESS] = email->address;
3547 text[COL_REMARKS] = email->remarks;
3548 nodeEMail = gtk_sctree_insert_node(
3550 text, FOLDER_SPACING,
3554 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3560 gchar *addressbook_set_col_name_guard(gchar *value)
3562 gchar *ret = "<not set>";
3563 gchar *tmp = g_strdup(value);
3565 if (tmp !=NULL && *tmp != '\0')
3571 static void addressbook_folder_load_one_person(
3572 GtkCMCTree *clist, ItemPerson *person,
3573 AddressTypeControlItem *atci,
3574 AddressTypeControlItem *atciMail )
3576 GtkCMCTreeNode *nodePerson = NULL;
3577 GtkCMCTreeNode *nodeEMail = NULL;
3578 gchar *text[N_LIST_COLS];
3579 gboolean flgFirst = TRUE, haveAddr = FALSE;
3582 AddressBookFile *abf = addressbook_get_book_file();
3585 if( person == NULL ) return;
3587 text[COL_NAME] = "";
3588 node = person->listEMail;
3590 ItemEMail *email = node->data;
3591 gchar *eMailAddr = NULL;
3592 node = g_list_next( node );
3594 text[COL_ADDRESS] = email->address;
3595 text[COL_REMARKS] = email->remarks;
3596 eMailAddr = ADDRITEM_NAME(email);
3597 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3599 /* First email belongs with person */
3600 gchar *str = addressbook_format_item_clist( person, email );
3602 text[COL_NAME] = addressbook_set_col_name_guard(str);
3605 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3606 person && person->nickName ) {
3607 if (person->nickName) {
3608 if (strcmp(person->nickName, "") != 0) {
3609 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3612 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3618 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3620 nodePerson = gtk_sctree_insert_node(
3622 text, FOLDER_SPACING,
3625 FALSE, person->isOpened );
3628 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3631 /* Subsequent email is a child node of person */
3632 text[COL_NAME] = ADDRITEM_NAME(email);
3633 nodeEMail = gtk_sctree_insert_node(
3634 clist, nodePerson, NULL,
3635 text, FOLDER_SPACING,
3637 atciMail->iconXpmOpen,
3639 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3645 /* Have name without EMail */
3646 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3647 text[COL_ADDRESS] = "";
3648 text[COL_REMARKS] = "";
3649 nodePerson = gtk_sctree_insert_node(
3651 text, FOLDER_SPACING,
3654 FALSE, person->isOpened );
3655 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3660 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3662 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3663 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3665 if( atci == NULL ) return;
3666 if( atciMail == NULL ) return;
3668 /* Load email addresses */
3669 items = addritem_folder_get_person_list( itemFolder );
3670 for( ; items != NULL; items = g_list_next( items ) ) {
3671 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3673 /* Free up the list */
3674 mgu_clear_list( items );
3675 g_list_free( items );
3678 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3679 addrbook.listSelected = NULL;
3680 gtk_cmctree_remove_node( clist, node );
3681 addressbook_menubar_set_sensitive( FALSE );
3682 addressbook_menuitem_set_sensitive(
3683 gtk_cmctree_node_get_row_data(
3684 GTK_CMCTREE(clist), addrbook.treeSelected ),
3685 addrbook.treeSelected );
3688 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3689 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3690 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3691 GtkCMCTreeNode *node;
3692 if( atci == NULL ) return;
3693 if( atciMail == NULL ) return;
3694 if( person == NULL ) return;
3695 /* unload the person */
3697 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3699 addressbook_folder_remove_node( clist, node );
3700 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3701 gtk_sctree_sort_node( clist, NULL );
3702 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3704 gtk_sctree_select( GTK_SCTREE(clist), node );
3705 if (!gtk_cmctree_node_is_visible( clist, node ) )
3706 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3710 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3711 GtkCMCTreeNode *node;
3713 if( person == NULL ) return;
3714 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3716 addressbook_folder_remove_node( clist, node );
3720 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3722 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3724 /* Load any groups */
3725 if( ! atci ) return;
3726 items = addritem_folder_get_group_list( itemFolder );
3727 for( ; items != NULL; items = g_list_next( items ) ) {
3728 GtkCMCTreeNode *nodeGroup = NULL;
3729 gchar *text[N_LIST_COLS];
3730 ItemGroup *group = items->data;
3731 if( group == NULL ) continue;
3732 text[COL_NAME] = ADDRITEM_NAME(group);
3733 text[COL_ADDRESS] = "";
3734 text[COL_REMARKS] = "";
3735 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3736 text, FOLDER_SPACING,
3740 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3741 gtk_sctree_sort_node(clist, NULL);
3743 /* Free up the list */
3744 mgu_clear_list( items );
3745 g_list_free( items );
3749 * Search ctree widget callback function.
3750 * \param pA Pointer to node.
3751 * \param pB Pointer to data item being sought.
3752 * \return Zero (0) if group found.
3754 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3757 aoA = ( AddressObject * ) pA;
3758 if( aoA->type == ADDR_ITEM_GROUP ) {
3759 ItemGroup *group, *grp;
3761 grp = ADAPTER_GROUP(aoA)->itemGroup;
3762 group = ( ItemGroup * ) pB;
3763 if( grp == group ) return 0; /* Found group */
3769 * Remove folder and group nodes from tree widget for items contained ("cut")
3772 static void addressbook_treenode_remove_item( void ) {
3774 AddrSelectItem *cutItem;
3775 AddressCache *cache;
3776 AddrItemObject *aio;
3777 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3780 node = _clipBoard_->objectList;
3782 cutItem = node->data;
3783 node = g_list_next( node );
3784 cache = addrindex_get_cache(
3785 _clipBoard_->addressIndex, cutItem->cacheID );
3786 if( cache == NULL ) continue;
3787 aio = addrcache_get_object( cache, cutItem->uid );
3790 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3793 folder = ( ItemFolder * ) aio;
3794 tn = gtk_cmctree_find_by_row_data_custom(
3795 ctree, NULL, folder,
3796 addressbook_treenode_find_folder_cb );
3798 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3801 group = ( ItemGroup * ) aio;
3802 tn = gtk_cmctree_find_by_row_data_custom(
3804 addressbook_treenode_find_group_cb );
3808 /* Free up adapter and remove node. */
3809 gtk_cmctree_remove_node( ctree, tn );
3816 * Find parent datasource for specified tree node.
3817 * \param node Node to test.
3818 * \return Data source, or NULL if not found.
3820 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3821 AddressDataSource *ds = NULL;
3824 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3827 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3828 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3830 /* g_print( "ao->type = %d\n", ao->type ); */
3831 if( ao->type == ADDR_DATASOURCE ) {
3832 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3833 /* g_print( "found it\n" ); */
3834 ds = ads->dataSource;
3838 node = GTK_CMCTREE_ROW(node)->parent;
3844 * Load address list widget with children of specified object.
3845 * \param obj Parent object to be loaded.
3847 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3848 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3849 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3850 AddressDataSource *ds = NULL;
3851 AdapterDSource *ads = NULL;
3852 static AddressObject *last_obj = NULL;
3854 if (addrbook.clist == NULL) {
3857 if (obj == last_obj && !refresh)
3862 gtk_cmclist_clear(clist);
3866 if( obj->type == ADDR_INTERFACE ) {
3867 /* g_print( "set_clist: loading datasource...\n" ); */
3868 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3872 gtk_cmclist_freeze(clist);
3873 gtk_cmclist_clear(clist);
3875 if( obj->type == ADDR_DATASOURCE ) {
3876 ads = ADAPTER_DSOURCE(obj);
3877 ds = ads->dataSource;
3879 /* Load root folder */
3880 ItemFolder *rootFolder = NULL;
3881 rootFolder = addrindex_ds_get_root_folder( ds );
3882 addressbook_folder_load_person(
3883 ctreelist, rootFolder );
3884 addressbook_folder_load_group(
3885 ctreelist, rootFolder );
3889 if( obj->type == ADDR_ITEM_GROUP ) {
3891 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3892 addressbook_load_group( ctreelist, itemGroup );
3894 else if( obj->type == ADDR_ITEM_FOLDER ) {
3896 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3897 addressbook_folder_load_person( ctreelist, itemFolder );
3898 addressbook_folder_load_group( ctreelist, itemFolder );
3901 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3902 clist->focus_row = -1;
3903 gtk_cmclist_thaw(clist);
3907 * Call back function to free adaptor. Call back is setup by function
3908 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3909 * called when the address book tree widget node is removed by calling
3910 * function gtk_cmctree_remove_node().
3912 * \param data Tree node's row data.
3914 static void addressbook_free_treenode( gpointer data ) {
3917 ao = ( AddressObject * ) data;
3918 if( ao == NULL ) return;
3919 if( ao->type == ADDR_INTERFACE ) {
3920 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3921 addrbookctl_free_interface( ai );
3923 else if( ao->type == ADDR_DATASOURCE ) {
3924 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3925 addrbookctl_free_datasource( ads );
3927 else if( ao->type == ADDR_ITEM_FOLDER ) {
3928 AdapterFolder *af = ADAPTER_FOLDER(ao);
3929 addrbookctl_free_folder( af );
3931 else if( ao->type == ADDR_ITEM_GROUP ) {
3932 AdapterGroup *ag = ADAPTER_GROUP(ao);
3933 addrbookctl_free_group( ag );
3938 * Create new adaptor for specified data source.
3940 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3941 AddressObjectType otype, gchar *name )
3943 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3944 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3945 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3946 adapter->dataSource = ds;
3947 adapter->subType = otype;
3951 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3952 ADDRESS_OBJECT_NAME(adapter) =
3953 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3957 * Load tree from address index with the initial data.
3959 static void addressbook_load_tree( void ) {
3960 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3961 GList *nodeIf, *nodeDS;
3962 AdapterInterface *adapter;
3963 AddressInterface *iface;
3964 AddressTypeControlItem *atci;
3965 AddressDataSource *ds;
3966 AdapterDSource *ads;
3967 GtkCMCTreeNode *node, *newNode;
3970 nodeIf = _addressInterfaceList_;
3972 adapter = nodeIf->data;
3973 node = adapter->treeNode;
3974 iface = adapter->interface;
3975 atci = adapter->atci;
3977 if( iface->useInterface ) {
3978 /* Load data sources below interface node */
3979 nodeDS = iface->listSource;
3982 name = addrindex_ds_get_name( ds );
3983 ads = addressbook_create_ds_adapter(
3984 ds, atci->objectType, name );
3985 newNode = addressbook_add_object(
3986 node, ADDRESS_OBJECT(ads) );
3987 if (newNode == NULL) {
3988 g_message("error adding addressbook object\n");
3990 nodeDS = g_list_next( nodeDS );
3992 gtk_cmctree_expand( ctree, node );
3995 nodeIf = g_list_next( nodeIf );
4000 * Convert the old address book to new format.
4002 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4003 gboolean retVal = FALSE;
4004 gboolean errFlag = TRUE;
4007 /* Read old address book, performing conversion */
4008 debug_print( "Reading and converting old address book...\n" );
4009 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4010 addrindex_read_data( addrIndex );
4011 if( addrIndex->retVal == MGU_NO_FILE ) {
4012 /* We do not have a file - new user */
4013 debug_print( "New user... create new books...\n" );
4014 addrindex_create_new_books( addrIndex );
4015 if( addrIndex->retVal == MGU_SUCCESS ) {
4016 /* Save index file */
4017 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4018 addrindex_save_data( addrIndex );
4019 if( addrIndex->retVal == MGU_SUCCESS ) {
4024 msg = _( "New user, could not save index file." );
4028 msg = _( "New user, could not save address book files." );
4032 /* We have an old file */
4033 if( addrIndex->wasConverted ) {
4034 /* Converted successfully - save address index */
4035 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4036 addrindex_save_data( addrIndex );
4037 if( addrIndex->retVal == MGU_SUCCESS ) {
4038 msg = _( "Old address book converted successfully." );
4043 msg = _("Old address book converted,\n"
4044 "could not save new address index file." );
4048 /* File conversion failed - just create new books */
4049 debug_print( "File conversion failed... just create new books...\n" );
4050 addrindex_create_new_books( addrIndex );
4051 if( addrIndex->retVal == MGU_SUCCESS ) {
4053 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4054 addrindex_save_data( addrIndex );
4055 if( addrIndex->retVal == MGU_SUCCESS ) {
4056 msg = _("Could not convert address book,\n"
4057 "but created empty new address book files." );
4062 msg = _("Could not convert address book,\n"
4063 "could not save new address index file." );
4067 msg = _("Could not convert address book\n"
4068 "and could not create new address book files." );
4073 debug_print( "Error\n%s\n", msg );
4074 alertpanel_full(_("Addressbook conversion error"), msg,
4075 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4076 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4079 debug_print( "Warning\n%s\n", msg );
4080 alertpanel_full(_("Addressbook conversion error"), msg,
4081 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4082 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4088 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4092 gboolean failed = FALSE;
4094 if( ( dp = opendir( origdir ) ) == NULL ) {
4098 while( ( d = readdir( dp ) ) != NULL ) {
4099 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4102 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4104 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4106 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4119 /* all copies succeeded, we can remove source files */
4120 if( ( dp = opendir( origdir ) ) == NULL ) {
4123 while( ( d = readdir( dp ) ) != NULL ) {
4124 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4127 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4129 claws_unlink(orig_file);
4139 void addressbook_read_file( void ) {
4140 AddressIndex *addrIndex = NULL;
4141 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4143 debug_print( "Reading address index...\n" );
4144 if( _addressIndex_ ) {
4145 debug_print( "address book already read!!!\n" );
4149 addrIndex = addrindex_create_index();
4150 addrindex_initialize();
4152 /* Use new address book index. */
4154 if ( !is_dir_exist(indexdir) ) {
4155 if ( make_dir(indexdir) < 0 ) {
4156 addrindex_set_file_path( addrIndex, get_rc_dir() );
4157 g_warning( "couldn't create dir %s\n", indexdir);
4159 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4160 remove_dir_recursive(indexdir);
4161 addrindex_set_file_path( addrIndex, get_rc_dir() );
4162 g_error("couldn't migrate dir %s", indexdir);
4164 addrindex_set_file_path( addrIndex, indexdir);
4168 addrindex_set_file_path( addrIndex, indexdir);
4171 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4172 addrindex_read_data( addrIndex );
4173 if( addrIndex->retVal == MGU_NO_FILE ) {
4174 /* Conversion required */
4175 debug_print( "Converting...\n" );
4176 if( addressbook_convert( addrIndex ) ) {
4177 _addressIndex_ = addrIndex;
4180 else if( addrIndex->retVal == MGU_SUCCESS ) {
4181 _addressIndex_ = addrIndex;
4184 /* Error reading address book */
4185 debug_print( "Could not read address index.\n" );
4186 addrindex_print_index( addrIndex, stdout );
4187 alertpanel_full(_("Addressbook Error"),
4188 _("Could not read address index"),
4189 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4190 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4192 debug_print( "done.\n" );
4196 * Add object into the address index tree widget.
4197 * Enter: node Parent node.
4198 * obj Object to add.
4199 * Return: Node that was added, or NULL if object not added.
4201 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4204 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4205 GtkCMCTreeNode *added;
4206 AddressObject *pobj;
4207 AddressObjectType otype;
4208 AddressTypeControlItem *atci = NULL;
4210 cm_return_val_if_fail(node != NULL, NULL);
4211 cm_return_val_if_fail(obj != NULL, NULL);
4213 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4214 cm_return_val_if_fail(pobj != NULL, NULL);
4216 /* Determine object type to be displayed */
4217 if( obj->type == ADDR_DATASOURCE ) {
4218 otype = ADAPTER_DSOURCE(obj)->subType;
4224 /* Handle any special conditions. */
4226 atci = addrbookctl_lookup( otype );
4228 if( atci->showInTree ) {
4229 /* Add object to tree */
4232 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4233 atci->iconXpm, atci->iconXpmOpen,
4234 atci->treeLeaf, atci->treeExpand );
4235 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4236 addressbook_free_treenode );
4240 gtk_sctree_sort_node(ctree, node);
4246 * Add group into the address index tree.
4247 * \param node Parent node.
4248 * \param ds Data source.
4249 * \param itemGroup Group to add.
4250 * \return Inserted node.
4252 static GtkCMCTreeNode *addressbook_node_add_group(
4253 GtkCMCTreeNode *node, AddressDataSource *ds,
4254 ItemGroup *itemGroup )
4256 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4257 GtkCMCTreeNode *newNode;
4258 AdapterGroup *adapter;
4259 AddressTypeControlItem *atci = NULL;
4262 if( ds == NULL ) return NULL;
4263 if( node == NULL || itemGroup == NULL ) return NULL;
4265 name = &itemGroup->obj.name;
4267 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4269 adapter = g_new0( AdapterGroup, 1 );
4270 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4271 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4272 adapter->itemGroup = itemGroup;
4274 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4275 atci->iconXpm, atci->iconXpm,
4276 atci->treeLeaf, atci->treeExpand );
4277 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4278 addressbook_free_treenode );
4279 gtk_sctree_sort_node( ctree, node );
4284 * Add folder into the address index tree. Only visible folders are loaded into
4285 * the address index tree. Note that the root folder is not inserted into the
4288 * \param node Parent node.
4289 * \param ds Data source.
4290 * \param itemFolder Folder to add.
4291 * \param otype Object type to display.
4292 * \return Inserted node for the folder.
4294 static GtkCMCTreeNode *addressbook_node_add_folder(
4295 GtkCMCTreeNode *node, AddressDataSource *ds,
4296 ItemFolder *itemFolder, AddressObjectType otype )
4298 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4299 GtkCMCTreeNode *newNode = NULL;
4300 AdapterFolder *adapter;
4301 AddressTypeControlItem *atci = NULL;
4302 GList *listItems = NULL;
4304 ItemFolder *rootFolder;
4306 /* Only visible folders */
4307 if( itemFolder == NULL || itemFolder->isHidden )
4312 if( node == NULL || itemFolder == NULL )
4315 /* Determine object type */
4316 atci = addrbookctl_lookup( otype );
4320 rootFolder = addrindex_ds_get_root_folder( ds );
4321 if( itemFolder == rootFolder ) {
4325 adapter = g_new0( AdapterFolder, 1 );
4326 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4327 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4328 adapter->itemFolder = itemFolder;
4330 name = ADDRITEM_NAME(itemFolder);
4331 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4332 atci->iconXpm, atci->iconXpm,
4333 atci->treeLeaf, atci->treeExpand );
4335 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4336 addressbook_free_treenode );
4340 listItems = itemFolder->listFolder;
4341 while( listItems ) {
4342 ItemFolder *item = listItems->data;
4343 addressbook_node_add_folder( newNode, ds, item, otype );
4344 listItems = g_list_next( listItems );
4346 listItems = itemFolder->listGroup;
4347 while( listItems ) {
4348 ItemGroup *item = listItems->data;
4349 addressbook_node_add_group( newNode, ds, item );
4350 listItems = g_list_next( listItems );
4352 gtk_sctree_sort_node( ctree, node );
4356 void addressbook_export_to_file( void ) {
4357 if( _addressIndex_ ) {
4358 /* Save all new address book data */
4359 debug_print( "Saving address books...\n" );
4360 addrindex_save_all_books( _addressIndex_ );
4362 debug_print( "Exporting addressbook to file...\n" );
4363 addrindex_save_data( _addressIndex_ );
4364 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4365 addrindex_print_index( _addressIndex_, stdout );
4368 /* Notify address completion of new data */
4369 invalidate_address_completion();
4373 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4375 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4376 addressbook_lup_clicked(NULL, NULL);
4381 * Comparison using cell contents (text in first column). Used for sort
4382 * address index widget.
4384 static gint addressbook_treenode_compare_func(
4385 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4387 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4388 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4389 gchar *name1 = NULL, *name2 = NULL;
4390 if( cell1 ) name1 = cell1->u.text;
4391 if( cell2 ) name2 = cell2->u.text;
4392 if( ! name1 ) return ( name2 != NULL );
4393 if( ! name2 ) return -1;
4394 return g_utf8_collate( name1, name2 );
4397 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4398 AdapterDSource *ads;
4399 AdapterInterface *adapter;
4400 GtkCMCTreeNode *newNode;
4402 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4403 if( adapter == NULL ) return;
4404 ads = addressbook_edit_book( _addressIndex_, NULL );
4406 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4408 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4409 addrbook.treeSelected = newNode;
4414 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4415 AdapterDSource *ads;
4416 AdapterInterface *adapter;
4417 GtkCMCTreeNode *newNode;
4419 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4420 if( adapter == NULL ) return;
4421 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4423 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4425 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4426 addrbook.treeSelected = newNode;
4432 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4433 AdapterDSource *ads;
4434 AdapterInterface *adapter;
4435 AddressInterface *iface;
4436 GtkCMCTreeNode *newNode;
4438 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4439 if( adapter == NULL ) return;
4440 iface = adapter->interface;
4441 if( ! iface->haveLibrary ) return;
4442 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4444 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4446 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4447 addrbook.treeSelected = newNode;
4454 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4455 AdapterDSource *ads;
4456 AdapterInterface *adapter;
4457 AddressInterface *iface;
4458 GtkCMCTreeNode *newNode;
4460 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4461 if( adapter == NULL ) return;
4462 iface = adapter->interface;
4463 if( ! iface->haveLibrary ) return;
4464 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4466 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4468 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4469 addrbook.treeSelected = newNode;
4476 * Display address search status message.
4477 * \param queryType Query type.
4478 * \param status Status/Error code.
4480 static void addressbook_search_message( gint queryType, gint sts ) {
4482 *addressbook_msgbuf = '\0';
4484 if( sts != MGU_SUCCESS ) {
4485 if( queryType == ADDRQUERY_LDAP ) {
4487 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4492 g_snprintf( addressbook_msgbuf,
4493 sizeof(addressbook_msgbuf), "%s", desc );
4494 addressbook_status_show( addressbook_msgbuf );
4497 addressbook_status_show( "" );
4502 * Refresh addressbook by forcing refresh of current selected object in
4505 static void addressbook_refresh_current( void ) {
4509 ctree = GTK_CMCTREE(addrbook.ctree);
4510 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4511 if( obj == NULL ) return;
4512 addressbook_set_clist( obj, TRUE );
4516 * Message that is displayed whilst a query is executing in a background
4519 static gchar *_tempMessage_ = N_( "Busy searching..." );
4522 * Address search idle function. This function is called during UI idle time
4523 * while a search is in progress.
4525 * \param data Idler data.
4527 static void addressbook_search_idle( gpointer data ) {
4531 queryID = GPOINTER_TO_INT( data );
4532 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4537 * Search completion callback function. This removes the query from the idle
4540 * \param sender Sender of query.
4541 * \param queryID Query ID of search request.
4542 * \param status Search status.
4543 * \param data Query data.
4545 static void addressbook_search_callback_end(
4546 gpointer sender, gint queryID, gint status, gpointer data )
4550 AddrQueryObject *aqo;
4552 /* Remove idler function */
4553 ptrQID = GINT_TO_POINTER( queryID );
4555 g_idle_remove_by_data( ptrQID );
4558 /* Refresh addressbook contents */
4559 addressbook_refresh_current();
4560 req = qrymgr_find_request( queryID );
4562 aqo = ( AddrQueryObject * ) req->queryList->data;
4563 addressbook_search_message( aqo->queryType, status );
4566 /* Stop the search */
4567 addrindex_stop_search( queryID );
4573 * \param ds Data source to search.
4574 * \param searchTerm String to lookup.
4575 * \param pNode Parent data source node.
4577 static void addressbook_perform_search(
4578 AddressDataSource *ds, gchar *searchTerm,
4579 GtkCMCTreeNode *pNode )
4587 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4589 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4591 /* Create a folder for the search results */
4592 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4593 folder = addressbook_setup_subf(ds, name, pNode);
4596 /* Setup the search */
4597 queryID = addrindex_setup_explicit_search(
4598 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4599 if( queryID == 0 ) return;
4601 /* Set up idler function */
4602 idleID = g_idle_add(
4603 (GSourceFunc) addressbook_search_idle,
4604 GINT_TO_POINTER( queryID ) );
4606 g_message("error adding addressbook_search_idle\n");
4609 /* Start search, sit back and wait for something to happen */
4610 addrindex_start_search( queryID );
4612 addressbook_status_show( _tempMessage_ );
4616 * Lookup button handler. Address search is only performed against
4617 * address interfaces for external queries.
4619 * \param button Lookup button widget.
4620 * \param data Data object.
4622 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4625 AddressDataSource *ds;
4626 AddressInterface *iface;
4628 GtkCMCTreeNode *node, *parentNode;
4630 node = addrbook.treeSelected;
4631 if( ! node ) return;
4632 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4634 ctree = GTK_CMCTREE(addrbook.ctree);
4635 obj = gtk_cmctree_node_get_row_data( ctree, node );
4636 if( obj == NULL ) return;
4638 ds = addressbook_find_datasource( node );
4639 if( ds == NULL ) return;
4641 /* We must have a datasource that is an external interface */
4642 iface = ds->interface;
4643 if( ! iface->haveLibrary ) return;
4644 if( ! iface->externalQuery ) return;
4647 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4648 g_strchomp( searchTerm );
4650 if( obj->type == ADDR_ITEM_FOLDER ) {
4651 parentNode = GTK_CMCTREE_ROW(node)->parent;
4656 addressbook_perform_search( ds, searchTerm, parentNode );
4658 gtk_widget_grab_focus( addrbook.entry );
4660 g_free( searchTerm );
4663 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4664 addressbook_close();
4669 * Browse address entry for highlighted entry.
4671 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4673 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4675 AddressDataSource *ds;
4676 AddressInterface *iface;
4680 if(addrbook.listSelected == NULL)
4683 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4687 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4691 iface = ds->interface;
4692 if(!iface || !iface->haveLibrary )
4696 if (obj->type == ADDR_ITEM_EMAIL) {
4697 email = ( ItemEMail * ) obj;
4701 person = (ItemPerson *) ADDRITEM_PARENT(email);
4703 else if (obj->type == ADDR_ITEM_PERSON) {
4704 person = (ItemPerson *) obj;
4711 if( iface && iface->type == ADDR_IF_LDAP ) {
4712 browseldap_entry(ds, person->externalID);
4717 /* **********************************************************************
4718 * Build lookup tables.
4719 * ***********************************************************************
4723 * Remap object types.
4724 * Enter: abType AddressObjectType (used in tree node).
4725 * Return: ItemObjectType (used in address cache data).
4727 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4728 ItemObjectType ioType;
4731 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4732 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4733 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4734 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4735 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4736 default: ioType = ITEMTYPE_NONE; break;
4741 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4742 atci = addrbookctl_lookup(id); \
4744 atci->iconXpm = icon; \
4745 atci->iconXpmOpen = iconopen; \
4747 g_warning("can't get atci %d\n", id); \
4752 * Build table that controls the rendering of object types.
4754 static void addrbookctl_build_icons( GtkWidget *window ) {
4755 AddressTypeControlItem *atci;
4759 g_object_unref(interfacexpm);
4761 g_object_unref(folderxpm);
4763 g_object_unref(folderopenxpm);
4765 g_object_unref(groupxpm);
4767 g_object_unref(vcardxpm);
4769 g_object_unref(bookxpm);
4771 g_object_unref(addressxpm);
4773 g_object_unref(jpilotxpm);
4775 g_object_unref(categoryxpm);
4777 g_object_unref(ldapxpm);
4779 g_object_unref(addrsearchxpm);
4780 stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacexpm );
4781 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4782 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4783 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4784 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4785 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4786 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4787 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4788 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4789 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4790 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4792 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4793 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4794 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4795 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4796 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4797 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4798 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4799 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4800 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4801 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4802 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4807 * Build table that controls the rendering of object types.
4809 static void addrbookctl_build_map( GtkWidget *window ) {
4810 AddressTypeControlItem *atci;
4812 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4813 _addressBookTypeList_ = NULL;
4816 atci = g_new0( AddressTypeControlItem, 1 );
4817 atci->objectType = ADDR_INTERFACE;
4818 atci->interfaceType = ADDR_IF_NONE;
4819 atci->showInTree = TRUE;
4820 atci->treeExpand = TRUE;
4821 atci->treeLeaf = FALSE;
4822 atci->displayName = _( "Interface" );
4823 atci->menuCommand = NULL;
4824 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4825 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4828 atci = g_new0( AddressTypeControlItem, 1 );
4829 atci->objectType = ADDR_BOOK;
4830 atci->interfaceType = ADDR_IF_BOOK;
4831 atci->showInTree = TRUE;
4832 atci->treeExpand = TRUE;
4833 atci->treeLeaf = FALSE;
4834 atci->displayName = _( "Address Book" );
4835 atci->menuCommand = "Menu/Book/NewBook";
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_ITEM_PERSON;
4842 atci->interfaceType = ADDR_IF_NONE;
4843 atci->showInTree = FALSE;
4844 atci->treeExpand = FALSE;
4845 atci->treeLeaf = FALSE;
4846 atci->displayName = _( "Person" );
4847 atci->menuCommand = NULL;
4848 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4849 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4852 atci = g_new0( AddressTypeControlItem, 1 );
4853 atci->objectType = ADDR_ITEM_EMAIL;
4854 atci->interfaceType = ADDR_IF_NONE;
4855 atci->showInTree = FALSE;
4856 atci->treeExpand = FALSE;
4857 atci->treeLeaf = TRUE;
4858 atci->displayName = _( "Email Address" );
4859 atci->menuCommand = NULL;
4860 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4861 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4864 atci = g_new0( AddressTypeControlItem, 1 );
4865 atci->objectType = ADDR_ITEM_GROUP;
4866 atci->interfaceType = ADDR_IF_BOOK;
4867 atci->showInTree = TRUE;
4868 atci->treeExpand = FALSE;
4869 atci->treeLeaf = FALSE;
4870 atci->displayName = _( "Group" );
4871 atci->menuCommand = NULL;
4872 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4873 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4876 atci = g_new0( AddressTypeControlItem, 1 );
4877 atci->objectType = ADDR_ITEM_FOLDER;
4878 atci->interfaceType = ADDR_IF_BOOK;
4879 atci->showInTree = TRUE;
4880 atci->treeExpand = FALSE;
4881 atci->treeLeaf = FALSE;
4882 atci->displayName = _( "Folder" );
4883 atci->menuCommand = NULL;
4884 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4885 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4888 atci = g_new0( AddressTypeControlItem, 1 );
4889 atci->objectType = ADDR_VCARD;
4890 atci->interfaceType = ADDR_IF_VCARD;
4891 atci->showInTree = TRUE;
4892 atci->treeExpand = TRUE;
4893 atci->treeLeaf = TRUE;
4894 atci->displayName = _( "vCard" );
4895 atci->menuCommand = "Menu/Book/NewVCard";
4896 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4897 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4900 atci = g_new0( AddressTypeControlItem, 1 );
4901 atci->objectType = ADDR_JPILOT;
4902 atci->interfaceType = ADDR_IF_JPILOT;
4903 atci->showInTree = TRUE;
4904 atci->treeExpand = TRUE;
4905 atci->treeLeaf = FALSE;
4906 atci->displayName = _( "JPilot" );
4907 atci->menuCommand = "Menu/Book/NewJPilot";
4908 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4909 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4912 atci = g_new0( AddressTypeControlItem, 1 );
4913 atci->objectType = ADDR_CATEGORY;
4914 atci->interfaceType = ADDR_IF_JPILOT;
4915 atci->showInTree = TRUE;
4916 atci->treeExpand = TRUE;
4917 atci->treeLeaf = TRUE;
4918 atci->displayName = _( "JPilot" );
4919 atci->menuCommand = NULL;
4920 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4921 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4924 atci = g_new0( AddressTypeControlItem, 1 );
4925 atci->objectType = ADDR_LDAP;
4926 atci->interfaceType = ADDR_IF_LDAP;
4927 atci->showInTree = TRUE;
4928 atci->treeExpand = TRUE;
4929 atci->treeLeaf = FALSE;
4930 atci->displayName = _( "LDAP servers" );
4931 atci->menuCommand = "Menu/Book/NewLDAPServer";
4932 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4933 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4936 atci = g_new0( AddressTypeControlItem, 1 );
4937 atci->objectType = ADDR_LDAP_QUERY;
4938 atci->interfaceType = ADDR_IF_LDAP;
4939 atci->showInTree = TRUE;
4940 atci->treeExpand = FALSE;
4941 atci->treeLeaf = TRUE;
4942 atci->displayName = _( "LDAP Query" );
4943 atci->menuCommand = NULL;
4944 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4945 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4947 addrbookctl_build_icons(window);
4950 void addressbook_reflect_prefs_pixmap_theme(void)
4952 if (addrbook.window)
4953 addrbookctl_build_icons(addrbook.window);
4957 * Search for specified object type.
4959 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4961 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4965 * Search for specified interface type.
4967 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4968 GList *node = _addressBookTypeList_;
4970 AddressTypeControlItem *atci = node->data;
4971 if( atci->interfaceType == ifType ) return atci;
4972 node = g_list_next( node );
4977 static void addrbookctl_free_address( AddressObject *obj ) {
4978 g_free( obj->name );
4979 obj->type = ADDR_NONE;
4983 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4984 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4985 adapter->interface = NULL;
4986 adapter->interfaceType = ADDR_IF_NONE;
4987 adapter->atci = NULL;
4988 adapter->enabled = FALSE;
4989 adapter->haveLibrary = FALSE;
4990 adapter->treeNode = NULL;
4994 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4995 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4996 adapter->dataSource = NULL;
4997 adapter->subType = ADDR_NONE;
5001 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5002 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5003 adapter->itemFolder = NULL;
5007 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5008 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5009 adapter->itemGroup = NULL;
5014 * Build GUI interface list.
5016 static void addrbookctl_build_iflist( void ) {
5017 AddressTypeControlItem *atci;
5018 AdapterInterface *adapter;
5021 if( _addressIndex_ == NULL ) {
5022 _addressIndex_ = addrindex_create_index();
5023 if( _clipBoard_ == NULL ) {
5024 _clipBoard_ = addrclip_create();
5026 addrclip_set_index( _clipBoard_, _addressIndex_ );
5028 _addressInterfaceList_ = NULL;
5029 list = addrindex_get_interface_list( _addressIndex_ );
5031 AddressInterface *interface = list->data;
5032 atci = addrbookctl_lookup_iface( interface->type );
5034 adapter = g_new0( AdapterInterface, 1 );
5035 adapter->interfaceType = interface->type;
5036 adapter->atci = atci;
5037 adapter->interface = interface;
5038 adapter->treeNode = NULL;
5039 adapter->enabled = TRUE;
5040 adapter->haveLibrary = interface->haveLibrary;
5041 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5042 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5043 _addressInterfaceList_ =
5044 g_list_append( _addressInterfaceList_, adapter );
5046 list = g_list_next( list );
5051 * Find GUI interface type specified interface type.
5052 * \param ifType Interface type.
5053 * \return Interface item, or NULL if not found.
5055 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5056 GList *node = _addressInterfaceList_;
5058 AdapterInterface *adapter = node->data;
5059 if( adapter->interfaceType == ifType ) return adapter;
5060 node = g_list_next( node );
5066 * Build interface list selection.
5068 static void addrbookctl_build_ifselect( void ) {
5069 GList *newList = NULL;
5074 gchar *endptr = NULL;
5075 /* gboolean enabled; */
5076 AdapterInterface *adapter;
5078 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5081 splitStr = g_strsplit( selectStr, ",", -1 );
5082 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5084 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5085 ifType = strtol( splitStr[i], &endptr, 10 );
5088 if( strcmp( endptr, "/n" ) == 0 ) {
5093 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5094 adapter = addrbookctl_find_interface( ifType );
5096 newList = g_list_append( newList, adapter );
5103 /* g_print( "i=%d\n", i ); */
5104 g_strfreev( splitStr );
5105 g_free( selectStr );
5107 /* Replace existing list */
5108 mgu_clear_list( _addressIFaceSelection_ );
5109 g_list_free( _addressIFaceSelection_ );
5110 _addressIFaceSelection_ = newList;
5114 /* ***********************************************************************
5115 * Add sender to address book.
5116 * ***********************************************************************
5120 * This function is used by the Add sender to address book function.
5122 gboolean addressbook_add_contact(
5123 const gchar *name, const gchar *address, const gchar *remarks,
5124 GdkPixbuf *picture )
5126 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5127 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5128 debug_print( "addressbook_add_contact - added\n" );
5129 addressbook_refresh();
5134 /* ***********************************************************************
5135 * Book/folder selection.
5136 * ***********************************************************************
5140 * This function is used by the matcher dialog to select a book/folder.
5142 gchar *addressbook_folder_selection( const gchar *folderpath)
5144 AddressBookFile *book = NULL;
5145 ItemFolder *folder = NULL;
5148 cm_return_val_if_fail( folderpath != NULL, NULL);
5150 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5152 if ( folder != NULL) {
5154 gchar *oldtmp = NULL;
5155 AddrItemObject *obj = NULL;
5157 /* walk thru folder->parent to build the full folder path */
5158 /* TODO: wwp: optimize this */
5160 tmp = g_strdup(obj->uid);
5161 while ( obj->parent ) {
5163 if ( obj->name != NULL ) {
5164 oldtmp = g_strdup(tmp);
5166 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5170 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5173 path = g_strdup_printf("%s", book->fileName);
5175 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5181 /* ***********************************************************************
5182 * Book/folder checking.
5183 * ***********************************************************************
5186 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5188 FolderInfo *fi = g_new0( FolderInfo, 1 );
5190 fi->folder = folder;
5194 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5195 FolderInfo *fiParent, FolderPathMatch *match )
5201 FolderPathMatch *nextmatch = NULL;
5206 list = parentFolder->listFolder;
5208 folder = list->data;
5209 fName = g_strdup( ADDRITEM_NAME(folder) );
5211 /* match folder name, match pointer will be set to NULL if next recursive call
5212 doesn't need to match subfolder name */
5213 if ( match != NULL &&
5214 match->matched == FALSE ) {
5215 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5216 /* folder name matches, prepare next subfolder match */
5217 debug_print("matched folder name '%s'\n", fName);
5219 if ( match->folder_path[match->index] == NULL ) {
5220 /* we've matched all elements */
5221 match->matched = TRUE;
5222 match->folder = folder;
5223 debug_print("book/folder path matched!\n");
5225 /* keep on matching */
5233 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5234 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5236 list = g_list_next( list );
5241 * This function is used by to check if a matcher book/folder path corresponds to an
5242 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5243 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5244 if book AND folder are NULL this means that folderpath was empty or Any.
5245 If folderpath is a simple book name (without folder), book will not be NULL and folder
5246 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5249 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5250 AddressDataSource **book,
5251 ItemFolder **folder )
5253 AddressDataSource *ds;
5254 GList *list, *nodeDS;
5255 ItemFolder *rootFolder;
5256 AddressBookFile *abf;
5258 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5265 if ( folderpath == NULL )
5268 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5271 /* split the folder path we've received, we'll try to match this path, subpath by
5272 subpath against the book/folder structure in order */
5273 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5274 if (!folder_path_match.folder_path)
5277 list = addrindex_get_interface_list( _addressIndex_ );
5278 while ( list && !folder_path_match.matched ) {
5279 AddressInterface *interface = list->data;
5280 if ( interface && interface->type == ADDR_IF_BOOK ) {
5281 nodeDS = interface->listSource;
5282 while ( nodeDS && !folder_path_match.matched ) {
5285 /* Read address book */
5286 if( ! addrindex_ds_get_read_flag( ds ) ) {
5287 addrindex_ds_read_data( ds );
5290 /* Add node for address book */
5291 abf = ds->rawDataSource;
5293 /* match book name */
5294 if ( abf && abf->fileName &&
5295 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5297 debug_print("matched book name '%s'\n", abf->fileName);
5298 folder_path_match.book = ds;
5300 if ( folder_path_match.folder_path[1] == NULL ) {
5301 /* no folder part to match */
5303 folder_path_match.matched = TRUE;
5304 folder_path_match.folder = NULL;
5305 debug_print("book path matched!\n");
5308 /* match folder part */
5310 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5311 rootFolder = addrindex_ds_get_root_folder( ds );
5313 /* prepare for recursive call */
5314 folder_path_match.index = 1;
5315 /* this call will set folder_path_match.matched and folder_path_match.folder */
5316 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5321 nodeDS = g_list_next( nodeDS );
5324 list = g_list_next( list );
5327 g_strfreev( folder_path_match.folder_path );
5330 *book = folder_path_match.book;
5332 *folder = folder_path_match.folder;
5333 return folder_path_match.matched;
5337 /* **********************************************************************
5339 * ***********************************************************************
5345 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5346 AddressDataSource *ds = NULL;
5347 AdapterDSource *ads = NULL;
5348 AddressBookFile *abf = NULL;
5349 AdapterInterface *adapter;
5350 GtkCMCTreeNode *newNode;
5352 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5354 if( adapter->treeNode ) {
5355 abf = addressbook_imp_ldif( _addressIndex_ );
5357 ds = addrindex_index_add_datasource(
5358 _addressIndex_, ADDR_IF_BOOK, abf );
5359 ads = addressbook_create_ds_adapter(
5360 ds, ADDR_BOOK, NULL );
5361 addressbook_ads_set_name(
5362 ads, addrbook_get_name( abf ) );
5363 newNode = addressbook_add_object(
5365 ADDRESS_OBJECT(ads) );
5367 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5369 addrbook.treeSelected = newNode;
5372 /* Notify address completion */
5373 invalidate_address_completion();
5382 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5383 AddressDataSource *ds = NULL;
5384 AdapterDSource *ads = NULL;
5385 AddressBookFile *abf = NULL;
5386 AdapterInterface *adapter;
5387 GtkCMCTreeNode *newNode;
5389 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5391 if( adapter->treeNode ) {
5392 abf = addressbook_imp_mutt( _addressIndex_ );
5394 ds = addrindex_index_add_datasource(
5395 _addressIndex_, ADDR_IF_BOOK, abf );
5396 ads = addressbook_create_ds_adapter(
5397 ds, ADDR_BOOK, NULL );
5398 addressbook_ads_set_name(
5399 ads, addrbook_get_name( abf ) );
5400 newNode = addressbook_add_object(
5402 ADDRESS_OBJECT(ads) );
5404 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5406 addrbook.treeSelected = newNode;
5409 /* Notify address completion */
5410 invalidate_address_completion();
5419 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5420 AddressDataSource *ds = NULL;
5421 AdapterDSource *ads = NULL;
5422 AddressBookFile *abf = NULL;
5423 AdapterInterface *adapter;
5424 GtkCMCTreeNode *newNode;
5426 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5428 if( adapter->treeNode ) {
5429 abf = addressbook_imp_pine( _addressIndex_ );
5431 ds = addrindex_index_add_datasource(
5432 _addressIndex_, ADDR_IF_BOOK, abf );
5433 ads = addressbook_create_ds_adapter(
5434 ds, ADDR_BOOK, NULL );
5435 addressbook_ads_set_name(
5436 ads, addrbook_get_name( abf ) );
5437 newNode = addressbook_add_object(
5439 ADDRESS_OBJECT(ads) );
5441 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5443 addrbook.treeSelected = newNode;
5446 /* Notify address completion */
5447 invalidate_address_completion();
5454 * Harvest addresses.
5455 * \param folderItem Folder to import.
5456 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5457 * \param msgList List of message numbers, or NULL to process folder.
5459 void addressbook_harvest(
5460 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5462 AddressDataSource *ds = NULL;
5463 AdapterDSource *ads = NULL;
5464 AddressBookFile *abf = NULL;
5465 AdapterInterface *adapter;
5466 GtkCMCTreeNode *newNode;
5468 abf = addrgather_dlg_execute(
5469 folderItem, _addressIndex_, sourceInd, msgList );
5471 ds = addrindex_index_add_datasource(
5472 _addressIndex_, ADDR_IF_BOOK, abf );
5474 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5476 if( adapter->treeNode ) {
5477 ads = addressbook_create_ds_adapter(
5478 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5479 newNode = addressbook_add_object(
5481 ADDRESS_OBJECT(ads) );
5482 if (newNode == NULL) {
5483 g_message("error adding addressbook object\n");
5488 /* Notify address completion */
5489 invalidate_address_completion();
5496 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5497 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5499 AddressDataSource *ds = NULL;
5500 AddrBookBase *adbase;
5501 AddressCache *cache;
5502 GtkCMCTreeNode *node = NULL;
5504 if( ! addrbook.treeSelected ) return;
5505 node = addrbook.treeSelected;
5506 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5507 obj = gtk_cmctree_node_get_row_data( ctree, node );
5508 if( obj == NULL ) return;
5510 ds = addressbook_find_datasource( node );
5511 if( ds == NULL ) return;
5512 adbase = ( AddrBookBase * ) ds->rawDataSource;
5513 cache = adbase->addressCache;
5514 addressbook_exp_html( cache );
5520 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5521 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5523 AddressDataSource *ds = NULL;
5524 AddrBookBase *adbase;
5525 AddressCache *cache;
5526 GtkCMCTreeNode *node = NULL;
5528 if( ! addrbook.treeSelected ) return;
5529 node = addrbook.treeSelected;
5530 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5531 obj = gtk_cmctree_node_get_row_data( ctree, node );
5532 if( obj == NULL ) return;
5534 ds = addressbook_find_datasource( node );
5535 if( ds == NULL ) return;
5536 adbase = ( AddrBookBase * ) ds->rawDataSource;
5537 cache = adbase->addressCache;
5538 addressbook_exp_ldif( cache );
5541 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5543 addrduplicates_find(GTK_WINDOW(addrbook.window));
5546 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5548 addressbook_custom_attr_edit();
5551 static void addressbook_start_drag(GtkWidget *widget, gint button,
5555 GdkDragContext *context;
5556 if (addressbook_target_list == NULL)
5557 addressbook_target_list = gtk_target_list_new(
5558 addressbook_drag_types, 1);
5559 context = gtk_drag_begin(widget, addressbook_target_list,
5560 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5561 gtk_drag_set_icon_default(context);
5564 static void addressbook_drag_data_get(GtkWidget *widget,
5565 GdkDragContext *drag_context,
5566 GtkSelectionData *selection_data,
5571 AddrItemObject *aio = NULL;
5572 AddressObject *pobj = NULL;
5573 AdapterDSource *ads = NULL;
5574 AddressDataSource *ds = NULL;
5577 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5579 if( pobj == NULL ) return;
5581 if( pobj->type == ADDR_DATASOURCE ) {
5582 ads = ADAPTER_DSOURCE(pobj);
5583 ds = ads->dataSource;
5584 } else if (pobj->type == ADDR_ITEM_GROUP) {
5589 else if( pobj->type != ADDR_INTERFACE ) {
5590 ds = addressbook_find_datasource( addrbook.treeSelected );
5596 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5597 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5598 GTK_CMCTREE_NODE(cur->data));
5599 while (aio && aio->type != ITEMTYPE_PERSON) {
5604 if (aio && aio->type == ITEMTYPE_PERSON) {
5605 if( ds && ds->interface && ds->interface->readOnly)
5606 gtk_selection_data_set(selection_data,
5607 gtk_selection_data_get_target(selection_data), 8,
5608 (const guchar *)"Dummy_addr_copy", 15);
5610 gtk_selection_data_set(selection_data,
5611 gtk_selection_data_get_target(selection_data), 8,
5612 (const guchar *)"Dummy_addr_move", 15);
5616 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5617 GdkDragContext *context,
5623 GtkAllocation allocation;
5624 GtkRequisition requisition;
5626 GtkCMCTreeNode *node = NULL;
5627 gboolean acceptable = FALSE;
5628 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5629 gint height = allocation.height;
5630 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5631 gint total_height = requisition.height;
5632 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5633 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5634 gfloat vpos = gtk_adjustment_get_value(pos);
5636 if (gtk_cmclist_get_selection_info
5637 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5639 if (y > height - 24 && height + vpos < total_height) {
5640 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5641 gtk_adjustment_changed(pos);
5643 if (y < 24 && y > 0) {
5644 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5645 gtk_adjustment_changed(pos);
5647 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5650 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5651 if( obj->type == ADDR_ITEM_FOLDER
5652 || obj->type == ADDR_ITEM_GROUP)
5655 AdapterDSource *ads = NULL;
5656 AddressDataSource *ds = NULL;
5657 ads = ADAPTER_DSOURCE(obj);
5658 if (ads == NULL ){ return FALSE;}
5659 ds = ads->dataSource;
5660 if (ds == NULL ) { return FALSE;}
5668 g_signal_handlers_block_by_func
5670 G_CALLBACK(addressbook_tree_selected), NULL);
5671 gtk_sctree_select( GTK_SCTREE(widget), node);
5672 g_signal_handlers_unblock_by_func
5674 G_CALLBACK(addressbook_tree_selected), NULL);
5675 gdk_drag_status(context,
5676 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5677 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5679 gdk_drag_status(context, 0, time);
5684 static void addressbook_drag_leave_cb(GtkWidget *widget,
5685 GdkDragContext *context,
5689 if (addrbook.treeSelected) {
5690 g_signal_handlers_block_by_func
5692 G_CALLBACK(addressbook_tree_selected), NULL);
5693 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5694 g_signal_handlers_unblock_by_func
5696 G_CALLBACK(addressbook_tree_selected), NULL);
5701 static void addressbook_drag_received_cb(GtkWidget *widget,
5702 GdkDragContext *drag_context,
5705 GtkSelectionData *data,
5711 GtkCMCTreeNode *node;
5712 GtkCMCTreeNode *lastopened = addrbook.opened;
5714 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5715 if (gtk_cmclist_get_selection_info
5716 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5720 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5721 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5724 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5725 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5726 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5727 addressbook_clip_copy_cb(NULL, NULL);
5729 addressbook_clip_cut_cb(NULL, NULL);
5730 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5731 addressbook_clip_paste_cb(NULL,NULL);
5732 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5733 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5734 gtk_drag_finish(drag_context, TRUE, TRUE, time);