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_MULTIPLE);
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 == ITEMTYPE_PERSON || aio->type == ITEMTYPE_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 == ITEMTYPE_GROUP ) {
1514 groups = g_list_prepend(groups, item);
1516 else if( aio->type == ITEMTYPE_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 == ITEMTYPE_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 == ITEMTYPE_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 == ITEMTYPE_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 == ITEMTYPE_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 == ITEMTYPE_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 == ITEMTYPE_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 == ITEMTYPE_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 == ITEMTYPE_PERSON ||
1750 aio->type == ITEMTYPE_EMAIL ) {
1751 addr = addressbook_format_address( aio );
1752 compose_entry_append(
1753 compose, addr, (ComposeEntryType) data, PREF_NONE );
1756 else if( aio->type == ITEMTYPE_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) == ADDR_ITEM_GROUP ) {
2143 group = ( ItemGroup * ) aio;
2144 nn = addressbook_node_add_group( treeNode, ds, group );
2146 g_message("error adding addressbook group\n");
2149 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2152 folder = ( ItemFolder * ) aio;
2153 nn = addressbook_node_add_folder(
2154 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2156 g_message("error adding addressbook folder\n");
2159 node = g_list_next( node );
2163 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2164 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2168 * Cut from address list widget.
2170 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2171 _clipBoard_->cutFlag = TRUE;
2172 addrclip_clear( _clipBoard_ );
2173 addrclip_add( _clipBoard_, _addressSelect_ );
2174 /* addrclip_list_show( _clipBoard_, stdout ); */
2178 * Copy from address list widget.
2180 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2181 _clipBoard_->cutFlag = FALSE;
2182 addrclip_clear( _clipBoard_ );
2183 addrclip_add( _clipBoard_, _addressSelect_ );
2184 /* addrclip_list_show( _clipBoard_, stdout ); */
2188 * Paste clipboard into address list widget.
2190 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2191 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2192 AddressObject *pobj = NULL;
2193 AddressDataSource *ds = NULL;
2194 AddressBookFile *abf = NULL;
2195 ItemFolder *folder = NULL;
2196 GList *folderGroup = NULL;
2198 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2199 if( ds == NULL ) return;
2200 if( addrindex_ds_get_readonly( ds ) ) {
2201 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2205 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2207 if( pobj->type == ADDR_ITEM_FOLDER ) {
2208 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2210 else if( pobj->type == ADDR_ITEM_GROUP ) {
2211 alertpanel_error( _("Cannot paste into an address group.") );
2216 /* Get an address book */
2217 abf = addressbook_get_book_file();
2218 if( abf == NULL ) return;
2220 if( _clipBoard_->cutFlag ) {
2222 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2224 /* Remove all groups and folders in clipboard from tree node */
2225 addressbook_treenode_remove_item();
2227 /* Remove all "cut" items */
2228 addrclip_delete_item( _clipBoard_ );
2230 /* Clear clipboard - cut items??? */
2231 addrclip_clear( _clipBoard_ );
2235 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2238 /* addrclip_list_show( _clipBoard_, stdout ); */
2240 /* Update tree by inserting node for each folder or group */
2241 addressbook_treenode_add_list(
2242 addrbook.treeSelected, ds, folderGroup );
2243 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2244 g_list_free( folderGroup );
2248 /* Display items pasted */
2249 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2250 addressbook_set_clist(
2251 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2259 * Add current treenode object to clipboard. Note that widget only allows
2260 * one entry from the tree list to be selected.
2262 static void addressbook_treenode_to_clipboard( void ) {
2263 AddressObject *obj = NULL;
2264 AddressDataSource *ds = NULL;
2265 AddrSelectItem *item;
2266 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2267 GtkCMCTreeNode *node;
2269 node = addrbook.treeSelected;
2270 if( node == NULL ) return;
2271 obj = gtk_cmctree_node_get_row_data( ctree, node );
2272 if( obj == NULL ) return;
2274 ds = addressbook_find_datasource( node );
2275 if( ds == NULL ) return;
2278 if( obj->type == ADDR_ITEM_FOLDER ) {
2279 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2280 ItemFolder *folder = adapter->itemFolder;
2282 item = addrselect_create_node( obj );
2283 item->uid = g_strdup( ADDRITEM_ID(folder) );
2285 else if( obj->type == ADDR_ITEM_GROUP ) {
2286 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2287 ItemGroup *group = adapter->itemGroup;
2289 item = addrselect_create_node( obj );
2290 item->uid = g_strdup( ADDRITEM_ID(group) );
2292 else if( obj->type == ADDR_DATASOURCE ) {
2294 item = addrselect_create_node( obj );
2299 /* Clear existing list and add item into list */
2302 addressbook_list_select_clear();
2303 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2304 addrselect_list_add( _addressSelect_, item, cacheID );
2310 * Cut from tree widget.
2312 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2313 _clipBoard_->cutFlag = TRUE;
2314 addressbook_treenode_to_clipboard();
2315 addrclip_clear( _clipBoard_ );
2316 addrclip_add( _clipBoard_, _addressSelect_ );
2317 /* addrclip_list_show( _clipBoard_, stdout ); */
2321 * Copy from tree widget.
2323 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2324 _clipBoard_->cutFlag = FALSE;
2325 addressbook_treenode_to_clipboard();
2326 addrclip_clear( _clipBoard_ );
2327 addrclip_add( _clipBoard_, _addressSelect_ );
2328 /* addrclip_list_show( _clipBoard_, stdout ); */
2332 * Paste clipboard into address tree widget.
2334 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2335 addressbook_clip_paste_cb(NULL,NULL);
2339 * Clear selected entries in clipboard.
2341 static void addressbook_list_select_clear( void ) {
2342 addrselect_list_clear( _addressSelect_ );
2346 * Add specified address item to selected address list.
2347 * \param aio Address item object.
2348 * \param ds Datasource.
2350 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2353 if( ds == NULL ) return;
2354 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2355 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2360 * Remove specified address item from selected address list.
2361 * \param aio Address item object.
2363 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2364 addrselect_list_remove( _addressSelect_, aio );
2368 * Invoke EMail compose window with addresses in selected address list.
2370 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2373 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2374 listAddress = addrselect_build_list( _addressSelect_ );
2375 compose_new_with_list( NULL, listAddress );
2376 mgu_free_dlist( listAddress );
2381 static void addressbook_list_row_selected( GtkCMCTree *clist,
2382 GtkCMCTreeNode *node,
2386 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2387 AddrItemObject *aio = NULL;
2388 AddressObject *pobj = NULL;
2389 AdapterDSource *ads = NULL;
2390 AddressDataSource *ds = NULL;
2392 gtk_entry_set_text( entry, "" );
2393 addrbook.listSelected = node;
2395 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2396 if( pobj == NULL ) return;
2398 if( pobj->type == ADDR_DATASOURCE ) {
2399 ads = ADAPTER_DSOURCE(pobj);
2400 ds = ads->dataSource;
2402 else if( pobj->type != ADDR_INTERFACE ) {
2403 ds = addressbook_find_datasource( addrbook.treeSelected );
2406 aio = gtk_cmctree_node_get_row_data( clist, node );
2408 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2409 addressbook_list_select_add( aio, ds );
2412 addressbook_list_menu_setup();
2414 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2415 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2417 if (obj && obj->type != ADDR_ITEM_GROUP)
2418 addressbook_edit_address(NULL, 0, NULL, FALSE);
2422 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2423 GtkCMCTreeNode *node,
2427 AddrItemObject *aio;
2429 aio = gtk_cmctree_node_get_row_data( ctree, node );
2431 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2432 addressbook_list_select_remove( aio );
2435 if (!prefs_common.addressbook_use_editaddress_dialog)
2436 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2439 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2440 GdkEventButton *event,
2443 if( ! event ) return FALSE;
2445 addressbook_list_menu_setup();
2447 if( event->button == 3 ) {
2448 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2449 event->button, event->time );
2450 } else if (event->button == 1) {
2451 if (event->type == GDK_2BUTTON_PRESS) {
2452 if (prefs_common.add_address_by_click &&
2453 addrbook.target_compose)
2454 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2456 if (prefs_common.addressbook_use_editaddress_dialog)
2457 addressbook_edit_address_cb(NULL, NULL);
2459 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2460 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2461 if( obj && obj->type == ADDR_ITEM_GROUP )
2462 addressbook_edit_address_cb(NULL, NULL);
2470 static gboolean addressbook_list_button_released(GtkWidget *widget,
2471 GdkEventButton *event,
2477 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2478 GdkEventButton *event,
2481 GtkCMCList *clist = GTK_CMCLIST(ctree);
2483 AddressObject *obj = NULL;
2484 AdapterDSource *ads = NULL;
2485 AddressInterface *iface = NULL;
2486 AddressDataSource *ds = NULL;
2487 gboolean canEdit = FALSE;
2488 gboolean canDelete = FALSE;
2489 gboolean canCut = FALSE;
2490 gboolean canCopy = FALSE;
2491 gboolean canPaste = FALSE;
2492 gboolean canTreeCut = FALSE;
2493 gboolean canTreeCopy = FALSE;
2494 gboolean canTreePaste = FALSE;
2495 gboolean canLookup = FALSE;
2496 GtkCMCTreeNode *node = NULL;
2498 if( ! event ) return FALSE;
2499 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2501 if (event->button == 1) {
2502 if (event->type == GDK_2BUTTON_PRESS) {
2503 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2504 gtkut_clist_set_focus_row(clist, row);
2505 obj = gtk_cmclist_get_row_data( clist, row );
2510 if (obj->type == ADDR_ITEM_GROUP) {
2512 addressbook_treenode_edit_cb(NULL, NULL);
2514 /* expand pr collapse */
2515 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2516 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2522 addressbook_menubar_set_sensitive( FALSE );
2524 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2525 gtkut_clist_set_focus_row(clist, row);
2526 obj = gtk_cmclist_get_row_data( clist, row );
2529 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2533 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2535 if( ! addrclip_is_empty( _clipBoard_ ) )
2536 canTreePaste = TRUE;
2538 if (obj->type == ADDR_INTERFACE) {
2539 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2540 iface = adapter->interface;
2543 if( !iface->readOnly ) {
2544 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2545 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2547 if( iface->externalQuery )
2550 if (obj->type == ADDR_DATASOURCE) {
2551 ads = ADAPTER_DSOURCE(obj);
2552 ds = ads->dataSource;
2555 iface = ds->interface;
2558 if( !iface->readOnly ) {
2560 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2561 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2562 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2566 if( iface->externalQuery )
2569 else if (obj->type == ADDR_ITEM_FOLDER) {
2570 ds = addressbook_find_datasource( node );
2573 iface = ds->interface;
2576 if( !iface->readOnly ) {
2580 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2581 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2582 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2586 if( iface->externalQuery ) {
2587 /* Enable deletion of LDAP folder */
2592 else if (obj->type == ADDR_ITEM_GROUP) {
2593 ds = addressbook_find_datasource( node );
2596 iface = ds->interface;
2599 if( ! iface->readOnly ) {
2602 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2603 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2607 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2609 if( ! addrselect_test_empty( _addressSelect_ ) )
2611 if( ! addrclip_is_empty( _clipBoard_ ) )
2614 /* Forbid write changes when read-only */
2615 if( iface && iface->readOnly ) {
2617 canTreePaste = FALSE;
2625 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2626 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2627 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2628 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2629 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2631 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2632 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2633 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2634 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2635 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2637 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2638 addrbook.target_compose != NULL);
2640 if( event->button == 3 )
2641 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2642 event->button, event->time);
2647 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2648 GdkEventButton *event,
2651 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2655 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2657 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2658 AddressObject *obj = NULL;
2659 AddressDataSource *ds = NULL;
2660 AddressBookFile *abf = NULL;
2661 ItemFolder *parentFolder = NULL;
2662 ItemFolder *folder = NULL;
2664 if( ! addrbook.treeSelected ) return;
2665 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2666 if( obj == NULL ) return;
2667 ds = addressbook_find_datasource( addrbook.treeSelected );
2668 if( ds == NULL ) return;
2670 if( obj->type == ADDR_DATASOURCE ) {
2671 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2673 else if( obj->type == ADDR_ITEM_FOLDER ) {
2674 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2680 abf = ds->rawDataSource;
2681 if( abf == NULL ) return;
2682 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2685 nn = addressbook_node_add_folder(
2686 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2688 g_message("error adding addressbook folder\n");
2690 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2691 if( addrbook.treeSelected == addrbook.opened )
2692 addressbook_set_clist(obj, TRUE);
2696 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2698 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2699 AddressObject *obj = NULL;
2700 AddressDataSource *ds = NULL;
2701 AddressBookFile *abf = NULL;
2702 ItemFolder *parentFolder = NULL;
2703 ItemGroup *group = NULL;
2705 if( ! addrbook.treeSelected ) return;
2706 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2707 if( obj == NULL ) return;
2708 ds = addressbook_find_datasource( addrbook.treeSelected );
2709 if( ds == NULL ) return;
2711 if( obj->type == ADDR_DATASOURCE ) {
2712 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2714 else if( obj->type == ADDR_ITEM_FOLDER ) {
2715 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2721 abf = ds->rawDataSource;
2722 if( abf == NULL ) return;
2723 group = addressbook_edit_group( abf, parentFolder, NULL );
2726 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2728 g_message("error adding addressbook group\n");
2730 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2731 if( addrbook.treeSelected == addrbook.opened )
2732 addressbook_set_clist(obj, TRUE);
2736 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2738 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2741 GdkPixbuf *pix_cl, *pix_op;
2742 gboolean is_leaf, expanded;
2744 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2746 &is_leaf, &expanded);
2747 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2754 * \param obj Address object to edit.
2755 * \param node Node in tree.
2756 * \return New name of data source.
2758 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2759 gchar *newName = NULL;
2760 AddressDataSource *ds = NULL;
2761 AddressInterface *iface = NULL;
2762 AdapterDSource *ads = NULL;
2764 ds = addressbook_find_datasource( node );
2765 if( ds == NULL ) return NULL;
2766 iface = ds->interface;
2767 if( ! iface->haveLibrary ) return NULL;
2769 /* Read data from data source */
2770 if( addrindex_ds_get_modify_flag( ds ) ) {
2771 addrindex_ds_read_data( ds );
2774 if( ! addrindex_ds_get_read_flag( ds ) ) {
2775 addrindex_ds_read_data( ds );
2779 ads = ADAPTER_DSOURCE(obj);
2780 if( ads->subType == ADDR_BOOK ) {
2781 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2783 else if( ads->subType == ADDR_VCARD ) {
2784 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2787 else if( ads->subType == ADDR_JPILOT ) {
2788 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2792 else if( ads->subType == ADDR_LDAP ) {
2793 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2799 newName = obj->name;
2804 * Edit an object that is in the address tree area.
2806 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2808 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2810 AddressDataSource *ds = NULL;
2811 AddressBookFile *abf = NULL;
2812 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2815 if( ! addrbook.treeSelected ) return;
2816 node = addrbook.treeSelected;
2817 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2818 obj = gtk_cmctree_node_get_row_data( ctree, node );
2819 if( obj == NULL ) return;
2820 parentNode = GTK_CMCTREE_ROW(node)->parent;
2822 ds = addressbook_find_datasource( node );
2823 if( ds == NULL ) return;
2825 if( obj->type == ADDR_DATASOURCE ) {
2826 name = addressbook_edit_datasource( obj, node );
2827 if( name == NULL ) return;
2830 abf = ds->rawDataSource;
2831 if( abf == NULL ) return;
2832 if( obj->type == ADDR_ITEM_FOLDER ) {
2833 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2834 ItemFolder *item = adapter->itemFolder;
2835 ItemFolder *parentFolder = NULL;
2836 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2837 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2838 name = ADDRITEM_NAME(item);
2840 else if( obj->type == ADDR_ITEM_GROUP ) {
2841 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2842 ItemGroup *item = adapter->itemGroup;
2843 ItemFolder *parentFolder = NULL;
2844 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2845 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2846 name = ADDRITEM_NAME(item);
2849 if( name && parentNode ) {
2850 /* Update node in tree view */
2851 addressbook_change_node_name( node, name );
2852 gtk_sctree_sort_node(ctree, parentNode);
2853 gtk_cmctree_expand( ctree, node );
2854 gtk_sctree_select( GTK_SCTREE( ctree), node );
2861 ADDRTREE_DEL_FOLDER_ONLY,
2862 ADDRTREE_DEL_FOLDER_ADDR
2866 * Delete an item from the tree widget.
2867 * \param data Data passed in.
2868 * \param action Action.
2869 * \param widget Widget issuing callback.
2871 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2873 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2874 GtkCMCTreeNode *node = NULL;
2878 AddrBookBase *adbase;
2879 AddressCache *cache;
2880 AdapterDSource *ads = NULL;
2881 AddressInterface *iface = NULL;
2882 AddressDataSource *ds = NULL;
2883 gboolean remFlag = FALSE;
2884 TreeItemDelType delType;
2886 if( ! addrbook.treeSelected ) return;
2887 node = addrbook.treeSelected;
2888 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2890 obj = gtk_cmctree_node_get_row_data( ctree, node );
2891 cm_return_if_fail(obj != NULL);
2893 if( obj->type == ADDR_DATASOURCE ) {
2894 ads = ADAPTER_DSOURCE(obj);
2895 if( ads == NULL ) return;
2896 ds = ads->dataSource;
2897 if( ds == NULL ) return;
2900 /* Must be folder or something else */
2901 ds = addressbook_find_datasource( node );
2902 if( ds == NULL ) return;
2904 /* Only allow deletion from non-readOnly */
2905 iface = ds->interface;
2906 if( iface->readOnly ) {
2907 /* Allow deletion of query results */
2908 if( ! iface->externalQuery ) return;
2912 /* Confirm deletion */
2913 delType = ADDRTREE_DEL_NONE;
2914 if( obj->type == ADDR_ITEM_FOLDER ) {
2915 if( iface && iface->externalQuery ) {
2916 message = g_strdup_printf( _(
2917 "Do you want to delete the query " \
2918 "results and addresses in '%s' ?" ),
2920 aval = alertpanel( _("Delete"), message,
2921 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2923 if( aval == G_ALERTALTERNATE ) {
2924 delType = ADDRTREE_DEL_FOLDER_ADDR;
2928 message = g_strdup_printf
2929 ( _( "Do you want to delete '%s' ? "
2930 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2932 aval = alertpanel( _("Delete folder"), message,
2933 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2935 if( aval == G_ALERTALTERNATE ) {
2936 delType = ADDRTREE_DEL_FOLDER_ONLY;
2938 else if( aval == G_ALERTOTHER ) {
2939 delType = ADDRTREE_DEL_FOLDER_ADDR;
2943 else if( obj->type == ADDR_ITEM_GROUP ) {
2944 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2945 "The addresses it contains will not be lost."), obj->name);
2946 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2947 "+" GTK_STOCK_DELETE, NULL);
2949 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2951 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2952 "The addresses it contains will be lost."), obj->name);
2953 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2954 "+" GTK_STOCK_DELETE, NULL);
2956 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2958 if( delType == ADDRTREE_DEL_NONE ) return;
2960 /* Proceed with deletion */
2961 if( obj->type == ADDR_DATASOURCE ) {
2962 /* Remove node from tree */
2963 gtk_cmctree_remove_node( ctree, node );
2965 if (delType == ADDRTREE_DEL_DATA &&
2966 ds->interface && ds->interface->type == ADDR_IF_BOOK)
2967 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
2969 /* Remove data source. */
2970 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2971 addrindex_free_datasource( ds );
2976 /* Get reference to cache */
2977 adbase = ( AddrBookBase * ) ds->rawDataSource;
2978 if( adbase == NULL ) return;
2979 cache = adbase->addressCache;
2981 /* Remove query results folder */
2982 if( iface && iface->externalQuery ) {
2983 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2984 ItemFolder *folder = adapter->itemFolder;
2986 adapter->itemFolder = NULL;
2988 g_print( "remove folder for ::%s::\n", obj->name );
2989 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2990 g_print( "-------------- remove results\n" );
2992 addrindex_remove_results( ds, folder );
2993 /* g_print( "-------------- remove node\n" ); */
2994 gtk_cmctree_remove_node( ctree, node );
2998 /* Code below is valid for regular address book deletion */
2999 if( obj->type == ADDR_ITEM_FOLDER ) {
3000 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3001 ItemFolder *item = adapter->itemFolder;
3003 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3004 /* Remove folder only */
3005 item = addrcache_remove_folder( cache, item );
3007 addritem_free_item_folder( item );
3008 addressbook_move_nodes_up( ctree, node );
3012 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3013 /* Remove folder and addresses */
3014 item = addrcache_remove_folder_delete( cache, item );
3016 addritem_free_item_folder( item );
3021 else if( obj->type == ADDR_ITEM_GROUP ) {
3022 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3023 ItemGroup *item = adapter->itemGroup;
3025 item = addrcache_remove_group( cache, item );
3027 addritem_free_item_group( item );
3034 gtk_cmctree_remove_node(ctree, node );
3038 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3040 if( person && addrbook.treeSelected == addrbook.opened ) {
3041 person->status = ADD_ENTRY;
3042 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3043 addressbook_folder_refresh_one_person(
3044 GTK_CMCTREE(addrbook.clist), person );
3046 addressbook_address_list_set_focus();
3049 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3051 if( person && addrbook.treeSelected == addrbook.opened) {
3052 person->status = ADD_ENTRY;
3053 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3054 addressbook_set_clist(
3055 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3059 addressbook_address_list_set_focus();
3063 * Label (a format string) that is used to name each folder.
3065 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3068 * Search ctree widget callback function.
3069 * \param pA Pointer to node.
3070 * \param pB Pointer to data item being sought.
3071 * \return Zero (0) if folder found.
3073 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3076 aoA = ( AddressObject * ) pA;
3077 if( aoA->type == ADDR_ITEM_FOLDER ) {
3078 ItemFolder *folder, *fld;
3080 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3081 folder = ( ItemFolder * ) pB;
3082 if( fld == folder ) return 0; /* Found folder */
3087 static ItemFolder * addressbook_setup_subf(
3088 AddressDataSource *ds, gchar *title,
3089 GtkCMCTreeNode *pNode )
3091 AddrBookBase *adbase;
3092 AddressCache *cache;
3095 GtkCMCTreeNode *nNode;
3097 AddressObjectType aoType = ADDR_NONE;
3100 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3102 if( ds && ds->type == ADDR_IF_LDAP ) {
3104 aoType = ADDR_LDAP_QUERY;
3111 ctree = GTK_CMCTREE(addrbook.ctree);
3112 /* Get reference to address cache */
3113 adbase = ( AddrBookBase * ) ds->rawDataSource;
3114 cache = adbase->addressCache;
3116 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3117 GList *cur = children;
3118 for (; cur; cur = cur->next) {
3119 ItemFolder *child = (ItemFolder *) cur->data;
3120 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3121 nNode = gtk_cmctree_find_by_row_data_custom(
3123 addressbook_treenode_find_folder_cb );
3125 addrindex_remove_results( ds, child );
3126 while( child->listPerson ) {
3127 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3128 item = addrcache_remove_person( cache, item );
3130 addritem_free_item_person( item );
3134 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3135 addrbook.treeSelected = nNode;
3142 /* Create a folder */
3143 folder = addrcache_add_new_folder( cache, NULL );
3144 name = g_strdup_printf( "%s", title );
3145 addritem_folder_set_name( folder, name );
3146 addritem_folder_set_remarks( folder, "" );
3149 /* Now let's see the folder */
3150 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3151 gtk_cmctree_expand( ctree, pNode );
3153 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3154 addrbook.treeSelected = nNode;
3160 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3161 AddressObject *pobj = NULL;
3162 AddressDataSource *ds = NULL;
3163 AddressBookFile *abf = NULL;
3164 debug_print("adding address\n");
3165 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3166 if( pobj == NULL ) {
3167 debug_print("no row data\n");
3170 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3172 debug_print("no datasource\n");
3176 abf = ds->rawDataSource;
3178 g_print("no addressbook file\n");
3182 if( pobj->type == ADDR_DATASOURCE ) {
3183 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3184 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3186 ItemFolder *folder = NULL;
3188 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3189 GtkCMCTreeNode *parentNode;
3190 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3191 if( ds == NULL ) return;
3193 /* We must have a datasource that is an external interface */
3194 if( ! ds->interface->haveLibrary ) return;
3195 if( ! ds->interface->externalQuery ) return;
3197 if( pobj->type == ADDR_ITEM_FOLDER ) {
3198 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3201 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3203 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3205 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3206 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3208 abf = ds->rawDataSource;
3211 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3212 addrbook.editaddress_vbox,
3213 addressbook_new_address_from_book_post_cb,
3216 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3217 LdapServer *server = ds->rawDataSource;
3218 ldapsvr_set_modified(server, TRUE);
3219 ldapsvr_update_book(server, NULL);
3220 if (server->retVal != LDAPRC_SUCCESS) {
3221 alertpanel( _("Add address(es)"),
3222 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3223 GTK_STOCK_CLOSE, NULL, NULL );
3224 server->retVal = LDAPRC_SUCCESS;
3229 if (prefs_common.addressbook_use_editaddress_dialog)
3230 addressbook_new_address_from_book_post_cb( person );
3233 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3235 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3238 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3239 GtkCMCTreeNode *parentNode;
3240 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3241 if( ds == NULL ) return;
3243 /* We must have a datasource that is an external interface */
3244 if( ! ds->interface->haveLibrary ) return;
3245 if( ! ds->interface->externalQuery ) return;
3247 if( pobj->type == ADDR_ITEM_FOLDER ) {
3248 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3251 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3253 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3256 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3257 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3259 abf = ds->rawDataSource;
3262 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3263 addrbook.editaddress_vbox,
3264 addressbook_new_address_from_folder_post_cb,
3267 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3268 LdapServer *server = ds->rawDataSource;
3269 ldapsvr_set_modified(server, TRUE);
3270 ldapsvr_update_book(server, NULL);
3271 if (server->retVal != LDAPRC_SUCCESS) {
3272 alertpanel( _("Add address(es)"),
3273 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3274 GTK_STOCK_CLOSE, NULL, NULL );
3279 if (prefs_common.addressbook_use_editaddress_dialog)
3280 addressbook_new_address_from_folder_post_cb( person );
3282 else if( pobj->type == ADDR_ITEM_GROUP ) {
3283 /* New address in group */
3284 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3285 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3286 if (addrbook.treeSelected == addrbook.opened) {
3287 /* Change node name in tree. */
3288 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3289 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3290 addressbook_set_clist(
3291 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3299 * Search for specified child group node in address index tree.
3300 * \param parent Parent node.
3301 * \param group Group to find.
3303 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3304 GtkCMCTreeNode *node = NULL;
3305 GtkCMCTreeRow *currRow;
3307 currRow = GTK_CMCTREE_ROW( parent );
3309 node = currRow->children;
3313 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3314 if( obj->type == ADDR_ITEM_GROUP ) {
3315 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3316 if( g == group ) return node;
3318 currRow = GTK_CMCTREE_ROW(node);
3319 node = currRow->sibling;
3325 static AddressBookFile *addressbook_get_book_file() {
3326 AddressBookFile *abf = NULL;
3327 AddressDataSource *ds = NULL;
3329 ds = addressbook_find_datasource( addrbook.treeSelected );
3330 if( ds == NULL ) return NULL;
3331 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3335 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3336 GtkCMCTreeNode *node;
3339 /* Remove existing folders and groups */
3340 row = GTK_CMCTREE_ROW( parent );
3342 while( (node = row->children) ) {
3343 gtk_cmctree_remove_node( ctree, node );
3348 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3349 GtkCMCTreeNode *parent, *child;
3350 GtkCMCTreeRow *currRow;
3351 currRow = GTK_CMCTREE_ROW( node );
3353 parent = currRow->parent;
3354 while( (child = currRow->children) ) {
3355 gtk_cmctree_move( ctree, child, parent, node );
3357 gtk_sctree_sort_node( ctree, parent );
3361 static void addressbook_edit_address_post_cb( ItemPerson *person )
3365 AddressBookFile *abf = addressbook_get_book_file();
3367 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3368 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3369 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3372 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3373 invalidate_address_completion();
3375 addressbook_address_list_set_focus();
3378 void addressbook_address_list_set_focus( void )
3380 if (!prefs_common.addressbook_use_editaddress_dialog) {
3381 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3382 addressbook_list_menu_setup();
3386 void addressbook_address_list_disable_some_actions(void)
3388 /* disable address copy/pasting when editing contact's detail (embedded form) */
3389 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3390 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3391 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3394 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3395 addressbook_edit_address(data, 0, NULL, TRUE);
3398 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3399 gboolean force_focus ) {
3400 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3402 AddressObject *obj = NULL, *pobj = NULL;
3403 AddressDataSource *ds = NULL;
3404 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3406 AddressBookFile *abf = NULL;
3408 if( addrbook.listSelected == NULL ) return;
3409 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3410 cm_return_if_fail(obj != NULL);
3412 ctree = GTK_CMCTREE( addrbook.ctree );
3413 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3414 node = gtk_cmctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3416 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3417 if( ds == NULL ) return;
3419 abf = addressbook_get_book_file();
3421 if( obj->type == ADDR_ITEM_EMAIL ) {
3422 ItemEMail *email = ( ItemEMail * ) obj;
3423 if( email == NULL ) return;
3424 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3425 /* Edit parent group */
3426 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3427 ItemGroup *itemGrp = adapter->itemGroup;
3428 if( abf == NULL ) return;
3429 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3430 name = ADDRITEM_NAME(itemGrp);
3431 node = addrbook.treeSelected;
3432 parentNode = GTK_CMCTREE_ROW(node)->parent;
3435 /* Edit person - email page */
3437 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3438 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3439 addressbook_edit_address_post_cb,
3440 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3443 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3444 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3445 person->status = UPDATE_ENTRY;
3448 if (prefs_common.addressbook_use_editaddress_dialog)
3449 addressbook_edit_address_post_cb( person );
3454 else if( obj->type == ADDR_ITEM_PERSON ) {
3455 /* Edit person - basic page */
3456 ItemPerson *person = ( ItemPerson * ) obj;
3457 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3458 addressbook_edit_address_post_cb,
3459 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3462 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3463 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3464 person->status = UPDATE_ENTRY;
3467 if (prefs_common.addressbook_use_editaddress_dialog)
3468 addressbook_edit_address_post_cb( person );
3472 else if( obj->type == ADDR_ITEM_GROUP ) {
3473 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3474 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3475 parentNode = addrbook.treeSelected;
3476 node = addressbook_find_group_node( parentNode, itemGrp );
3477 name = ADDRITEM_NAME(itemGrp);
3478 invalidate_address_completion();
3484 /* Update tree node with node name */
3485 if( node == NULL ) return;
3486 addressbook_change_node_name( node, name );
3487 gtk_sctree_sort_node( ctree, parentNode );
3488 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3489 addressbook_set_clist(
3490 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3495 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3497 addressbook_del_clicked(NULL, NULL);
3500 static void close_cb(GtkAction *action, gpointer data)
3502 addressbook_close();
3505 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3506 addressbook_export_to_file();
3509 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3511 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3512 if( person ) addritem_person_set_opened( person, TRUE );
3516 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3518 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3519 if( person ) addritem_person_set_opened( person, FALSE );
3523 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3525 gchar *eMailAlias = ADDRITEM_NAME(email);
3526 if( eMailAlias && *eMailAlias != '\0' ) {
3528 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3531 str = g_strdup( eMailAlias );
3537 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3538 GList *items = itemGroup->listEMail;
3539 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3540 for( ; items != NULL; items = g_list_next( items ) ) {
3541 GtkCMCTreeNode *nodeEMail = NULL;
3542 gchar *text[N_LIST_COLS];
3543 ItemEMail *email = items->data;
3547 if( ! email ) continue;
3549 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3550 str = addressbook_format_item_clist( person, email );
3552 text[COL_NAME] = addressbook_set_col_name_guard(str);
3555 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3557 text[COL_ADDRESS] = email->address;
3558 text[COL_REMARKS] = email->remarks;
3559 nodeEMail = gtk_sctree_insert_node(
3561 text, FOLDER_SPACING,
3565 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3571 gchar *addressbook_set_col_name_guard(gchar *value)
3573 gchar *ret = "<not set>";
3574 gchar *tmp = g_strdup(value);
3576 if (tmp !=NULL && *tmp != '\0')
3582 static void addressbook_folder_load_one_person(
3583 GtkCMCTree *clist, ItemPerson *person,
3584 AddressTypeControlItem *atci,
3585 AddressTypeControlItem *atciMail )
3587 GtkCMCTreeNode *nodePerson = NULL;
3588 GtkCMCTreeNode *nodeEMail = NULL;
3589 gchar *text[N_LIST_COLS];
3590 gboolean flgFirst = TRUE, haveAddr = FALSE;
3593 AddressBookFile *abf = addressbook_get_book_file();
3596 if( person == NULL ) return;
3598 text[COL_NAME] = "";
3599 node = person->listEMail;
3601 ItemEMail *email = node->data;
3602 gchar *eMailAddr = NULL;
3603 node = g_list_next( node );
3605 text[COL_ADDRESS] = email->address;
3606 text[COL_REMARKS] = email->remarks;
3607 eMailAddr = ADDRITEM_NAME(email);
3608 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3610 /* First email belongs with person */
3611 gchar *str = addressbook_format_item_clist( person, email );
3613 text[COL_NAME] = addressbook_set_col_name_guard(str);
3616 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3617 person && person->nickName ) {
3618 if (person->nickName) {
3619 if (strcmp(person->nickName, "") != 0) {
3620 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3623 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3629 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3631 nodePerson = gtk_sctree_insert_node(
3633 text, FOLDER_SPACING,
3636 FALSE, person->isOpened );
3639 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3642 /* Subsequent email is a child node of person */
3643 text[COL_NAME] = ADDRITEM_NAME(email);
3644 nodeEMail = gtk_sctree_insert_node(
3645 clist, nodePerson, NULL,
3646 text, FOLDER_SPACING,
3648 atciMail->iconXpmOpen,
3650 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3656 /* Have name without EMail */
3657 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3658 text[COL_ADDRESS] = "";
3659 text[COL_REMARKS] = "";
3660 nodePerson = gtk_sctree_insert_node(
3662 text, FOLDER_SPACING,
3665 FALSE, person->isOpened );
3666 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3671 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3673 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3674 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3676 if( atci == NULL ) return;
3677 if( atciMail == NULL ) return;
3679 /* Load email addresses */
3680 items = addritem_folder_get_person_list( itemFolder );
3681 for( ; items != NULL; items = g_list_next( items ) ) {
3682 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3684 /* Free up the list */
3685 mgu_clear_list( items );
3686 g_list_free( items );
3689 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3690 addrbook.listSelected = NULL;
3691 gtk_cmctree_remove_node( clist, node );
3692 addressbook_menubar_set_sensitive( FALSE );
3693 addressbook_menuitem_set_sensitive(
3694 gtk_cmctree_node_get_row_data(
3695 GTK_CMCTREE(clist), addrbook.treeSelected ),
3696 addrbook.treeSelected );
3699 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3700 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3701 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3702 GtkCMCTreeNode *node;
3703 if( atci == NULL ) return;
3704 if( atciMail == NULL ) return;
3705 if( person == NULL ) return;
3706 /* unload the person */
3708 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3710 addressbook_folder_remove_node( clist, node );
3711 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3712 gtk_sctree_sort_node( clist, NULL );
3713 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3715 gtk_sctree_select( GTK_SCTREE(clist), node );
3716 if (!gtk_cmctree_node_is_visible( clist, node ) )
3717 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3721 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3722 GtkCMCTreeNode *node;
3724 if( person == NULL ) return;
3725 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3727 addressbook_folder_remove_node( clist, node );
3731 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3733 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3735 /* Load any groups */
3736 if( ! atci ) return;
3737 items = addritem_folder_get_group_list( itemFolder );
3738 for( ; items != NULL; items = g_list_next( items ) ) {
3739 GtkCMCTreeNode *nodeGroup = NULL;
3740 gchar *text[N_LIST_COLS];
3741 ItemGroup *group = items->data;
3742 if( group == NULL ) continue;
3743 text[COL_NAME] = ADDRITEM_NAME(group);
3744 text[COL_ADDRESS] = "";
3745 text[COL_REMARKS] = "";
3746 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3747 text, FOLDER_SPACING,
3751 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3752 gtk_sctree_sort_node(clist, NULL);
3754 /* Free up the list */
3755 mgu_clear_list( items );
3756 g_list_free( items );
3760 * Search ctree widget callback function.
3761 * \param pA Pointer to node.
3762 * \param pB Pointer to data item being sought.
3763 * \return Zero (0) if group found.
3765 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3768 aoA = ( AddressObject * ) pA;
3769 if( aoA->type == ADDR_ITEM_GROUP ) {
3770 ItemGroup *group, *grp;
3772 grp = ADAPTER_GROUP(aoA)->itemGroup;
3773 group = ( ItemGroup * ) pB;
3774 if( grp == group ) return 0; /* Found group */
3780 * Remove folder and group nodes from tree widget for items contained ("cut")
3783 static void addressbook_treenode_remove_item( void ) {
3785 AddrSelectItem *cutItem;
3786 AddressCache *cache;
3787 AddrItemObject *aio;
3788 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3791 node = _clipBoard_->objectList;
3793 cutItem = node->data;
3794 node = g_list_next( node );
3795 cache = addrindex_get_cache(
3796 _clipBoard_->addressIndex, cutItem->cacheID );
3797 if( cache == NULL ) continue;
3798 aio = addrcache_get_object( cache, cutItem->uid );
3801 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3804 folder = ( ItemFolder * ) aio;
3805 tn = gtk_cmctree_find_by_row_data_custom(
3806 ctree, NULL, folder,
3807 addressbook_treenode_find_folder_cb );
3809 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3812 group = ( ItemGroup * ) aio;
3813 tn = gtk_cmctree_find_by_row_data_custom(
3815 addressbook_treenode_find_group_cb );
3819 /* Free up adapter and remove node. */
3820 gtk_cmctree_remove_node( ctree, tn );
3827 * Find parent datasource for specified tree node.
3828 * \param node Node to test.
3829 * \return Data source, or NULL if not found.
3831 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3832 AddressDataSource *ds = NULL;
3835 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3838 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3839 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3841 /* g_print( "ao->type = %d\n", ao->type ); */
3842 if( ao->type == ADDR_DATASOURCE ) {
3843 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3844 /* g_print( "found it\n" ); */
3845 ds = ads->dataSource;
3849 node = GTK_CMCTREE_ROW(node)->parent;
3855 * Load address list widget with children of specified object.
3856 * \param obj Parent object to be loaded.
3858 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3859 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3860 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3861 AddressDataSource *ds = NULL;
3862 AdapterDSource *ads = NULL;
3863 static AddressObject *last_obj = NULL;
3865 if (addrbook.clist == NULL) {
3868 if (obj == last_obj && !refresh)
3873 gtk_cmclist_clear(clist);
3877 if( obj->type == ADDR_INTERFACE ) {
3878 /* g_print( "set_clist: loading datasource...\n" ); */
3879 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3883 gtk_cmclist_freeze(clist);
3884 gtk_cmclist_clear(clist);
3886 if( obj->type == ADDR_DATASOURCE ) {
3887 ads = ADAPTER_DSOURCE(obj);
3888 ds = ads->dataSource;
3890 /* Load root folder */
3891 ItemFolder *rootFolder = NULL;
3892 rootFolder = addrindex_ds_get_root_folder( ds );
3893 addressbook_folder_load_person(
3894 ctreelist, rootFolder );
3895 addressbook_folder_load_group(
3896 ctreelist, rootFolder );
3900 if( obj->type == ADDR_ITEM_GROUP ) {
3902 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3903 addressbook_load_group( ctreelist, itemGroup );
3905 else if( obj->type == ADDR_ITEM_FOLDER ) {
3907 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3908 addressbook_folder_load_person( ctreelist, itemFolder );
3909 addressbook_folder_load_group( ctreelist, itemFolder );
3912 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3913 clist->focus_row = -1;
3914 gtk_cmclist_thaw(clist);
3918 * Call back function to free adaptor. Call back is setup by function
3919 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3920 * called when the address book tree widget node is removed by calling
3921 * function gtk_cmctree_remove_node().
3923 * \param data Tree node's row data.
3925 static void addressbook_free_treenode( gpointer data ) {
3928 ao = ( AddressObject * ) data;
3929 if( ao == NULL ) return;
3930 if( ao->type == ADDR_INTERFACE ) {
3931 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3932 addrbookctl_free_interface( ai );
3934 else if( ao->type == ADDR_DATASOURCE ) {
3935 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3936 addrbookctl_free_datasource( ads );
3938 else if( ao->type == ADDR_ITEM_FOLDER ) {
3939 AdapterFolder *af = ADAPTER_FOLDER(ao);
3940 addrbookctl_free_folder( af );
3942 else if( ao->type == ADDR_ITEM_GROUP ) {
3943 AdapterGroup *ag = ADAPTER_GROUP(ao);
3944 addrbookctl_free_group( ag );
3949 * Create new adaptor for specified data source.
3951 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3952 AddressObjectType otype, gchar *name )
3954 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3955 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3956 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3957 adapter->dataSource = ds;
3958 adapter->subType = otype;
3962 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3963 ADDRESS_OBJECT_NAME(adapter) =
3964 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3968 * Load tree from address index with the initial data.
3970 static void addressbook_load_tree( void ) {
3971 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3972 GList *nodeIf, *nodeDS;
3973 AdapterInterface *adapter;
3974 AddressInterface *iface;
3975 AddressTypeControlItem *atci;
3976 AddressDataSource *ds;
3977 AdapterDSource *ads;
3978 GtkCMCTreeNode *node, *newNode;
3981 nodeIf = _addressInterfaceList_;
3983 adapter = nodeIf->data;
3984 node = adapter->treeNode;
3985 iface = adapter->interface;
3986 atci = adapter->atci;
3988 if( iface->useInterface ) {
3989 /* Load data sources below interface node */
3990 nodeDS = iface->listSource;
3993 name = addrindex_ds_get_name( ds );
3994 ads = addressbook_create_ds_adapter(
3995 ds, atci->objectType, name );
3996 newNode = addressbook_add_object(
3997 node, ADDRESS_OBJECT(ads) );
3998 if (newNode == NULL) {
3999 g_message("error adding addressbook object\n");
4001 nodeDS = g_list_next( nodeDS );
4003 gtk_cmctree_expand( ctree, node );
4006 nodeIf = g_list_next( nodeIf );
4011 * Convert the old address book to new format.
4013 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4014 gboolean retVal = FALSE;
4015 gboolean errFlag = TRUE;
4018 /* Read old address book, performing conversion */
4019 debug_print( "Reading and converting old address book...\n" );
4020 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4021 addrindex_read_data( addrIndex );
4022 if( addrIndex->retVal == MGU_NO_FILE ) {
4023 /* We do not have a file - new user */
4024 debug_print( "New user... create new books...\n" );
4025 addrindex_create_new_books( addrIndex );
4026 if( addrIndex->retVal == MGU_SUCCESS ) {
4027 /* Save index file */
4028 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4029 addrindex_save_data( addrIndex );
4030 if( addrIndex->retVal == MGU_SUCCESS ) {
4035 msg = _( "New user, could not save index file." );
4039 msg = _( "New user, could not save address book files." );
4043 /* We have an old file */
4044 if( addrIndex->wasConverted ) {
4045 /* Converted successfully - save address index */
4046 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4047 addrindex_save_data( addrIndex );
4048 if( addrIndex->retVal == MGU_SUCCESS ) {
4049 msg = _( "Old address book converted successfully." );
4054 msg = _("Old address book converted,\n"
4055 "could not save new address index file." );
4059 /* File conversion failed - just create new books */
4060 debug_print( "File conversion failed... just create new books...\n" );
4061 addrindex_create_new_books( addrIndex );
4062 if( addrIndex->retVal == MGU_SUCCESS ) {
4064 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4065 addrindex_save_data( addrIndex );
4066 if( addrIndex->retVal == MGU_SUCCESS ) {
4067 msg = _("Could not convert address book,\n"
4068 "but created empty new address book files." );
4073 msg = _("Could not convert address book,\n"
4074 "could not save new address index file." );
4078 msg = _("Could not convert address book\n"
4079 "and could not create new address book files." );
4084 debug_print( "Error\n%s\n", msg );
4085 alertpanel_full(_("Addressbook conversion error"), msg,
4086 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4087 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4090 debug_print( "Warning\n%s\n", msg );
4091 alertpanel_full(_("Addressbook conversion error"), msg,
4092 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4093 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4099 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4103 gboolean failed = FALSE;
4105 if( ( dp = opendir( origdir ) ) == NULL ) {
4109 while( ( d = readdir( dp ) ) != NULL ) {
4110 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4113 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4115 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4117 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4130 /* all copies succeeded, we can remove source files */
4131 if( ( dp = opendir( origdir ) ) == NULL ) {
4134 while( ( d = readdir( dp ) ) != NULL ) {
4135 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4138 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4140 claws_unlink(orig_file);
4150 void addressbook_read_file( void ) {
4151 AddressIndex *addrIndex = NULL;
4152 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4154 debug_print( "Reading address index...\n" );
4155 if( _addressIndex_ ) {
4156 debug_print( "address book already read!!!\n" );
4160 addrIndex = addrindex_create_index();
4161 addrindex_initialize();
4163 /* Use new address book index. */
4165 if ( !is_dir_exist(indexdir) ) {
4166 if ( make_dir(indexdir) < 0 ) {
4167 addrindex_set_file_path( addrIndex, get_rc_dir() );
4168 g_warning( "couldn't create dir %s\n", indexdir);
4170 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4171 remove_dir_recursive(indexdir);
4172 addrindex_set_file_path( addrIndex, get_rc_dir() );
4173 g_error("couldn't migrate dir %s", indexdir);
4175 addrindex_set_file_path( addrIndex, indexdir);
4179 addrindex_set_file_path( addrIndex, indexdir);
4182 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4183 addrindex_read_data( addrIndex );
4184 if( addrIndex->retVal == MGU_NO_FILE ) {
4185 /* Conversion required */
4186 debug_print( "Converting...\n" );
4187 if( addressbook_convert( addrIndex ) ) {
4188 _addressIndex_ = addrIndex;
4191 else if( addrIndex->retVal == MGU_SUCCESS ) {
4192 _addressIndex_ = addrIndex;
4195 /* Error reading address book */
4196 debug_print( "Could not read address index.\n" );
4197 addrindex_print_index( addrIndex, stdout );
4198 alertpanel_full(_("Addressbook Error"),
4199 _("Could not read address index"),
4200 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4201 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4203 debug_print( "done.\n" );
4207 * Add object into the address index tree widget.
4208 * Enter: node Parent node.
4209 * obj Object to add.
4210 * Return: Node that was added, or NULL if object not added.
4212 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4215 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4216 GtkCMCTreeNode *added;
4217 AddressObject *pobj;
4218 AddressObjectType otype;
4219 AddressTypeControlItem *atci = NULL;
4221 cm_return_val_if_fail(node != NULL, NULL);
4222 cm_return_val_if_fail(obj != NULL, NULL);
4224 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4225 cm_return_val_if_fail(pobj != NULL, NULL);
4227 /* Determine object type to be displayed */
4228 if( obj->type == ADDR_DATASOURCE ) {
4229 otype = ADAPTER_DSOURCE(obj)->subType;
4235 /* Handle any special conditions. */
4237 atci = addrbookctl_lookup( otype );
4239 if( atci->showInTree ) {
4240 /* Add object to tree */
4243 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4244 atci->iconXpm, atci->iconXpmOpen,
4245 atci->treeLeaf, atci->treeExpand );
4246 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4247 addressbook_free_treenode );
4251 gtk_sctree_sort_node(ctree, node);
4257 * Add group into the address index tree.
4258 * \param node Parent node.
4259 * \param ds Data source.
4260 * \param itemGroup Group to add.
4261 * \return Inserted node.
4263 static GtkCMCTreeNode *addressbook_node_add_group(
4264 GtkCMCTreeNode *node, AddressDataSource *ds,
4265 ItemGroup *itemGroup )
4267 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4268 GtkCMCTreeNode *newNode;
4269 AdapterGroup *adapter;
4270 AddressTypeControlItem *atci = NULL;
4273 if( ds == NULL ) return NULL;
4274 if( node == NULL || itemGroup == NULL ) return NULL;
4276 name = &itemGroup->obj.name;
4278 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4280 adapter = g_new0( AdapterGroup, 1 );
4281 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4282 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4283 adapter->itemGroup = itemGroup;
4285 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4286 atci->iconXpm, atci->iconXpm,
4287 atci->treeLeaf, atci->treeExpand );
4288 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4289 addressbook_free_treenode );
4290 gtk_sctree_sort_node( ctree, node );
4295 * Add folder into the address index tree. Only visible folders are loaded into
4296 * the address index tree. Note that the root folder is not inserted into the
4299 * \param node Parent node.
4300 * \param ds Data source.
4301 * \param itemFolder Folder to add.
4302 * \param otype Object type to display.
4303 * \return Inserted node for the folder.
4305 static GtkCMCTreeNode *addressbook_node_add_folder(
4306 GtkCMCTreeNode *node, AddressDataSource *ds,
4307 ItemFolder *itemFolder, AddressObjectType otype )
4309 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4310 GtkCMCTreeNode *newNode = NULL;
4311 AdapterFolder *adapter;
4312 AddressTypeControlItem *atci = NULL;
4313 GList *listItems = NULL;
4315 ItemFolder *rootFolder;
4317 /* Only visible folders */
4318 if( itemFolder == NULL || itemFolder->isHidden )
4323 if( node == NULL || itemFolder == NULL )
4326 /* Determine object type */
4327 atci = addrbookctl_lookup( otype );
4331 rootFolder = addrindex_ds_get_root_folder( ds );
4332 if( itemFolder == rootFolder ) {
4336 adapter = g_new0( AdapterFolder, 1 );
4337 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4338 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4339 adapter->itemFolder = itemFolder;
4341 name = ADDRITEM_NAME(itemFolder);
4342 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4343 atci->iconXpm, atci->iconXpm,
4344 atci->treeLeaf, atci->treeExpand );
4346 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4347 addressbook_free_treenode );
4351 listItems = itemFolder->listFolder;
4352 while( listItems ) {
4353 ItemFolder *item = listItems->data;
4354 addressbook_node_add_folder( newNode, ds, item, otype );
4355 listItems = g_list_next( listItems );
4357 listItems = itemFolder->listGroup;
4358 while( listItems ) {
4359 ItemGroup *item = listItems->data;
4360 addressbook_node_add_group( newNode, ds, item );
4361 listItems = g_list_next( listItems );
4363 gtk_sctree_sort_node( ctree, node );
4367 void addressbook_export_to_file( void ) {
4368 if( _addressIndex_ ) {
4369 /* Save all new address book data */
4370 debug_print( "Saving address books...\n" );
4371 addrindex_save_all_books( _addressIndex_ );
4373 debug_print( "Exporting addressbook to file...\n" );
4374 addrindex_save_data( _addressIndex_ );
4375 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4376 addrindex_print_index( _addressIndex_, stdout );
4379 /* Notify address completion of new data */
4380 invalidate_address_completion();
4384 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4386 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4387 addressbook_lup_clicked(NULL, NULL);
4392 * Comparison using cell contents (text in first column). Used for sort
4393 * address index widget.
4395 static gint addressbook_treenode_compare_func(
4396 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4398 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4399 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4400 gchar *name1 = NULL, *name2 = NULL;
4401 if( cell1 ) name1 = cell1->u.text;
4402 if( cell2 ) name2 = cell2->u.text;
4403 if( ! name1 ) return ( name2 != NULL );
4404 if( ! name2 ) return -1;
4405 return g_utf8_collate( name1, name2 );
4408 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4409 AdapterDSource *ads;
4410 AdapterInterface *adapter;
4411 GtkCMCTreeNode *newNode;
4413 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4414 if( adapter == NULL ) return;
4415 ads = addressbook_edit_book( _addressIndex_, NULL );
4417 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4419 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4420 addrbook.treeSelected = newNode;
4425 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4426 AdapterDSource *ads;
4427 AdapterInterface *adapter;
4428 GtkCMCTreeNode *newNode;
4430 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4431 if( adapter == NULL ) return;
4432 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4434 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4436 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4437 addrbook.treeSelected = newNode;
4443 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4444 AdapterDSource *ads;
4445 AdapterInterface *adapter;
4446 AddressInterface *iface;
4447 GtkCMCTreeNode *newNode;
4449 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4450 if( adapter == NULL ) return;
4451 iface = adapter->interface;
4452 if( ! iface->haveLibrary ) return;
4453 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4455 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4457 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4458 addrbook.treeSelected = newNode;
4465 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4466 AdapterDSource *ads;
4467 AdapterInterface *adapter;
4468 AddressInterface *iface;
4469 GtkCMCTreeNode *newNode;
4471 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4472 if( adapter == NULL ) return;
4473 iface = adapter->interface;
4474 if( ! iface->haveLibrary ) return;
4475 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4477 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4479 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4480 addrbook.treeSelected = newNode;
4487 * Display address search status message.
4488 * \param queryType Query type.
4489 * \param status Status/Error code.
4491 static void addressbook_search_message( gint queryType, gint sts ) {
4493 *addressbook_msgbuf = '\0';
4495 if( sts != MGU_SUCCESS ) {
4496 if( queryType == ADDRQUERY_LDAP ) {
4498 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4503 g_snprintf( addressbook_msgbuf,
4504 sizeof(addressbook_msgbuf), "%s", desc );
4505 addressbook_status_show( addressbook_msgbuf );
4508 addressbook_status_show( "" );
4513 * Refresh addressbook by forcing refresh of current selected object in
4516 static void addressbook_refresh_current( void ) {
4520 ctree = GTK_CMCTREE(addrbook.ctree);
4521 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4522 if( obj == NULL ) return;
4523 addressbook_set_clist( obj, TRUE );
4527 * Message that is displayed whilst a query is executing in a background
4530 static gchar *_tempMessage_ = N_( "Busy searching..." );
4533 * Address search idle function. This function is called during UI idle time
4534 * while a search is in progress.
4536 * \param data Idler data.
4538 static void addressbook_search_idle( gpointer data ) {
4542 queryID = GPOINTER_TO_INT( data );
4543 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4548 * Search completion callback function. This removes the query from the idle
4551 * \param sender Sender of query.
4552 * \param queryID Query ID of search request.
4553 * \param status Search status.
4554 * \param data Query data.
4556 static void addressbook_search_callback_end(
4557 gpointer sender, gint queryID, gint status, gpointer data )
4561 AddrQueryObject *aqo;
4563 /* Remove idler function */
4564 ptrQID = GINT_TO_POINTER( queryID );
4566 g_idle_remove_by_data( ptrQID );
4569 /* Refresh addressbook contents */
4570 addressbook_refresh_current();
4571 req = qrymgr_find_request( queryID );
4573 aqo = ( AddrQueryObject * ) req->queryList->data;
4574 addressbook_search_message( aqo->queryType, status );
4577 /* Stop the search */
4578 addrindex_stop_search( queryID );
4584 * \param ds Data source to search.
4585 * \param searchTerm String to lookup.
4586 * \param pNode Parent data source node.
4588 static void addressbook_perform_search(
4589 AddressDataSource *ds, gchar *searchTerm,
4590 GtkCMCTreeNode *pNode )
4598 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4600 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4602 /* Create a folder for the search results */
4603 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4604 folder = addressbook_setup_subf(ds, name, pNode);
4607 /* Setup the search */
4608 queryID = addrindex_setup_explicit_search(
4609 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4610 if( queryID == 0 ) return;
4612 /* Set up idler function */
4613 idleID = g_idle_add(
4614 (GSourceFunc) addressbook_search_idle,
4615 GINT_TO_POINTER( queryID ) );
4617 g_message("error adding addressbook_search_idle\n");
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;
5086 /* gboolean enabled; */
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 ) {
5104 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5105 adapter = addrbookctl_find_interface( ifType );
5107 newList = g_list_append( newList, adapter );
5114 /* g_print( "i=%d\n", i ); */
5115 g_strfreev( splitStr );
5116 g_free( selectStr );
5118 /* Replace existing list */
5119 mgu_clear_list( _addressIFaceSelection_ );
5120 g_list_free( _addressIFaceSelection_ );
5121 _addressIFaceSelection_ = newList;
5125 /* ***********************************************************************
5126 * Add sender to address book.
5127 * ***********************************************************************
5131 * This function is used by the Add sender to address book function.
5133 gboolean addressbook_add_contact(
5134 const gchar *name, const gchar *address, const gchar *remarks,
5135 GdkPixbuf *picture )
5137 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5138 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5139 debug_print( "addressbook_add_contact - added\n" );
5140 addressbook_refresh();
5145 /* ***********************************************************************
5146 * Book/folder selection.
5147 * ***********************************************************************
5151 * This function is used by the matcher dialog to select a book/folder.
5153 gchar *addressbook_folder_selection( const gchar *folderpath)
5155 AddressBookFile *book = NULL;
5156 ItemFolder *folder = NULL;
5159 cm_return_val_if_fail( folderpath != NULL, NULL);
5161 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5163 if ( folder != NULL) {
5165 gchar *oldtmp = NULL;
5166 AddrItemObject *obj = NULL;
5168 /* walk thru folder->parent to build the full folder path */
5169 /* TODO: wwp: optimize this */
5171 tmp = g_strdup(obj->uid);
5172 while ( obj->parent ) {
5174 if ( obj->name != NULL ) {
5175 oldtmp = g_strdup(tmp);
5177 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5181 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5184 path = g_strdup_printf("%s", book->fileName);
5186 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5192 /* ***********************************************************************
5193 * Book/folder checking.
5194 * ***********************************************************************
5197 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5199 FolderInfo *fi = g_new0( FolderInfo, 1 );
5201 fi->folder = folder;
5205 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5206 FolderInfo *fiParent, FolderPathMatch *match )
5212 FolderPathMatch *nextmatch = NULL;
5217 list = parentFolder->listFolder;
5219 folder = list->data;
5220 fName = g_strdup( ADDRITEM_NAME(folder) );
5222 /* match folder name, match pointer will be set to NULL if next recursive call
5223 doesn't need to match subfolder name */
5224 if ( match != NULL &&
5225 match->matched == FALSE ) {
5226 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5227 /* folder name matches, prepare next subfolder match */
5228 debug_print("matched folder name '%s'\n", fName);
5230 if ( match->folder_path[match->index] == NULL ) {
5231 /* we've matched all elements */
5232 match->matched = TRUE;
5233 match->folder = folder;
5234 debug_print("book/folder path matched!\n");
5236 /* keep on matching */
5244 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5245 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5247 list = g_list_next( list );
5252 * This function is used by to check if a matcher book/folder path corresponds to an
5253 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5254 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5255 if book AND folder are NULL this means that folderpath was empty or Any.
5256 If folderpath is a simple book name (without folder), book will not be NULL and folder
5257 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5260 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5261 AddressDataSource **book,
5262 ItemFolder **folder )
5264 AddressDataSource *ds;
5265 GList *list, *nodeDS;
5266 ItemFolder *rootFolder;
5267 AddressBookFile *abf;
5269 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5276 if ( folderpath == NULL )
5279 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5282 /* split the folder path we've received, we'll try to match this path, subpath by
5283 subpath against the book/folder structure in order */
5284 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5285 if (!folder_path_match.folder_path)
5288 list = addrindex_get_interface_list( _addressIndex_ );
5289 while ( list && !folder_path_match.matched ) {
5290 AddressInterface *interface = list->data;
5291 if ( interface && interface->type == ADDR_IF_BOOK ) {
5292 nodeDS = interface->listSource;
5293 while ( nodeDS && !folder_path_match.matched ) {
5296 /* Read address book */
5297 if( ! addrindex_ds_get_read_flag( ds ) ) {
5298 addrindex_ds_read_data( ds );
5301 /* Add node for address book */
5302 abf = ds->rawDataSource;
5304 /* match book name */
5305 if ( abf && abf->fileName &&
5306 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5308 debug_print("matched book name '%s'\n", abf->fileName);
5309 folder_path_match.book = ds;
5311 if ( folder_path_match.folder_path[1] == NULL ) {
5312 /* no folder part to match */
5314 folder_path_match.matched = TRUE;
5315 folder_path_match.folder = NULL;
5316 debug_print("book path matched!\n");
5319 /* match folder part */
5321 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5322 rootFolder = addrindex_ds_get_root_folder( ds );
5324 /* prepare for recursive call */
5325 folder_path_match.index = 1;
5326 /* this call will set folder_path_match.matched and folder_path_match.folder */
5327 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5332 nodeDS = g_list_next( nodeDS );
5335 list = g_list_next( list );
5338 g_strfreev( folder_path_match.folder_path );
5341 *book = folder_path_match.book;
5343 *folder = folder_path_match.folder;
5344 return folder_path_match.matched;
5348 /* **********************************************************************
5350 * ***********************************************************************
5356 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5357 AddressDataSource *ds = NULL;
5358 AdapterDSource *ads = NULL;
5359 AddressBookFile *abf = NULL;
5360 AdapterInterface *adapter;
5361 GtkCMCTreeNode *newNode;
5363 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5365 if( adapter->treeNode ) {
5366 abf = addressbook_imp_ldif( _addressIndex_ );
5368 ds = addrindex_index_add_datasource(
5369 _addressIndex_, ADDR_IF_BOOK, abf );
5370 ads = addressbook_create_ds_adapter(
5371 ds, ADDR_BOOK, NULL );
5372 addressbook_ads_set_name(
5373 ads, addrbook_get_name( abf ) );
5374 newNode = addressbook_add_object(
5376 ADDRESS_OBJECT(ads) );
5378 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5380 addrbook.treeSelected = newNode;
5383 /* Notify address completion */
5384 invalidate_address_completion();
5393 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5394 AddressDataSource *ds = NULL;
5395 AdapterDSource *ads = NULL;
5396 AddressBookFile *abf = NULL;
5397 AdapterInterface *adapter;
5398 GtkCMCTreeNode *newNode;
5400 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5402 if( adapter->treeNode ) {
5403 abf = addressbook_imp_mutt( _addressIndex_ );
5405 ds = addrindex_index_add_datasource(
5406 _addressIndex_, ADDR_IF_BOOK, abf );
5407 ads = addressbook_create_ds_adapter(
5408 ds, ADDR_BOOK, NULL );
5409 addressbook_ads_set_name(
5410 ads, addrbook_get_name( abf ) );
5411 newNode = addressbook_add_object(
5413 ADDRESS_OBJECT(ads) );
5415 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5417 addrbook.treeSelected = newNode;
5420 /* Notify address completion */
5421 invalidate_address_completion();
5430 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5431 AddressDataSource *ds = NULL;
5432 AdapterDSource *ads = NULL;
5433 AddressBookFile *abf = NULL;
5434 AdapterInterface *adapter;
5435 GtkCMCTreeNode *newNode;
5437 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5439 if( adapter->treeNode ) {
5440 abf = addressbook_imp_pine( _addressIndex_ );
5442 ds = addrindex_index_add_datasource(
5443 _addressIndex_, ADDR_IF_BOOK, abf );
5444 ads = addressbook_create_ds_adapter(
5445 ds, ADDR_BOOK, NULL );
5446 addressbook_ads_set_name(
5447 ads, addrbook_get_name( abf ) );
5448 newNode = addressbook_add_object(
5450 ADDRESS_OBJECT(ads) );
5452 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5454 addrbook.treeSelected = newNode;
5457 /* Notify address completion */
5458 invalidate_address_completion();
5465 * Harvest addresses.
5466 * \param folderItem Folder to import.
5467 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5468 * \param msgList List of message numbers, or NULL to process folder.
5470 void addressbook_harvest(
5471 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5473 AddressDataSource *ds = NULL;
5474 AdapterDSource *ads = NULL;
5475 AddressBookFile *abf = NULL;
5476 AdapterInterface *adapter;
5477 GtkCMCTreeNode *newNode;
5479 abf = addrgather_dlg_execute(
5480 folderItem, _addressIndex_, sourceInd, msgList );
5482 ds = addrindex_index_add_datasource(
5483 _addressIndex_, ADDR_IF_BOOK, abf );
5485 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5487 if( adapter->treeNode ) {
5488 ads = addressbook_create_ds_adapter(
5489 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5490 newNode = addressbook_add_object(
5492 ADDRESS_OBJECT(ads) );
5493 if (newNode == NULL) {
5494 g_message("error adding addressbook object\n");
5499 /* Notify address completion */
5500 invalidate_address_completion();
5507 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5508 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5510 AddressDataSource *ds = NULL;
5511 AddrBookBase *adbase;
5512 AddressCache *cache;
5513 GtkCMCTreeNode *node = NULL;
5515 if( ! addrbook.treeSelected ) return;
5516 node = addrbook.treeSelected;
5517 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5518 obj = gtk_cmctree_node_get_row_data( ctree, node );
5519 if( obj == NULL ) return;
5521 ds = addressbook_find_datasource( node );
5522 if( ds == NULL ) return;
5523 adbase = ( AddrBookBase * ) ds->rawDataSource;
5524 cache = adbase->addressCache;
5525 addressbook_exp_html( cache );
5531 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5532 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5534 AddressDataSource *ds = NULL;
5535 AddrBookBase *adbase;
5536 AddressCache *cache;
5537 GtkCMCTreeNode *node = NULL;
5539 if( ! addrbook.treeSelected ) return;
5540 node = addrbook.treeSelected;
5541 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5542 obj = gtk_cmctree_node_get_row_data( ctree, node );
5543 if( obj == NULL ) return;
5545 ds = addressbook_find_datasource( node );
5546 if( ds == NULL ) return;
5547 adbase = ( AddrBookBase * ) ds->rawDataSource;
5548 cache = adbase->addressCache;
5549 addressbook_exp_ldif( cache );
5552 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5554 addrduplicates_find(GTK_WINDOW(addrbook.window));
5557 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5559 addressbook_custom_attr_edit();
5562 static void addressbook_start_drag(GtkWidget *widget, gint button,
5566 GdkDragContext *context;
5567 if (addressbook_target_list == NULL)
5568 addressbook_target_list = gtk_target_list_new(
5569 addressbook_drag_types, 1);
5570 context = gtk_drag_begin(widget, addressbook_target_list,
5571 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5572 gtk_drag_set_icon_default(context);
5575 static void addressbook_drag_data_get(GtkWidget *widget,
5576 GdkDragContext *drag_context,
5577 GtkSelectionData *selection_data,
5582 AddrItemObject *aio = NULL;
5583 AddressObject *pobj = NULL;
5584 AdapterDSource *ads = NULL;
5585 AddressDataSource *ds = NULL;
5588 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5590 if( pobj == NULL ) return;
5592 if( pobj->type == ADDR_DATASOURCE ) {
5593 ads = ADAPTER_DSOURCE(pobj);
5594 ds = ads->dataSource;
5595 } else if (pobj->type == ADDR_ITEM_GROUP) {
5600 else if( pobj->type != ADDR_INTERFACE ) {
5601 ds = addressbook_find_datasource( addrbook.treeSelected );
5607 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5608 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5609 GTK_CMCTREE_NODE(cur->data));
5610 while (aio && aio->type != ITEMTYPE_PERSON) {
5615 if (aio && aio->type == ITEMTYPE_PERSON) {
5616 if( ds && ds->interface && ds->interface->readOnly)
5617 gtk_selection_data_set(selection_data,
5618 gtk_selection_data_get_target(selection_data), 8,
5619 (const guchar *)"Dummy_addr_copy", 15);
5621 gtk_selection_data_set(selection_data,
5622 gtk_selection_data_get_target(selection_data), 8,
5623 (const guchar *)"Dummy_addr_move", 15);
5627 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5628 GdkDragContext *context,
5634 GtkAllocation allocation;
5635 GtkRequisition requisition;
5637 GtkCMCTreeNode *node = NULL;
5638 gboolean acceptable = FALSE;
5639 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5640 gint height = allocation.height;
5641 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5642 gint total_height = requisition.height;
5643 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5644 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5645 gfloat vpos = gtk_adjustment_get_value(pos);
5647 if (gtk_cmclist_get_selection_info
5648 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5650 if (y > height - 24 && height + vpos < total_height) {
5651 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5652 gtk_adjustment_changed(pos);
5654 if (y < 24 && y > 0) {
5655 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5656 gtk_adjustment_changed(pos);
5658 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5661 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5662 if( obj->type == ADDR_ITEM_FOLDER
5663 || obj->type == ADDR_ITEM_GROUP)
5666 AdapterDSource *ads = NULL;
5667 AddressDataSource *ds = NULL;
5668 ads = ADAPTER_DSOURCE(obj);
5669 if (ads == NULL ){ return FALSE;}
5670 ds = ads->dataSource;
5671 if (ds == NULL ) { return FALSE;}
5679 g_signal_handlers_block_by_func
5681 G_CALLBACK(addressbook_tree_selected), NULL);
5682 gtk_sctree_select( GTK_SCTREE(widget), node);
5683 g_signal_handlers_unblock_by_func
5685 G_CALLBACK(addressbook_tree_selected), NULL);
5686 gdk_drag_status(context,
5687 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5688 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5690 gdk_drag_status(context, 0, time);
5695 static void addressbook_drag_leave_cb(GtkWidget *widget,
5696 GdkDragContext *context,
5700 if (addrbook.treeSelected) {
5701 g_signal_handlers_block_by_func
5703 G_CALLBACK(addressbook_tree_selected), NULL);
5704 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5705 g_signal_handlers_unblock_by_func
5707 G_CALLBACK(addressbook_tree_selected), NULL);
5712 static void addressbook_drag_received_cb(GtkWidget *widget,
5713 GdkDragContext *drag_context,
5716 GtkSelectionData *data,
5722 GtkCMCTreeNode *node;
5723 GtkCMCTreeNode *lastopened = addrbook.opened;
5725 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5726 if (gtk_cmclist_get_selection_info
5727 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5731 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5732 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5735 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5736 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5737 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5738 addressbook_clip_copy_cb(NULL, NULL);
5740 addressbook_clip_cut_cb(NULL, NULL);
5741 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5742 addressbook_clip_paste_cb(NULL,NULL);
5743 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5744 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5745 gtk_drag_finish(drag_context, TRUE, TRUE, time);