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->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->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;
3713 if( person == NULL ) return;
3714 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3715 row = gtk_cmclist_find_row_from_data( GTK_CMCLIST(clist), person );
3717 addressbook_folder_remove_node( clist, node );
3721 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3723 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3725 /* Load any groups */
3726 if( ! atci ) return;
3727 items = addritem_folder_get_group_list( itemFolder );
3728 for( ; items != NULL; items = g_list_next( items ) ) {
3729 GtkCMCTreeNode *nodeGroup = NULL;
3730 gchar *text[N_LIST_COLS];
3731 ItemGroup *group = items->data;
3732 if( group == NULL ) continue;
3733 text[COL_NAME] = ADDRITEM_NAME(group);
3734 text[COL_ADDRESS] = "";
3735 text[COL_REMARKS] = "";
3736 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3737 text, FOLDER_SPACING,
3741 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3742 gtk_sctree_sort_node(clist, NULL);
3744 /* Free up the list */
3745 mgu_clear_list( items );
3746 g_list_free( items );
3750 * Search ctree widget callback function.
3751 * \param pA Pointer to node.
3752 * \param pB Pointer to data item being sought.
3753 * \return Zero (0) if group found.
3755 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3758 aoA = ( AddressObject * ) pA;
3759 if( aoA->type == ADDR_ITEM_GROUP ) {
3760 ItemGroup *group, *grp;
3762 grp = ADAPTER_GROUP(aoA)->itemGroup;
3763 group = ( ItemGroup * ) pB;
3764 if( grp == group ) return 0; /* Found group */
3770 * Remove folder and group nodes from tree widget for items contained ("cut")
3773 static void addressbook_treenode_remove_item( void ) {
3775 AddrSelectItem *cutItem;
3776 AddressCache *cache;
3777 AddrItemObject *aio;
3778 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3781 node = _clipBoard_->objectList;
3783 cutItem = node->data;
3784 node = g_list_next( node );
3785 cache = addrindex_get_cache(
3786 _clipBoard_->addressIndex, cutItem->cacheID );
3787 if( cache == NULL ) continue;
3788 aio = addrcache_get_object( cache, cutItem->uid );
3791 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3794 folder = ( ItemFolder * ) aio;
3795 tn = gtk_cmctree_find_by_row_data_custom(
3796 ctree, NULL, folder,
3797 addressbook_treenode_find_folder_cb );
3799 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3802 group = ( ItemGroup * ) aio;
3803 tn = gtk_cmctree_find_by_row_data_custom(
3805 addressbook_treenode_find_group_cb );
3809 /* Free up adapter and remove node. */
3810 gtk_cmctree_remove_node( ctree, tn );
3817 * Find parent datasource for specified tree node.
3818 * \param node Node to test.
3819 * \return Data source, or NULL if not found.
3821 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3822 AddressDataSource *ds = NULL;
3825 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3828 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3829 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3831 /* g_print( "ao->type = %d\n", ao->type ); */
3832 if( ao->type == ADDR_DATASOURCE ) {
3833 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3834 /* g_print( "found it\n" ); */
3835 ds = ads->dataSource;
3839 node = GTK_CMCTREE_ROW(node)->parent;
3845 * Load address list widget with children of specified object.
3846 * \param obj Parent object to be loaded.
3848 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3849 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3850 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3851 AddressDataSource *ds = NULL;
3852 AdapterDSource *ads = NULL;
3853 static AddressObject *last_obj = NULL;
3855 if (addrbook.clist == NULL) {
3858 if (obj == last_obj && !refresh)
3863 gtk_cmclist_clear(clist);
3867 if( obj->type == ADDR_INTERFACE ) {
3868 /* g_print( "set_clist: loading datasource...\n" ); */
3869 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3873 gtk_cmclist_freeze(clist);
3874 gtk_cmclist_clear(clist);
3876 if( obj->type == ADDR_DATASOURCE ) {
3877 ads = ADAPTER_DSOURCE(obj);
3878 ds = ADAPTER_DSOURCE(obj)->dataSource;
3880 /* Load root folder */
3881 ItemFolder *rootFolder = NULL;
3882 rootFolder = addrindex_ds_get_root_folder( ds );
3883 addressbook_folder_load_person(
3884 ctreelist, addrindex_ds_get_root_folder( ds ) );
3885 addressbook_folder_load_group(
3886 ctreelist, addrindex_ds_get_root_folder( ds ) );
3890 if( obj->type == ADDR_ITEM_GROUP ) {
3892 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3893 addressbook_load_group( ctreelist, itemGroup );
3895 else if( obj->type == ADDR_ITEM_FOLDER ) {
3897 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3898 addressbook_folder_load_person( ctreelist, itemFolder );
3899 addressbook_folder_load_group( ctreelist, itemFolder );
3902 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3903 clist->focus_row = -1;
3904 gtk_cmclist_thaw(clist);
3908 * Call back function to free adaptor. Call back is setup by function
3909 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3910 * called when the address book tree widget node is removed by calling
3911 * function gtk_cmctree_remove_node().
3913 * \param data Tree node's row data.
3915 static void addressbook_free_treenode( gpointer data ) {
3918 ao = ( AddressObject * ) data;
3919 if( ao == NULL ) return;
3920 if( ao->type == ADDR_INTERFACE ) {
3921 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3922 addrbookctl_free_interface( ai );
3924 else if( ao->type == ADDR_DATASOURCE ) {
3925 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3926 addrbookctl_free_datasource( ads );
3928 else if( ao->type == ADDR_ITEM_FOLDER ) {
3929 AdapterFolder *af = ADAPTER_FOLDER(ao);
3930 addrbookctl_free_folder( af );
3932 else if( ao->type == ADDR_ITEM_GROUP ) {
3933 AdapterGroup *ag = ADAPTER_GROUP(ao);
3934 addrbookctl_free_group( ag );
3939 * Create new adaptor for specified data source.
3941 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3942 AddressObjectType otype, gchar *name )
3944 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3945 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3946 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3947 adapter->dataSource = ds;
3948 adapter->subType = otype;
3952 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3953 ADDRESS_OBJECT_NAME(adapter) =
3954 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3958 * Load tree from address index with the initial data.
3960 static void addressbook_load_tree( void ) {
3961 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3962 GList *nodeIf, *nodeDS;
3963 AdapterInterface *adapter;
3964 AddressInterface *iface;
3965 AddressTypeControlItem *atci;
3966 AddressDataSource *ds;
3967 AdapterDSource *ads;
3968 GtkCMCTreeNode *node, *newNode;
3971 nodeIf = _addressInterfaceList_;
3973 adapter = nodeIf->data;
3974 node = adapter->treeNode;
3975 iface = adapter->interface;
3976 atci = adapter->atci;
3978 if( iface->useInterface ) {
3979 /* Load data sources below interface node */
3980 nodeDS = iface->listSource;
3984 name = addrindex_ds_get_name( ds );
3985 ads = addressbook_create_ds_adapter(
3986 ds, atci->objectType, name );
3987 newNode = addressbook_add_object(
3988 node, ADDRESS_OBJECT(ads) );
3989 nodeDS = g_list_next( nodeDS );
3991 gtk_cmctree_expand( ctree, node );
3994 nodeIf = g_list_next( nodeIf );
3999 * Convert the old address book to new format.
4001 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4002 gboolean retVal = FALSE;
4003 gboolean errFlag = TRUE;
4006 /* Read old address book, performing conversion */
4007 debug_print( "Reading and converting old address book...\n" );
4008 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4009 addrindex_read_data( addrIndex );
4010 if( addrIndex->retVal == MGU_NO_FILE ) {
4011 /* We do not have a file - new user */
4012 debug_print( "New user... create new books...\n" );
4013 addrindex_create_new_books( addrIndex );
4014 if( addrIndex->retVal == MGU_SUCCESS ) {
4015 /* Save index file */
4016 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4017 addrindex_save_data( addrIndex );
4018 if( addrIndex->retVal == MGU_SUCCESS ) {
4023 msg = _( "New user, could not save index file." );
4027 msg = _( "New user, could not save address book files." );
4031 /* We have an old file */
4032 if( addrIndex->wasConverted ) {
4033 /* Converted successfully - save address index */
4034 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4035 addrindex_save_data( addrIndex );
4036 if( addrIndex->retVal == MGU_SUCCESS ) {
4037 msg = _( "Old address book converted successfully." );
4042 msg = _("Old address book converted,\n"
4043 "could not save new address index file." );
4047 /* File conversion failed - just create new books */
4048 debug_print( "File conversion failed... just create new books...\n" );
4049 addrindex_create_new_books( addrIndex );
4050 if( addrIndex->retVal == MGU_SUCCESS ) {
4052 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4053 addrindex_save_data( addrIndex );
4054 if( addrIndex->retVal == MGU_SUCCESS ) {
4055 msg = _("Could not convert address book,\n"
4056 "but created empty new address book files." );
4061 msg = _("Could not convert address book,\n"
4062 "could not save new address index file." );
4066 msg = _("Could not convert address book\n"
4067 "and could not create new address book files." );
4072 debug_print( "Error\n%s\n", msg );
4073 alertpanel_full(_("Addressbook conversion error"), msg,
4074 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4075 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4078 debug_print( "Warning\n%s\n", msg );
4079 alertpanel_full(_("Addressbook conversion error"), msg,
4080 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4081 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4087 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4091 gboolean failed = FALSE;
4093 if( ( dp = opendir( origdir ) ) == NULL ) {
4097 while( ( d = readdir( dp ) ) != NULL ) {
4098 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4101 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4103 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4105 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4118 /* all copies succeeded, we can remove source files */
4119 if( ( dp = opendir( origdir ) ) == NULL ) {
4122 while( ( d = readdir( dp ) ) != NULL ) {
4123 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4126 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4128 claws_unlink(orig_file);
4138 void addressbook_read_file( void ) {
4139 AddressIndex *addrIndex = NULL;
4140 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4142 debug_print( "Reading address index...\n" );
4143 if( _addressIndex_ ) {
4144 debug_print( "address book already read!!!\n" );
4148 addrIndex = addrindex_create_index();
4149 addrindex_initialize();
4151 /* Use new address book index. */
4153 if ( !is_dir_exist(indexdir) ) {
4154 if ( make_dir(indexdir) < 0 ) {
4155 addrindex_set_file_path( addrIndex, get_rc_dir() );
4156 g_warning( "couldn't create dir %s\n", indexdir);
4158 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4159 remove_dir_recursive(indexdir);
4160 addrindex_set_file_path( addrIndex, get_rc_dir() );
4161 g_error("couldn't migrate dir %s", indexdir);
4163 addrindex_set_file_path( addrIndex, indexdir);
4167 addrindex_set_file_path( addrIndex, indexdir);
4170 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4171 addrindex_read_data( addrIndex );
4172 if( addrIndex->retVal == MGU_NO_FILE ) {
4173 /* Conversion required */
4174 debug_print( "Converting...\n" );
4175 if( addressbook_convert( addrIndex ) ) {
4176 _addressIndex_ = addrIndex;
4179 else if( addrIndex->retVal == MGU_SUCCESS ) {
4180 _addressIndex_ = addrIndex;
4183 /* Error reading address book */
4184 debug_print( "Could not read address index.\n" );
4185 addrindex_print_index( addrIndex, stdout );
4186 alertpanel_full(_("Addressbook Error"),
4187 _("Could not read address index"),
4188 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4189 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4191 debug_print( "done.\n" );
4195 * Add object into the address index tree widget.
4196 * Enter: node Parent node.
4197 * obj Object to add.
4198 * Return: Node that was added, or NULL if object not added.
4200 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4203 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4204 GtkCMCTreeNode *added;
4205 AddressObject *pobj;
4206 AddressObjectType otype;
4207 AddressTypeControlItem *atci = NULL;
4209 cm_return_val_if_fail(node != NULL, NULL);
4210 cm_return_val_if_fail(obj != NULL, NULL);
4212 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4213 cm_return_val_if_fail(pobj != NULL, NULL);
4215 /* Determine object type to be displayed */
4216 if( obj->type == ADDR_DATASOURCE ) {
4217 otype = ADAPTER_DSOURCE(obj)->subType;
4223 /* Handle any special conditions. */
4225 atci = addrbookctl_lookup( otype );
4227 if( atci->showInTree ) {
4228 /* Add object to tree */
4231 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4232 atci->iconXpm, atci->iconXpmOpen,
4233 atci->treeLeaf, atci->treeExpand );
4234 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4235 addressbook_free_treenode );
4239 gtk_sctree_sort_node(ctree, node);
4245 * Add group into the address index tree.
4246 * \param node Parent node.
4247 * \param ds Data source.
4248 * \param itemGroup Group to add.
4249 * \return Inserted node.
4251 static GtkCMCTreeNode *addressbook_node_add_group(
4252 GtkCMCTreeNode *node, AddressDataSource *ds,
4253 ItemGroup *itemGroup )
4255 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4256 GtkCMCTreeNode *newNode;
4257 AdapterGroup *adapter;
4258 AddressTypeControlItem *atci = NULL;
4261 if( ds == NULL ) return NULL;
4262 if( node == NULL || itemGroup == NULL ) return NULL;
4264 name = &itemGroup->obj.name;
4266 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4268 adapter = g_new0( AdapterGroup, 1 );
4269 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4270 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4271 adapter->itemGroup = itemGroup;
4273 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4274 atci->iconXpm, atci->iconXpm,
4275 atci->treeLeaf, atci->treeExpand );
4276 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4277 addressbook_free_treenode );
4278 gtk_sctree_sort_node( ctree, node );
4283 * Add folder into the address index tree. Only visible folders are loaded into
4284 * the address index tree. Note that the root folder is not inserted into the
4287 * \param node Parent node.
4288 * \param ds Data source.
4289 * \param itemFolder Folder to add.
4290 * \param otype Object type to display.
4291 * \return Inserted node for the folder.
4293 static GtkCMCTreeNode *addressbook_node_add_folder(
4294 GtkCMCTreeNode *node, AddressDataSource *ds,
4295 ItemFolder *itemFolder, AddressObjectType otype )
4297 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4298 GtkCMCTreeNode *newNode = NULL;
4299 AdapterFolder *adapter;
4300 AddressTypeControlItem *atci = NULL;
4301 GList *listItems = NULL;
4303 ItemFolder *rootFolder;
4305 /* Only visible folders */
4306 if( itemFolder == NULL || itemFolder->isHidden )
4311 if( node == NULL || itemFolder == NULL )
4314 /* Determine object type */
4315 atci = addrbookctl_lookup( otype );
4319 rootFolder = addrindex_ds_get_root_folder( ds );
4320 if( itemFolder == rootFolder ) {
4324 adapter = g_new0( AdapterFolder, 1 );
4325 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4326 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4327 adapter->itemFolder = itemFolder;
4329 name = ADDRITEM_NAME(itemFolder);
4330 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4331 atci->iconXpm, atci->iconXpm,
4332 atci->treeLeaf, atci->treeExpand );
4334 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4335 addressbook_free_treenode );
4339 listItems = itemFolder->listFolder;
4340 while( listItems ) {
4341 ItemFolder *item = listItems->data;
4342 addressbook_node_add_folder( newNode, ds, item, otype );
4343 listItems = g_list_next( listItems );
4345 listItems = itemFolder->listGroup;
4346 while( listItems ) {
4347 ItemGroup *item = listItems->data;
4348 addressbook_node_add_group( newNode, ds, item );
4349 listItems = g_list_next( listItems );
4351 gtk_sctree_sort_node( ctree, node );
4355 void addressbook_export_to_file( void ) {
4356 if( _addressIndex_ ) {
4357 /* Save all new address book data */
4358 debug_print( "Saving address books...\n" );
4359 addrindex_save_all_books( _addressIndex_ );
4361 debug_print( "Exporting addressbook to file...\n" );
4362 addrindex_save_data( _addressIndex_ );
4363 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4364 addrindex_print_index( _addressIndex_, stdout );
4367 /* Notify address completion of new data */
4368 invalidate_address_completion();
4372 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4374 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4375 addressbook_lup_clicked(NULL, NULL);
4380 * Comparison using cell contents (text in first column). Used for sort
4381 * address index widget.
4383 static gint addressbook_treenode_compare_func(
4384 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4386 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4387 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4388 gchar *name1 = NULL, *name2 = NULL;
4389 if( cell1 ) name1 = cell1->u.text;
4390 if( cell2 ) name2 = cell2->u.text;
4391 if( ! name1 ) return ( name2 != NULL );
4392 if( ! name2 ) return -1;
4393 return g_utf8_collate( name1, name2 );
4396 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4397 AdapterDSource *ads;
4398 AdapterInterface *adapter;
4399 GtkCMCTreeNode *newNode;
4401 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4402 if( adapter == NULL ) return;
4403 ads = addressbook_edit_book( _addressIndex_, NULL );
4405 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4407 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4408 addrbook.treeSelected = newNode;
4413 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4414 AdapterDSource *ads;
4415 AdapterInterface *adapter;
4416 GtkCMCTreeNode *newNode;
4418 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4419 if( adapter == NULL ) return;
4420 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4422 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4424 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4425 addrbook.treeSelected = newNode;
4431 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4432 AdapterDSource *ads;
4433 AdapterInterface *adapter;
4434 AddressInterface *iface;
4435 GtkCMCTreeNode *newNode;
4437 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4438 if( adapter == NULL ) return;
4439 iface = adapter->interface;
4440 if( ! iface->haveLibrary ) return;
4441 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4443 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4445 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4446 addrbook.treeSelected = newNode;
4453 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4454 AdapterDSource *ads;
4455 AdapterInterface *adapter;
4456 AddressInterface *iface;
4457 GtkCMCTreeNode *newNode;
4459 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4460 if( adapter == NULL ) return;
4461 iface = adapter->interface;
4462 if( ! iface->haveLibrary ) return;
4463 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4465 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4467 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4468 addrbook.treeSelected = newNode;
4475 * Display address search status message.
4476 * \param queryType Query type.
4477 * \param status Status/Error code.
4479 static void addressbook_search_message( gint queryType, gint sts ) {
4481 *addressbook_msgbuf = '\0';
4483 if( sts != MGU_SUCCESS ) {
4484 if( queryType == ADDRQUERY_LDAP ) {
4486 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4491 g_snprintf( addressbook_msgbuf,
4492 sizeof(addressbook_msgbuf), "%s", desc );
4493 addressbook_status_show( addressbook_msgbuf );
4496 addressbook_status_show( "" );
4501 * Refresh addressbook by forcing refresh of current selected object in
4504 static void addressbook_refresh_current( void ) {
4508 ctree = GTK_CMCTREE(addrbook.ctree);
4509 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4510 if( obj == NULL ) return;
4511 addressbook_set_clist( obj, TRUE );
4515 * Message that is displayed whilst a query is executing in a background
4518 static gchar *_tempMessage_ = N_( "Busy searching..." );
4521 * Address search idle function. This function is called during UI idle time
4522 * while a search is in progress.
4524 * \param data Idler data.
4526 static void addressbook_search_idle( gpointer data ) {
4530 queryID = GPOINTER_TO_INT( data );
4531 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4536 * Search completion callback function. This removes the query from the idle
4539 * \param sender Sender of query.
4540 * \param queryID Query ID of search request.
4541 * \param status Search status.
4542 * \param data Query data.
4544 static void addressbook_search_callback_end(
4545 gpointer sender, gint queryID, gint status, gpointer data )
4549 AddrQueryObject *aqo;
4551 /* Remove idler function */
4552 ptrQID = GINT_TO_POINTER( queryID );
4554 g_idle_remove_by_data( ptrQID );
4557 /* Refresh addressbook contents */
4558 addressbook_refresh_current();
4559 req = qrymgr_find_request( queryID );
4561 aqo = ( AddrQueryObject * ) req->queryList->data;
4562 addressbook_search_message( aqo->queryType, status );
4565 /* Stop the search */
4566 addrindex_stop_search( queryID );
4572 * \param ds Data source to search.
4573 * \param searchTerm String to lookup.
4574 * \param pNode Parent data source node.
4576 static void addressbook_perform_search(
4577 AddressDataSource *ds, gchar *searchTerm,
4578 GtkCMCTreeNode *pNode )
4580 AddrBookBase *adbase;
4581 AddressCache *cache;
4587 AddressObjectType aoType = ADDR_NONE;
4591 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4593 if( ds && ds->type == ADDR_IF_LDAP ) {
4595 aoType = ADDR_LDAP_QUERY;
4601 /* Get reference to address cache */
4602 adbase = ( AddrBookBase * ) ds->rawDataSource;
4603 cache = adbase->addressCache;
4605 /* Create a folder for the search results */
4606 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4607 folder = addressbook_setup_subf(ds, name, pNode);
4610 /* Setup the search */
4611 queryID = addrindex_setup_explicit_search(
4612 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4613 if( queryID == 0 ) return;
4615 /* Set up idler function */
4616 idleID = g_idle_add(
4617 (GSourceFunc) addressbook_search_idle,
4618 GINT_TO_POINTER( queryID ) );
4620 /* Start search, sit back and wait for something to happen */
4621 addrindex_start_search( queryID );
4623 addressbook_status_show( _tempMessage_ );
4627 * Lookup button handler. Address search is only performed against
4628 * address interfaces for external queries.
4630 * \param button Lookup button widget.
4631 * \param data Data object.
4633 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4636 AddressDataSource *ds;
4637 AddressInterface *iface;
4639 GtkCMCTreeNode *node, *parentNode;
4641 node = addrbook.treeSelected;
4642 if( ! node ) return;
4643 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4645 ctree = GTK_CMCTREE(addrbook.ctree);
4646 obj = gtk_cmctree_node_get_row_data( ctree, node );
4647 if( obj == NULL ) return;
4649 ds = addressbook_find_datasource( node );
4650 if( ds == NULL ) return;
4652 /* We must have a datasource that is an external interface */
4653 iface = ds->interface;
4654 if( ! iface->haveLibrary ) return;
4655 if( ! iface->externalQuery ) return;
4658 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4659 g_strchomp( searchTerm );
4661 if( obj->type == ADDR_ITEM_FOLDER ) {
4662 parentNode = GTK_CMCTREE_ROW(node)->parent;
4667 addressbook_perform_search( ds, searchTerm, parentNode );
4669 gtk_widget_grab_focus( addrbook.entry );
4671 g_free( searchTerm );
4674 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4675 addressbook_close();
4680 * Browse address entry for highlighted entry.
4682 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4684 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4686 AddressDataSource *ds;
4687 AddressInterface *iface;
4691 if(addrbook.listSelected == NULL)
4694 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4698 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4702 iface = ds->interface;
4703 if(!iface || !iface->haveLibrary )
4707 if (obj->type == ADDR_ITEM_EMAIL) {
4708 email = ( ItemEMail * ) obj;
4712 person = (ItemPerson *) ADDRITEM_PARENT(email);
4714 else if (obj->type == ADDR_ITEM_PERSON) {
4715 person = (ItemPerson *) obj;
4722 if( iface && iface->type == ADDR_IF_LDAP ) {
4723 browseldap_entry(ds, person->externalID);
4728 /* **********************************************************************
4729 * Build lookup tables.
4730 * ***********************************************************************
4734 * Remap object types.
4735 * Enter: abType AddressObjectType (used in tree node).
4736 * Return: ItemObjectType (used in address cache data).
4738 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4739 ItemObjectType ioType;
4742 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4743 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4744 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4745 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4746 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4747 default: ioType = ITEMTYPE_NONE; break;
4752 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4753 atci = addrbookctl_lookup(id); \
4755 atci->iconXpm = icon; \
4756 atci->iconXpmOpen = iconopen; \
4758 g_warning("can't get atci %d\n", id); \
4763 * Build table that controls the rendering of object types.
4765 static void addrbookctl_build_icons( GtkWidget *window ) {
4766 AddressTypeControlItem *atci;
4770 g_object_unref(interfacexpm);
4772 g_object_unref(folderxpm);
4774 g_object_unref(folderopenxpm);
4776 g_object_unref(groupxpm);
4778 g_object_unref(vcardxpm);
4780 g_object_unref(bookxpm);
4782 g_object_unref(addressxpm);
4784 g_object_unref(jpilotxpm);
4786 g_object_unref(categoryxpm);
4788 g_object_unref(ldapxpm);
4790 g_object_unref(addrsearchxpm);
4791 stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacexpm );
4792 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4793 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4794 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4795 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4796 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4797 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4798 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4799 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4800 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4801 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4803 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4804 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4805 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4806 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4807 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4808 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4809 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4810 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4811 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4812 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4813 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4818 * Build table that controls the rendering of object types.
4820 static void addrbookctl_build_map( GtkWidget *window ) {
4821 AddressTypeControlItem *atci;
4823 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4824 _addressBookTypeList_ = NULL;
4827 atci = g_new0( AddressTypeControlItem, 1 );
4828 atci->objectType = ADDR_INTERFACE;
4829 atci->interfaceType = ADDR_IF_NONE;
4830 atci->showInTree = TRUE;
4831 atci->treeExpand = TRUE;
4832 atci->treeLeaf = FALSE;
4833 atci->displayName = _( "Interface" );
4834 atci->menuCommand = NULL;
4835 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4836 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4839 atci = g_new0( AddressTypeControlItem, 1 );
4840 atci->objectType = ADDR_BOOK;
4841 atci->interfaceType = ADDR_IF_BOOK;
4842 atci->showInTree = TRUE;
4843 atci->treeExpand = TRUE;
4844 atci->treeLeaf = FALSE;
4845 atci->displayName = _( "Address Book" );
4846 atci->menuCommand = "Menu/Book/NewBook";
4847 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4848 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4851 atci = g_new0( AddressTypeControlItem, 1 );
4852 atci->objectType = ADDR_ITEM_PERSON;
4853 atci->interfaceType = ADDR_IF_NONE;
4854 atci->showInTree = FALSE;
4855 atci->treeExpand = FALSE;
4856 atci->treeLeaf = FALSE;
4857 atci->displayName = _( "Person" );
4858 atci->menuCommand = NULL;
4859 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4860 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4863 atci = g_new0( AddressTypeControlItem, 1 );
4864 atci->objectType = ADDR_ITEM_EMAIL;
4865 atci->interfaceType = ADDR_IF_NONE;
4866 atci->showInTree = FALSE;
4867 atci->treeExpand = FALSE;
4868 atci->treeLeaf = TRUE;
4869 atci->displayName = _( "Email Address" );
4870 atci->menuCommand = NULL;
4871 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4872 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4875 atci = g_new0( AddressTypeControlItem, 1 );
4876 atci->objectType = ADDR_ITEM_GROUP;
4877 atci->interfaceType = ADDR_IF_BOOK;
4878 atci->showInTree = TRUE;
4879 atci->treeExpand = FALSE;
4880 atci->treeLeaf = FALSE;
4881 atci->displayName = _( "Group" );
4882 atci->menuCommand = NULL;
4883 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4884 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4887 atci = g_new0( AddressTypeControlItem, 1 );
4888 atci->objectType = ADDR_ITEM_FOLDER;
4889 atci->interfaceType = ADDR_IF_BOOK;
4890 atci->showInTree = TRUE;
4891 atci->treeExpand = FALSE;
4892 atci->treeLeaf = FALSE;
4893 atci->displayName = _( "Folder" );
4894 atci->menuCommand = NULL;
4895 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4896 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4899 atci = g_new0( AddressTypeControlItem, 1 );
4900 atci->objectType = ADDR_VCARD;
4901 atci->interfaceType = ADDR_IF_VCARD;
4902 atci->showInTree = TRUE;
4903 atci->treeExpand = TRUE;
4904 atci->treeLeaf = TRUE;
4905 atci->displayName = _( "vCard" );
4906 atci->menuCommand = "Menu/Book/NewVCard";
4907 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4908 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4911 atci = g_new0( AddressTypeControlItem, 1 );
4912 atci->objectType = ADDR_JPILOT;
4913 atci->interfaceType = ADDR_IF_JPILOT;
4914 atci->showInTree = TRUE;
4915 atci->treeExpand = TRUE;
4916 atci->treeLeaf = FALSE;
4917 atci->displayName = _( "JPilot" );
4918 atci->menuCommand = "Menu/Book/NewJPilot";
4919 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4920 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4923 atci = g_new0( AddressTypeControlItem, 1 );
4924 atci->objectType = ADDR_CATEGORY;
4925 atci->interfaceType = ADDR_IF_JPILOT;
4926 atci->showInTree = TRUE;
4927 atci->treeExpand = TRUE;
4928 atci->treeLeaf = TRUE;
4929 atci->displayName = _( "JPilot" );
4930 atci->menuCommand = NULL;
4931 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4932 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4935 atci = g_new0( AddressTypeControlItem, 1 );
4936 atci->objectType = ADDR_LDAP;
4937 atci->interfaceType = ADDR_IF_LDAP;
4938 atci->showInTree = TRUE;
4939 atci->treeExpand = TRUE;
4940 atci->treeLeaf = FALSE;
4941 atci->displayName = _( "LDAP servers" );
4942 atci->menuCommand = "Menu/Book/NewLDAPServer";
4943 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4944 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4947 atci = g_new0( AddressTypeControlItem, 1 );
4948 atci->objectType = ADDR_LDAP_QUERY;
4949 atci->interfaceType = ADDR_IF_LDAP;
4950 atci->showInTree = TRUE;
4951 atci->treeExpand = FALSE;
4952 atci->treeLeaf = TRUE;
4953 atci->displayName = _( "LDAP Query" );
4954 atci->menuCommand = NULL;
4955 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4956 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4958 addrbookctl_build_icons(window);
4961 void addressbook_reflect_prefs_pixmap_theme(void)
4963 if (addrbook.window)
4964 addrbookctl_build_icons(addrbook.window);
4968 * Search for specified object type.
4970 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4972 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4976 * Search for specified interface type.
4978 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4979 GList *node = _addressBookTypeList_;
4981 AddressTypeControlItem *atci = node->data;
4982 if( atci->interfaceType == ifType ) return atci;
4983 node = g_list_next( node );
4988 static void addrbookctl_free_address( AddressObject *obj ) {
4989 g_free( obj->name );
4990 obj->type = ADDR_NONE;
4994 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4995 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4996 adapter->interface = NULL;
4997 adapter->interfaceType = ADDR_IF_NONE;
4998 adapter->atci = NULL;
4999 adapter->enabled = FALSE;
5000 adapter->haveLibrary = FALSE;
5001 adapter->treeNode = NULL;
5005 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5006 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5007 adapter->dataSource = NULL;
5008 adapter->subType = ADDR_NONE;
5012 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5013 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5014 adapter->itemFolder = NULL;
5018 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5019 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5020 adapter->itemGroup = NULL;
5025 * Build GUI interface list.
5027 static void addrbookctl_build_iflist( void ) {
5028 AddressTypeControlItem *atci;
5029 AdapterInterface *adapter;
5032 if( _addressIndex_ == NULL ) {
5033 _addressIndex_ = addrindex_create_index();
5034 if( _clipBoard_ == NULL ) {
5035 _clipBoard_ = addrclip_create();
5037 addrclip_set_index( _clipBoard_, _addressIndex_ );
5039 _addressInterfaceList_ = NULL;
5040 list = addrindex_get_interface_list( _addressIndex_ );
5042 AddressInterface *interface = list->data;
5043 atci = addrbookctl_lookup_iface( interface->type );
5045 adapter = g_new0( AdapterInterface, 1 );
5046 adapter->interfaceType = interface->type;
5047 adapter->atci = atci;
5048 adapter->interface = interface;
5049 adapter->treeNode = NULL;
5050 adapter->enabled = TRUE;
5051 adapter->haveLibrary = interface->haveLibrary;
5052 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5053 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5054 _addressInterfaceList_ =
5055 g_list_append( _addressInterfaceList_, adapter );
5057 list = g_list_next( list );
5062 * Find GUI interface type specified interface type.
5063 * \param ifType Interface type.
5064 * \return Interface item, or NULL if not found.
5066 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5067 GList *node = _addressInterfaceList_;
5069 AdapterInterface *adapter = node->data;
5070 if( adapter->interfaceType == ifType ) return adapter;
5071 node = g_list_next( node );
5077 * Build interface list selection.
5079 static void addrbookctl_build_ifselect( void ) {
5080 GList *newList = NULL;
5085 gchar *endptr = NULL;
5087 AdapterInterface *adapter;
5089 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5092 splitStr = g_strsplit( selectStr, ",", -1 );
5093 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5095 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5096 ifType = strtol( splitStr[i], &endptr, 10 );
5099 if( strcmp( endptr, "/n" ) == 0 ) {
5103 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5104 adapter = addrbookctl_find_interface( ifType );
5106 newList = g_list_append( newList, adapter );
5113 /* g_print( "i=%d\n", i ); */
5114 g_strfreev( splitStr );
5115 g_free( selectStr );
5117 /* Replace existing list */
5118 mgu_clear_list( _addressIFaceSelection_ );
5119 g_list_free( _addressIFaceSelection_ );
5120 _addressIFaceSelection_ = newList;
5124 /* ***********************************************************************
5125 * Add sender to address book.
5126 * ***********************************************************************
5130 * This function is used by the Add sender to address book function.
5132 gboolean addressbook_add_contact(
5133 const gchar *name, const gchar *address, const gchar *remarks,
5134 GdkPixbuf *picture )
5136 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5137 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5138 debug_print( "addressbook_add_contact - added\n" );
5139 addressbook_refresh();
5144 /* ***********************************************************************
5145 * Book/folder selection.
5146 * ***********************************************************************
5150 * This function is used by the matcher dialog to select a book/folder.
5152 gchar *addressbook_folder_selection( const gchar *folderpath)
5154 AddressBookFile *book = NULL;
5155 ItemFolder *folder = NULL;
5158 cm_return_val_if_fail( folderpath != NULL, NULL);
5160 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5162 if ( folder != NULL) {
5164 gchar *oldtmp = NULL;
5165 AddrItemObject *obj = NULL;
5167 /* walk thru folder->parent to build the full folder path */
5168 /* TODO: wwp: optimize this */
5170 tmp = g_strdup(obj->uid);
5171 while ( obj->parent ) {
5173 if ( obj->name != NULL ) {
5174 oldtmp = g_strdup(tmp);
5176 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5180 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5183 path = g_strdup_printf("%s", book->fileName);
5185 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5191 /* ***********************************************************************
5192 * Book/folder checking.
5193 * ***********************************************************************
5196 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5198 FolderInfo *fi = g_new0( FolderInfo, 1 );
5200 fi->folder = folder;
5204 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5205 FolderInfo *fiParent, FolderPathMatch *match )
5211 FolderPathMatch *nextmatch = NULL;
5216 list = parentFolder->listFolder;
5218 folder = list->data;
5219 fName = g_strdup( ADDRITEM_NAME(folder) );
5221 /* match folder name, match pointer will be set to NULL if next recursive call
5222 doesn't need to match subfolder name */
5223 if ( match != NULL &&
5224 match->matched == FALSE ) {
5225 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5226 /* folder name matches, prepare next subfolder match */
5227 debug_print("matched folder name '%s'\n", fName);
5229 if ( match->folder_path[match->index] == NULL ) {
5230 /* we've matched all elements */
5231 match->matched = TRUE;
5232 match->folder = folder;
5233 debug_print("book/folder path matched!\n");
5235 /* keep on matching */
5243 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5244 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5246 list = g_list_next( list );
5251 * This function is used by to check if a matcher book/folder path corresponds to an
5252 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5253 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5254 if book AND folder are NULL this means that folderpath was empty or Any.
5255 If folderpath is a simple book name (without folder), book will not be NULL and folder
5256 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5259 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5260 AddressDataSource **book,
5261 ItemFolder **folder )
5263 AddressDataSource *ds;
5264 GList *list, *nodeDS;
5265 ItemFolder *rootFolder;
5266 AddressBookFile *abf;
5268 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5275 if ( folderpath == NULL )
5278 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5281 /* split the folder path we've received, we'll try to match this path, subpath by
5282 subpath against the book/folder structure in order */
5283 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5284 if (!folder_path_match.folder_path)
5287 list = addrindex_get_interface_list( _addressIndex_ );
5288 while ( list && !folder_path_match.matched ) {
5289 AddressInterface *interface = list->data;
5290 if ( interface && interface->type == ADDR_IF_BOOK ) {
5291 nodeDS = interface->listSource;
5292 while ( nodeDS && !folder_path_match.matched ) {
5295 /* Read address book */
5296 if( ! addrindex_ds_get_read_flag( ds ) ) {
5297 addrindex_ds_read_data( ds );
5300 /* Add node for address book */
5301 abf = ds->rawDataSource;
5303 /* match book name */
5304 if ( abf && abf->fileName &&
5305 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5307 debug_print("matched book name '%s'\n", abf->fileName);
5308 folder_path_match.book = ds;
5310 if ( folder_path_match.folder_path[1] == NULL ) {
5311 /* no folder part to match */
5313 folder_path_match.matched = TRUE;
5314 folder_path_match.folder = NULL;
5315 debug_print("book path matched!\n");
5318 /* match folder part */
5320 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5321 rootFolder = addrindex_ds_get_root_folder( ds );
5323 /* prepare for recursive call */
5324 folder_path_match.index = 1;
5325 /* this call will set folder_path_match.matched and folder_path_match.folder */
5326 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5331 nodeDS = g_list_next( nodeDS );
5334 list = g_list_next( list );
5337 g_strfreev( folder_path_match.folder_path );
5340 *book = folder_path_match.book;
5342 *folder = folder_path_match.folder;
5343 return folder_path_match.matched;
5347 /* **********************************************************************
5349 * ***********************************************************************
5355 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5356 AddressDataSource *ds = NULL;
5357 AdapterDSource *ads = NULL;
5358 AddressBookFile *abf = NULL;
5359 AdapterInterface *adapter;
5360 GtkCMCTreeNode *newNode;
5362 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5364 if( adapter->treeNode ) {
5365 abf = addressbook_imp_ldif( _addressIndex_ );
5367 ds = addrindex_index_add_datasource(
5368 _addressIndex_, ADDR_IF_BOOK, abf );
5369 ads = addressbook_create_ds_adapter(
5370 ds, ADDR_BOOK, NULL );
5371 addressbook_ads_set_name(
5372 ads, addrbook_get_name( abf ) );
5373 newNode = addressbook_add_object(
5375 ADDRESS_OBJECT(ads) );
5377 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5379 addrbook.treeSelected = newNode;
5382 /* Notify address completion */
5383 invalidate_address_completion();
5392 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5393 AddressDataSource *ds = NULL;
5394 AdapterDSource *ads = NULL;
5395 AddressBookFile *abf = NULL;
5396 AdapterInterface *adapter;
5397 GtkCMCTreeNode *newNode;
5399 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5401 if( adapter->treeNode ) {
5402 abf = addressbook_imp_mutt( _addressIndex_ );
5404 ds = addrindex_index_add_datasource(
5405 _addressIndex_, ADDR_IF_BOOK, abf );
5406 ads = addressbook_create_ds_adapter(
5407 ds, ADDR_BOOK, NULL );
5408 addressbook_ads_set_name(
5409 ads, addrbook_get_name( abf ) );
5410 newNode = addressbook_add_object(
5412 ADDRESS_OBJECT(ads) );
5414 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5416 addrbook.treeSelected = newNode;
5419 /* Notify address completion */
5420 invalidate_address_completion();
5429 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5430 AddressDataSource *ds = NULL;
5431 AdapterDSource *ads = NULL;
5432 AddressBookFile *abf = NULL;
5433 AdapterInterface *adapter;
5434 GtkCMCTreeNode *newNode;
5436 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5438 if( adapter->treeNode ) {
5439 abf = addressbook_imp_pine( _addressIndex_ );
5441 ds = addrindex_index_add_datasource(
5442 _addressIndex_, ADDR_IF_BOOK, abf );
5443 ads = addressbook_create_ds_adapter(
5444 ds, ADDR_BOOK, NULL );
5445 addressbook_ads_set_name(
5446 ads, addrbook_get_name( abf ) );
5447 newNode = addressbook_add_object(
5449 ADDRESS_OBJECT(ads) );
5451 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5453 addrbook.treeSelected = newNode;
5456 /* Notify address completion */
5457 invalidate_address_completion();
5464 * Harvest addresses.
5465 * \param folderItem Folder to import.
5466 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5467 * \param msgList List of message numbers, or NULL to process folder.
5469 void addressbook_harvest(
5470 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5472 AddressDataSource *ds = NULL;
5473 AdapterDSource *ads = NULL;
5474 AddressBookFile *abf = NULL;
5475 AdapterInterface *adapter;
5476 GtkCMCTreeNode *newNode;
5478 abf = addrgather_dlg_execute(
5479 folderItem, _addressIndex_, sourceInd, msgList );
5481 ds = addrindex_index_add_datasource(
5482 _addressIndex_, ADDR_IF_BOOK, abf );
5484 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5486 if( adapter->treeNode ) {
5487 ads = addressbook_create_ds_adapter(
5488 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5489 newNode = addressbook_add_object(
5491 ADDRESS_OBJECT(ads) );
5495 /* Notify address completion */
5496 invalidate_address_completion();
5503 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5504 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5506 AddressDataSource *ds = NULL;
5507 AddrBookBase *adbase;
5508 AddressCache *cache;
5509 GtkCMCTreeNode *node = NULL;
5511 if( ! addrbook.treeSelected ) return;
5512 node = addrbook.treeSelected;
5513 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5514 obj = gtk_cmctree_node_get_row_data( ctree, node );
5515 if( obj == NULL ) return;
5517 ds = addressbook_find_datasource( node );
5518 if( ds == NULL ) return;
5519 adbase = ( AddrBookBase * ) ds->rawDataSource;
5520 cache = adbase->addressCache;
5521 addressbook_exp_html( cache );
5527 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5528 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5530 AddressDataSource *ds = NULL;
5531 AddrBookBase *adbase;
5532 AddressCache *cache;
5533 GtkCMCTreeNode *node = NULL;
5535 if( ! addrbook.treeSelected ) return;
5536 node = addrbook.treeSelected;
5537 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5538 obj = gtk_cmctree_node_get_row_data( ctree, node );
5539 if( obj == NULL ) return;
5541 ds = addressbook_find_datasource( node );
5542 if( ds == NULL ) return;
5543 adbase = ( AddrBookBase * ) ds->rawDataSource;
5544 cache = adbase->addressCache;
5545 addressbook_exp_ldif( cache );
5548 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5550 addrduplicates_find(GTK_WINDOW(addrbook.window));
5553 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5555 addressbook_custom_attr_edit();
5558 static void addressbook_start_drag(GtkWidget *widget, gint button,
5562 GdkDragContext *context;
5563 if (addressbook_target_list == NULL)
5564 addressbook_target_list = gtk_target_list_new(
5565 addressbook_drag_types, 1);
5566 context = gtk_drag_begin(widget, addressbook_target_list,
5567 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5568 gtk_drag_set_icon_default(context);
5571 static void addressbook_drag_data_get(GtkWidget *widget,
5572 GdkDragContext *drag_context,
5573 GtkSelectionData *selection_data,
5578 AddrItemObject *aio = NULL;
5579 AddressObject *pobj = NULL;
5580 AdapterDSource *ads = NULL;
5581 AddressDataSource *ds = NULL;
5584 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5586 if( pobj == NULL ) return;
5588 if( pobj->type == ADDR_DATASOURCE ) {
5589 ads = ADAPTER_DSOURCE(pobj);
5590 ds = ads->dataSource;
5591 } else if (pobj->type == ADDR_ITEM_GROUP) {
5596 else if( pobj->type != ADDR_INTERFACE ) {
5597 ds = addressbook_find_datasource( addrbook.treeSelected );
5603 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5604 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5605 GTK_CMCTREE_NODE(cur->data));
5606 while (aio && aio->type != ADDR_ITEM_PERSON) {
5611 if (aio && aio->type == ADDR_ITEM_PERSON) {
5612 if( ds && ds->interface && ds->interface->readOnly)
5613 gtk_selection_data_set(selection_data,
5614 gtk_selection_data_get_target(selection_data), 8,
5615 (const guchar *)"Dummy_addr_copy", 15);
5617 gtk_selection_data_set(selection_data,
5618 gtk_selection_data_get_target(selection_data), 8,
5619 (const guchar *)"Dummy_addr_move", 15);
5623 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5624 GdkDragContext *context,
5630 GtkAllocation allocation;
5631 GtkRequisition requisition;
5633 GtkCMCTreeNode *node = NULL;
5634 gboolean acceptable = FALSE;
5635 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5636 gint height = allocation.height;
5637 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5638 gint total_height = requisition.height;
5639 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5640 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5641 gfloat vpos = gtk_adjustment_get_value(pos);
5643 if (gtk_cmclist_get_selection_info
5644 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5646 if (y > height - 24 && height + vpos < total_height) {
5647 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5648 gtk_adjustment_changed(pos);
5650 if (y < 24 && y > 0) {
5651 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5652 gtk_adjustment_changed(pos);
5654 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5657 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5658 if( obj->type == ADDR_ITEM_FOLDER
5659 || obj->type == ADDR_ITEM_GROUP)
5662 AdapterDSource *ads = NULL;
5663 AddressDataSource *ds = NULL;
5664 ads = ADAPTER_DSOURCE(obj);
5665 if (ads == NULL ){ return FALSE;}
5666 ds = ads->dataSource;
5667 if (ds == NULL ) { return FALSE;}
5675 g_signal_handlers_block_by_func
5677 G_CALLBACK(addressbook_tree_selected), NULL);
5678 gtk_sctree_select( GTK_SCTREE(widget), node);
5679 g_signal_handlers_unblock_by_func
5681 G_CALLBACK(addressbook_tree_selected), NULL);
5682 gdk_drag_status(context,
5683 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5684 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5686 gdk_drag_status(context, 0, time);
5691 static void addressbook_drag_leave_cb(GtkWidget *widget,
5692 GdkDragContext *context,
5696 if (addrbook.treeSelected) {
5697 g_signal_handlers_block_by_func
5699 G_CALLBACK(addressbook_tree_selected), NULL);
5700 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5701 g_signal_handlers_unblock_by_func
5703 G_CALLBACK(addressbook_tree_selected), NULL);
5708 static void addressbook_drag_received_cb(GtkWidget *widget,
5709 GdkDragContext *drag_context,
5712 GtkSelectionData *data,
5718 GtkCMCTreeNode *node;
5719 GtkCMCTreeNode *lastopened = addrbook.opened;
5721 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5722 if (gtk_cmclist_get_selection_info
5723 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5727 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5728 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5731 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5732 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5733 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5734 addressbook_clip_copy_cb(NULL, NULL);
5736 addressbook_clip_cut_cb(NULL, NULL);
5737 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5738 addressbook_clip_paste_cb(NULL,NULL);
5739 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5740 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5741 gtk_drag_finish(drag_context, TRUE, TRUE, time);