2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2012 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 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
636 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
638 if (!prefs_common.addressbook_use_editaddress_dialog)
639 addressbook_edit_person_widgetset_hide();
641 address_completion_start(addrbook.window);
643 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
644 addressbook_set_target_compose(target);
648 * Destroy addressbook.
650 void addressbook_destroy( void ) {
651 /* Free up address stuff */
652 if( _addressSelect_ != NULL ) {
653 addrselect_list_free( _addressSelect_ );
655 if( _clipBoard_ != NULL ) {
656 addrclip_free( _clipBoard_ );
658 if( _addressIndex_ != NULL ) {
659 addrindex_free_index( _addressIndex_ );
660 addrindex_teardown();
662 _addressSelect_ = NULL;
664 _addressIndex_ = NULL;
667 void addressbook_set_target_compose(Compose *target)
669 addrbook.target_compose = target;
672 Compose *addressbook_get_target_compose(void)
674 return addrbook.target_compose;
678 * Refresh addressbook and save to file(s).
680 void addressbook_refresh( void )
682 if (addrbook.window) {
683 if (addrbook.treeSelected) {
684 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
685 addrbook.treeSelected);
686 addressbook_set_clist(
687 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
688 addrbook.treeSelected),
693 addressbook_export_to_file();
696 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
698 if (event && event->keyval == GDK_KEY_Escape)
700 else if (event && event->keyval == GDK_KEY_Delete) {
701 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
702 if ( /* address_index_has_focus || */ address_list_has_focus )
703 addressbook_del_clicked(NULL, NULL);
709 *\brief Save Gtk object size to prefs dataset
711 static void addressbook_size_allocate_cb(GtkWidget *widget,
712 GtkAllocation *allocation)
714 cm_return_if_fail(allocation != NULL);
716 prefs_common.addressbookwin_width = allocation->width;
717 prefs_common.addressbookwin_height = allocation->height;
720 static gint sort_column_number = 0;
721 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
723 static gint list_case_sort(
724 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
726 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
727 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
728 gchar *name1 = NULL, *name2 = NULL;
729 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
730 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
732 if( aio1->type == aio2->type ) {
734 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
736 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
737 if( ! name1 ) return ( name2 != NULL );
738 if( ! name2 ) return -1;
739 return g_utf8_collate( name1, name2 );
741 /* Order groups before person */
742 if( aio1->type == ITEMTYPE_GROUP ) {
743 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
744 } else if( aio2->type == ITEMTYPE_GROUP ) {
745 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
751 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
752 const GtkSortType sort_type)
755 GtkWidget *hbox, *label, *arrow;
757 sort_column_number = col;
758 sort_column_type = sort_type;
759 gtk_cmclist_set_compare_func(clist, list_case_sort);
760 gtk_cmclist_set_sort_type(clist, sort_type);
761 gtk_cmclist_set_sort_column(clist, col);
763 gtk_cmclist_freeze(clist);
764 gtk_cmclist_sort(clist);
766 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
767 hbox = gtk_hbox_new(FALSE, 4);
768 label = gtk_label_new(gettext(list_titles[pos]));
769 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
772 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
773 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
774 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
777 gtk_widget_show_all(hbox);
778 gtk_cmclist_set_column_widget(clist, pos, hbox);
781 gtk_cmclist_thaw(clist);
784 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
786 static GtkSortType sort_type = GTK_SORT_ASCENDING;
788 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
790 addressbook_sort_list(clist, COL_NAME, sort_type);
793 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
795 static GtkSortType sort_type = GTK_SORT_ASCENDING;
797 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
799 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
802 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
804 static GtkSortType sort_type = GTK_SORT_ASCENDING;
806 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
808 addressbook_sort_list(clist, COL_REMARKS, sort_type);
811 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
814 address_index_has_focus = TRUE;
818 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
821 address_index_has_focus = FALSE;
822 if (!prefs_common.addressbook_use_editaddress_dialog
823 && !address_list_has_focus)
824 addressbook_address_list_disable_some_actions();
828 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
831 address_list_has_focus = TRUE;
835 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
838 address_list_has_focus = FALSE;
839 if (!prefs_common.addressbook_use_editaddress_dialog
840 && !address_index_has_focus)
841 addressbook_address_list_disable_some_actions();
845 /* save hpane and vpane's handle position when it moves */
846 static void addressbook_pane_save_position(void)
849 prefs_common.addressbook_hpaned_pos =
850 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
852 prefs_common.addressbook_vpaned_pos =
853 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
857 * Create the address book widgets. The address book contains two CTree widgets: the
858 * address index tree on the left and the address list on the right.
860 * The address index tree displays a hierarchy of interfaces and groups. Each node in
861 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
862 * data sources and folder objects.
864 * The address list displays group, person and email objects. These items are linked
865 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
868 * In the tradition of MVC architecture, the data stores have been separated from the
869 * GUI components. The addrindex.c file provides the interface to all data stores.
871 static void addressbook_create(void)
877 GtkWidget *ctree_swin;
879 GtkWidget *editaddress_vbox;
880 GtkWidget *clist_vbox;
881 GtkWidget *clist_swin;
888 GtkWidget *statusbar;
899 GtkWidget *close_btn;
900 GtkWidget *tree_popup;
901 GtkWidget *list_popup;
903 GtkUIManager *ui_manager;
904 GtkActionGroup *action_group;
905 gchar *index_titles[N_INDEX_COLS];
909 static GdkGeometry geometry;
911 debug_print("Creating addressbook window...\n");
913 index_titles[COL_SOURCES] = _("Sources");
915 /* Address book window */
916 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
917 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
918 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
919 gtk_widget_realize(window);
921 g_signal_connect(G_OBJECT(window), "delete_event",
922 G_CALLBACK(addressbook_close), NULL);
923 g_signal_connect(G_OBJECT(window), "size_allocate",
924 G_CALLBACK(addressbook_size_allocate_cb), NULL);
925 g_signal_connect(G_OBJECT(window), "key_press_event",
926 G_CALLBACK(key_pressed), NULL);
927 MANAGE_WINDOW_SIGNALS_CONNECT(window);
929 vbox = gtk_vbox_new(FALSE, 0);
930 gtk_container_add(GTK_CONTAINER(window), vbox);
933 ui_manager = gtk_ui_manager_new();
934 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
935 G_N_ELEMENTS(addressbook_entries), NULL);
936 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
937 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
938 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
939 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
942 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_POPUP)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
950 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
955 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
957 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
990 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
991 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
992 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
993 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
996 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
998 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
1001 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1003 hildon_window_set_menu(HILDON_WINDOW(window), GTK_MENU(menubar));
1006 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1007 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1008 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1010 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1011 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1012 GTK_POLICY_AUTOMATIC,
1013 GTK_POLICY_AUTOMATIC);
1014 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1017 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1018 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1020 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1021 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1022 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1023 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1024 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1025 GTK_CMCTREE_EXPANDER_TRIANGLE);
1026 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1027 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1028 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1029 addressbook_treenode_compare_func);
1031 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1032 G_CALLBACK(addressbook_tree_selected), NULL);
1033 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1034 G_CALLBACK(addressbook_tree_button_pressed),
1036 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1037 G_CALLBACK(addressbook_tree_button_released),
1040 g_signal_connect(G_OBJECT(ctree), "select_row",
1041 G_CALLBACK(addressbook_select_row_tree), NULL);
1043 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1044 addressbook_drag_types, 1,
1045 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1046 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1047 G_CALLBACK(addressbook_drag_motion_cb),
1049 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1050 G_CALLBACK(addressbook_drag_leave_cb),
1052 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1053 G_CALLBACK(addressbook_drag_received_cb),
1055 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1056 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1057 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1058 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1060 clist_vbox = gtk_vbox_new(FALSE, 4);
1062 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1063 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1064 GTK_POLICY_AUTOMATIC,
1065 GTK_POLICY_AUTOMATIC);
1066 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1069 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1070 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1071 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_EXTENDED);
1072 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1073 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1074 GTK_CMCTREE_EXPANDER_TRIANGLE);
1075 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1076 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1077 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1079 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1081 gtk_widget_set_size_request(clist, -1, 80);
1083 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1084 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1085 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1086 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1087 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1088 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1089 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1090 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1091 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1092 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1093 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1095 for (i = 0; i < N_LIST_COLS; i++)
1096 gtkut_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1099 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1100 G_CALLBACK(addressbook_list_row_selected), NULL);
1101 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1102 G_CALLBACK(addressbook_list_row_unselected), NULL);
1103 g_signal_connect(G_OBJECT(clist), "button_press_event",
1104 G_CALLBACK(addressbook_list_button_pressed),
1106 g_signal_connect(G_OBJECT(clist), "button_release_event",
1107 G_CALLBACK(addressbook_list_button_released),
1109 g_signal_connect(G_OBJECT(clist), "tree_expand",
1110 G_CALLBACK(addressbook_person_expand_node), NULL );
1111 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1112 G_CALLBACK(addressbook_person_collapse_node), NULL );
1113 g_signal_connect(G_OBJECT(clist), "start_drag",
1114 G_CALLBACK(addressbook_start_drag), NULL);
1115 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1116 G_CALLBACK(addressbook_drag_data_get), NULL);
1117 hbox = gtk_hbox_new(FALSE, 4);
1118 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1120 label = gtk_label_new(_("Lookup name:"));
1121 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1123 entry = gtk_entry_new();
1124 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1126 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1128 g_signal_connect(G_OBJECT(entry), "key_press_event",
1129 G_CALLBACK(addressbook_entry_key_pressed),
1132 if (!prefs_common.addressbook_use_editaddress_dialog) {
1133 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1134 vpaned = gtk_vpaned_new();
1135 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1136 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1139 editaddress_vbox = NULL;
1141 hpaned = gtk_hpaned_new();
1142 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1143 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1144 if (prefs_common.addressbook_use_editaddress_dialog)
1145 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1147 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1150 hsbox = gtk_hbox_new(FALSE, 0);
1151 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1152 statusbar = gtk_statusbar_new();
1153 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1156 hbbox = gtk_hbutton_box_new();
1157 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1158 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1159 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1160 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1162 gtkut_stock_button_add_help(hbbox, &help_btn);
1164 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1165 gtkut_widget_set_can_default(edit_btn, TRUE);
1166 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1167 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1168 gtkut_widget_set_can_default(del_btn, TRUE);
1169 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1170 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1171 gtkut_widget_set_can_default(reg_btn, TRUE);
1172 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1175 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1176 gtkut_widget_set_can_default(lup_btn, TRUE);
1177 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1179 g_signal_connect(G_OBJECT(help_btn), "clicked",
1180 G_CALLBACK(manual_open_with_anchor_cb),
1181 MANUAL_ANCHOR_ADDRBOOK);
1183 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1184 G_CALLBACK(addressbook_edit_clicked), NULL);
1185 g_signal_connect(G_OBJECT(del_btn), "clicked",
1186 G_CALLBACK(addressbook_del_clicked), NULL);
1187 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1188 G_CALLBACK(addressbook_reg_clicked), NULL);
1189 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1190 G_CALLBACK(addressbook_lup_clicked), NULL);
1192 to_btn = gtk_button_new_with_label
1193 (prefs_common_translated_header_name("To:"));
1194 gtkut_widget_set_can_default(to_btn, TRUE);
1195 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1196 cc_btn = gtk_button_new_with_label
1197 (prefs_common_translated_header_name("Cc:"));
1198 gtkut_widget_set_can_default(cc_btn, TRUE);
1199 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1200 bcc_btn = gtk_button_new_with_label
1201 (prefs_common_translated_header_name("Bcc:"));
1202 gtkut_widget_set_can_default(bcc_btn, TRUE);
1203 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1205 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1206 gtkut_widget_set_can_default(close_btn, TRUE);
1207 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1209 g_signal_connect(G_OBJECT(to_btn), "clicked",
1210 G_CALLBACK(addressbook_to_clicked),
1211 GINT_TO_POINTER(COMPOSE_TO));
1212 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1213 G_CALLBACK(addressbook_to_clicked),
1214 GINT_TO_POINTER(COMPOSE_CC));
1215 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1216 G_CALLBACK(addressbook_to_clicked),
1217 GINT_TO_POINTER(COMPOSE_BCC));
1218 g_signal_connect(G_OBJECT(close_btn), "clicked",
1219 G_CALLBACK(addressbook_close_clicked), NULL);
1221 /* Build icons for interface */
1223 /* Build control tables */
1224 addrbookctl_build_map(window);
1225 addrbookctl_build_iflist();
1226 addrbookctl_build_ifselect();
1228 addrbook.clist = NULL;
1230 /* Add each interface into the tree as a root level folder */
1231 nodeIf = _addressInterfaceList_;
1233 AdapterInterface *adapter = nodeIf->data;
1234 AddressInterface *iface = adapter->interface;
1235 nodeIf = g_list_next(nodeIf);
1237 if(iface->useInterface) {
1238 AddressTypeControlItem *atci = adapter->atci;
1239 text = atci->displayName;
1241 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1242 NULL, NULL, &text, FOLDER_SPACING,
1246 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1247 gtk_cmctree_node_set_row_data_full(
1248 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1249 addressbook_free_treenode );
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1268 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1269 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1281 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1284 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1286 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1288 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1289 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1291 addrbook.window = window;
1292 addrbook.hpaned = hpaned;
1293 addrbook.vpaned = vpaned;
1294 addrbook.menubar = menubar;
1295 addrbook.ctree = ctree;
1298 addrbook.editaddress_vbox = editaddress_vbox;
1299 addrbook.clist = clist;
1300 addrbook.label = label;
1301 addrbook.entry = entry;
1302 addrbook.statusbar = statusbar;
1303 addrbook.status_cid = gtk_statusbar_get_context_id(
1304 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1306 addrbook.help_btn = help_btn;
1307 addrbook.edit_btn = edit_btn;
1308 addrbook.del_btn = del_btn;
1309 addrbook.reg_btn = reg_btn;
1310 addrbook.lup_btn = lup_btn;
1311 addrbook.to_btn = to_btn;
1312 addrbook.cc_btn = cc_btn;
1313 addrbook.bcc_btn = bcc_btn;
1315 addrbook.tree_popup = tree_popup;
1316 addrbook.list_popup = list_popup;
1317 addrbook.ui_manager = ui_manager;
1319 addrbook.listSelected = NULL;
1321 if (!geometry.min_height) {
1322 geometry.min_width = ADDRESSBOOK_WIDTH;
1323 geometry.min_height = ADDRESSBOOK_HEIGHT;
1326 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1328 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1329 prefs_common.addressbookwin_height);
1331 gtk_window_move(GTK_WINDOW(window), 48, 48);
1334 if (!prefs_common.addressbook_use_editaddress_dialog) {
1335 if (prefs_common.addressbook_vpaned_pos > 0)
1336 gtk_paned_set_position(GTK_PANED(vpaned),
1337 prefs_common.addressbook_vpaned_pos);
1339 if (prefs_common.addressbook_hpaned_pos > 0)
1340 gtk_paned_set_position(GTK_PANED(hpaned),
1341 prefs_common.addressbook_hpaned_pos);
1344 gtk_widget_show_all(window);
1348 * Close address book window and save to file(s).
1350 static gint addressbook_close( void ) {
1351 address_completion_end(addrbook.window);
1352 if (!prefs_common.addressbook_use_editaddress_dialog)
1353 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1355 addressbook_pane_save_position();
1357 gtk_widget_hide(addrbook.window);
1358 addressbook_export_to_file();
1363 * Display message in status line.
1364 * \param msg Message to display.
1366 static void addressbook_status_show( gchar *msg ) {
1367 if( addrbook.statusbar != NULL ) {
1369 GTK_STATUSBAR(addrbook.statusbar),
1370 addrbook.status_cid );
1373 GTK_STATUSBAR(addrbook.statusbar),
1374 addrbook.status_cid, msg );
1379 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1383 *addressbook_msgbuf = '\0';
1385 name = addrindex_ds_get_name( ds );
1386 retVal = addrindex_ds_get_status_code( ds );
1387 if( retVal == MGU_SUCCESS ) {
1388 g_snprintf( addressbook_msgbuf,
1389 sizeof(addressbook_msgbuf), "%s", name );
1392 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1393 g_snprintf( addressbook_msgbuf,
1394 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1397 addressbook_status_show( addressbook_msgbuf );
1400 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1402 addressbook_edit_address_cb(NULL, NULL);
1405 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1407 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1411 * Delete one or more objects from address list.
1413 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1415 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1416 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1417 AddressObject *pobj;
1418 AdapterDSource *ads = NULL;
1419 GtkCMCTreeNode *nodeList;
1422 AddressBookFile *abf = NULL;
1423 AddressDataSource *ds = NULL;
1424 AddressInterface *iface;
1425 AddrItemObject *aio;
1426 AddrSelectItem *item;
1428 gboolean refreshList = FALSE;
1430 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1431 cm_return_if_fail(pobj != NULL);
1433 /* Test whether anything selected for deletion */
1434 nodeList = addrbook.listSelected;
1436 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1437 if( aio == NULL) return;
1438 ds = addressbook_find_datasource( addrbook.treeSelected );
1439 if( ds == NULL ) return;
1441 /* Test for read only */
1442 iface = ds->interface;
1443 if( iface->readOnly ) {
1444 alertpanel( _("Delete address(es)"),
1445 _("This address data is readonly and cannot be deleted."),
1446 GTK_STOCK_CLOSE, NULL, NULL );
1450 /* Test whether Ok to proceed */
1452 if( pobj->type == ADDR_DATASOURCE ) {
1453 ads = ADAPTER_DSOURCE(pobj);
1454 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1456 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1459 else if( pobj->type == ADDR_ITEM_GROUP ) {
1462 if( ! procFlag ) return;
1463 abf = ds->rawDataSource;
1464 if( abf == NULL ) return;
1466 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1467 g_signal_handlers_block_by_func
1468 (G_OBJECT(addrbook.clist),
1469 G_CALLBACK(addressbook_list_row_unselected), NULL);
1471 /* Process deletions */
1472 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1473 GList *groups = NULL, *persons = NULL, *emails = NULL;
1474 gboolean group_delete = TRUE;
1475 /* Items inside folders */
1476 list = addrselect_get_list( _addressSelect_ );
1477 /* Confirm deletion */
1481 node = g_list_next( node );
1482 aio = ( AddrItemObject * ) item->addressItem;
1483 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1484 group_delete = FALSE;
1489 aval = alertpanel( _("Delete group"),
1490 _("Really delete the group(s)?\n"
1491 "The addresses it contains will not be lost."),
1492 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1493 if( aval != G_ALERTALTERNATE ) {
1497 aval = alertpanel( _("Delete address(es)"),
1498 _("Really delete the address(es)?"),
1499 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1500 if( aval != G_ALERTALTERNATE ) {
1505 /* first, set lists of groups and persons to remove */
1509 node = g_list_next( node );
1510 aio = ( AddrItemObject * ) item->addressItem;
1513 if( aio->type == ADDR_ITEM_GROUP ) {
1514 groups = g_list_prepend(groups, item);
1516 else if( aio->type == ADDR_ITEM_PERSON ) {
1517 persons = g_list_prepend(persons, item);
1520 /* then set list of emails to remove *if* they're not children of
1521 * persons to remove */
1525 node = g_list_next( node );
1526 aio = ( AddrItemObject * ) item->addressItem;
1529 if( aio->type == ADDR_ITEM_EMAIL ) {
1530 ItemEMail *sitem = ( ItemEMail * ) aio;
1531 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1532 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1533 emails = g_list_prepend(emails, item);
1535 /* else, the email will be removed via the parent person */
1538 /* then delete groups */
1542 node = g_list_next( node );
1543 aio = ( AddrItemObject * ) item->addressItem;
1546 if( aio->type == ADDR_ITEM_GROUP ) {
1547 ItemGroup *item = ( ItemGroup * ) aio;
1548 GtkCMCTreeNode *nd = NULL;
1549 nd = addressbook_find_group_node( addrbook.opened, item );
1550 item = addrbook_remove_group( abf, item );
1552 addritem_free_item_group( item );
1554 /* Remove group from parent node */
1555 gtk_cmctree_remove_node( ctree, nd );
1559 /* then delete persons */
1563 node = g_list_next( node );
1564 aio = ( AddrItemObject * ) item->addressItem;
1567 if( aio->type == ADDR_ITEM_PERSON ) {
1568 ItemPerson *item = ( ItemPerson * ) aio;
1569 item->status = DELETE_ENTRY;
1570 addressbook_folder_remove_one_person( clist, item );
1571 if (pobj->type == ADDR_ITEM_FOLDER)
1572 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1573 item = addrbook_remove_person( abf, item );
1575 if (ds && ds->type == ADDR_IF_LDAP) {
1576 LdapServer *server = ds->rawDataSource;
1577 ldapsvr_set_modified(server, TRUE);
1578 ldapsvr_update_book(server, item);
1582 gchar *filename = addritem_person_get_picture(item);
1583 if (filename && is_file_exist(filename))
1584 claws_unlink(filename);
1586 addritem_free_item_person( item );
1590 /* then delete emails */
1594 node = g_list_next( node );
1595 aio = ( AddrItemObject * ) item->addressItem;
1599 if( aio->type == ADDR_ITEM_EMAIL ) {
1600 ItemEMail *sitem = ( ItemEMail * ) aio;
1601 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1602 sitem = addrbook_person_remove_email( abf, person, sitem );
1604 addrcache_remove_email(abf->addressCache, sitem);
1605 addritem_free_item_email( sitem );
1607 addressbook_folder_refresh_one_person( clist, person );
1610 g_list_free( groups );
1611 g_list_free( persons );
1612 g_list_free( emails );
1613 g_list_free( list );
1614 addressbook_list_select_clear();
1616 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1617 addressbook_set_clist(
1618 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1622 addrbook_set_dirty(abf, TRUE);
1623 addressbook_export_to_file();
1624 addressbook_list_menu_setup();
1627 else if( pobj->type == ADDR_ITEM_GROUP ) {
1628 /* Items inside groups */
1629 list = addrselect_get_list( _addressSelect_ );
1633 node = g_list_next( node );
1634 aio = ( AddrItemObject * ) item->addressItem;
1635 if( aio->type == ADDR_ITEM_EMAIL ) {
1636 ItemEMail *item = ( ItemEMail * ) aio;
1637 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1638 item = addrbook_person_remove_email( abf, person, item );
1640 addritem_free_item_email( item );
1644 g_list_free( list );
1645 addressbook_list_select_clear();
1646 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1647 addressbook_set_clist(
1648 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1652 addrbook_set_dirty(abf, TRUE);
1653 addressbook_export_to_file();
1654 addressbook_list_menu_setup();
1658 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1659 gtk_cmctree_remove_node( clist, nodeList );
1661 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1662 g_signal_handlers_unblock_by_func
1663 (G_OBJECT(addrbook.clist),
1664 G_CALLBACK(addressbook_list_row_unselected), NULL);
1667 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1669 addressbook_new_address_cb( NULL, NULL );
1672 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1675 gchar *address = NULL;
1677 if( aio->type == ADDR_ITEM_EMAIL ) {
1678 ItemPerson *person = NULL;
1679 ItemEMail *email = ( ItemEMail * ) aio;
1681 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1682 if( email->address ) {
1683 if( ADDRITEM_NAME(email) ) {
1684 name = ADDRITEM_NAME(email);
1685 if( *name == '\0' ) {
1686 name = ADDRITEM_NAME(person);
1689 else if( ADDRITEM_NAME(person) ) {
1690 name = ADDRITEM_NAME(person);
1693 buf = g_strdup( email->address );
1695 address = email->address;
1698 else if( aio->type == ADDR_ITEM_PERSON ) {
1699 ItemPerson *person = ( ItemPerson * ) aio;
1700 GList *node = person->listEMail;
1702 name = ADDRITEM_NAME(person);
1704 ItemEMail *email = ( ItemEMail * ) node->data;
1705 address = email->address;
1709 if( name && name[0] != '\0' ) {
1710 if( strchr_with_skip_quote( name, '"', ',' ) )
1711 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1713 buf = g_strdup_printf( "%s <%s>", name, address );
1716 buf = g_strdup( address );
1723 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1727 AddrSelectItem *item;
1728 AddrItemObject *aio;
1731 compose = addrbook.target_compose;
1732 if( ! compose ) return;
1734 /* Nothing selected, but maybe there is something in text entry */
1735 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1737 compose_entry_append(
1738 compose, addr, (ComposeEntryType)data , PREF_NONE);
1741 /* Select from address list */
1742 list = addrselect_get_list( _addressSelect_ );
1747 node = g_list_next( node );
1748 aio = item->addressItem;
1749 if( aio->type == ADDR_ITEM_PERSON ||
1750 aio->type == ADDR_ITEM_EMAIL ) {
1751 addr = addressbook_format_address( aio );
1752 compose_entry_append(
1753 compose, addr, (ComposeEntryType) data, PREF_NONE );
1756 else if( aio->type == ADDR_ITEM_GROUP ) {
1757 ItemGroup *group = ( ItemGroup * ) aio;
1758 GList *nodeMail = group->listEMail;
1760 ItemEMail *email = nodeMail->data;
1762 addr = addressbook_format_address(
1763 ( AddrItemObject * ) email );
1764 compose_entry_append(
1765 compose, addr, (ComposeEntryType) data, PREF_NONE );
1767 nodeMail = g_list_next( nodeMail );
1772 AddressObject *obj = NULL;
1774 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1776 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1777 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1778 GList *nodeMail = itemGroup->listEMail;
1780 ItemEMail *email = nodeMail->data;
1782 addr = addressbook_format_address(
1783 ( AddrItemObject * ) email );
1784 compose_entry_append(
1785 compose, addr, (ComposeEntryType) data, PREF_NONE );
1787 nodeMail = g_list_next( nodeMail );
1791 g_list_free( list );
1794 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1797 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1799 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1800 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1801 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1802 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1804 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1805 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1806 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1807 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1808 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1811 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1812 gboolean canEdit = FALSE;
1813 gboolean canDelete = TRUE;
1814 gboolean canAdd = FALSE;
1815 gboolean canEditTr = TRUE;
1816 gboolean editAddress = FALSE;
1817 gboolean canExport = TRUE;
1818 AddressTypeControlItem *atci = NULL;
1819 AddressDataSource *ds = NULL;
1820 AddressInterface *iface = NULL;
1822 if( obj == NULL ) return;
1823 if( obj->type == ADDR_INTERFACE ) {
1824 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1825 iface = adapter->interface;
1827 if( iface->haveLibrary ) {
1828 /* Enable appropriate File / New command */
1829 atci = adapter->atci;
1830 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1833 canEditTr = canExport = FALSE;
1835 else if( obj->type == ADDR_DATASOURCE ) {
1836 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1837 ds = ads->dataSource;
1838 iface = ds->interface;
1839 if( ! iface->readOnly ) {
1840 canAdd = canEdit = editAddress = canDelete = TRUE;
1842 if( ! iface->haveLibrary ) {
1843 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1846 else if( obj->type == ADDR_ITEM_FOLDER ) {
1847 ds = addressbook_find_datasource( addrbook.treeSelected );
1849 iface = ds->interface;
1850 if( iface->readOnly ) {
1855 canAdd = editAddress = TRUE;
1859 else if( obj->type == ADDR_ITEM_GROUP ) {
1860 ds = addressbook_find_datasource( addrbook.treeSelected );
1862 iface = ds->interface;
1863 if( ! iface->readOnly ) {
1869 if( addrbook.listSelected == NULL )
1873 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1875 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1876 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1879 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1880 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1881 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1882 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1884 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1885 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1888 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1889 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1893 * Address book tree callback function that responds to selection of tree
1896 * \param ctree Tree widget.
1897 * \param node Node that was selected.
1898 * \param column Column number where selected occurred.
1899 * \param data Pointer to user data.
1901 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1902 gint column, gpointer data)
1904 AddressObject *obj = NULL;
1905 AdapterDSource *ads = NULL;
1906 AddressDataSource *ds = NULL;
1907 ItemFolder *rootFolder = NULL;
1908 AddressObjectType aot;
1910 addrbook.treeSelected = node;
1911 addrbook.listSelected = NULL;
1912 addressbook_status_show( "" );
1913 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1915 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1917 addressbook_set_clist(NULL, TRUE);
1920 addrbook.opened = node;
1922 if( obj->type == ADDR_DATASOURCE ) {
1923 /* Read from file */
1924 static gboolean tVal = TRUE;
1926 ads = ADAPTER_DSOURCE(obj);
1927 if( ads == NULL ) return;
1928 ds = ads->dataSource;
1929 if( ds == NULL ) return;
1931 if( addrindex_ds_get_modify_flag( ds ) ) {
1932 addrindex_ds_read_data( ds );
1935 if( ! addrindex_ds_get_read_flag( ds ) ) {
1936 addrindex_ds_read_data( ds );
1938 addressbook_ds_show_message( ds );
1940 if( ! addrindex_ds_get_access_flag( ds ) ) {
1941 /* Remove existing folders and groups */
1942 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1943 addressbook_tree_remove_children( ctree, node );
1944 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1946 /* Load folders into the tree */
1947 rootFolder = addrindex_ds_get_root_folder( ds );
1948 if( ds && ds->type == ADDR_IF_JPILOT ) {
1949 aot = ADDR_CATEGORY;
1951 else if( ds && ds->type == ADDR_IF_LDAP ) {
1952 aot = ADDR_LDAP_QUERY;
1955 aot = ADDR_ITEM_FOLDER;
1957 addressbook_node_add_folder( node, ds, rootFolder, aot );
1958 addrindex_ds_set_access_flag( ds, &tVal );
1959 gtk_cmctree_expand( ctree, node );
1962 addressbook_set_clist(NULL, TRUE);
1965 /* Update address list */
1966 g_signal_handlers_block_by_func
1968 G_CALLBACK(addressbook_tree_selected), NULL);
1969 addressbook_set_clist( obj, FALSE );
1970 g_signal_handlers_unblock_by_func
1972 G_CALLBACK(addressbook_tree_selected), NULL);
1973 if (!prefs_common.addressbook_use_editaddress_dialog)
1974 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1976 /* Setup main menu selections */
1977 addressbook_menubar_set_sensitive( FALSE );
1978 addressbook_menuitem_set_sensitive( obj, node );
1979 addressbook_list_select_clear();
1980 addressbook_list_menu_setup();
1985 * Setup address list popup menu items. Items are enabled or disabled as
1988 static void addressbook_list_menu_setup( void ) {
1989 GtkCMCTree *clist = NULL;
1990 AddressObject *pobj = NULL;
1991 AddressObject *obj = NULL;
1992 AdapterDSource *ads = NULL;
1993 AddressInterface *iface = NULL;
1994 AddressDataSource *ds = NULL;
1995 gboolean canEdit = FALSE;
1996 gboolean canDelete = FALSE;
1997 gboolean canCut = FALSE;
1998 gboolean canCopy = FALSE;
1999 gboolean canPaste = FALSE;
2000 gboolean canBrowse = FALSE;
2002 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2003 if( pobj == NULL ) return;
2005 clist = GTK_CMCTREE(addrbook.clist);
2006 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2007 if( obj == NULL ) canEdit = FALSE;
2009 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2010 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2012 if( pobj->type == ADDR_DATASOURCE ) {
2013 /* Parent object is a data source */
2014 ads = ADAPTER_DSOURCE(pobj);
2015 ds = ads->dataSource;
2018 iface = ds->interface;
2021 if( ! iface->readOnly ) {
2022 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2023 if (iface->type != ADDR_IF_LDAP)
2024 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2025 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2028 canDelete = canEdit;
2031 else if( pobj->type != ADDR_INTERFACE ) {
2032 /* Parent object is not an interface */
2033 ds = addressbook_find_datasource( addrbook.treeSelected );
2036 iface = ds->interface;
2039 if( ! iface->readOnly ) {
2040 /* Folder or group */
2041 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2042 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2043 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2044 if( obj ) canEdit = TRUE;
2047 if( pobj->type == ADDR_ITEM_FOLDER ) {
2048 if (iface->type != ADDR_IF_LDAP)
2049 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2050 if( obj ) canEdit = TRUE;
2052 canDelete = canEdit;
2054 if( iface->type == ADDR_IF_LDAP ) {
2055 if( obj ) canBrowse = TRUE;
2062 /* Enable cut and paste */
2063 if( ! addrclip_is_empty( _clipBoard_ ) )
2065 if( ! addrselect_test_empty( _addressSelect_ ) )
2067 /* Enable copy if something is selected */
2068 if( ! addrselect_test_empty( _addressSelect_ ) )
2072 /* Disable edit or browse if more than one row selected */
2073 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2078 /* Forbid write changes when read-only */
2079 if( iface && iface->readOnly ) {
2085 /* Now go finalize menu items */
2086 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2087 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2089 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2090 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2091 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2093 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2095 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2096 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2097 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2099 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2101 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2103 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2104 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2106 if (addrbook.target_compose) {
2107 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2108 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2109 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2112 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2116 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2117 GtkCMCTreeNode *node,
2124 * Add list of items into tree node below specified tree node.
2125 * \param treeNode Tree node.
2126 * \param ds Data source.
2127 * \param listItems List of items.
2129 static void addressbook_treenode_add_list(
2130 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2136 AddrItemObject *aio;
2140 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2143 group = ( ItemGroup * ) aio;
2144 nn = addressbook_node_add_group( treeNode, ds, group );
2146 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2149 folder = ( ItemFolder * ) aio;
2150 nn = addressbook_node_add_folder(
2151 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2153 node = g_list_next( node );
2157 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2158 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2162 * Cut from address list widget.
2164 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2165 _clipBoard_->cutFlag = TRUE;
2166 addrclip_clear( _clipBoard_ );
2167 addrclip_add( _clipBoard_, _addressSelect_ );
2168 /* addrclip_list_show( _clipBoard_, stdout ); */
2172 * Copy from address list widget.
2174 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2175 _clipBoard_->cutFlag = FALSE;
2176 addrclip_clear( _clipBoard_ );
2177 addrclip_add( _clipBoard_, _addressSelect_ );
2178 /* addrclip_list_show( _clipBoard_, stdout ); */
2182 * Paste clipboard into address list widget.
2184 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2185 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2186 AddressObject *pobj = NULL;
2187 AddressDataSource *ds = NULL;
2188 AddressBookFile *abf = NULL;
2189 ItemFolder *folder = NULL;
2190 GList *folderGroup = NULL;
2192 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2193 if( ds == NULL ) return;
2194 if( addrindex_ds_get_readonly( ds ) ) {
2195 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2199 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2201 if( pobj->type == ADDR_ITEM_FOLDER ) {
2202 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2204 else if( pobj->type == ADDR_ITEM_GROUP ) {
2205 alertpanel_error( _("Cannot paste into an address group.") );
2210 /* Get an address book */
2211 abf = addressbook_get_book_file();
2212 if( abf == NULL ) return;
2214 if( _clipBoard_->cutFlag ) {
2216 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2218 /* Remove all groups and folders in clipboard from tree node */
2219 addressbook_treenode_remove_item();
2221 /* Remove all "cut" items */
2222 addrclip_delete_item( _clipBoard_ );
2224 /* Clear clipboard - cut items??? */
2225 addrclip_clear( _clipBoard_ );
2229 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2232 /* addrclip_list_show( _clipBoard_, stdout ); */
2234 /* Update tree by inserting node for each folder or group */
2235 addressbook_treenode_add_list(
2236 addrbook.treeSelected, ds, folderGroup );
2237 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2238 g_list_free( folderGroup );
2242 /* Display items pasted */
2243 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2244 addressbook_set_clist(
2245 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2253 * Add current treenode object to clipboard. Note that widget only allows
2254 * one entry from the tree list to be selected.
2256 static void addressbook_treenode_to_clipboard( void ) {
2257 AddressObject *obj = NULL;
2258 AddressDataSource *ds = NULL;
2259 AddrSelectItem *item;
2260 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2261 GtkCMCTreeNode *node;
2263 node = addrbook.treeSelected;
2264 if( node == NULL ) return;
2265 obj = gtk_cmctree_node_get_row_data( ctree, node );
2266 if( obj == NULL ) return;
2268 ds = addressbook_find_datasource( node );
2269 if( ds == NULL ) return;
2272 if( obj->type == ADDR_ITEM_FOLDER ) {
2273 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2274 ItemFolder *folder = adapter->itemFolder;
2276 item = addrselect_create_node( obj );
2277 item->uid = g_strdup( ADDRITEM_ID(folder) );
2279 else if( obj->type == ADDR_ITEM_GROUP ) {
2280 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2281 ItemGroup *group = adapter->itemGroup;
2283 item = addrselect_create_node( obj );
2284 item->uid = g_strdup( ADDRITEM_ID(group) );
2286 else if( obj->type == ADDR_DATASOURCE ) {
2288 item = addrselect_create_node( obj );
2293 /* Clear existing list and add item into list */
2296 addressbook_list_select_clear();
2297 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2298 addrselect_list_add( _addressSelect_, item, cacheID );
2304 * Cut from tree widget.
2306 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2307 _clipBoard_->cutFlag = TRUE;
2308 addressbook_treenode_to_clipboard();
2309 addrclip_clear( _clipBoard_ );
2310 addrclip_add( _clipBoard_, _addressSelect_ );
2311 /* addrclip_list_show( _clipBoard_, stdout ); */
2315 * Copy from tree widget.
2317 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2318 _clipBoard_->cutFlag = FALSE;
2319 addressbook_treenode_to_clipboard();
2320 addrclip_clear( _clipBoard_ );
2321 addrclip_add( _clipBoard_, _addressSelect_ );
2322 /* addrclip_list_show( _clipBoard_, stdout ); */
2326 * Paste clipboard into address tree widget.
2328 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2329 addressbook_clip_paste_cb(NULL,NULL);
2333 * Clear selected entries in clipboard.
2335 static void addressbook_list_select_clear( void ) {
2336 addrselect_list_clear( _addressSelect_ );
2340 * Add specified address item to selected address list.
2341 * \param aio Address item object.
2342 * \param ds Datasource.
2344 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2347 if( ds == NULL ) return;
2348 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2349 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2354 * Remove specified address item from selected address list.
2355 * \param aio Address item object.
2357 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2358 addrselect_list_remove( _addressSelect_, aio );
2362 * Invoke EMail compose window with addresses in selected address list.
2364 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2367 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2368 listAddress = addrselect_build_list( _addressSelect_ );
2369 compose_new_with_list( NULL, listAddress );
2370 mgu_free_dlist( listAddress );
2375 static void addressbook_list_row_selected( GtkCMCTree *clist,
2376 GtkCMCTreeNode *node,
2380 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2381 AddrItemObject *aio = NULL;
2382 AddressObject *pobj = NULL;
2383 AdapterDSource *ads = NULL;
2384 AddressDataSource *ds = NULL;
2386 gtk_entry_set_text( entry, "" );
2387 addrbook.listSelected = node;
2389 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2390 if( pobj == NULL ) return;
2392 if( pobj->type == ADDR_DATASOURCE ) {
2393 ads = ADAPTER_DSOURCE(pobj);
2394 ds = ads->dataSource;
2396 else if( pobj->type != ADDR_INTERFACE ) {
2397 ds = addressbook_find_datasource( addrbook.treeSelected );
2400 aio = gtk_cmctree_node_get_row_data( clist, node );
2402 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2403 addressbook_list_select_add( aio, ds );
2406 addressbook_list_menu_setup();
2408 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2409 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2411 if (obj && obj->type != ADDR_ITEM_GROUP)
2412 addressbook_edit_address(NULL, 0, NULL, FALSE);
2416 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2417 GtkCMCTreeNode *node,
2421 AddrItemObject *aio;
2423 aio = gtk_cmctree_node_get_row_data( ctree, node );
2425 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2426 addressbook_list_select_remove( aio );
2429 if (!prefs_common.addressbook_use_editaddress_dialog)
2430 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2433 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2434 GdkEventButton *event,
2437 if( ! event ) return FALSE;
2439 addressbook_list_menu_setup();
2441 if( event->button == 3 ) {
2442 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2443 event->button, event->time );
2444 } else if (event->button == 1) {
2445 if (event->type == GDK_2BUTTON_PRESS) {
2446 if (prefs_common.add_address_by_click &&
2447 addrbook.target_compose)
2448 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2450 if (prefs_common.addressbook_use_editaddress_dialog)
2451 addressbook_edit_address_cb(NULL, NULL);
2453 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2454 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2455 if( obj && obj->type == ADDR_ITEM_GROUP )
2456 addressbook_edit_address_cb(NULL, NULL);
2464 static gboolean addressbook_list_button_released(GtkWidget *widget,
2465 GdkEventButton *event,
2471 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2472 GdkEventButton *event,
2475 GtkCMCList *clist = GTK_CMCLIST(ctree);
2477 AddressObject *obj = NULL;
2478 AdapterDSource *ads = NULL;
2479 AddressInterface *iface = NULL;
2480 AddressDataSource *ds = NULL;
2481 gboolean canEdit = FALSE;
2482 gboolean canDelete = FALSE;
2483 gboolean canCut = FALSE;
2484 gboolean canCopy = FALSE;
2485 gboolean canPaste = FALSE;
2486 gboolean canTreeCut = FALSE;
2487 gboolean canTreeCopy = FALSE;
2488 gboolean canTreePaste = FALSE;
2489 gboolean canLookup = FALSE;
2490 GtkCMCTreeNode *node = NULL;
2492 if( ! event ) return FALSE;
2493 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2495 if (event->button == 1) {
2496 if (event->type == GDK_2BUTTON_PRESS) {
2497 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2498 gtkut_clist_set_focus_row(clist, row);
2499 obj = gtk_cmclist_get_row_data( clist, row );
2504 if (obj->type == ADDR_ITEM_GROUP) {
2506 addressbook_treenode_edit_cb(NULL, NULL);
2508 /* expand pr collapse */
2509 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2510 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2516 addressbook_menubar_set_sensitive( FALSE );
2518 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2519 gtkut_clist_set_focus_row(clist, row);
2520 obj = gtk_cmclist_get_row_data( clist, row );
2523 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2527 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2529 if( ! addrclip_is_empty( _clipBoard_ ) )
2530 canTreePaste = TRUE;
2532 if (obj->type == ADDR_INTERFACE) {
2533 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2534 iface = adapter->interface;
2537 if( !iface->readOnly ) {
2538 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2539 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2541 if( iface->externalQuery )
2544 if (obj->type == ADDR_DATASOURCE) {
2545 ads = ADAPTER_DSOURCE(obj);
2546 ds = ads->dataSource;
2549 iface = ds->interface;
2552 if( !iface->readOnly ) {
2554 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2555 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2556 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2560 if( iface->externalQuery )
2563 else if (obj->type == ADDR_ITEM_FOLDER) {
2564 ds = addressbook_find_datasource( node );
2567 iface = ds->interface;
2570 if( !iface->readOnly ) {
2574 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2575 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2576 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2580 if( iface->externalQuery ) {
2581 /* Enable deletion of LDAP folder */
2586 else if (obj->type == ADDR_ITEM_GROUP) {
2587 ds = addressbook_find_datasource( node );
2590 iface = ds->interface;
2593 if( ! iface->readOnly ) {
2596 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2597 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2601 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2603 if( ! addrselect_test_empty( _addressSelect_ ) )
2605 if( ! addrclip_is_empty( _clipBoard_ ) )
2608 /* Forbid write changes when read-only */
2609 if( iface && iface->readOnly ) {
2611 canTreePaste = FALSE;
2619 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2620 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2621 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2622 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2623 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2625 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2626 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2627 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2628 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2629 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2631 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2632 addrbook.target_compose != NULL);
2634 if( event->button == 3 )
2635 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2636 event->button, event->time);
2641 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2642 GdkEventButton *event,
2645 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2649 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2651 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2652 AddressObject *obj = NULL;
2653 AddressDataSource *ds = NULL;
2654 AddressBookFile *abf = NULL;
2655 ItemFolder *parentFolder = NULL;
2656 ItemFolder *folder = NULL;
2658 if( ! addrbook.treeSelected ) return;
2659 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2660 if( obj == NULL ) return;
2661 ds = addressbook_find_datasource( addrbook.treeSelected );
2662 if( ds == NULL ) return;
2664 if( obj->type == ADDR_DATASOURCE ) {
2665 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2667 else if( obj->type == ADDR_ITEM_FOLDER ) {
2668 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2674 abf = ds->rawDataSource;
2675 if( abf == NULL ) return;
2676 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2679 nn = addressbook_node_add_folder(
2680 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2681 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2682 if( addrbook.treeSelected == addrbook.opened )
2683 addressbook_set_clist(obj, TRUE);
2687 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2689 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2690 AddressObject *obj = NULL;
2691 AddressDataSource *ds = NULL;
2692 AddressBookFile *abf = NULL;
2693 ItemFolder *parentFolder = NULL;
2694 ItemGroup *group = NULL;
2696 if( ! addrbook.treeSelected ) return;
2697 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2698 if( obj == NULL ) return;
2699 ds = addressbook_find_datasource( addrbook.treeSelected );
2700 if( ds == NULL ) return;
2702 if( obj->type == ADDR_DATASOURCE ) {
2703 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2705 else if( obj->type == ADDR_ITEM_FOLDER ) {
2706 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2712 abf = ds->rawDataSource;
2713 if( abf == NULL ) return;
2714 group = addressbook_edit_group( abf, parentFolder, NULL );
2717 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2718 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2719 if( addrbook.treeSelected == addrbook.opened )
2720 addressbook_set_clist(obj, TRUE);
2724 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2726 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2729 GdkPixbuf *pix_cl, *pix_op;
2730 gboolean is_leaf, expanded;
2732 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2734 &is_leaf, &expanded);
2735 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2742 * \param obj Address object to edit.
2743 * \param node Node in tree.
2744 * \return New name of data source.
2746 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2747 gchar *newName = NULL;
2748 AddressDataSource *ds = NULL;
2749 AddressInterface *iface = NULL;
2750 AdapterDSource *ads = NULL;
2752 ds = addressbook_find_datasource( node );
2753 if( ds == NULL ) return NULL;
2754 iface = ds->interface;
2755 if( ! iface->haveLibrary ) return NULL;
2757 /* Read data from data source */
2758 if( addrindex_ds_get_modify_flag( ds ) ) {
2759 addrindex_ds_read_data( ds );
2762 if( ! addrindex_ds_get_read_flag( ds ) ) {
2763 addrindex_ds_read_data( ds );
2767 ads = ADAPTER_DSOURCE(obj);
2768 if( ads->subType == ADDR_BOOK ) {
2769 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2771 else if( ads->subType == ADDR_VCARD ) {
2772 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2775 else if( ads->subType == ADDR_JPILOT ) {
2776 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2780 else if( ads->subType == ADDR_LDAP ) {
2781 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2787 newName = obj->name;
2792 * Edit an object that is in the address tree area.
2794 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2796 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2798 AddressDataSource *ds = NULL;
2799 AddressBookFile *abf = NULL;
2800 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2803 if( ! addrbook.treeSelected ) return;
2804 node = addrbook.treeSelected;
2805 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2806 obj = gtk_cmctree_node_get_row_data( ctree, node );
2807 if( obj == NULL ) return;
2808 parentNode = GTK_CMCTREE_ROW(node)->parent;
2810 ds = addressbook_find_datasource( node );
2811 if( ds == NULL ) return;
2813 if( obj->type == ADDR_DATASOURCE ) {
2814 name = addressbook_edit_datasource( obj, node );
2815 if( name == NULL ) return;
2818 abf = ds->rawDataSource;
2819 if( abf == NULL ) return;
2820 if( obj->type == ADDR_ITEM_FOLDER ) {
2821 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2822 ItemFolder *item = adapter->itemFolder;
2823 ItemFolder *parentFolder = NULL;
2824 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2825 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2826 name = ADDRITEM_NAME(item);
2828 else if( obj->type == ADDR_ITEM_GROUP ) {
2829 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2830 ItemGroup *item = adapter->itemGroup;
2831 ItemFolder *parentFolder = NULL;
2832 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2833 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2834 name = ADDRITEM_NAME(item);
2837 if( name && parentNode ) {
2838 /* Update node in tree view */
2839 addressbook_change_node_name( node, name );
2840 gtk_sctree_sort_node(ctree, parentNode);
2841 gtk_cmctree_expand( ctree, node );
2842 gtk_sctree_select( GTK_SCTREE( ctree), node );
2849 ADDRTREE_DEL_FOLDER_ONLY,
2850 ADDRTREE_DEL_FOLDER_ADDR
2854 * Delete an item from the tree widget.
2855 * \param data Data passed in.
2856 * \param action Action.
2857 * \param widget Widget issuing callback.
2859 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2861 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2862 GtkCMCTreeNode *node = NULL;
2866 AddrBookBase *adbase;
2867 AddressCache *cache;
2868 AdapterDSource *ads = NULL;
2869 AddressInterface *iface = NULL;
2870 AddressDataSource *ds = NULL;
2871 gboolean remFlag = FALSE;
2872 TreeItemDelType delType;
2874 if( ! addrbook.treeSelected ) return;
2875 node = addrbook.treeSelected;
2876 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2878 obj = gtk_cmctree_node_get_row_data( ctree, node );
2879 cm_return_if_fail(obj != NULL);
2881 if( obj->type == ADDR_DATASOURCE ) {
2882 ads = ADAPTER_DSOURCE(obj);
2883 if( ads == NULL ) return;
2884 ds = ads->dataSource;
2885 if( ds == NULL ) return;
2888 /* Must be folder or something else */
2889 ds = addressbook_find_datasource( node );
2890 if( ds == NULL ) return;
2892 /* Only allow deletion from non-readOnly */
2893 iface = ds->interface;
2894 if( iface->readOnly ) {
2895 /* Allow deletion of query results */
2896 if( ! iface->externalQuery ) return;
2900 /* Confirm deletion */
2901 delType = ADDRTREE_DEL_NONE;
2902 if( obj->type == ADDR_ITEM_FOLDER ) {
2903 if( iface && iface->externalQuery ) {
2904 message = g_strdup_printf( _(
2905 "Do you want to delete the query " \
2906 "results and addresses in '%s' ?" ),
2908 aval = alertpanel( _("Delete"), message,
2909 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2911 if( aval == G_ALERTALTERNATE ) {
2912 delType = ADDRTREE_DEL_FOLDER_ADDR;
2916 message = g_strdup_printf
2917 ( _( "Do you want to delete '%s' ? "
2918 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2920 aval = alertpanel( _("Delete folder"), message,
2921 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2923 if( aval == G_ALERTALTERNATE ) {
2924 delType = ADDRTREE_DEL_FOLDER_ONLY;
2926 else if( aval == G_ALERTOTHER ) {
2927 delType = ADDRTREE_DEL_FOLDER_ADDR;
2931 else if( obj->type == ADDR_ITEM_GROUP ) {
2932 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2933 "The addresses it contains will not be lost."), obj->name);
2934 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2935 "+" GTK_STOCK_DELETE, NULL);
2937 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2939 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2940 "The addresses it contains will be lost."), obj->name);
2941 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2942 "+" GTK_STOCK_DELETE, NULL);
2944 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2946 if( delType == ADDRTREE_DEL_NONE ) return;
2948 /* Proceed with deletion */
2949 if( obj->type == ADDR_DATASOURCE ) {
2950 /* Remove node from tree */
2951 gtk_cmctree_remove_node( ctree, node );
2953 if (delType == ADDRTREE_DEL_DATA &&
2954 ds->interface && ds->interface->type == ADDR_IF_BOOK)
2955 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
2957 /* Remove data source. */
2958 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2959 addrindex_free_datasource( ds );
2964 /* Get reference to cache */
2965 adbase = ( AddrBookBase * ) ds->rawDataSource;
2966 if( adbase == NULL ) return;
2967 cache = adbase->addressCache;
2969 /* Remove query results folder */
2970 if( iface && iface->externalQuery ) {
2971 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2972 ItemFolder *folder = adapter->itemFolder;
2974 adapter->itemFolder = NULL;
2976 g_print( "remove folder for ::%s::\n", obj->name );
2977 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2978 g_print( "-------------- remove results\n" );
2980 addrindex_remove_results( ds, folder );
2981 /* g_print( "-------------- remove node\n" ); */
2982 gtk_cmctree_remove_node( ctree, node );
2986 /* Code below is valid for regular address book deletion */
2987 if( obj->type == ADDR_ITEM_FOLDER ) {
2988 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2989 ItemFolder *item = adapter->itemFolder;
2991 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2992 /* Remove folder only */
2993 item = addrcache_remove_folder( cache, item );
2995 addritem_free_item_folder( item );
2996 addressbook_move_nodes_up( ctree, node );
3000 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3001 /* Remove folder and addresses */
3002 item = addrcache_remove_folder_delete( cache, item );
3004 addritem_free_item_folder( item );
3009 else if( obj->type == ADDR_ITEM_GROUP ) {
3010 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3011 ItemGroup *item = adapter->itemGroup;
3013 item = addrcache_remove_group( cache, item );
3015 addritem_free_item_group( item );
3022 gtk_cmctree_remove_node(ctree, node );
3026 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3028 if( person && addrbook.treeSelected == addrbook.opened ) {
3029 person->status = ADD_ENTRY;
3030 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3031 addressbook_folder_refresh_one_person(
3032 GTK_CMCTREE(addrbook.clist), person );
3034 addressbook_address_list_set_focus();
3037 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3039 if( person && addrbook.treeSelected == addrbook.opened) {
3040 person->status = ADD_ENTRY;
3041 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3042 addressbook_set_clist(
3043 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3047 addressbook_address_list_set_focus();
3051 * Label (a format string) that is used to name each folder.
3053 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3056 * Search ctree widget callback function.
3057 * \param pA Pointer to node.
3058 * \param pB Pointer to data item being sought.
3059 * \return Zero (0) if folder found.
3061 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3064 aoA = ( AddressObject * ) pA;
3065 if( aoA->type == ADDR_ITEM_FOLDER ) {
3066 ItemFolder *folder, *fld;
3068 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3069 folder = ( ItemFolder * ) pB;
3070 if( fld == folder ) return 0; /* Found folder */
3075 static ItemFolder * addressbook_setup_subf(
3076 AddressDataSource *ds, gchar *title,
3077 GtkCMCTreeNode *pNode )
3079 AddrBookBase *adbase;
3080 AddressCache *cache;
3083 GtkCMCTreeNode *nNode;
3085 AddressObjectType aoType = ADDR_NONE;
3088 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3090 if( ds && ds->type == ADDR_IF_LDAP ) {
3092 aoType = ADDR_LDAP_QUERY;
3099 ctree = GTK_CMCTREE(addrbook.ctree);
3100 /* Get reference to address cache */
3101 adbase = ( AddrBookBase * ) ds->rawDataSource;
3102 cache = adbase->addressCache;
3104 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3105 GList *cur = children;
3106 for (; cur; cur = cur->next) {
3107 ItemFolder *child = (ItemFolder *) cur->data;
3108 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3109 nNode = gtk_cmctree_find_by_row_data_custom(
3111 addressbook_treenode_find_folder_cb );
3113 addrindex_remove_results( ds, child );
3114 while( child->listPerson ) {
3115 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3116 item = addrcache_remove_person( cache, item );
3118 addritem_free_item_person( item );
3122 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3123 addrbook.treeSelected = nNode;
3130 /* Create a folder */
3131 folder = addrcache_add_new_folder( cache, NULL );
3132 name = g_strdup_printf( "%s", title );
3133 addritem_folder_set_name( folder, name );
3134 addritem_folder_set_remarks( folder, "" );
3137 /* Now let's see the folder */
3138 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3139 gtk_cmctree_expand( ctree, pNode );
3141 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3142 addrbook.treeSelected = nNode;
3148 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3149 AddressObject *pobj = NULL;
3150 AddressDataSource *ds = NULL;
3151 AddressBookFile *abf = NULL;
3152 debug_print("adding address\n");
3153 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3154 if( pobj == NULL ) {
3155 debug_print("no row data\n");
3158 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3160 debug_print("no datasource\n");
3164 abf = ds->rawDataSource;
3166 g_print("no addressbook file\n");
3170 if( pobj->type == ADDR_DATASOURCE ) {
3171 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3172 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3174 ItemFolder *folder = NULL;
3176 if (abf && abf->type == ADDR_IF_LDAP) {
3177 GtkCMCTreeNode *parentNode;
3178 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3179 if( ds == NULL ) return;
3181 /* We must have a datasource that is an external interface */
3182 if( ! ds->interface->haveLibrary ) return;
3183 if( ! ds->interface->externalQuery ) return;
3185 if( pobj->type == ADDR_ITEM_FOLDER ) {
3186 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3189 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3191 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3193 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3194 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3196 abf = ds->rawDataSource;
3199 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3200 addrbook.editaddress_vbox,
3201 addressbook_new_address_from_book_post_cb,
3204 if (ds && abf && abf->type == ADDR_IF_LDAP) {
3205 LdapServer *server = ds->rawDataSource;
3206 ldapsvr_set_modified(server, TRUE);
3207 ldapsvr_update_book(server, NULL);
3208 if (server->retVal != LDAPRC_SUCCESS) {
3209 alertpanel( _("Add address(es)"),
3210 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3211 GTK_STOCK_CLOSE, NULL, NULL );
3212 server->retVal = LDAPRC_SUCCESS;
3217 if (prefs_common.addressbook_use_editaddress_dialog)
3218 addressbook_new_address_from_book_post_cb( person );
3221 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3223 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3226 if (abf && abf->type == ADDR_IF_LDAP) {
3227 GtkCMCTreeNode *parentNode;
3228 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3229 if( ds == NULL ) return;
3231 /* We must have a datasource that is an external interface */
3232 if( ! ds->interface->haveLibrary ) return;
3233 if( ! ds->interface->externalQuery ) return;
3235 if( pobj->type == ADDR_ITEM_FOLDER ) {
3236 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3239 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3241 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3244 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3245 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3247 abf = ds->rawDataSource;
3250 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3251 addrbook.editaddress_vbox,
3252 addressbook_new_address_from_folder_post_cb,
3255 if (ds && abf && abf->type == ADDR_IF_LDAP) {
3256 LdapServer *server = ds->rawDataSource;
3257 ldapsvr_set_modified(server, TRUE);
3258 ldapsvr_update_book(server, NULL);
3259 if (server->retVal != LDAPRC_SUCCESS) {
3260 alertpanel( _("Add address(es)"),
3261 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3262 GTK_STOCK_CLOSE, NULL, NULL );
3267 if (prefs_common.addressbook_use_editaddress_dialog)
3268 addressbook_new_address_from_folder_post_cb( person );
3270 else if( pobj->type == ADDR_ITEM_GROUP ) {
3271 /* New address in group */
3272 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3273 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3274 if (addrbook.treeSelected == addrbook.opened) {
3275 /* Change node name in tree. */
3276 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3277 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3278 addressbook_set_clist(
3279 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3287 * Search for specified child group node in address index tree.
3288 * \param parent Parent node.
3289 * \param group Group to find.
3291 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3292 GtkCMCTreeNode *node = NULL;
3293 GtkCMCTreeRow *currRow;
3295 currRow = GTK_CMCTREE_ROW( parent );
3297 node = currRow->children;
3301 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3302 if( obj->type == ADDR_ITEM_GROUP ) {
3303 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3304 if( g == group ) return node;
3306 currRow = GTK_CMCTREE_ROW(node);
3307 node = currRow->sibling;
3313 static AddressBookFile *addressbook_get_book_file() {
3314 AddressBookFile *abf = NULL;
3315 AddressDataSource *ds = NULL;
3317 ds = addressbook_find_datasource( addrbook.treeSelected );
3318 if( ds == NULL ) return NULL;
3319 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3323 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3324 GtkCMCTreeNode *node;
3327 /* Remove existing folders and groups */
3328 row = GTK_CMCTREE_ROW( parent );
3330 while( (node = row->children) ) {
3331 gtk_cmctree_remove_node( ctree, node );
3336 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3337 GtkCMCTreeNode *parent, *child;
3338 GtkCMCTreeRow *currRow;
3339 currRow = GTK_CMCTREE_ROW( node );
3341 parent = currRow->parent;
3342 while( (child = currRow->children) ) {
3343 gtk_cmctree_move( ctree, child, parent, node );
3345 gtk_sctree_sort_node( ctree, parent );
3349 static void addressbook_edit_address_post_cb( ItemPerson *person )
3353 AddressBookFile *abf = addressbook_get_book_file();
3355 if (abf && abf->type == ADDR_IF_LDAP) {
3356 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3357 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3360 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3361 invalidate_address_completion();
3363 addressbook_address_list_set_focus();
3366 void addressbook_address_list_set_focus( void )
3368 if (!prefs_common.addressbook_use_editaddress_dialog) {
3369 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3370 addressbook_list_menu_setup();
3374 void addressbook_address_list_disable_some_actions(void)
3376 /* disable address copy/pasting when editing contact's detail (embedded form) */
3377 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3378 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3379 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3382 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3383 addressbook_edit_address(data, 0, NULL, TRUE);
3386 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3387 gboolean force_focus ) {
3388 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3390 AddressObject *obj = NULL, *pobj = NULL;
3391 AddressDataSource *ds = NULL;
3392 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3394 AddressBookFile *abf = NULL;
3396 if( addrbook.listSelected == NULL ) return;
3397 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3398 cm_return_if_fail(obj != NULL);
3400 ctree = GTK_CMCTREE( addrbook.ctree );
3401 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3402 node = gtk_cmctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3404 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3405 if( ds == NULL ) return;
3407 abf = addressbook_get_book_file();
3409 if( obj->type == ADDR_ITEM_EMAIL ) {
3410 ItemEMail *email = ( ItemEMail * ) obj;
3411 if( email == NULL ) return;
3412 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3413 /* Edit parent group */
3414 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3415 ItemGroup *itemGrp = adapter->itemGroup;
3416 if( abf == NULL ) return;
3417 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3418 name = ADDRITEM_NAME(itemGrp);
3419 node = addrbook.treeSelected;
3420 parentNode = GTK_CMCTREE_ROW(node)->parent;
3423 /* Edit person - email page */
3425 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3426 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3427 addressbook_edit_address_post_cb,
3428 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3431 if (abf && abf->type == ADDR_IF_LDAP) {
3432 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3433 person->status = UPDATE_ENTRY;
3436 if (prefs_common.addressbook_use_editaddress_dialog)
3437 addressbook_edit_address_post_cb( person );
3442 else if( obj->type == ADDR_ITEM_PERSON ) {
3443 /* Edit person - basic page */
3444 ItemPerson *person = ( ItemPerson * ) obj;
3445 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3446 addressbook_edit_address_post_cb,
3447 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3450 if (abf && abf->type == ADDR_IF_LDAP) {
3451 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3452 person->status = UPDATE_ENTRY;
3455 if (prefs_common.addressbook_use_editaddress_dialog)
3456 addressbook_edit_address_post_cb( person );
3460 else if( obj->type == ADDR_ITEM_GROUP ) {
3461 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3462 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3463 parentNode = addrbook.treeSelected;
3464 node = addressbook_find_group_node( parentNode, itemGrp );
3465 name = ADDRITEM_NAME(itemGrp);
3466 invalidate_address_completion();
3472 /* Update tree node with node name */
3473 if( node == NULL ) return;
3474 addressbook_change_node_name( node, name );
3475 gtk_sctree_sort_node( ctree, parentNode );
3476 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3477 addressbook_set_clist(
3478 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3483 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3485 addressbook_del_clicked(NULL, NULL);
3488 static void close_cb(GtkAction *action, gpointer data)
3490 addressbook_close();
3493 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3494 addressbook_export_to_file();
3497 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3499 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3500 if( person ) addritem_person_set_opened( person, TRUE );
3504 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3506 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3507 if( person ) addritem_person_set_opened( person, FALSE );
3511 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3513 gchar *eMailAlias = ADDRITEM_NAME(email);
3514 if( eMailAlias && *eMailAlias != '\0' ) {
3516 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3519 str = g_strdup( eMailAlias );
3525 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3526 GList *items = itemGroup->listEMail;
3527 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3528 for( ; items != NULL; items = g_list_next( items ) ) {
3529 GtkCMCTreeNode *nodeEMail = NULL;
3530 gchar *text[N_LIST_COLS];
3531 ItemEMail *email = items->data;
3535 if( ! email ) continue;
3537 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3538 str = addressbook_format_item_clist( person, email );
3540 text[COL_NAME] = addressbook_set_col_name_guard(str);
3543 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3545 text[COL_ADDRESS] = email->address;
3546 text[COL_REMARKS] = email->remarks;
3547 nodeEMail = gtk_sctree_insert_node(
3549 text, FOLDER_SPACING,
3553 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3559 gchar *addressbook_set_col_name_guard(gchar *value)
3561 gchar *ret = "<not set>";
3562 gchar *tmp = g_strdup(value);
3564 if (tmp !=NULL && *tmp != '\0')
3570 static void addressbook_folder_load_one_person(
3571 GtkCMCTree *clist, ItemPerson *person,
3572 AddressTypeControlItem *atci,
3573 AddressTypeControlItem *atciMail )
3575 GtkCMCTreeNode *nodePerson = NULL;
3576 GtkCMCTreeNode *nodeEMail = NULL;
3577 gchar *text[N_LIST_COLS];
3578 gboolean flgFirst = TRUE, haveAddr = FALSE;
3581 AddressBookFile *abf = addressbook_get_book_file();
3584 if( person == NULL ) return;
3586 text[COL_NAME] = "";
3587 node = person->listEMail;
3589 ItemEMail *email = node->data;
3590 gchar *eMailAddr = NULL;
3591 node = g_list_next( node );
3593 text[COL_ADDRESS] = email->address;
3594 text[COL_REMARKS] = email->remarks;
3595 eMailAddr = ADDRITEM_NAME(email);
3596 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3598 /* First email belongs with person */
3599 gchar *str = addressbook_format_item_clist( person, email );
3601 text[COL_NAME] = addressbook_set_col_name_guard(str);
3604 else if( abf && abf->type == ADDR_IF_LDAP &&
3605 person && person->nickName ) {
3606 if (person->nickName) {
3607 if (strcmp(person->nickName, "") != 0) {
3608 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3611 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3617 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3619 nodePerson = gtk_sctree_insert_node(
3621 text, FOLDER_SPACING,
3624 FALSE, person->isOpened );
3627 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3630 /* Subsequent email is a child node of person */
3631 text[COL_NAME] = ADDRITEM_NAME(email);
3632 nodeEMail = gtk_sctree_insert_node(
3633 clist, nodePerson, NULL,
3634 text, FOLDER_SPACING,
3636 atciMail->iconXpmOpen,
3638 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3644 /* Have name without EMail */
3645 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3646 text[COL_ADDRESS] = "";
3647 text[COL_REMARKS] = "";
3648 nodePerson = gtk_sctree_insert_node(
3650 text, FOLDER_SPACING,
3653 FALSE, person->isOpened );
3654 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3659 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3661 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3662 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3664 if( atci == NULL ) return;
3665 if( atciMail == NULL ) return;
3667 /* Load email addresses */
3668 items = addritem_folder_get_person_list( itemFolder );
3669 for( ; items != NULL; items = g_list_next( items ) ) {
3670 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3672 /* Free up the list */
3673 mgu_clear_list( items );
3674 g_list_free( items );
3677 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3678 addrbook.listSelected = NULL;
3679 gtk_cmctree_remove_node( clist, node );
3680 addressbook_menubar_set_sensitive( FALSE );
3681 addressbook_menuitem_set_sensitive(
3682 gtk_cmctree_node_get_row_data(
3683 GTK_CMCTREE(clist), addrbook.treeSelected ),
3684 addrbook.treeSelected );
3687 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3688 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3689 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3690 GtkCMCTreeNode *node;
3691 if( atci == NULL ) return;
3692 if( atciMail == NULL ) return;
3693 if( person == NULL ) return;
3694 /* unload the person */
3696 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3698 addressbook_folder_remove_node( clist, node );
3699 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3700 gtk_sctree_sort_node( clist, NULL );
3701 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3703 gtk_sctree_select( GTK_SCTREE(clist), node );
3704 if (!gtk_cmctree_node_is_visible( clist, node ) )
3705 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3709 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3710 GtkCMCTreeNode *node;
3712 if( person == NULL ) return;
3713 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3715 addressbook_folder_remove_node( clist, node );
3719 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3721 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3723 /* Load any groups */
3724 if( ! atci ) return;
3725 items = addritem_folder_get_group_list( itemFolder );
3726 for( ; items != NULL; items = g_list_next( items ) ) {
3727 GtkCMCTreeNode *nodeGroup = NULL;
3728 gchar *text[N_LIST_COLS];
3729 ItemGroup *group = items->data;
3730 if( group == NULL ) continue;
3731 text[COL_NAME] = ADDRITEM_NAME(group);
3732 text[COL_ADDRESS] = "";
3733 text[COL_REMARKS] = "";
3734 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3735 text, FOLDER_SPACING,
3739 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3740 gtk_sctree_sort_node(clist, NULL);
3742 /* Free up the list */
3743 mgu_clear_list( items );
3744 g_list_free( items );
3748 * Search ctree widget callback function.
3749 * \param pA Pointer to node.
3750 * \param pB Pointer to data item being sought.
3751 * \return Zero (0) if group found.
3753 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3756 aoA = ( AddressObject * ) pA;
3757 if( aoA->type == ADDR_ITEM_GROUP ) {
3758 ItemGroup *group, *grp;
3760 grp = ADAPTER_GROUP(aoA)->itemGroup;
3761 group = ( ItemGroup * ) pB;
3762 if( grp == group ) return 0; /* Found group */
3768 * Remove folder and group nodes from tree widget for items contained ("cut")
3771 static void addressbook_treenode_remove_item( void ) {
3773 AddrSelectItem *cutItem;
3774 AddressCache *cache;
3775 AddrItemObject *aio;
3776 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3779 node = _clipBoard_->objectList;
3781 cutItem = node->data;
3782 node = g_list_next( node );
3783 cache = addrindex_get_cache(
3784 _clipBoard_->addressIndex, cutItem->cacheID );
3785 if( cache == NULL ) continue;
3786 aio = addrcache_get_object( cache, cutItem->uid );
3789 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3792 folder = ( ItemFolder * ) aio;
3793 tn = gtk_cmctree_find_by_row_data_custom(
3794 ctree, NULL, folder,
3795 addressbook_treenode_find_folder_cb );
3797 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3800 group = ( ItemGroup * ) aio;
3801 tn = gtk_cmctree_find_by_row_data_custom(
3803 addressbook_treenode_find_group_cb );
3807 /* Free up adapter and remove node. */
3808 gtk_cmctree_remove_node( ctree, tn );
3815 * Find parent datasource for specified tree node.
3816 * \param node Node to test.
3817 * \return Data source, or NULL if not found.
3819 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3820 AddressDataSource *ds = NULL;
3823 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3826 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3827 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3829 /* g_print( "ao->type = %d\n", ao->type ); */
3830 if( ao->type == ADDR_DATASOURCE ) {
3831 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3832 /* g_print( "found it\n" ); */
3833 ds = ads->dataSource;
3837 node = GTK_CMCTREE_ROW(node)->parent;
3843 * Load address list widget with children of specified object.
3844 * \param obj Parent object to be loaded.
3846 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3847 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3848 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3849 AddressDataSource *ds = NULL;
3850 AdapterDSource *ads = NULL;
3851 static AddressObject *last_obj = NULL;
3853 if (addrbook.clist == NULL) {
3856 if (obj == last_obj && !refresh)
3861 gtk_cmclist_clear(clist);
3865 if( obj->type == ADDR_INTERFACE ) {
3866 /* g_print( "set_clist: loading datasource...\n" ); */
3867 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3871 gtk_cmclist_freeze(clist);
3872 gtk_cmclist_clear(clist);
3874 if( obj->type == ADDR_DATASOURCE ) {
3875 ads = ADAPTER_DSOURCE(obj);
3876 ds = ads->dataSource;
3878 /* Load root folder */
3879 ItemFolder *rootFolder = NULL;
3880 rootFolder = addrindex_ds_get_root_folder( ds );
3881 addressbook_folder_load_person(
3882 ctreelist, rootFolder );
3883 addressbook_folder_load_group(
3884 ctreelist, rootFolder );
3888 if( obj->type == ADDR_ITEM_GROUP ) {
3890 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3891 addressbook_load_group( ctreelist, itemGroup );
3893 else if( obj->type == ADDR_ITEM_FOLDER ) {
3895 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3896 addressbook_folder_load_person( ctreelist, itemFolder );
3897 addressbook_folder_load_group( ctreelist, itemFolder );
3900 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3901 clist->focus_row = -1;
3902 gtk_cmclist_thaw(clist);
3906 * Call back function to free adaptor. Call back is setup by function
3907 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3908 * called when the address book tree widget node is removed by calling
3909 * function gtk_cmctree_remove_node().
3911 * \param data Tree node's row data.
3913 static void addressbook_free_treenode( gpointer data ) {
3916 ao = ( AddressObject * ) data;
3917 if( ao == NULL ) return;
3918 if( ao->type == ADDR_INTERFACE ) {
3919 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3920 addrbookctl_free_interface( ai );
3922 else if( ao->type == ADDR_DATASOURCE ) {
3923 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3924 addrbookctl_free_datasource( ads );
3926 else if( ao->type == ADDR_ITEM_FOLDER ) {
3927 AdapterFolder *af = ADAPTER_FOLDER(ao);
3928 addrbookctl_free_folder( af );
3930 else if( ao->type == ADDR_ITEM_GROUP ) {
3931 AdapterGroup *ag = ADAPTER_GROUP(ao);
3932 addrbookctl_free_group( ag );
3937 * Create new adaptor for specified data source.
3939 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3940 AddressObjectType otype, gchar *name )
3942 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3943 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3944 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3945 adapter->dataSource = ds;
3946 adapter->subType = otype;
3950 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3951 ADDRESS_OBJECT_NAME(adapter) =
3952 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3956 * Load tree from address index with the initial data.
3958 static void addressbook_load_tree( void ) {
3959 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3960 GList *nodeIf, *nodeDS;
3961 AdapterInterface *adapter;
3962 AddressInterface *iface;
3963 AddressTypeControlItem *atci;
3964 AddressDataSource *ds;
3965 AdapterDSource *ads;
3966 GtkCMCTreeNode *node, *newNode;
3969 nodeIf = _addressInterfaceList_;
3971 adapter = nodeIf->data;
3972 node = adapter->treeNode;
3973 iface = adapter->interface;
3974 atci = adapter->atci;
3976 if( iface->useInterface ) {
3977 /* Load data sources below interface node */
3978 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 nodeDS = g_list_next( nodeDS );
3989 gtk_cmctree_expand( ctree, node );
3992 nodeIf = g_list_next( nodeIf );
3997 * Convert the old address book to new format.
3999 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4000 gboolean retVal = FALSE;
4001 gboolean errFlag = TRUE;
4004 /* Read old address book, performing conversion */
4005 debug_print( "Reading and converting old address book...\n" );
4006 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4007 addrindex_read_data( addrIndex );
4008 if( addrIndex->retVal == MGU_NO_FILE ) {
4009 /* We do not have a file - new user */
4010 debug_print( "New user... create new books...\n" );
4011 addrindex_create_new_books( addrIndex );
4012 if( addrIndex->retVal == MGU_SUCCESS ) {
4013 /* Save index file */
4014 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4015 addrindex_save_data( addrIndex );
4016 if( addrIndex->retVal == MGU_SUCCESS ) {
4021 msg = _( "New user, could not save index file." );
4025 msg = _( "New user, could not save address book files." );
4029 /* We have an old file */
4030 if( addrIndex->wasConverted ) {
4031 /* Converted successfully - save address index */
4032 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4033 addrindex_save_data( addrIndex );
4034 if( addrIndex->retVal == MGU_SUCCESS ) {
4035 msg = _( "Old address book converted successfully." );
4040 msg = _("Old address book converted,\n"
4041 "could not save new address index file." );
4045 /* File conversion failed - just create new books */
4046 debug_print( "File conversion failed... just create new books...\n" );
4047 addrindex_create_new_books( addrIndex );
4048 if( addrIndex->retVal == MGU_SUCCESS ) {
4050 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4051 addrindex_save_data( addrIndex );
4052 if( addrIndex->retVal == MGU_SUCCESS ) {
4053 msg = _("Could not convert address book,\n"
4054 "but created empty new address book files." );
4059 msg = _("Could not convert address book,\n"
4060 "could not save new address index file." );
4064 msg = _("Could not convert address book\n"
4065 "and could not create new address book files." );
4070 debug_print( "Error\n%s\n", msg );
4071 alertpanel_full(_("Addressbook conversion error"), msg,
4072 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4073 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4076 debug_print( "Warning\n%s\n", msg );
4077 alertpanel_full(_("Addressbook conversion error"), msg,
4078 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4079 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4085 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4089 gboolean failed = FALSE;
4091 if( ( dp = opendir( origdir ) ) == NULL ) {
4095 while( ( d = readdir( dp ) ) != NULL ) {
4096 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4099 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4101 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4103 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4116 /* all copies succeeded, we can remove source files */
4117 if( ( dp = opendir( origdir ) ) == NULL ) {
4120 while( ( d = readdir( dp ) ) != NULL ) {
4121 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4124 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4126 claws_unlink(orig_file);
4136 void addressbook_read_file( void ) {
4137 AddressIndex *addrIndex = NULL;
4138 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4140 debug_print( "Reading address index...\n" );
4141 if( _addressIndex_ ) {
4142 debug_print( "address book already read!!!\n" );
4146 addrIndex = addrindex_create_index();
4147 addrindex_initialize();
4149 /* Use new address book index. */
4151 if ( !is_dir_exist(indexdir) ) {
4152 if ( make_dir(indexdir) < 0 ) {
4153 addrindex_set_file_path( addrIndex, get_rc_dir() );
4154 g_warning( "couldn't create dir %s\n", indexdir);
4156 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4157 remove_dir_recursive(indexdir);
4158 addrindex_set_file_path( addrIndex, get_rc_dir() );
4159 g_error("couldn't migrate dir %s", indexdir);
4161 addrindex_set_file_path( addrIndex, indexdir);
4165 addrindex_set_file_path( addrIndex, indexdir);
4168 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4169 addrindex_read_data( addrIndex );
4170 if( addrIndex->retVal == MGU_NO_FILE ) {
4171 /* Conversion required */
4172 debug_print( "Converting...\n" );
4173 if( addressbook_convert( addrIndex ) ) {
4174 _addressIndex_ = addrIndex;
4177 else if( addrIndex->retVal == MGU_SUCCESS ) {
4178 _addressIndex_ = addrIndex;
4181 /* Error reading address book */
4182 debug_print( "Could not read address index.\n" );
4183 addrindex_print_index( addrIndex, stdout );
4184 alertpanel_full(_("Addressbook Error"),
4185 _("Could not read address index"),
4186 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4187 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4189 debug_print( "done.\n" );
4193 * Add object into the address index tree widget.
4194 * Enter: node Parent node.
4195 * obj Object to add.
4196 * Return: Node that was added, or NULL if object not added.
4198 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4201 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4202 GtkCMCTreeNode *added;
4203 AddressObject *pobj;
4204 AddressObjectType otype;
4205 AddressTypeControlItem *atci = NULL;
4207 cm_return_val_if_fail(node != NULL, NULL);
4208 cm_return_val_if_fail(obj != NULL, NULL);
4210 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4211 cm_return_val_if_fail(pobj != NULL, NULL);
4213 /* Determine object type to be displayed */
4214 if( obj->type == ADDR_DATASOURCE ) {
4215 otype = ADAPTER_DSOURCE(obj)->subType;
4221 /* Handle any special conditions. */
4223 atci = addrbookctl_lookup( otype );
4225 if( atci->showInTree ) {
4226 /* Add object to tree */
4229 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4230 atci->iconXpm, atci->iconXpmOpen,
4231 atci->treeLeaf, atci->treeExpand );
4232 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4233 addressbook_free_treenode );
4237 gtk_sctree_sort_node(ctree, node);
4243 * Add group into the address index tree.
4244 * \param node Parent node.
4245 * \param ds Data source.
4246 * \param itemGroup Group to add.
4247 * \return Inserted node.
4249 static GtkCMCTreeNode *addressbook_node_add_group(
4250 GtkCMCTreeNode *node, AddressDataSource *ds,
4251 ItemGroup *itemGroup )
4253 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4254 GtkCMCTreeNode *newNode;
4255 AdapterGroup *adapter;
4256 AddressTypeControlItem *atci = NULL;
4259 if( ds == NULL ) return NULL;
4260 if( node == NULL || itemGroup == NULL ) return NULL;
4262 name = &itemGroup->obj.name;
4264 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4266 adapter = g_new0( AdapterGroup, 1 );
4267 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4268 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4269 adapter->itemGroup = itemGroup;
4271 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4272 atci->iconXpm, atci->iconXpm,
4273 atci->treeLeaf, atci->treeExpand );
4274 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4275 addressbook_free_treenode );
4276 gtk_sctree_sort_node( ctree, node );
4281 * Add folder into the address index tree. Only visible folders are loaded into
4282 * the address index tree. Note that the root folder is not inserted into the
4285 * \param node Parent node.
4286 * \param ds Data source.
4287 * \param itemFolder Folder to add.
4288 * \param otype Object type to display.
4289 * \return Inserted node for the folder.
4291 static GtkCMCTreeNode *addressbook_node_add_folder(
4292 GtkCMCTreeNode *node, AddressDataSource *ds,
4293 ItemFolder *itemFolder, AddressObjectType otype )
4295 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4296 GtkCMCTreeNode *newNode = NULL;
4297 AdapterFolder *adapter;
4298 AddressTypeControlItem *atci = NULL;
4299 GList *listItems = NULL;
4301 ItemFolder *rootFolder;
4303 /* Only visible folders */
4304 if( itemFolder == NULL || itemFolder->isHidden )
4309 if( node == NULL || itemFolder == NULL )
4312 /* Determine object type */
4313 atci = addrbookctl_lookup( otype );
4317 rootFolder = addrindex_ds_get_root_folder( ds );
4318 if( itemFolder == rootFolder ) {
4322 adapter = g_new0( AdapterFolder, 1 );
4323 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4324 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4325 adapter->itemFolder = itemFolder;
4327 name = ADDRITEM_NAME(itemFolder);
4328 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4329 atci->iconXpm, atci->iconXpm,
4330 atci->treeLeaf, atci->treeExpand );
4332 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4333 addressbook_free_treenode );
4337 listItems = itemFolder->listFolder;
4338 while( listItems ) {
4339 ItemFolder *item = listItems->data;
4340 addressbook_node_add_folder( newNode, ds, item, otype );
4341 listItems = g_list_next( listItems );
4343 listItems = itemFolder->listGroup;
4344 while( listItems ) {
4345 ItemGroup *item = listItems->data;
4346 addressbook_node_add_group( newNode, ds, item );
4347 listItems = g_list_next( listItems );
4349 gtk_sctree_sort_node( ctree, node );
4353 void addressbook_export_to_file( void ) {
4354 if( _addressIndex_ ) {
4355 /* Save all new address book data */
4356 debug_print( "Saving address books...\n" );
4357 addrindex_save_all_books( _addressIndex_ );
4359 debug_print( "Exporting addressbook to file...\n" );
4360 addrindex_save_data( _addressIndex_ );
4361 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4362 addrindex_print_index( _addressIndex_, stdout );
4365 /* Notify address completion of new data */
4366 invalidate_address_completion();
4370 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4372 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4373 addressbook_lup_clicked(NULL, NULL);
4378 * Comparison using cell contents (text in first column). Used for sort
4379 * address index widget.
4381 static gint addressbook_treenode_compare_func(
4382 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4384 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4385 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4386 gchar *name1 = NULL, *name2 = NULL;
4387 if( cell1 ) name1 = cell1->u.text;
4388 if( cell2 ) name2 = cell2->u.text;
4389 if( ! name1 ) return ( name2 != NULL );
4390 if( ! name2 ) return -1;
4391 return g_utf8_collate( name1, name2 );
4394 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4395 AdapterDSource *ads;
4396 AdapterInterface *adapter;
4397 GtkCMCTreeNode *newNode;
4399 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4400 if( adapter == NULL ) return;
4401 ads = addressbook_edit_book( _addressIndex_, NULL );
4403 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4405 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4406 addrbook.treeSelected = newNode;
4411 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4412 AdapterDSource *ads;
4413 AdapterInterface *adapter;
4414 GtkCMCTreeNode *newNode;
4416 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4417 if( adapter == NULL ) return;
4418 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4420 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4422 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4423 addrbook.treeSelected = newNode;
4429 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4430 AdapterDSource *ads;
4431 AdapterInterface *adapter;
4432 AddressInterface *iface;
4433 GtkCMCTreeNode *newNode;
4435 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4436 if( adapter == NULL ) return;
4437 iface = adapter->interface;
4438 if( ! iface->haveLibrary ) return;
4439 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4441 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4443 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4444 addrbook.treeSelected = newNode;
4451 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4452 AdapterDSource *ads;
4453 AdapterInterface *adapter;
4454 AddressInterface *iface;
4455 GtkCMCTreeNode *newNode;
4457 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4458 if( adapter == NULL ) return;
4459 iface = adapter->interface;
4460 if( ! iface->haveLibrary ) return;
4461 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4463 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4465 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4466 addrbook.treeSelected = newNode;
4473 * Display address search status message.
4474 * \param queryType Query type.
4475 * \param status Status/Error code.
4477 static void addressbook_search_message( gint queryType, gint sts ) {
4479 *addressbook_msgbuf = '\0';
4481 if( sts != MGU_SUCCESS ) {
4482 if( queryType == ADDRQUERY_LDAP ) {
4484 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4489 g_snprintf( addressbook_msgbuf,
4490 sizeof(addressbook_msgbuf), "%s", desc );
4491 addressbook_status_show( addressbook_msgbuf );
4494 addressbook_status_show( "" );
4499 * Refresh addressbook by forcing refresh of current selected object in
4502 static void addressbook_refresh_current( void ) {
4506 ctree = GTK_CMCTREE(addrbook.ctree);
4507 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4508 if( obj == NULL ) return;
4509 addressbook_set_clist( obj, TRUE );
4513 * Message that is displayed whilst a query is executing in a background
4516 static gchar *_tempMessage_ = N_( "Busy searching..." );
4519 * Address search idle function. This function is called during UI idle time
4520 * while a search is in progress.
4522 * \param data Idler data.
4524 static void addressbook_search_idle( gpointer data ) {
4528 queryID = GPOINTER_TO_INT( data );
4529 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4534 * Search completion callback function. This removes the query from the idle
4537 * \param sender Sender of query.
4538 * \param queryID Query ID of search request.
4539 * \param status Search status.
4540 * \param data Query data.
4542 static void addressbook_search_callback_end(
4543 gpointer sender, gint queryID, gint status, gpointer data )
4547 AddrQueryObject *aqo;
4549 /* Remove idler function */
4550 ptrQID = GINT_TO_POINTER( queryID );
4552 g_idle_remove_by_data( ptrQID );
4555 /* Refresh addressbook contents */
4556 addressbook_refresh_current();
4557 req = qrymgr_find_request( queryID );
4559 aqo = ( AddrQueryObject * ) req->queryList->data;
4560 addressbook_search_message( aqo->queryType, status );
4563 /* Stop the search */
4564 addrindex_stop_search( queryID );
4570 * \param ds Data source to search.
4571 * \param searchTerm String to lookup.
4572 * \param pNode Parent data source node.
4574 static void addressbook_perform_search(
4575 AddressDataSource *ds, gchar *searchTerm,
4576 GtkCMCTreeNode *pNode )
4583 AddressObjectType aoType = ADDR_NONE;
4587 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4589 if( ds && ds->type == ADDR_IF_LDAP ) {
4591 aoType = ADDR_LDAP_QUERY;
4598 /* Create a folder for the search results */
4599 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4600 folder = addressbook_setup_subf(ds, name, pNode);
4603 /* Setup the search */
4604 queryID = addrindex_setup_explicit_search(
4605 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4606 if( queryID == 0 ) return;
4608 /* Set up idler function */
4609 idleID = g_idle_add(
4610 (GSourceFunc) addressbook_search_idle,
4611 GINT_TO_POINTER( queryID ) );
4613 /* Start search, sit back and wait for something to happen */
4614 addrindex_start_search( queryID );
4616 addressbook_status_show( _tempMessage_ );
4620 * Lookup button handler. Address search is only performed against
4621 * address interfaces for external queries.
4623 * \param button Lookup button widget.
4624 * \param data Data object.
4626 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4629 AddressDataSource *ds;
4630 AddressInterface *iface;
4632 GtkCMCTreeNode *node, *parentNode;
4634 node = addrbook.treeSelected;
4635 if( ! node ) return;
4636 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4638 ctree = GTK_CMCTREE(addrbook.ctree);
4639 obj = gtk_cmctree_node_get_row_data( ctree, node );
4640 if( obj == NULL ) return;
4642 ds = addressbook_find_datasource( node );
4643 if( ds == NULL ) return;
4645 /* We must have a datasource that is an external interface */
4646 iface = ds->interface;
4647 if( ! iface->haveLibrary ) return;
4648 if( ! iface->externalQuery ) return;
4651 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4652 g_strchomp( searchTerm );
4654 if( obj->type == ADDR_ITEM_FOLDER ) {
4655 parentNode = GTK_CMCTREE_ROW(node)->parent;
4660 addressbook_perform_search( ds, searchTerm, parentNode );
4662 gtk_widget_grab_focus( addrbook.entry );
4664 g_free( searchTerm );
4667 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4668 addressbook_close();
4673 * Browse address entry for highlighted entry.
4675 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4677 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4679 AddressDataSource *ds;
4680 AddressInterface *iface;
4684 if(addrbook.listSelected == NULL)
4687 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4691 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4695 iface = ds->interface;
4696 if(!iface || !iface->haveLibrary )
4700 if (obj->type == ADDR_ITEM_EMAIL) {
4701 email = ( ItemEMail * ) obj;
4705 person = (ItemPerson *) ADDRITEM_PARENT(email);
4707 else if (obj->type == ADDR_ITEM_PERSON) {
4708 person = (ItemPerson *) obj;
4715 if( iface && iface->type == ADDR_IF_LDAP ) {
4716 browseldap_entry(ds, person->externalID);
4721 /* **********************************************************************
4722 * Build lookup tables.
4723 * ***********************************************************************
4727 * Remap object types.
4728 * Enter: abType AddressObjectType (used in tree node).
4729 * Return: ItemObjectType (used in address cache data).
4731 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4732 ItemObjectType ioType;
4735 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4736 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4737 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4738 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4739 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4740 default: ioType = ITEMTYPE_NONE; break;
4745 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4746 atci = addrbookctl_lookup(id); \
4748 atci->iconXpm = icon; \
4749 atci->iconXpmOpen = iconopen; \
4751 g_warning("can't get atci %d\n", id); \
4756 * Build table that controls the rendering of object types.
4758 static void addrbookctl_build_icons( GtkWidget *window ) {
4759 AddressTypeControlItem *atci;
4763 g_object_unref(interfacexpm);
4765 g_object_unref(folderxpm);
4767 g_object_unref(folderopenxpm);
4769 g_object_unref(groupxpm);
4771 g_object_unref(vcardxpm);
4773 g_object_unref(bookxpm);
4775 g_object_unref(addressxpm);
4777 g_object_unref(jpilotxpm);
4779 g_object_unref(categoryxpm);
4781 g_object_unref(ldapxpm);
4783 g_object_unref(addrsearchxpm);
4784 stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacexpm );
4785 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4786 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4787 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4788 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4789 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4790 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4791 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4792 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4793 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4794 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4796 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4797 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4798 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4799 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4800 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4801 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4802 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4803 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4804 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4805 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4806 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4811 * Build table that controls the rendering of object types.
4813 static void addrbookctl_build_map( GtkWidget *window ) {
4814 AddressTypeControlItem *atci;
4816 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4817 _addressBookTypeList_ = NULL;
4820 atci = g_new0( AddressTypeControlItem, 1 );
4821 atci->objectType = ADDR_INTERFACE;
4822 atci->interfaceType = ADDR_IF_NONE;
4823 atci->showInTree = TRUE;
4824 atci->treeExpand = TRUE;
4825 atci->treeLeaf = FALSE;
4826 atci->displayName = _( "Interface" );
4827 atci->menuCommand = NULL;
4828 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4829 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4832 atci = g_new0( AddressTypeControlItem, 1 );
4833 atci->objectType = ADDR_BOOK;
4834 atci->interfaceType = ADDR_IF_BOOK;
4835 atci->showInTree = TRUE;
4836 atci->treeExpand = TRUE;
4837 atci->treeLeaf = FALSE;
4838 atci->displayName = _( "Address Book" );
4839 atci->menuCommand = "Menu/Book/NewBook";
4840 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4841 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4844 atci = g_new0( AddressTypeControlItem, 1 );
4845 atci->objectType = ADDR_ITEM_PERSON;
4846 atci->interfaceType = ADDR_IF_NONE;
4847 atci->showInTree = FALSE;
4848 atci->treeExpand = FALSE;
4849 atci->treeLeaf = FALSE;
4850 atci->displayName = _( "Person" );
4851 atci->menuCommand = NULL;
4852 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4853 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4856 atci = g_new0( AddressTypeControlItem, 1 );
4857 atci->objectType = ADDR_ITEM_EMAIL;
4858 atci->interfaceType = ADDR_IF_NONE;
4859 atci->showInTree = FALSE;
4860 atci->treeExpand = FALSE;
4861 atci->treeLeaf = TRUE;
4862 atci->displayName = _( "Email Address" );
4863 atci->menuCommand = NULL;
4864 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4865 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4868 atci = g_new0( AddressTypeControlItem, 1 );
4869 atci->objectType = ADDR_ITEM_GROUP;
4870 atci->interfaceType = ADDR_IF_BOOK;
4871 atci->showInTree = TRUE;
4872 atci->treeExpand = FALSE;
4873 atci->treeLeaf = FALSE;
4874 atci->displayName = _( "Group" );
4875 atci->menuCommand = NULL;
4876 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4877 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4880 atci = g_new0( AddressTypeControlItem, 1 );
4881 atci->objectType = ADDR_ITEM_FOLDER;
4882 atci->interfaceType = ADDR_IF_BOOK;
4883 atci->showInTree = TRUE;
4884 atci->treeExpand = FALSE;
4885 atci->treeLeaf = FALSE;
4886 atci->displayName = _( "Folder" );
4887 atci->menuCommand = NULL;
4888 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4889 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4892 atci = g_new0( AddressTypeControlItem, 1 );
4893 atci->objectType = ADDR_VCARD;
4894 atci->interfaceType = ADDR_IF_VCARD;
4895 atci->showInTree = TRUE;
4896 atci->treeExpand = TRUE;
4897 atci->treeLeaf = TRUE;
4898 atci->displayName = _( "vCard" );
4899 atci->menuCommand = "Menu/Book/NewVCard";
4900 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4901 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4904 atci = g_new0( AddressTypeControlItem, 1 );
4905 atci->objectType = ADDR_JPILOT;
4906 atci->interfaceType = ADDR_IF_JPILOT;
4907 atci->showInTree = TRUE;
4908 atci->treeExpand = TRUE;
4909 atci->treeLeaf = FALSE;
4910 atci->displayName = _( "JPilot" );
4911 atci->menuCommand = "Menu/Book/NewJPilot";
4912 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4913 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4916 atci = g_new0( AddressTypeControlItem, 1 );
4917 atci->objectType = ADDR_CATEGORY;
4918 atci->interfaceType = ADDR_IF_JPILOT;
4919 atci->showInTree = TRUE;
4920 atci->treeExpand = TRUE;
4921 atci->treeLeaf = TRUE;
4922 atci->displayName = _( "JPilot" );
4923 atci->menuCommand = NULL;
4924 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4925 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4928 atci = g_new0( AddressTypeControlItem, 1 );
4929 atci->objectType = ADDR_LDAP;
4930 atci->interfaceType = ADDR_IF_LDAP;
4931 atci->showInTree = TRUE;
4932 atci->treeExpand = TRUE;
4933 atci->treeLeaf = FALSE;
4934 atci->displayName = _( "LDAP servers" );
4935 atci->menuCommand = "Menu/Book/NewLDAPServer";
4936 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4937 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4940 atci = g_new0( AddressTypeControlItem, 1 );
4941 atci->objectType = ADDR_LDAP_QUERY;
4942 atci->interfaceType = ADDR_IF_LDAP;
4943 atci->showInTree = TRUE;
4944 atci->treeExpand = FALSE;
4945 atci->treeLeaf = TRUE;
4946 atci->displayName = _( "LDAP Query" );
4947 atci->menuCommand = NULL;
4948 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4949 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4951 addrbookctl_build_icons(window);
4954 void addressbook_reflect_prefs_pixmap_theme(void)
4956 if (addrbook.window)
4957 addrbookctl_build_icons(addrbook.window);
4961 * Search for specified object type.
4963 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4965 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4969 * Search for specified interface type.
4971 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4972 GList *node = _addressBookTypeList_;
4974 AddressTypeControlItem *atci = node->data;
4975 if( atci->interfaceType == ifType ) return atci;
4976 node = g_list_next( node );
4981 static void addrbookctl_free_address( AddressObject *obj ) {
4982 g_free( obj->name );
4983 obj->type = ADDR_NONE;
4987 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4988 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4989 adapter->interface = NULL;
4990 adapter->interfaceType = ADDR_IF_NONE;
4991 adapter->atci = NULL;
4992 adapter->enabled = FALSE;
4993 adapter->haveLibrary = FALSE;
4994 adapter->treeNode = NULL;
4998 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4999 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5000 adapter->dataSource = NULL;
5001 adapter->subType = ADDR_NONE;
5005 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5006 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5007 adapter->itemFolder = NULL;
5011 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5012 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5013 adapter->itemGroup = NULL;
5018 * Build GUI interface list.
5020 static void addrbookctl_build_iflist( void ) {
5021 AddressTypeControlItem *atci;
5022 AdapterInterface *adapter;
5025 if( _addressIndex_ == NULL ) {
5026 _addressIndex_ = addrindex_create_index();
5027 if( _clipBoard_ == NULL ) {
5028 _clipBoard_ = addrclip_create();
5030 addrclip_set_index( _clipBoard_, _addressIndex_ );
5032 _addressInterfaceList_ = NULL;
5033 list = addrindex_get_interface_list( _addressIndex_ );
5035 AddressInterface *interface = list->data;
5036 atci = addrbookctl_lookup_iface( interface->type );
5038 adapter = g_new0( AdapterInterface, 1 );
5039 adapter->interfaceType = interface->type;
5040 adapter->atci = atci;
5041 adapter->interface = interface;
5042 adapter->treeNode = NULL;
5043 adapter->enabled = TRUE;
5044 adapter->haveLibrary = interface->haveLibrary;
5045 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5046 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5047 _addressInterfaceList_ =
5048 g_list_append( _addressInterfaceList_, adapter );
5050 list = g_list_next( list );
5055 * Find GUI interface type specified interface type.
5056 * \param ifType Interface type.
5057 * \return Interface item, or NULL if not found.
5059 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5060 GList *node = _addressInterfaceList_;
5062 AdapterInterface *adapter = node->data;
5063 if( adapter->interfaceType == ifType ) return adapter;
5064 node = g_list_next( node );
5070 * Build interface list selection.
5072 static void addrbookctl_build_ifselect( void ) {
5073 GList *newList = NULL;
5078 gchar *endptr = NULL;
5080 AdapterInterface *adapter;
5082 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5085 splitStr = g_strsplit( selectStr, ",", -1 );
5086 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5088 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5089 ifType = strtol( splitStr[i], &endptr, 10 );
5092 if( strcmp( endptr, "/n" ) == 0 ) {
5096 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5097 adapter = addrbookctl_find_interface( ifType );
5099 newList = g_list_append( newList, adapter );
5106 /* g_print( "i=%d\n", i ); */
5107 g_strfreev( splitStr );
5108 g_free( selectStr );
5110 /* Replace existing list */
5111 mgu_clear_list( _addressIFaceSelection_ );
5112 g_list_free( _addressIFaceSelection_ );
5113 _addressIFaceSelection_ = newList;
5117 /* ***********************************************************************
5118 * Add sender to address book.
5119 * ***********************************************************************
5123 * This function is used by the Add sender to address book function.
5125 gboolean addressbook_add_contact(
5126 const gchar *name, const gchar *address, const gchar *remarks,
5127 GdkPixbuf *picture )
5129 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5130 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5131 debug_print( "addressbook_add_contact - added\n" );
5132 addressbook_refresh();
5137 /* ***********************************************************************
5138 * Book/folder selection.
5139 * ***********************************************************************
5143 * This function is used by the matcher dialog to select a book/folder.
5145 gchar *addressbook_folder_selection( const gchar *folderpath)
5147 AddressBookFile *book = NULL;
5148 ItemFolder *folder = NULL;
5151 cm_return_val_if_fail( folderpath != NULL, NULL);
5153 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5155 if ( folder != NULL) {
5157 gchar *oldtmp = NULL;
5158 AddrItemObject *obj = NULL;
5160 /* walk thru folder->parent to build the full folder path */
5161 /* TODO: wwp: optimize this */
5163 tmp = g_strdup(obj->uid);
5164 while ( obj->parent ) {
5166 if ( obj->name != NULL ) {
5167 oldtmp = g_strdup(tmp);
5169 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5173 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5176 path = g_strdup_printf("%s", book->fileName);
5178 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5184 /* ***********************************************************************
5185 * Book/folder checking.
5186 * ***********************************************************************
5189 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5191 FolderInfo *fi = g_new0( FolderInfo, 1 );
5193 fi->folder = folder;
5197 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5198 FolderInfo *fiParent, FolderPathMatch *match )
5204 FolderPathMatch *nextmatch = NULL;
5209 list = parentFolder->listFolder;
5211 folder = list->data;
5212 fName = g_strdup( ADDRITEM_NAME(folder) );
5214 /* match folder name, match pointer will be set to NULL if next recursive call
5215 doesn't need to match subfolder name */
5216 if ( match != NULL &&
5217 match->matched == FALSE ) {
5218 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5219 /* folder name matches, prepare next subfolder match */
5220 debug_print("matched folder name '%s'\n", fName);
5222 if ( match->folder_path[match->index] == NULL ) {
5223 /* we've matched all elements */
5224 match->matched = TRUE;
5225 match->folder = folder;
5226 debug_print("book/folder path matched!\n");
5228 /* keep on matching */
5236 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5237 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5239 list = g_list_next( list );
5244 * This function is used by to check if a matcher book/folder path corresponds to an
5245 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5246 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5247 if book AND folder are NULL this means that folderpath was empty or Any.
5248 If folderpath is a simple book name (without folder), book will not be NULL and folder
5249 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5252 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5253 AddressDataSource **book,
5254 ItemFolder **folder )
5256 AddressDataSource *ds;
5257 GList *list, *nodeDS;
5258 ItemFolder *rootFolder;
5259 AddressBookFile *abf;
5261 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5268 if ( folderpath == NULL )
5271 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5274 /* split the folder path we've received, we'll try to match this path, subpath by
5275 subpath against the book/folder structure in order */
5276 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5277 if (!folder_path_match.folder_path)
5280 list = addrindex_get_interface_list( _addressIndex_ );
5281 while ( list && !folder_path_match.matched ) {
5282 AddressInterface *interface = list->data;
5283 if ( interface && interface->type == ADDR_IF_BOOK ) {
5284 nodeDS = interface->listSource;
5285 while ( nodeDS && !folder_path_match.matched ) {
5288 /* Read address book */
5289 if( ! addrindex_ds_get_read_flag( ds ) ) {
5290 addrindex_ds_read_data( ds );
5293 /* Add node for address book */
5294 abf = ds->rawDataSource;
5296 /* match book name */
5297 if ( abf && abf->fileName &&
5298 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5300 debug_print("matched book name '%s'\n", abf->fileName);
5301 folder_path_match.book = ds;
5303 if ( folder_path_match.folder_path[1] == NULL ) {
5304 /* no folder part to match */
5306 folder_path_match.matched = TRUE;
5307 folder_path_match.folder = NULL;
5308 debug_print("book path matched!\n");
5311 /* match folder part */
5313 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5314 rootFolder = addrindex_ds_get_root_folder( ds );
5316 /* prepare for recursive call */
5317 folder_path_match.index = 1;
5318 /* this call will set folder_path_match.matched and folder_path_match.folder */
5319 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5324 nodeDS = g_list_next( nodeDS );
5327 list = g_list_next( list );
5330 g_strfreev( folder_path_match.folder_path );
5333 *book = folder_path_match.book;
5335 *folder = folder_path_match.folder;
5336 return folder_path_match.matched;
5340 /* **********************************************************************
5342 * ***********************************************************************
5348 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5349 AddressDataSource *ds = NULL;
5350 AdapterDSource *ads = NULL;
5351 AddressBookFile *abf = NULL;
5352 AdapterInterface *adapter;
5353 GtkCMCTreeNode *newNode;
5355 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5357 if( adapter->treeNode ) {
5358 abf = addressbook_imp_ldif( _addressIndex_ );
5360 ds = addrindex_index_add_datasource(
5361 _addressIndex_, ADDR_IF_BOOK, abf );
5362 ads = addressbook_create_ds_adapter(
5363 ds, ADDR_BOOK, NULL );
5364 addressbook_ads_set_name(
5365 ads, addrbook_get_name( abf ) );
5366 newNode = addressbook_add_object(
5368 ADDRESS_OBJECT(ads) );
5370 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5372 addrbook.treeSelected = newNode;
5375 /* Notify address completion */
5376 invalidate_address_completion();
5385 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5386 AddressDataSource *ds = NULL;
5387 AdapterDSource *ads = NULL;
5388 AddressBookFile *abf = NULL;
5389 AdapterInterface *adapter;
5390 GtkCMCTreeNode *newNode;
5392 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5394 if( adapter->treeNode ) {
5395 abf = addressbook_imp_mutt( _addressIndex_ );
5397 ds = addrindex_index_add_datasource(
5398 _addressIndex_, ADDR_IF_BOOK, abf );
5399 ads = addressbook_create_ds_adapter(
5400 ds, ADDR_BOOK, NULL );
5401 addressbook_ads_set_name(
5402 ads, addrbook_get_name( abf ) );
5403 newNode = addressbook_add_object(
5405 ADDRESS_OBJECT(ads) );
5407 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5409 addrbook.treeSelected = newNode;
5412 /* Notify address completion */
5413 invalidate_address_completion();
5422 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5423 AddressDataSource *ds = NULL;
5424 AdapterDSource *ads = NULL;
5425 AddressBookFile *abf = NULL;
5426 AdapterInterface *adapter;
5427 GtkCMCTreeNode *newNode;
5429 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5431 if( adapter->treeNode ) {
5432 abf = addressbook_imp_pine( _addressIndex_ );
5434 ds = addrindex_index_add_datasource(
5435 _addressIndex_, ADDR_IF_BOOK, abf );
5436 ads = addressbook_create_ds_adapter(
5437 ds, ADDR_BOOK, NULL );
5438 addressbook_ads_set_name(
5439 ads, addrbook_get_name( abf ) );
5440 newNode = addressbook_add_object(
5442 ADDRESS_OBJECT(ads) );
5444 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5446 addrbook.treeSelected = newNode;
5449 /* Notify address completion */
5450 invalidate_address_completion();
5457 * Harvest addresses.
5458 * \param folderItem Folder to import.
5459 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5460 * \param msgList List of message numbers, or NULL to process folder.
5462 void addressbook_harvest(
5463 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5465 AddressDataSource *ds = NULL;
5466 AdapterDSource *ads = NULL;
5467 AddressBookFile *abf = NULL;
5468 AdapterInterface *adapter;
5469 GtkCMCTreeNode *newNode;
5471 abf = addrgather_dlg_execute(
5472 folderItem, _addressIndex_, sourceInd, msgList );
5474 ds = addrindex_index_add_datasource(
5475 _addressIndex_, ADDR_IF_BOOK, abf );
5477 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5479 if( adapter->treeNode ) {
5480 ads = addressbook_create_ds_adapter(
5481 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5482 newNode = addressbook_add_object(
5484 ADDRESS_OBJECT(ads) );
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 != ADDR_ITEM_PERSON) {
5604 if (aio && aio->type == ADDR_ITEM_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);