2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2013 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "claws-features.h"
28 #include <glib/gi18n.h>
29 #include <gdk/gdkkeysyms.h>
33 #include <sys/types.h>
37 #include "addressbook.h"
38 #include "manage_window.h"
39 #include "prefs_common.h"
40 #include "alertpanel.h"
41 #include "inputdialog.h"
43 #include "stock_pixmap.h"
45 #include "prefs_gtk.h"
51 #include "addr_compl.h"
54 #include "addressitem.h"
56 #include "addrcache.h"
58 #include "addrindex.h"
59 #include "addressadd.h"
60 #include "addrduplicates.h"
61 #include "addressbook_foldersel.h"
63 #include "editvcard.h"
64 #include "editgroup.h"
65 #include "editaddress.h"
67 #include "importldif.h"
68 #include "importmutt.h"
69 #include "importpine.h"
74 #include "editjpilot.h"
79 #include "ldapserver.h"
81 #include "ldapupdate.h"
83 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
86 #include "addrquery.h"
87 #include "addrselect.h"
89 #include "addrgather.h"
90 #include "adbookbase.h"
91 #include "exphtmldlg.h"
92 #include "expldifdlg.h"
93 #include "browseldap.h"
94 #include "addrcustomattr.h"
102 } AddressIndexColumns;
110 } AddressListColumns;
113 AddressBookFile *book;
121 AddressDataSource *book;
125 static gchar *list_titles[] = { N_("Name"),
129 #define COL_NAME_WIDTH 164
130 #define COL_ADDRESS_WIDTH 156
132 #define COL_FOLDER_WIDTH 170
133 #define ADDRESSBOOK_WIDTH 640
134 #define ADDRESSBOOK_HEIGHT 360
136 #define ADDRESSBOOK_MSGBUF_SIZE 2048
138 static GdkPixbuf *folderxpm = NULL;
139 static GdkPixbuf *folderopenxpm = NULL;
140 static GdkPixbuf *groupxpm = NULL;
141 static GdkPixbuf *interfacexpm = NULL;
142 static GdkPixbuf *bookxpm = NULL;
143 static GdkPixbuf *addressxpm = NULL;
144 static GdkPixbuf *vcardxpm = NULL;
145 static GdkPixbuf *jpilotxpm = NULL;
146 static GdkPixbuf *categoryxpm = NULL;
147 static GdkPixbuf *ldapxpm = NULL;
148 static GdkPixbuf *addrsearchxpm = NULL;
151 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
153 /* Address list selection */
154 static AddrSelectList *_addressSelect_ = NULL;
155 static AddressClipboard *_clipBoard_ = NULL;
157 /* Address index file and interfaces */
158 static AddressIndex *_addressIndex_ = NULL;
159 static GList *_addressInterfaceList_ = NULL;
160 static GList *_addressIFaceSelection_ = NULL;
161 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
163 static AddressBook_win addrbook;
165 static GHashTable *_addressBookTypeHash_ = NULL;
166 static GList *_addressBookTypeList_ = NULL;
168 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
169 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
170 static void addressbook_edit_address_post_cb( ItemPerson *person );
172 static void addressbook_create (void);
173 static gint addressbook_close (void);
175 static gboolean address_index_has_focus = FALSE;
176 static gboolean address_list_has_focus = FALSE;
178 /* callback functions */
179 static void addressbook_del_clicked (GtkButton *button,
181 static void addressbook_reg_clicked (GtkButton *button,
183 static void addressbook_to_clicked (GtkButton *button,
185 static void addressbook_lup_clicked (GtkButton *button,
187 static void addressbook_close_clicked (GtkButton *button,
190 static void addressbook_tree_selected (GtkCMCTree *ctree,
191 GtkCMCTreeNode *node,
194 static void addressbook_select_row_tree (GtkCMCTree *ctree,
195 GtkCMCTreeNode *node,
198 static void addressbook_list_row_selected (GtkCMCTree *clist,
199 GtkCMCTreeNode *node,
202 static void addressbook_list_row_unselected (GtkCMCTree *clist,
203 GtkCMCTreeNode *node,
206 static void addressbook_person_expand_node (GtkCMCTree *ctree,
209 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
213 static void addressbook_entry_activated (GtkWidget *widget,
216 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
217 GdkEventButton *event,
219 static gboolean addressbook_list_button_released(GtkWidget *widget,
220 GdkEventButton *event,
222 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
223 GdkEventButton *event,
225 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
226 GdkEventButton *event,
229 static void addressbook_new_folder_cb (GtkAction *action,
231 static void addressbook_new_group_cb (GtkAction *action,
233 static void addressbook_treenode_edit_cb (GtkAction *action,
235 static void addressbook_treenode_delete_cb (GtkAction *action,
238 static void addressbook_change_node_name (GtkCMCTreeNode *node,
241 static void addressbook_new_address_cb (GtkAction *action,
243 static void addressbook_edit_address_cb (GtkAction *action,
245 static void addressbook_delete_address_cb (GtkAction *action,
248 static void close_cb (GtkAction *action,
250 static void addressbook_file_save_cb (GtkAction *action,
253 /* Data source edit stuff */
254 static void addressbook_new_book_cb (GtkAction *action,
256 static void addressbook_new_vcard_cb (GtkAction *action,
260 static void addressbook_new_jpilot_cb (GtkAction *action,
265 static void addressbook_new_ldap_cb (GtkAction *action,
269 static void addressbook_set_clist (AddressObject *obj,
272 static void addressbook_load_tree (void);
273 void addressbook_read_file (void);
275 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
277 static void addressbook_treenode_remove_item ( void );
279 static AddressDataSource *addressbook_find_datasource
280 (GtkCMCTreeNode *node );
282 static AddressBookFile *addressbook_get_book_file(void);
284 static GtkCMCTreeNode *addressbook_node_add_folder
285 (GtkCMCTreeNode *node,
286 AddressDataSource *ds,
287 ItemFolder *itemFolder,
288 AddressObjectType otype);
289 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
290 AddressDataSource *ds,
291 ItemGroup *itemGroup);
292 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
293 GtkCMCTreeNode *parent);
294 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
295 GtkCMCTreeNode *node);
296 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
298 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
301 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
304 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
306 AddressTypeControlItem *atci,
307 AddressTypeControlItem *atciMail);
308 static void addressbook_folder_refresh_one_person(GtkCMCTree *clist,
310 static void addressbook_folder_remove_one_person(GtkCMCTree *clist,
312 static void addressbook_folder_remove_node (GtkCMCTree *clist,
313 GtkCMCTreeNode *node);
315 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
316 gboolean force_focus );
318 /* LUT's and IF stuff */
319 static void addressbook_free_treenode ( gpointer data );
320 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
321 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
323 static void addrbookctl_build_map (GtkWidget *window);
324 static void addrbookctl_build_iflist (void);
325 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
326 static void addrbookctl_build_ifselect (void);
328 static void addrbookctl_free_interface (AdapterInterface *adapter);
329 static void addrbookctl_free_datasource (AdapterDSource *adapter);
330 static void addrbookctl_free_folder (AdapterFolder *adapter);
331 static void addrbookctl_free_group (AdapterGroup *adapter);
333 static void addressbook_list_select_clear ( void );
334 static void addressbook_list_select_add ( AddrItemObject *aio,
335 AddressDataSource *ds );
336 static void addressbook_list_select_remove ( AddrItemObject *aio );
338 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
339 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
340 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
341 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
342 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
343 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
344 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
345 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
346 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
347 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
348 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
349 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
350 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
351 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
353 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
356 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
358 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
360 static void addressbook_start_drag(GtkWidget *widget, gint button,
363 static void addressbook_drag_data_get(GtkWidget *widget,
364 GdkDragContext *drag_context,
365 GtkSelectionData *selection_data,
369 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
370 GdkDragContext *context,
375 static void addressbook_drag_leave_cb(GtkWidget *widget,
376 GdkDragContext *context,
379 static void addressbook_drag_received_cb(GtkWidget *widget,
380 GdkDragContext *drag_context,
383 GtkSelectionData *data,
387 static void addressbook_list_menu_setup( void );
389 static GtkTargetEntry addressbook_drag_types[] =
391 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
394 static GtkTargetList *addressbook_target_list = NULL;
396 static void about_show_cb(GtkAction *action, gpointer data)
401 static GtkActionEntry addressbook_entries[] =
403 {"Menu", NULL, "Menu" },
405 {"Book", NULL, N_("_Book") },
406 {"Address", NULL, N_("_Edit") },
407 {"Tools", NULL, N_("_Tools") },
408 {"Help", NULL, N_("_Help") },
411 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
412 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
413 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
417 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
420 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
422 {"Book/---", NULL, "---", NULL, NULL, NULL },
424 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
425 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
426 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
427 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
428 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
431 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
432 {"Address/---", NULL, "---", NULL, NULL, NULL },
433 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
434 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
435 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
436 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
437 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
438 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
439 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
440 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
441 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
442 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
443 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
447 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
448 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
449 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
450 {"Tools/---", NULL, "---", NULL, NULL, NULL },
451 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
452 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
453 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
454 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
455 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
458 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
462 static GtkActionEntry addressbook_tree_popup_entries[] =
464 {"ABTreePopup", NULL, "ABTreePopup" },
465 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
466 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
467 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
468 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
469 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
470 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
471 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
472 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
473 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
474 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
477 static GtkActionEntry addressbook_list_popup_entries[] =
479 {"ABListPopup", NULL, "ABListPopup" },
480 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
481 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
482 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
483 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
484 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
485 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
486 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
487 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
488 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
489 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
490 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
491 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
492 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
494 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
499 * Structure of error message table.
501 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
502 struct _ErrMsgTableEntry {
507 static gchar *_errMsgUnknown_ = N_( "Unknown" );
510 * Lookup table of error messages for general errors. Note that a NULL
511 * description signifies the end of the table.
513 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
514 { MGU_SUCCESS, N_("Success") },
515 { MGU_BAD_ARGS, N_("Bad arguments") },
516 { MGU_NO_FILE, N_("File not specified") },
517 { MGU_OPEN_FILE, N_("Error opening file") },
518 { MGU_ERROR_READ, N_("Error reading file") },
519 { MGU_EOF, N_("End of file encountered") },
520 { MGU_OO_MEMORY, N_("Error allocating memory") },
521 { MGU_BAD_FORMAT, N_("Bad file format") },
522 { MGU_ERROR_WRITE, N_("Error writing to file") },
523 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
524 { MGU_NO_PATH, N_("No path specified") },
530 * Lookup table of error messages for LDAP errors.
532 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
533 { LDAPRC_SUCCESS, N_("Success") },
534 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
535 { LDAPRC_INIT, N_("Error initializing LDAP") },
536 { LDAPRC_BIND, N_("Error binding to LDAP server") },
537 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
538 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
539 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
540 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
541 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
542 { LDAPRC_TLS, N_("Error starting TLS connection") },
543 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
544 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
545 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
546 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
552 * Lookup message for specified error code.
553 * \param lut Lookup table.
554 * \param code Code to lookup.
555 * \return Description associated to code.
557 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
559 ErrMsgTableEntry entry;
562 for( i = 0; ; i++ ) {
564 if( entry.description == NULL ) break;
565 if( entry.code == code ) {
566 desc = entry.description;
571 desc = _errMsgUnknown_;
576 static gboolean lastCanLookup = FALSE;
578 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
580 if (add_and_delete) {
581 gtk_widget_show(addrbook.edit_btn);
582 gtk_widget_show(addrbook.del_btn);
583 gtk_widget_show(addrbook.reg_btn);
585 gtk_widget_hide(addrbook.edit_btn);
586 gtk_widget_hide(addrbook.del_btn);
587 gtk_widget_hide(addrbook.reg_btn);
591 gtk_widget_show(addrbook.lup_btn);
592 gtk_widget_show(addrbook.entry);
593 gtk_widget_show(addrbook.label);
595 gtk_widget_hide(addrbook.lup_btn);
596 gtk_widget_hide(addrbook.entry);
597 gtk_widget_hide(addrbook.label);
600 lastCanLookup = lookup;
603 gtk_widget_show(addrbook.to_btn);
604 gtk_widget_show(addrbook.cc_btn);
605 gtk_widget_show(addrbook.bcc_btn);
607 gtk_widget_hide(addrbook.to_btn);
608 gtk_widget_hide(addrbook.cc_btn);
609 gtk_widget_hide(addrbook.bcc_btn);
613 void addressbook_open(Compose *target)
615 /* Initialize all static members */
616 if( _clipBoard_ == NULL ) {
617 _clipBoard_ = addrclip_create();
619 if( _addressIndex_ != NULL ) {
620 addrclip_set_index( _clipBoard_, _addressIndex_ );
622 if( _addressSelect_ == NULL ) {
623 _addressSelect_ = addrselect_list_create();
625 if (!addrbook.window) {
626 addressbook_read_file();
627 addressbook_create();
628 addressbook_load_tree();
629 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
630 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
633 gtk_widget_hide(addrbook.window);
636 gtk_widget_show_all(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);
941 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
945 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
950 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
992 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
994 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
996 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
998 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
999 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1000 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1002 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1003 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1004 GTK_POLICY_AUTOMATIC,
1005 GTK_POLICY_AUTOMATIC);
1006 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1009 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1010 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1012 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1013 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1014 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1015 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1016 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1017 GTK_CMCTREE_EXPANDER_TRIANGLE);
1018 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1019 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1020 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1021 addressbook_treenode_compare_func);
1023 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1024 G_CALLBACK(addressbook_tree_selected), NULL);
1025 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1026 G_CALLBACK(addressbook_tree_button_pressed),
1028 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1029 G_CALLBACK(addressbook_tree_button_released),
1032 g_signal_connect(G_OBJECT(ctree), "select_row",
1033 G_CALLBACK(addressbook_select_row_tree), NULL);
1035 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1036 addressbook_drag_types, 1,
1037 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1038 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1039 G_CALLBACK(addressbook_drag_motion_cb),
1041 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1042 G_CALLBACK(addressbook_drag_leave_cb),
1044 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1045 G_CALLBACK(addressbook_drag_received_cb),
1047 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1048 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1049 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1050 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1052 clist_vbox = gtk_vbox_new(FALSE, 4);
1054 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1055 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1056 GTK_POLICY_AUTOMATIC,
1057 GTK_POLICY_AUTOMATIC);
1058 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1061 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1062 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1063 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1064 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1065 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1066 GTK_CMCTREE_EXPANDER_TRIANGLE);
1067 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1068 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1069 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1071 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1073 gtk_widget_set_size_request(clist, -1, 80);
1075 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1076 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1077 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1078 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1079 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1080 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1081 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1082 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1083 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1084 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1085 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1087 for (i = 0; i < N_LIST_COLS; i++)
1088 gtkut_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1091 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1092 G_CALLBACK(addressbook_list_row_selected), NULL);
1093 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1094 G_CALLBACK(addressbook_list_row_unselected), NULL);
1095 g_signal_connect(G_OBJECT(clist), "button_press_event",
1096 G_CALLBACK(addressbook_list_button_pressed),
1098 g_signal_connect(G_OBJECT(clist), "button_release_event",
1099 G_CALLBACK(addressbook_list_button_released),
1101 g_signal_connect(G_OBJECT(clist), "tree_expand",
1102 G_CALLBACK(addressbook_person_expand_node), NULL );
1103 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1104 G_CALLBACK(addressbook_person_collapse_node), NULL );
1105 g_signal_connect(G_OBJECT(clist), "start_drag",
1106 G_CALLBACK(addressbook_start_drag), NULL);
1107 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1108 G_CALLBACK(addressbook_drag_data_get), NULL);
1109 hbox = gtk_hbox_new(FALSE, 4);
1110 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1112 label = gtk_label_new(_("Search"));
1113 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1115 entry = gtk_entry_new();
1116 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1118 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1120 g_signal_connect(G_OBJECT(entry), "key_press_event",
1121 G_CALLBACK(addressbook_entry_key_pressed),
1123 g_signal_connect(G_OBJECT(entry), "activate",
1124 G_CALLBACK(addressbook_entry_activated), NULL);
1126 if (!prefs_common.addressbook_use_editaddress_dialog) {
1127 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1128 vpaned = gtk_vpaned_new();
1129 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1130 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1133 editaddress_vbox = NULL;
1135 hpaned = gtk_hpaned_new();
1136 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1137 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1138 if (prefs_common.addressbook_use_editaddress_dialog)
1139 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1141 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1144 hsbox = gtk_hbox_new(FALSE, 0);
1145 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1146 statusbar = gtk_statusbar_new();
1147 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1150 hbbox = gtk_hbutton_box_new();
1151 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1152 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1153 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1154 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1156 gtkut_stock_button_add_help(hbbox, &help_btn);
1158 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1159 gtkut_widget_set_can_default(edit_btn, TRUE);
1160 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1161 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1162 gtkut_widget_set_can_default(del_btn, TRUE);
1163 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1164 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1165 gtkut_widget_set_can_default(reg_btn, TRUE);
1166 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1169 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1170 gtkut_widget_set_can_default(lup_btn, TRUE);
1171 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1173 g_signal_connect(G_OBJECT(help_btn), "clicked",
1174 G_CALLBACK(manual_open_with_anchor_cb),
1175 MANUAL_ANCHOR_ADDRBOOK);
1177 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1178 G_CALLBACK(addressbook_edit_clicked), NULL);
1179 g_signal_connect(G_OBJECT(del_btn), "clicked",
1180 G_CALLBACK(addressbook_del_clicked), NULL);
1181 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1182 G_CALLBACK(addressbook_reg_clicked), NULL);
1183 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1184 G_CALLBACK(addressbook_lup_clicked), NULL);
1186 to_btn = gtk_button_new_with_label
1187 (prefs_common_translated_header_name("To:"));
1188 gtkut_widget_set_can_default(to_btn, TRUE);
1189 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1190 cc_btn = gtk_button_new_with_label
1191 (prefs_common_translated_header_name("Cc:"));
1192 gtkut_widget_set_can_default(cc_btn, TRUE);
1193 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1194 bcc_btn = gtk_button_new_with_label
1195 (prefs_common_translated_header_name("Bcc:"));
1196 gtkut_widget_set_can_default(bcc_btn, TRUE);
1197 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1199 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1200 gtkut_widget_set_can_default(close_btn, TRUE);
1201 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1203 g_signal_connect(G_OBJECT(to_btn), "clicked",
1204 G_CALLBACK(addressbook_to_clicked),
1205 GINT_TO_POINTER(COMPOSE_TO));
1206 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1207 G_CALLBACK(addressbook_to_clicked),
1208 GINT_TO_POINTER(COMPOSE_CC));
1209 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1210 G_CALLBACK(addressbook_to_clicked),
1211 GINT_TO_POINTER(COMPOSE_BCC));
1212 g_signal_connect(G_OBJECT(close_btn), "clicked",
1213 G_CALLBACK(addressbook_close_clicked), NULL);
1215 /* Build icons for interface */
1217 /* Build control tables */
1218 addrbookctl_build_map(window);
1219 addrbookctl_build_iflist();
1220 addrbookctl_build_ifselect();
1222 addrbook.clist = NULL;
1224 /* Add each interface into the tree as a root level folder */
1225 nodeIf = _addressInterfaceList_;
1227 AdapterInterface *adapter = nodeIf->data;
1228 AddressInterface *iface = adapter->interface;
1229 nodeIf = g_list_next(nodeIf);
1231 if(iface->useInterface) {
1232 AddressTypeControlItem *atci = adapter->atci;
1233 text = atci->displayName;
1235 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1236 NULL, NULL, &text, FOLDER_SPACING,
1240 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1241 gtk_cmctree_node_set_row_data_full(
1242 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1243 addressbook_free_treenode );
1249 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1250 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1262 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1263 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1282 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1283 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1285 addrbook.window = window;
1286 addrbook.hpaned = hpaned;
1287 addrbook.vpaned = vpaned;
1288 addrbook.menubar = menubar;
1289 addrbook.ctree = ctree;
1292 addrbook.editaddress_vbox = editaddress_vbox;
1293 addrbook.clist = clist;
1294 addrbook.label = label;
1295 addrbook.entry = entry;
1296 addrbook.statusbar = statusbar;
1297 addrbook.status_cid = gtk_statusbar_get_context_id(
1298 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1300 addrbook.help_btn = help_btn;
1301 addrbook.edit_btn = edit_btn;
1302 addrbook.del_btn = del_btn;
1303 addrbook.reg_btn = reg_btn;
1304 addrbook.lup_btn = lup_btn;
1305 addrbook.to_btn = to_btn;
1306 addrbook.cc_btn = cc_btn;
1307 addrbook.bcc_btn = bcc_btn;
1309 addrbook.tree_popup = tree_popup;
1310 addrbook.list_popup = list_popup;
1311 addrbook.ui_manager = ui_manager;
1313 addrbook.listSelected = NULL;
1315 if (!geometry.min_height) {
1316 geometry.min_width = ADDRESSBOOK_WIDTH;
1317 geometry.min_height = ADDRESSBOOK_HEIGHT;
1320 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1322 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1323 prefs_common.addressbookwin_height);
1325 gtk_window_move(GTK_WINDOW(window), 48, 48);
1328 if (!prefs_common.addressbook_use_editaddress_dialog) {
1329 if (prefs_common.addressbook_vpaned_pos > 0)
1330 gtk_paned_set_position(GTK_PANED(vpaned),
1331 prefs_common.addressbook_vpaned_pos);
1333 if (prefs_common.addressbook_hpaned_pos > 0)
1334 gtk_paned_set_position(GTK_PANED(hpaned),
1335 prefs_common.addressbook_hpaned_pos);
1338 gtk_widget_show_all(window);
1342 * Close address book window and save to file(s).
1344 static gint addressbook_close( void ) {
1345 address_completion_end(addrbook.window);
1346 if (!prefs_common.addressbook_use_editaddress_dialog)
1347 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1349 addressbook_pane_save_position();
1351 gtk_widget_hide(addrbook.window);
1352 addressbook_export_to_file();
1357 * Display message in status line.
1358 * \param msg Message to display.
1360 static void addressbook_status_show( gchar *msg ) {
1361 if( addrbook.statusbar != NULL ) {
1363 GTK_STATUSBAR(addrbook.statusbar),
1364 addrbook.status_cid );
1367 GTK_STATUSBAR(addrbook.statusbar),
1368 addrbook.status_cid, msg );
1373 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1377 *addressbook_msgbuf = '\0';
1379 name = addrindex_ds_get_name( ds );
1380 retVal = addrindex_ds_get_status_code( ds );
1381 if( retVal == MGU_SUCCESS ) {
1382 g_snprintf( addressbook_msgbuf,
1383 sizeof(addressbook_msgbuf), "%s", name );
1386 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1387 g_snprintf( addressbook_msgbuf,
1388 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1391 addressbook_status_show( addressbook_msgbuf );
1394 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1396 addressbook_edit_address_cb(NULL, NULL);
1399 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1401 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1405 * Delete one or more objects from address list.
1407 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1409 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1410 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1411 AddressObject *pobj;
1412 AdapterDSource *ads = NULL;
1413 GtkCMCTreeNode *nodeList;
1416 AddressBookFile *abf = NULL;
1417 AddressDataSource *ds = NULL;
1418 AddressInterface *iface;
1419 AddrItemObject *aio;
1420 AddrSelectItem *item;
1422 gboolean refreshList = FALSE;
1424 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1425 cm_return_if_fail(pobj != NULL);
1427 /* Test whether anything selected for deletion */
1428 nodeList = addrbook.listSelected;
1430 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1431 if( aio == NULL) return;
1432 ds = addressbook_find_datasource( addrbook.treeSelected );
1433 if( ds == NULL ) return;
1435 /* Test for read only */
1436 iface = ds->interface;
1437 if( iface->readOnly ) {
1438 alertpanel( _("Delete address(es)"),
1439 _("This address data is readonly and cannot be deleted."),
1440 GTK_STOCK_CLOSE, NULL, NULL );
1444 /* Test whether Ok to proceed */
1446 if( pobj->type == ADDR_DATASOURCE ) {
1447 ads = ADAPTER_DSOURCE(pobj);
1448 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1450 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1453 else if( pobj->type == ADDR_ITEM_GROUP ) {
1456 if( ! procFlag ) return;
1457 abf = ds->rawDataSource;
1458 if( abf == NULL ) return;
1460 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1461 g_signal_handlers_block_by_func
1462 (G_OBJECT(addrbook.clist),
1463 G_CALLBACK(addressbook_list_row_unselected), NULL);
1465 /* Process deletions */
1466 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1467 GList *groups = NULL, *persons = NULL, *emails = NULL;
1468 gboolean group_delete = TRUE;
1469 /* Items inside folders */
1470 list = addrselect_get_list( _addressSelect_ );
1471 /* Confirm deletion */
1475 node = g_list_next( node );
1476 aio = ( AddrItemObject * ) item->addressItem;
1477 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1478 group_delete = FALSE;
1483 aval = alertpanel( _("Delete group"),
1484 _("Really delete the group(s)?\n"
1485 "The addresses it contains will not be lost."),
1486 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1487 if( aval != G_ALERTALTERNATE ) {
1491 aval = alertpanel( _("Delete address(es)"),
1492 _("Really delete the address(es)?"),
1493 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1494 if( aval != G_ALERTALTERNATE ) {
1499 /* first, set lists of groups and persons to remove */
1503 node = g_list_next( node );
1504 aio = ( AddrItemObject * ) item->addressItem;
1507 if( aio->type == ITEMTYPE_GROUP ) {
1508 groups = g_list_prepend(groups, item);
1510 else if( aio->type == ITEMTYPE_PERSON ) {
1511 persons = g_list_prepend(persons, item);
1514 /* then set list of emails to remove *if* they're not children of
1515 * persons to remove */
1519 node = g_list_next( node );
1520 aio = ( AddrItemObject * ) item->addressItem;
1523 if( aio->type == ITEMTYPE_EMAIL ) {
1524 ItemEMail *sitem = ( ItemEMail * ) aio;
1525 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1526 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1527 emails = g_list_prepend(emails, item);
1529 /* else, the email will be removed via the parent person */
1532 /* then delete groups */
1536 node = g_list_next( node );
1537 aio = ( AddrItemObject * ) item->addressItem;
1540 if( aio->type == ITEMTYPE_GROUP ) {
1541 ItemGroup *item = ( ItemGroup * ) aio;
1542 GtkCMCTreeNode *nd = NULL;
1543 nd = addressbook_find_group_node( addrbook.opened, item );
1544 item = addrbook_remove_group( abf, item );
1546 addritem_free_item_group( item );
1548 /* Remove group from parent node */
1549 gtk_cmctree_remove_node( ctree, nd );
1553 /* then delete persons */
1557 node = g_list_next( node );
1558 aio = ( AddrItemObject * ) item->addressItem;
1561 if( aio->type == ITEMTYPE_PERSON ) {
1562 ItemPerson *item = ( ItemPerson * ) aio;
1563 item->status = DELETE_ENTRY;
1564 addressbook_folder_remove_one_person( clist, item );
1565 if (pobj->type == ADDR_ITEM_FOLDER)
1566 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1567 item = addrbook_remove_person( abf, item );
1569 if (ds && ds->type == ADDR_IF_LDAP) {
1570 LdapServer *server = ds->rawDataSource;
1571 ldapsvr_set_modified(server, TRUE);
1572 ldapsvr_update_book(server, item);
1576 gchar *filename = addritem_person_get_picture(item);
1577 if (filename && is_file_exist(filename))
1578 claws_unlink(filename);
1580 addritem_free_item_person( item );
1584 /* then delete emails */
1588 node = g_list_next( node );
1589 aio = ( AddrItemObject * ) item->addressItem;
1593 if( aio->type == ITEMTYPE_EMAIL ) {
1594 ItemEMail *sitem = ( ItemEMail * ) aio;
1595 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1596 sitem = addrbook_person_remove_email( abf, person, sitem );
1598 addrcache_remove_email(abf->addressCache, sitem);
1599 addritem_free_item_email( sitem );
1601 addressbook_folder_refresh_one_person( clist, person );
1604 g_list_free( groups );
1605 g_list_free( persons );
1606 g_list_free( emails );
1607 g_list_free( list );
1608 addressbook_list_select_clear();
1610 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1611 addressbook_set_clist(
1612 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1616 addrbook_set_dirty(abf, TRUE);
1617 addressbook_export_to_file();
1618 addressbook_list_menu_setup();
1621 else if( pobj->type == ADDR_ITEM_GROUP ) {
1622 /* Items inside groups */
1623 list = addrselect_get_list( _addressSelect_ );
1627 node = g_list_next( node );
1628 aio = ( AddrItemObject * ) item->addressItem;
1629 if( aio->type == ITEMTYPE_EMAIL ) {
1630 ItemEMail *item = ( ItemEMail * ) aio;
1631 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1632 item = addrbook_person_remove_email( abf, person, item );
1634 addritem_free_item_email( item );
1638 g_list_free( list );
1639 addressbook_list_select_clear();
1640 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1641 addressbook_set_clist(
1642 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1646 addrbook_set_dirty(abf, TRUE);
1647 addressbook_export_to_file();
1648 addressbook_list_menu_setup();
1652 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1653 gtk_cmctree_remove_node( clist, nodeList );
1655 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1656 g_signal_handlers_unblock_by_func
1657 (G_OBJECT(addrbook.clist),
1658 G_CALLBACK(addressbook_list_row_unselected), NULL);
1661 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1663 addressbook_new_address_cb( NULL, NULL );
1666 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1669 gchar *address = NULL;
1671 if( aio->type == ITEMTYPE_EMAIL ) {
1672 ItemPerson *person = NULL;
1673 ItemEMail *email = ( ItemEMail * ) aio;
1675 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1676 if( email->address ) {
1677 if( ADDRITEM_NAME(email) ) {
1678 name = ADDRITEM_NAME(email);
1679 if( *name == '\0' ) {
1680 name = ADDRITEM_NAME(person);
1683 else if( ADDRITEM_NAME(person) ) {
1684 name = ADDRITEM_NAME(person);
1687 buf = g_strdup( email->address );
1689 address = email->address;
1692 else if( aio->type == ITEMTYPE_PERSON ) {
1693 ItemPerson *person = ( ItemPerson * ) aio;
1694 GList *node = person->listEMail;
1696 name = ADDRITEM_NAME(person);
1698 ItemEMail *email = ( ItemEMail * ) node->data;
1699 address = email->address;
1703 if( name && name[0] != '\0' ) {
1704 if( strchr_with_skip_quote( name, '"', ',' ) )
1705 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1707 buf = g_strdup_printf( "%s <%s>", name, address );
1710 buf = g_strdup( address );
1717 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1721 AddrSelectItem *item;
1722 AddrItemObject *aio;
1725 compose = addrbook.target_compose;
1726 if( ! compose ) return;
1728 /* Nothing selected, but maybe there is something in text entry */
1729 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1731 compose_entry_append(
1732 compose, addr, (ComposeEntryType)data , PREF_NONE);
1735 /* Select from address list */
1736 list = addrselect_get_list( _addressSelect_ );
1741 node = g_list_next( node );
1742 aio = item->addressItem;
1743 if( aio->type == ITEMTYPE_PERSON ||
1744 aio->type == ITEMTYPE_EMAIL ) {
1745 addr = addressbook_format_address( aio );
1746 compose_entry_append(
1747 compose, addr, (ComposeEntryType) data, PREF_NONE );
1750 else if( aio->type == ITEMTYPE_GROUP ) {
1751 ItemGroup *group = ( ItemGroup * ) aio;
1752 GList *nodeMail = group->listEMail;
1754 ItemEMail *email = nodeMail->data;
1756 addr = addressbook_format_address(
1757 ( AddrItemObject * ) email );
1758 compose_entry_append(
1759 compose, addr, (ComposeEntryType) data, PREF_NONE );
1761 nodeMail = g_list_next( nodeMail );
1766 AddressObject *obj = NULL;
1768 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1770 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1771 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1772 GList *nodeMail = itemGroup->listEMail;
1774 ItemEMail *email = nodeMail->data;
1776 addr = addressbook_format_address(
1777 ( AddrItemObject * ) email );
1778 compose_entry_append(
1779 compose, addr, (ComposeEntryType) data, PREF_NONE );
1781 nodeMail = g_list_next( nodeMail );
1785 g_list_free( list );
1788 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1798 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1799 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1800 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1801 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1802 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1805 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1806 gboolean canEdit = FALSE;
1807 gboolean canDelete = TRUE;
1808 gboolean canAdd = FALSE;
1809 gboolean canEditTr = TRUE;
1810 gboolean editAddress = FALSE;
1811 gboolean canExport = TRUE;
1812 AddressTypeControlItem *atci = NULL;
1813 AddressDataSource *ds = NULL;
1814 AddressInterface *iface = NULL;
1816 if( obj == NULL ) return;
1817 if( obj->type == ADDR_INTERFACE ) {
1818 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1819 iface = adapter->interface;
1821 if( iface->haveLibrary ) {
1822 /* Enable appropriate File / New command */
1823 atci = adapter->atci;
1824 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1827 canEditTr = canExport = FALSE;
1829 else if( obj->type == ADDR_DATASOURCE ) {
1830 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1831 ds = ads->dataSource;
1832 iface = ds->interface;
1833 if( ! iface->readOnly ) {
1834 canAdd = canEdit = editAddress = canDelete = TRUE;
1836 if( ! iface->haveLibrary ) {
1837 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1840 else if( obj->type == ADDR_ITEM_FOLDER ) {
1841 ds = addressbook_find_datasource( addrbook.treeSelected );
1843 iface = ds->interface;
1844 if( iface->readOnly ) {
1849 canAdd = editAddress = TRUE;
1853 else if( obj->type == ADDR_ITEM_GROUP ) {
1854 ds = addressbook_find_datasource( addrbook.treeSelected );
1856 iface = ds->interface;
1857 if( ! iface->readOnly ) {
1863 if( addrbook.listSelected == NULL )
1867 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1868 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1869 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1870 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1873 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1875 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1876 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1878 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1879 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1882 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1883 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1887 * Address book tree callback function that responds to selection of tree
1890 * \param ctree Tree widget.
1891 * \param node Node that was selected.
1892 * \param column Column number where selected occurred.
1893 * \param data Pointer to user data.
1895 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1896 gint column, gpointer data)
1898 AddressObject *obj = NULL;
1899 AdapterDSource *ads = NULL;
1900 AddressDataSource *ds = NULL;
1901 ItemFolder *rootFolder = NULL;
1902 AddressObjectType aot;
1904 addrbook.treeSelected = node;
1905 addrbook.listSelected = NULL;
1906 addressbook_status_show( "" );
1907 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1909 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1911 addressbook_set_clist(NULL, TRUE);
1914 addrbook.opened = node;
1916 if( obj->type == ADDR_DATASOURCE ) {
1917 /* Read from file */
1918 static gboolean tVal = TRUE;
1920 ads = ADAPTER_DSOURCE(obj);
1922 ds = ads->dataSource;
1923 if( ds == NULL ) return;
1925 if( addrindex_ds_get_modify_flag( ds ) ) {
1926 addrindex_ds_read_data( ds );
1929 if( ! addrindex_ds_get_read_flag( ds ) ) {
1930 addrindex_ds_read_data( ds );
1932 addressbook_ds_show_message( ds );
1934 if( ! addrindex_ds_get_access_flag( ds ) ) {
1935 /* Remove existing folders and groups */
1936 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1937 addressbook_tree_remove_children( ctree, node );
1938 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1940 /* Load folders into the tree */
1941 rootFolder = addrindex_ds_get_root_folder( ds );
1942 if( ds && ds->type == ADDR_IF_JPILOT ) {
1943 aot = ADDR_CATEGORY;
1945 else if( ds && ds->type == ADDR_IF_LDAP ) {
1946 aot = ADDR_LDAP_QUERY;
1949 aot = ADDR_ITEM_FOLDER;
1951 addressbook_node_add_folder( node, ds, rootFolder, aot );
1952 addrindex_ds_set_access_flag( ds, &tVal );
1953 gtk_cmctree_expand( ctree, node );
1956 addressbook_set_clist(NULL, TRUE);
1959 /* Update address list */
1960 g_signal_handlers_block_by_func
1962 G_CALLBACK(addressbook_tree_selected), NULL);
1963 addressbook_set_clist( obj, FALSE );
1964 g_signal_handlers_unblock_by_func
1966 G_CALLBACK(addressbook_tree_selected), NULL);
1967 if (!prefs_common.addressbook_use_editaddress_dialog)
1968 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1970 /* Setup main menu selections */
1971 addressbook_menubar_set_sensitive( FALSE );
1972 addressbook_menuitem_set_sensitive( obj, node );
1973 addressbook_list_select_clear();
1974 addressbook_list_menu_setup();
1979 * Setup address list popup menu items. Items are enabled or disabled as
1982 static void addressbook_list_menu_setup( void ) {
1983 GtkCMCTree *clist = NULL;
1984 AddressObject *pobj = NULL;
1985 AddressObject *obj = NULL;
1986 AdapterDSource *ads = NULL;
1987 AddressInterface *iface = NULL;
1988 AddressDataSource *ds = NULL;
1989 gboolean canEdit = FALSE;
1990 gboolean canDelete = FALSE;
1991 gboolean canCut = FALSE;
1992 gboolean canCopy = FALSE;
1993 gboolean canPaste = FALSE;
1994 gboolean canBrowse = FALSE;
1996 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1997 if( pobj == NULL ) return;
1999 clist = GTK_CMCTREE(addrbook.clist);
2000 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2001 if( obj == NULL ) canEdit = FALSE;
2003 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2004 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2006 if( pobj->type == ADDR_DATASOURCE ) {
2007 /* Parent object is a data source */
2008 ads = ADAPTER_DSOURCE(pobj);
2009 ds = ads->dataSource;
2012 iface = ds->interface;
2015 if( ! iface->readOnly ) {
2016 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2017 if (iface->type != ADDR_IF_LDAP)
2018 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2019 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2022 canDelete = canEdit;
2025 else if( pobj->type != ADDR_INTERFACE ) {
2026 /* Parent object is not an interface */
2027 ds = addressbook_find_datasource( addrbook.treeSelected );
2030 iface = ds->interface;
2033 if( ! iface->readOnly ) {
2034 /* Folder or group */
2035 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2036 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2037 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2038 if( obj ) canEdit = TRUE;
2041 if( pobj->type == ADDR_ITEM_FOLDER ) {
2042 if (iface->type != ADDR_IF_LDAP)
2043 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2044 if( obj ) canEdit = TRUE;
2046 canDelete = canEdit;
2048 if( iface->type == ADDR_IF_LDAP ) {
2049 if( obj ) canBrowse = TRUE;
2056 /* Enable cut and paste */
2057 if( ! addrclip_is_empty( _clipBoard_ ) )
2059 if( ! addrselect_test_empty( _addressSelect_ ) )
2061 /* Enable copy if something is selected */
2062 if( ! addrselect_test_empty( _addressSelect_ ) )
2066 /* Disable edit or browse if more than one row selected */
2067 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2072 /* Forbid write changes when read-only */
2073 if( iface && iface->readOnly ) {
2079 /* Now go finalize menu items */
2080 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2081 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2083 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2084 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2085 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2087 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2089 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2090 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2091 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2093 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2094 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2095 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2097 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2098 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2100 if (addrbook.target_compose) {
2101 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2102 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2103 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2106 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2110 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2111 GtkCMCTreeNode *node,
2118 * Add list of items into tree node below specified tree node.
2119 * \param treeNode Tree node.
2120 * \param ds Data source.
2121 * \param listItems List of items.
2123 static void addressbook_treenode_add_list(
2124 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2130 AddrItemObject *aio;
2134 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2137 group = ( ItemGroup * ) aio;
2138 nn = addressbook_node_add_group( treeNode, ds, group );
2140 g_message("error adding addressbook group\n");
2143 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2146 folder = ( ItemFolder * ) aio;
2147 nn = addressbook_node_add_folder(
2148 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2150 g_message("error adding addressbook folder\n");
2153 node = g_list_next( node );
2157 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2158 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2162 * Cut from address list widget.
2164 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2165 _clipBoard_->cutFlag = TRUE;
2166 addrclip_clear( _clipBoard_ );
2167 addrclip_add( _clipBoard_, _addressSelect_ );
2168 /* addrclip_list_show( _clipBoard_, stdout ); */
2172 * Copy from address list widget.
2174 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2175 _clipBoard_->cutFlag = FALSE;
2176 addrclip_clear( _clipBoard_ );
2177 addrclip_add( _clipBoard_, _addressSelect_ );
2178 /* addrclip_list_show( _clipBoard_, stdout ); */
2182 * Paste clipboard into address list widget.
2184 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2185 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2186 AddressObject *pobj = NULL;
2187 AddressDataSource *ds = NULL;
2188 AddressBookFile *abf = NULL;
2189 ItemFolder *folder = NULL;
2190 GList *folderGroup = NULL;
2192 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2193 if( ds == NULL ) return;
2194 if( addrindex_ds_get_readonly( ds ) ) {
2195 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2199 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2201 if( pobj->type == ADDR_ITEM_FOLDER ) {
2202 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2204 else if( pobj->type == ADDR_ITEM_GROUP ) {
2205 alertpanel_error( _("Cannot paste into an address group.") );
2210 /* Get an address book */
2211 abf = addressbook_get_book_file();
2212 if( abf == NULL ) return;
2214 if( _clipBoard_->cutFlag ) {
2216 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2218 /* Remove all groups and folders in clipboard from tree node */
2219 addressbook_treenode_remove_item();
2221 /* Remove all "cut" items */
2222 addrclip_delete_item( _clipBoard_ );
2224 /* Clear clipboard - cut items??? */
2225 addrclip_clear( _clipBoard_ );
2229 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2232 /* addrclip_list_show( _clipBoard_, stdout ); */
2234 /* Update tree by inserting node for each folder or group */
2235 addressbook_treenode_add_list(
2236 addrbook.treeSelected, ds, folderGroup );
2237 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2238 g_list_free( folderGroup );
2242 /* Display items pasted */
2243 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2244 addressbook_set_clist(
2245 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2253 * Add current treenode object to clipboard. Note that widget only allows
2254 * one entry from the tree list to be selected.
2256 static void addressbook_treenode_to_clipboard( void ) {
2257 AddressObject *obj = NULL;
2258 AddressDataSource *ds = NULL;
2259 AddrSelectItem *item;
2260 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2261 GtkCMCTreeNode *node;
2263 node = addrbook.treeSelected;
2264 if( node == NULL ) return;
2265 obj = gtk_cmctree_node_get_row_data( ctree, node );
2266 if( obj == NULL ) return;
2268 ds = addressbook_find_datasource( node );
2269 if( ds == NULL ) return;
2272 if( obj->type == ADDR_ITEM_FOLDER ) {
2273 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2274 ItemFolder *folder = adapter->itemFolder;
2276 item = addrselect_create_node( obj );
2277 item->uid = g_strdup( ADDRITEM_ID(folder) );
2279 else if( obj->type == ADDR_ITEM_GROUP ) {
2280 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2281 ItemGroup *group = adapter->itemGroup;
2283 item = addrselect_create_node( obj );
2284 item->uid = g_strdup( ADDRITEM_ID(group) );
2286 else if( obj->type == ADDR_DATASOURCE ) {
2288 item = addrselect_create_node( obj );
2293 /* Clear existing list and add item into list */
2296 addressbook_list_select_clear();
2297 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2298 addrselect_list_add( _addressSelect_, item, cacheID );
2304 * Cut from tree widget.
2306 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2307 _clipBoard_->cutFlag = TRUE;
2308 addressbook_treenode_to_clipboard();
2309 addrclip_clear( _clipBoard_ );
2310 addrclip_add( _clipBoard_, _addressSelect_ );
2311 /* addrclip_list_show( _clipBoard_, stdout ); */
2315 * Copy from tree widget.
2317 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2318 _clipBoard_->cutFlag = FALSE;
2319 addressbook_treenode_to_clipboard();
2320 addrclip_clear( _clipBoard_ );
2321 addrclip_add( _clipBoard_, _addressSelect_ );
2322 /* addrclip_list_show( _clipBoard_, stdout ); */
2326 * Paste clipboard into address tree widget.
2328 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2329 addressbook_clip_paste_cb(NULL,NULL);
2333 * Clear selected entries in clipboard.
2335 static void addressbook_list_select_clear( void ) {
2336 addrselect_list_clear( _addressSelect_ );
2340 * Add specified address item to selected address list.
2341 * \param aio Address item object.
2342 * \param ds Datasource.
2344 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2347 if( ds == NULL ) return;
2348 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2349 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2354 * Remove specified address item from selected address list.
2355 * \param aio Address item object.
2357 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2358 addrselect_list_remove( _addressSelect_, aio );
2362 * Invoke EMail compose window with addresses in selected address list.
2364 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2367 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2368 listAddress = addrselect_build_list( _addressSelect_ );
2369 compose_new_with_list( NULL, listAddress );
2370 mgu_free_dlist( listAddress );
2375 static void addressbook_list_row_selected( GtkCMCTree *clist,
2376 GtkCMCTreeNode *node,
2380 AddrItemObject *aio = NULL;
2381 AddressObject *pobj = NULL;
2382 AdapterDSource *ads = NULL;
2383 AddressDataSource *ds = NULL;
2385 addrbook.listSelected = node;
2387 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2388 if( pobj == NULL ) return;
2390 if( pobj->type == ADDR_DATASOURCE ) {
2391 ads = ADAPTER_DSOURCE(pobj);
2392 ds = ads->dataSource;
2394 else if( pobj->type != ADDR_INTERFACE ) {
2395 ds = addressbook_find_datasource( addrbook.treeSelected );
2398 aio = gtk_cmctree_node_get_row_data( clist, node );
2400 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2401 addressbook_list_select_add( aio, ds );
2404 addressbook_list_menu_setup();
2406 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2407 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2409 if (obj && obj->type != ADDR_ITEM_GROUP)
2410 addressbook_edit_address(NULL, 0, NULL, FALSE);
2414 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2415 GtkCMCTreeNode *node,
2419 AddrItemObject *aio;
2421 aio = gtk_cmctree_node_get_row_data( ctree, node );
2423 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2424 addressbook_list_select_remove( aio );
2427 if (!prefs_common.addressbook_use_editaddress_dialog)
2428 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2431 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2433 addressbook_lup_clicked(NULL, NULL);
2436 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2437 GdkEventButton *event,
2440 if( ! event ) return FALSE;
2442 addressbook_list_menu_setup();
2444 if( event->button == 3 ) {
2445 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2446 event->button, event->time );
2447 } else if (event->button == 1) {
2448 if (event->type == GDK_2BUTTON_PRESS) {
2449 if (prefs_common.add_address_by_click &&
2450 addrbook.target_compose)
2451 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2453 if (prefs_common.addressbook_use_editaddress_dialog)
2454 addressbook_edit_address_cb(NULL, NULL);
2456 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2457 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2458 if( obj && obj->type == ADDR_ITEM_GROUP )
2459 addressbook_edit_address_cb(NULL, NULL);
2467 static gboolean addressbook_list_button_released(GtkWidget *widget,
2468 GdkEventButton *event,
2474 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2475 GdkEventButton *event,
2478 GtkCMCList *clist = GTK_CMCLIST(ctree);
2480 AddressObject *obj = NULL;
2481 AdapterDSource *ads = NULL;
2482 AddressInterface *iface = NULL;
2483 AddressDataSource *ds = NULL;
2484 gboolean canEdit = FALSE;
2485 gboolean canDelete = FALSE;
2486 gboolean canCut = FALSE;
2487 gboolean canCopy = FALSE;
2488 gboolean canPaste = FALSE;
2489 gboolean canTreeCut = FALSE;
2490 gboolean canTreeCopy = FALSE;
2491 gboolean canTreePaste = FALSE;
2492 gboolean canLookup = FALSE;
2493 GtkCMCTreeNode *node = NULL;
2495 if( ! event ) return FALSE;
2496 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2498 if (event->button == 1) {
2499 if (event->type == GDK_2BUTTON_PRESS) {
2500 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2501 gtkut_clist_set_focus_row(clist, row);
2502 obj = gtk_cmclist_get_row_data( clist, row );
2507 if (obj->type == ADDR_ITEM_GROUP) {
2509 addressbook_treenode_edit_cb(NULL, NULL);
2511 /* expand pr collapse */
2512 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2513 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2519 addressbook_menubar_set_sensitive( FALSE );
2521 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2522 gtkut_clist_set_focus_row(clist, row);
2523 obj = gtk_cmclist_get_row_data( clist, row );
2526 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2530 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2532 if( ! addrclip_is_empty( _clipBoard_ ) )
2533 canTreePaste = TRUE;
2535 if (obj->type == ADDR_INTERFACE) {
2536 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2537 iface = adapter->interface;
2540 if( !iface->readOnly ) {
2541 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2542 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2544 if( iface->externalQuery )
2547 if (obj->type == ADDR_DATASOURCE) {
2549 ads = ADAPTER_DSOURCE(obj);
2550 ds = ads->dataSource;
2553 iface = ds->interface;
2556 if( !iface->readOnly ) {
2558 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2559 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2560 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2565 else if (obj->type == ADDR_ITEM_FOLDER) {
2567 ds = addressbook_find_datasource( node );
2570 iface = ds->interface;
2573 if( !iface->readOnly ) {
2577 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2578 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2579 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2583 if( iface->externalQuery ) {
2584 /* Enable deletion of LDAP folder */
2588 else if (obj->type == ADDR_ITEM_GROUP) {
2590 ds = addressbook_find_datasource( node );
2593 iface = ds->interface;
2596 if( ! iface->readOnly ) {
2599 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2600 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2604 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2606 if( ! addrselect_test_empty( _addressSelect_ ) )
2608 if( ! addrclip_is_empty( _clipBoard_ ) )
2611 /* Forbid write changes when read-only */
2612 if( iface && iface->readOnly ) {
2614 canTreePaste = FALSE;
2622 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2623 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2624 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2625 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2626 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2628 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2629 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2630 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2631 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2632 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2634 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2635 addrbook.target_compose != NULL);
2637 if( event->button == 3 )
2638 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2639 event->button, event->time);
2644 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2645 GdkEventButton *event,
2648 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2652 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2654 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2655 AddressObject *obj = NULL;
2656 AddressDataSource *ds = NULL;
2657 AddressBookFile *abf = NULL;
2658 ItemFolder *parentFolder = NULL;
2659 ItemFolder *folder = NULL;
2661 if( ! addrbook.treeSelected ) return;
2662 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2663 if( obj == NULL ) return;
2664 ds = addressbook_find_datasource( addrbook.treeSelected );
2665 if( ds == NULL ) return;
2667 if( obj->type == ADDR_DATASOURCE ) {
2668 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2670 else if( obj->type == ADDR_ITEM_FOLDER ) {
2671 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2677 abf = ds->rawDataSource;
2678 if( abf == NULL ) return;
2679 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2682 nn = addressbook_node_add_folder(
2683 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2685 g_message("error adding addressbook folder\n");
2687 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2688 if( addrbook.treeSelected == addrbook.opened )
2689 addressbook_set_clist(obj, TRUE);
2693 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2695 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2696 AddressObject *obj = NULL;
2697 AddressDataSource *ds = NULL;
2698 AddressBookFile *abf = NULL;
2699 ItemFolder *parentFolder = NULL;
2700 ItemGroup *group = NULL;
2702 if( ! addrbook.treeSelected ) return;
2703 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2704 if( obj == NULL ) return;
2705 ds = addressbook_find_datasource( addrbook.treeSelected );
2706 if( ds == NULL ) return;
2708 if( obj->type == ADDR_DATASOURCE ) {
2709 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2711 else if( obj->type == ADDR_ITEM_FOLDER ) {
2712 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2718 abf = ds->rawDataSource;
2719 if( abf == NULL ) return;
2720 group = addressbook_edit_group( abf, parentFolder, NULL );
2723 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2725 g_message("error adding addressbook group\n");
2727 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2728 if( addrbook.treeSelected == addrbook.opened )
2729 addressbook_set_clist(obj, TRUE);
2733 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2735 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2738 GdkPixbuf *pix_cl, *pix_op;
2739 gboolean is_leaf, expanded;
2741 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2743 &is_leaf, &expanded);
2744 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2751 * \param obj Address object to edit.
2752 * \param node Node in tree.
2753 * \return New name of data source.
2755 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2756 gchar *newName = NULL;
2757 AddressDataSource *ds = NULL;
2758 AddressInterface *iface = NULL;
2759 AdapterDSource *ads = NULL;
2761 ds = addressbook_find_datasource( node );
2762 if( ds == NULL ) return NULL;
2763 iface = ds->interface;
2764 if( ! iface->haveLibrary ) return NULL;
2766 /* Read data from data source */
2767 if( addrindex_ds_get_modify_flag( ds ) ) {
2768 addrindex_ds_read_data( ds );
2771 if( ! addrindex_ds_get_read_flag( ds ) ) {
2772 addrindex_ds_read_data( ds );
2776 ads = ADAPTER_DSOURCE(obj);
2777 if( ads->subType == ADDR_BOOK ) {
2778 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2780 else if( ads->subType == ADDR_VCARD ) {
2781 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2784 else if( ads->subType == ADDR_JPILOT ) {
2785 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2789 else if( ads->subType == ADDR_LDAP ) {
2790 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2796 newName = obj->name;
2801 * Edit an object that is in the address tree area.
2803 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2805 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2807 AddressDataSource *ds = NULL;
2808 AddressBookFile *abf = NULL;
2809 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2812 if( ! addrbook.treeSelected ) return;
2813 node = addrbook.treeSelected;
2814 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2815 obj = gtk_cmctree_node_get_row_data( ctree, node );
2816 if( obj == NULL ) return;
2817 parentNode = GTK_CMCTREE_ROW(node)->parent;
2819 ds = addressbook_find_datasource( node );
2820 if( ds == NULL ) return;
2822 if( obj->type == ADDR_DATASOURCE ) {
2823 name = addressbook_edit_datasource( obj, node );
2824 if( name == NULL ) return;
2827 abf = ds->rawDataSource;
2828 if( abf == NULL ) return;
2829 if( obj->type == ADDR_ITEM_FOLDER ) {
2830 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2831 ItemFolder *item = adapter->itemFolder;
2832 ItemFolder *parentFolder = NULL;
2833 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2834 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2835 name = ADDRITEM_NAME(item);
2837 else if( obj->type == ADDR_ITEM_GROUP ) {
2838 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2839 ItemGroup *item = adapter->itemGroup;
2840 ItemFolder *parentFolder = NULL;
2841 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2842 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2843 name = ADDRITEM_NAME(item);
2846 if( name && parentNode ) {
2847 /* Update node in tree view */
2848 addressbook_change_node_name( node, name );
2849 gtk_sctree_sort_node(ctree, parentNode);
2850 gtk_cmctree_expand( ctree, node );
2851 gtk_sctree_select( GTK_SCTREE( ctree), node );
2858 ADDRTREE_DEL_FOLDER_ONLY,
2859 ADDRTREE_DEL_FOLDER_ADDR
2863 * Delete an item from the tree widget.
2864 * \param data Data passed in.
2865 * \param action Action.
2866 * \param widget Widget issuing callback.
2868 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2870 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2871 GtkCMCTreeNode *node = NULL;
2875 AddrBookBase *adbase;
2876 AddressCache *cache;
2877 AdapterDSource *ads = NULL;
2878 AddressInterface *iface = NULL;
2879 AddressDataSource *ds = NULL;
2880 gboolean remFlag = FALSE;
2881 TreeItemDelType delType;
2883 if( ! addrbook.treeSelected ) return;
2884 node = addrbook.treeSelected;
2885 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2887 obj = gtk_cmctree_node_get_row_data( ctree, node );
2888 cm_return_if_fail(obj != NULL);
2890 if( obj->type == ADDR_DATASOURCE ) {
2891 ads = ADAPTER_DSOURCE(obj);
2893 ds = ads->dataSource;
2894 if( ds == NULL ) return;
2897 /* Must be folder or something else */
2898 ds = addressbook_find_datasource( node );
2899 if( ds == NULL ) return;
2901 /* Only allow deletion from non-readOnly */
2902 iface = ds->interface;
2903 if( iface->readOnly ) {
2904 /* Allow deletion of query results */
2905 if( ! iface->externalQuery ) return;
2909 /* Confirm deletion */
2910 delType = ADDRTREE_DEL_NONE;
2911 if( obj->type == ADDR_ITEM_FOLDER ) {
2912 if( iface && iface->externalQuery ) {
2913 message = g_strdup_printf( _(
2914 "Do you want to delete the query " \
2915 "results and addresses in '%s'?" ),
2917 aval = alertpanel( _("Delete"), message,
2918 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2920 if( aval == G_ALERTALTERNATE ) {
2921 delType = ADDRTREE_DEL_FOLDER_ADDR;
2925 message = g_strdup_printf
2926 ( _( "Do you want to delete '%s'? "
2927 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2929 aval = alertpanel( _("Delete folder"), message,
2930 GTK_STOCK_CANCEL, g_strconcat("+",_("Delete _folder only"), NULL), _("Delete folder and _addresses"));
2932 if( aval == G_ALERTALTERNATE ) {
2933 delType = ADDRTREE_DEL_FOLDER_ONLY;
2935 else if( aval == G_ALERTOTHER ) {
2936 delType = ADDRTREE_DEL_FOLDER_ADDR;
2940 else if( obj->type == ADDR_ITEM_GROUP ) {
2941 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2942 "The addresses it contains will not be lost."), obj->name);
2943 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2944 "+" GTK_STOCK_DELETE, NULL);
2946 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2948 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2949 "The addresses it contains will be lost."), obj->name);
2950 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2951 "+" GTK_STOCK_DELETE, NULL);
2953 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2955 if( delType == ADDRTREE_DEL_NONE ) return;
2957 /* Proceed with deletion */
2958 if( obj->type == ADDR_DATASOURCE ) {
2959 /* Remove node from tree */
2960 gtk_cmctree_remove_node( ctree, node );
2962 if (delType == ADDRTREE_DEL_DATA &&
2963 ds->interface && ds->interface->type == ADDR_IF_BOOK)
2964 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
2966 /* Remove data source. */
2967 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2968 addrindex_free_datasource( ds );
2973 /* Get reference to cache */
2974 adbase = ( AddrBookBase * ) ds->rawDataSource;
2975 if( adbase == NULL ) return;
2976 cache = adbase->addressCache;
2978 /* Remove query results folder */
2979 if( iface && iface->externalQuery ) {
2980 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2981 ItemFolder *folder = adapter->itemFolder;
2983 adapter->itemFolder = NULL;
2985 g_print( "remove folder for ::%s::\n", obj->name );
2986 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2987 g_print( "-------------- remove results\n" );
2989 addrindex_remove_results( ds, folder );
2990 /* g_print( "-------------- remove node\n" ); */
2991 gtk_cmctree_remove_node( ctree, node );
2995 /* Code below is valid for regular address book deletion */
2996 if( obj->type == ADDR_ITEM_FOLDER ) {
2997 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2998 ItemFolder *item = adapter->itemFolder;
3000 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3001 /* Remove folder only */
3002 item = addrcache_remove_folder( cache, item );
3004 addritem_free_item_folder( item );
3005 addressbook_move_nodes_up( ctree, node );
3009 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3010 /* Remove folder and addresses */
3011 item = addrcache_remove_folder_delete( cache, item );
3013 addritem_free_item_folder( item );
3018 else if( obj->type == ADDR_ITEM_GROUP ) {
3019 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3020 ItemGroup *item = adapter->itemGroup;
3022 item = addrcache_remove_group( cache, item );
3024 addritem_free_item_group( item );
3031 gtk_cmctree_remove_node(ctree, node );
3035 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3037 if( person && addrbook.treeSelected == addrbook.opened ) {
3038 person->status = ADD_ENTRY;
3039 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3040 addressbook_folder_refresh_one_person(
3041 GTK_CMCTREE(addrbook.clist), person );
3043 addressbook_address_list_set_focus();
3046 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3048 if( person && addrbook.treeSelected == addrbook.opened) {
3049 person->status = ADD_ENTRY;
3050 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3051 addressbook_set_clist(
3052 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3056 addressbook_address_list_set_focus();
3060 * Label (a format string) that is used to name each folder.
3062 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3065 * Search ctree widget callback function.
3066 * \param pA Pointer to node.
3067 * \param pB Pointer to data item being sought.
3068 * \return Zero (0) if folder found.
3070 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3073 aoA = ( AddressObject * ) pA;
3074 if( aoA->type == ADDR_ITEM_FOLDER ) {
3075 ItemFolder *folder, *fld;
3077 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3078 folder = ( ItemFolder * ) pB;
3079 if( fld == folder ) return 0; /* Found folder */
3084 static ItemFolder * addressbook_setup_subf(
3085 AddressDataSource *ds, gchar *title,
3086 GtkCMCTreeNode *pNode )
3088 AddrBookBase *adbase;
3089 AddressCache *cache;
3092 GtkCMCTreeNode *nNode;
3094 AddressObjectType aoType = ADDR_NONE;
3097 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3099 if( ds && ds->type == ADDR_IF_LDAP ) {
3101 aoType = ADDR_LDAP_QUERY;
3108 ctree = GTK_CMCTREE(addrbook.ctree);
3109 /* Get reference to address cache */
3110 adbase = ( AddrBookBase * ) ds->rawDataSource;
3111 cache = adbase->addressCache;
3113 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3114 GList *cur = children;
3115 for (; cur; cur = cur->next) {
3116 ItemFolder *child = (ItemFolder *) cur->data;
3117 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3118 nNode = gtk_cmctree_find_by_row_data_custom(
3120 addressbook_treenode_find_folder_cb );
3122 addrindex_remove_results( ds, child );
3123 while( child->listPerson ) {
3124 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3125 item = addrcache_remove_person( cache, item );
3127 addritem_free_item_person( item );
3131 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3132 addrbook.treeSelected = nNode;
3139 /* Create a folder */
3140 folder = addrcache_add_new_folder( cache, NULL );
3141 name = g_strdup_printf( "%s", title );
3142 addritem_folder_set_name( folder, name );
3143 addritem_folder_set_remarks( folder, "" );
3146 /* Now let's see the folder */
3147 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3148 gtk_cmctree_expand( ctree, pNode );
3150 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3151 addrbook.treeSelected = nNode;
3157 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3158 AddressObject *pobj = NULL;
3159 AddressDataSource *ds = NULL;
3160 AddressBookFile *abf = NULL;
3161 debug_print("adding address\n");
3162 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3163 if( pobj == NULL ) {
3164 debug_print("no row data\n");
3167 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3169 debug_print("no datasource\n");
3173 abf = ds->rawDataSource;
3175 g_print("no addressbook file\n");
3179 if( pobj->type == ADDR_DATASOURCE ) {
3180 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3181 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3183 ItemFolder *folder = NULL;
3185 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3186 GtkCMCTreeNode *parentNode;
3187 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3188 if( ds == NULL ) return;
3190 /* We must have a datasource that is an external interface */
3191 if( ! ds->interface->haveLibrary ) return;
3192 if( ! ds->interface->externalQuery ) return;
3194 if( pobj->type == ADDR_ITEM_FOLDER ) {
3195 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3198 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3200 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3202 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3204 abf = ds->rawDataSource;
3207 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3208 addrbook.editaddress_vbox,
3209 addressbook_new_address_from_book_post_cb,
3212 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3213 LdapServer *server = ds->rawDataSource;
3214 ldapsvr_set_modified(server, TRUE);
3215 ldapsvr_update_book(server, NULL);
3216 if (server->retVal != LDAPRC_SUCCESS) {
3217 alertpanel( _("Add address(es)"),
3218 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3219 GTK_STOCK_CLOSE, NULL, NULL );
3220 server->retVal = LDAPRC_SUCCESS;
3225 if (prefs_common.addressbook_use_editaddress_dialog)
3226 addressbook_new_address_from_book_post_cb( person );
3229 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3231 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3234 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3235 GtkCMCTreeNode *parentNode;
3236 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3237 if( ds == NULL ) return;
3239 /* We must have a datasource that is an external interface */
3240 if( ! ds->interface->haveLibrary ) return;
3241 if( ! ds->interface->externalQuery ) return;
3243 if( pobj->type == ADDR_ITEM_FOLDER ) {
3244 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3247 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3249 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3253 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3255 abf = ds->rawDataSource;
3258 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3259 addrbook.editaddress_vbox,
3260 addressbook_new_address_from_folder_post_cb,
3263 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3264 LdapServer *server = ds->rawDataSource;
3265 ldapsvr_set_modified(server, TRUE);
3266 ldapsvr_update_book(server, NULL);
3267 if (server->retVal != LDAPRC_SUCCESS) {
3268 alertpanel( _("Add address(es)"),
3269 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3270 GTK_STOCK_CLOSE, NULL, NULL );
3275 if (prefs_common.addressbook_use_editaddress_dialog)
3276 addressbook_new_address_from_folder_post_cb( person );
3278 else if( pobj->type == ADDR_ITEM_GROUP ) {
3279 /* New address in group */
3280 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3281 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3282 if (addrbook.treeSelected == addrbook.opened) {
3283 /* Change node name in tree. */
3284 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3285 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3286 addressbook_set_clist(
3287 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3295 * Search for specified child group node in address index tree.
3296 * \param parent Parent node.
3297 * \param group Group to find.
3299 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3300 GtkCMCTreeNode *node = NULL;
3301 GtkCMCTreeRow *currRow;
3303 currRow = GTK_CMCTREE_ROW( parent );
3305 node = currRow->children;
3309 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3310 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3311 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3312 if( g == group ) return node;
3314 currRow = GTK_CMCTREE_ROW(node);
3315 node = currRow->sibling;
3321 static AddressBookFile *addressbook_get_book_file() {
3322 AddressBookFile *abf = NULL;
3323 AddressDataSource *ds = NULL;
3325 ds = addressbook_find_datasource( addrbook.treeSelected );
3326 if( ds == NULL ) return NULL;
3327 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3331 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3332 GtkCMCTreeNode *node;
3335 /* Remove existing folders and groups */
3336 row = GTK_CMCTREE_ROW( parent );
3338 while( (node = row->children) ) {
3339 gtk_cmctree_remove_node( ctree, node );
3344 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3345 GtkCMCTreeNode *parent, *child;
3346 GtkCMCTreeRow *currRow;
3347 currRow = GTK_CMCTREE_ROW( node );
3349 parent = currRow->parent;
3350 while( (child = currRow->children) ) {
3351 gtk_cmctree_move( ctree, child, parent, node );
3353 gtk_sctree_sort_node( ctree, parent );
3357 static void addressbook_edit_address_post_cb( ItemPerson *person )
3361 AddressBookFile *abf = addressbook_get_book_file();
3363 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3364 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3365 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3368 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3369 invalidate_address_completion();
3371 addressbook_address_list_set_focus();
3374 void addressbook_address_list_set_focus( void )
3376 if (!prefs_common.addressbook_use_editaddress_dialog) {
3377 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3378 addressbook_list_menu_setup();
3382 void addressbook_address_list_disable_some_actions(void)
3384 /* disable address copy/pasting when editing contact's detail (embedded form) */
3385 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3386 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3387 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3390 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3391 addressbook_edit_address(data, 0, NULL, TRUE);
3394 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3395 gboolean force_focus ) {
3396 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3398 AddressObject *obj = NULL, *pobj = NULL;
3399 AddressDataSource *ds = NULL;
3400 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3402 AddressBookFile *abf = NULL;
3404 if( addrbook.listSelected == NULL ) return;
3405 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3406 cm_return_if_fail(obj != NULL);
3408 ctree = GTK_CMCTREE( addrbook.ctree );
3409 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3411 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3412 if( ds == NULL ) return;
3414 abf = addressbook_get_book_file();
3416 if( obj->type == ADDR_ITEM_EMAIL ) {
3417 ItemEMail *email = ( ItemEMail * ) obj;
3419 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3420 /* Edit parent group */
3421 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3422 ItemGroup *itemGrp = adapter->itemGroup;
3423 if( abf == NULL ) return;
3424 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3425 name = ADDRITEM_NAME(itemGrp);
3426 node = addrbook.treeSelected;
3427 parentNode = GTK_CMCTREE_ROW(node)->parent;
3430 /* Edit person - email page */
3432 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3433 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3434 addressbook_edit_address_post_cb,
3435 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3438 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3439 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3440 person->status = UPDATE_ENTRY;
3443 if (prefs_common.addressbook_use_editaddress_dialog)
3444 addressbook_edit_address_post_cb( person );
3449 else if( obj->type == ADDR_ITEM_PERSON ) {
3450 /* Edit person - basic page */
3451 ItemPerson *person = ( ItemPerson * ) obj;
3452 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3453 addressbook_edit_address_post_cb,
3454 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3457 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3458 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3459 person->status = UPDATE_ENTRY;
3462 if (prefs_common.addressbook_use_editaddress_dialog)
3463 addressbook_edit_address_post_cb( person );
3467 else if( obj->type == ADDR_ITEM_GROUP ) {
3468 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3469 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3470 parentNode = addrbook.treeSelected;
3471 node = addressbook_find_group_node( parentNode, itemGrp );
3472 name = ADDRITEM_NAME(itemGrp);
3473 invalidate_address_completion();
3479 /* Update tree node with node name */
3480 if( node == NULL ) return;
3481 addressbook_change_node_name( node, name );
3482 gtk_sctree_sort_node( ctree, parentNode );
3483 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3484 addressbook_set_clist(
3485 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3490 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3492 addressbook_del_clicked(NULL, NULL);
3495 static void close_cb(GtkAction *action, gpointer data)
3497 addressbook_close();
3500 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3501 addressbook_export_to_file();
3504 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3506 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3507 if( person ) addritem_person_set_opened( person, TRUE );
3511 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3513 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3514 if( person ) addritem_person_set_opened( person, FALSE );
3518 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3520 gchar *eMailAlias = ADDRITEM_NAME(email);
3521 if( eMailAlias && *eMailAlias != '\0' ) {
3523 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3526 str = g_strdup( eMailAlias );
3532 static gboolean addressbook_match_item(const gchar *name,
3533 const gchar *email_alias,
3535 const gchar *remarks,
3540 if (!str || str[0] == '\0')
3542 if (strcasestr(name, str))
3544 else if (email_alias && strcasestr(email_alias, str))
3546 else if (addr && strcasestr(addr, str))
3548 else if (remarks && strcasestr(remarks, str))
3554 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3555 GList *items = itemGroup->listEMail;
3556 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3557 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3558 for( ; items != NULL; items = g_list_next( items ) ) {
3559 GtkCMCTreeNode *nodeEMail = NULL;
3560 gchar *text[N_LIST_COLS];
3561 ItemEMail *email = items->data;
3565 if( ! email ) continue;
3567 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3569 if( !addressbook_match_item(ADDRITEM_NAME(person),
3570 ADDRITEM_NAME(email),
3571 email->address, email->remarks,
3575 str = addressbook_format_item_clist( person, email );
3577 text[COL_NAME] = addressbook_set_col_name_guard(str);
3580 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3582 text[COL_ADDRESS] = email->address;
3583 text[COL_REMARKS] = email->remarks;
3584 nodeEMail = gtk_sctree_insert_node(
3586 text, FOLDER_SPACING,
3590 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3596 gchar *addressbook_set_col_name_guard(gchar *value)
3598 gchar *ret = "<not set>";
3599 gchar *tmp = g_strdup(value);
3601 if (tmp !=NULL && *tmp != '\0')
3607 static void addressbook_folder_load_one_person(
3608 GtkCMCTree *clist, ItemPerson *person,
3609 AddressTypeControlItem *atci,
3610 AddressTypeControlItem *atciMail )
3612 GtkCMCTreeNode *nodePerson = NULL;
3613 GtkCMCTreeNode *nodeEMail = NULL;
3614 gchar *text[N_LIST_COLS];
3615 gboolean flgFirst = TRUE, haveAddr = FALSE;
3618 AddressBookFile *abf = addressbook_get_book_file();
3621 if( person == NULL ) return;
3623 text[COL_NAME] = "";
3624 node = person->listEMail;
3626 ItemEMail *email = node->data;
3627 gchar *eMailAddr = NULL;
3628 node = g_list_next( node );
3630 text[COL_ADDRESS] = email->address;
3631 text[COL_REMARKS] = email->remarks;
3632 eMailAddr = ADDRITEM_NAME(email);
3633 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3635 /* First email belongs with person */
3636 gchar *str = addressbook_format_item_clist( person, email );
3638 text[COL_NAME] = addressbook_set_col_name_guard(str);
3641 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3642 person && person->nickName ) {
3643 if (person->nickName) {
3644 if (strcmp(person->nickName, "") != 0) {
3645 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3648 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3654 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3656 nodePerson = gtk_sctree_insert_node(
3658 text, FOLDER_SPACING,
3661 FALSE, person->isOpened );
3664 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3667 /* Subsequent email is a child node of person */
3668 text[COL_NAME] = ADDRITEM_NAME(email);
3669 nodeEMail = gtk_sctree_insert_node(
3670 clist, nodePerson, NULL,
3671 text, FOLDER_SPACING,
3673 atciMail->iconXpmOpen,
3675 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3681 /* Have name without EMail */
3682 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3683 text[COL_ADDRESS] = "";
3684 text[COL_REMARKS] = "";
3685 nodePerson = gtk_sctree_insert_node(
3687 text, FOLDER_SPACING,
3690 FALSE, person->isOpened );
3691 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3696 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3698 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3699 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3700 const gchar *search_str;
3702 if( atci == NULL ) return;
3703 if( atciMail == NULL ) return;
3705 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3707 /* Load email addresses */
3708 items = addritem_folder_get_person_list( itemFolder );
3709 for( ; items != NULL; items = g_list_next( items ) ) {
3714 person = (ItemPerson *)items->data;
3717 node = person->listEMail;
3718 if (node && node->data) {
3720 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3723 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3727 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3729 /* Free up the list */
3730 mgu_clear_list( items );
3731 g_list_free( items );
3734 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3735 addrbook.listSelected = NULL;
3736 gtk_cmctree_remove_node( clist, node );
3737 addressbook_menubar_set_sensitive( FALSE );
3738 addressbook_menuitem_set_sensitive(
3739 gtk_cmctree_node_get_row_data(
3740 GTK_CMCTREE(clist), addrbook.treeSelected ),
3741 addrbook.treeSelected );
3744 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3745 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3746 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3747 GtkCMCTreeNode *node;
3748 if( atci == NULL ) return;
3749 if( atciMail == NULL ) return;
3750 if( person == NULL ) return;
3751 /* unload the person */
3753 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3755 addressbook_folder_remove_node( clist, node );
3756 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3757 gtk_sctree_sort_node( clist, NULL );
3758 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3760 gtk_sctree_select( GTK_SCTREE(clist), node );
3761 if (!gtk_cmctree_node_is_visible( clist, node ) )
3762 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3766 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3767 GtkCMCTreeNode *node;
3769 if( person == NULL ) return;
3770 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3772 addressbook_folder_remove_node( clist, node );
3776 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3778 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3779 const gchar *search_str;
3781 /* Load any groups */
3782 if( ! atci ) return;
3784 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3786 items = addritem_folder_get_group_list( itemFolder );
3787 for( ; items != NULL; items = g_list_next( items ) ) {
3788 GtkCMCTreeNode *nodeGroup = NULL;
3789 gchar *text[N_LIST_COLS];
3790 ItemGroup *group = items->data;
3791 if( group == NULL ) continue;
3792 if( !addressbook_match_item(ADDRITEM_NAME(group),
3793 NULL, NULL, NULL, search_str) )
3796 text[COL_NAME] = ADDRITEM_NAME(group);
3797 text[COL_ADDRESS] = "";
3798 text[COL_REMARKS] = "";
3799 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3800 text, FOLDER_SPACING,
3804 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3805 gtk_sctree_sort_node(clist, NULL);
3807 /* Free up the list */
3808 mgu_clear_list( items );
3809 g_list_free( items );
3813 * Search ctree widget callback function.
3814 * \param pA Pointer to node.
3815 * \param pB Pointer to data item being sought.
3816 * \return Zero (0) if group found.
3818 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3821 aoA = ( AddressObject * ) pA;
3822 if( aoA->type == ADDR_ITEM_GROUP ) {
3823 ItemGroup *group, *grp;
3825 grp = ADAPTER_GROUP(aoA)->itemGroup;
3826 group = ( ItemGroup * ) pB;
3827 if( grp == group ) return 0; /* Found group */
3833 * Remove folder and group nodes from tree widget for items contained ("cut")
3836 static void addressbook_treenode_remove_item( void ) {
3838 AddrSelectItem *cutItem;
3839 AddressCache *cache;
3840 AddrItemObject *aio;
3841 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3844 node = _clipBoard_->objectList;
3846 cutItem = node->data;
3847 node = g_list_next( node );
3848 cache = addrindex_get_cache(
3849 _clipBoard_->addressIndex, cutItem->cacheID );
3850 if( cache == NULL ) continue;
3851 aio = addrcache_get_object( cache, cutItem->uid );
3854 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3857 folder = ( ItemFolder * ) aio;
3858 tn = gtk_cmctree_find_by_row_data_custom(
3859 ctree, NULL, folder,
3860 addressbook_treenode_find_folder_cb );
3862 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3865 group = ( ItemGroup * ) aio;
3866 tn = gtk_cmctree_find_by_row_data_custom(
3868 addressbook_treenode_find_group_cb );
3872 /* Free up adapter and remove node. */
3873 gtk_cmctree_remove_node( ctree, tn );
3880 * Find parent datasource for specified tree node.
3881 * \param node Node to test.
3882 * \return Data source, or NULL if not found.
3884 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3885 AddressDataSource *ds = NULL;
3888 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3891 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3892 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3894 /* g_print( "ao->type = %d\n", ao->type ); */
3895 if( ao->type == ADDR_DATASOURCE ) {
3896 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3897 /* g_print( "found it\n" ); */
3898 ds = ads->dataSource;
3902 node = GTK_CMCTREE_ROW(node)->parent;
3908 * Load address list widget with children of specified object.
3909 * \param obj Parent object to be loaded.
3911 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3912 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3913 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3914 AddressDataSource *ds = NULL;
3915 AdapterDSource *ads = NULL;
3916 static AddressObject *last_obj = NULL;
3918 if (addrbook.clist == NULL) {
3921 if (obj == last_obj && !refresh)
3926 gtk_cmclist_clear(clist);
3930 if( obj->type == ADDR_INTERFACE ) {
3931 /* g_print( "set_clist: loading datasource...\n" ); */
3932 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3936 gtk_cmclist_freeze(clist);
3937 gtk_cmclist_clear(clist);
3939 if( obj->type == ADDR_DATASOURCE ) {
3940 ads = ADAPTER_DSOURCE(obj);
3941 ds = ads->dataSource;
3943 /* Load root folder */
3944 ItemFolder *rootFolder = NULL;
3945 rootFolder = addrindex_ds_get_root_folder( ds );
3946 addressbook_folder_load_person(
3947 ctreelist, rootFolder );
3948 addressbook_folder_load_group(
3949 ctreelist, rootFolder );
3953 if( obj->type == ADDR_ITEM_GROUP ) {
3955 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3956 addressbook_load_group( ctreelist, itemGroup );
3958 else if( obj->type == ADDR_ITEM_FOLDER ) {
3960 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3961 addressbook_folder_load_person( ctreelist, itemFolder );
3962 addressbook_folder_load_group( ctreelist, itemFolder );
3965 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3966 clist->focus_row = -1;
3967 gtk_cmclist_thaw(clist);
3971 * Call back function to free adaptor. Call back is setup by function
3972 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3973 * called when the address book tree widget node is removed by calling
3974 * function gtk_cmctree_remove_node().
3976 * \param data Tree node's row data.
3978 static void addressbook_free_treenode( gpointer data ) {
3981 ao = ( AddressObject * ) data;
3982 if( ao == NULL ) return;
3983 if( ao->type == ADDR_INTERFACE ) {
3984 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3985 addrbookctl_free_interface( ai );
3987 else if( ao->type == ADDR_DATASOURCE ) {
3988 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3989 addrbookctl_free_datasource( ads );
3991 else if( ao->type == ADDR_ITEM_FOLDER ) {
3992 AdapterFolder *af = ADAPTER_FOLDER(ao);
3993 addrbookctl_free_folder( af );
3995 else if( ao->type == ADDR_ITEM_GROUP ) {
3996 AdapterGroup *ag = ADAPTER_GROUP(ao);
3997 addrbookctl_free_group( ag );
4002 * Create new adaptor for specified data source.
4004 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4005 AddressObjectType otype, gchar *name )
4007 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4008 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4009 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4010 adapter->dataSource = ds;
4011 adapter->subType = otype;
4015 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4016 ADDRESS_OBJECT_NAME(adapter) =
4017 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4021 * Load tree from address index with the initial data.
4023 static void addressbook_load_tree( void ) {
4024 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4025 GList *nodeIf, *nodeDS;
4026 AdapterInterface *adapter;
4027 AddressInterface *iface;
4028 AddressTypeControlItem *atci;
4029 AddressDataSource *ds;
4030 AdapterDSource *ads;
4031 GtkCMCTreeNode *node, *newNode;
4034 nodeIf = _addressInterfaceList_;
4036 adapter = nodeIf->data;
4037 node = adapter->treeNode;
4038 iface = adapter->interface;
4039 atci = adapter->atci;
4041 if( iface->useInterface ) {
4042 /* Load data sources below interface node */
4043 nodeDS = iface->listSource;
4046 name = addrindex_ds_get_name( ds );
4047 ads = addressbook_create_ds_adapter(
4048 ds, atci->objectType, name );
4049 newNode = addressbook_add_object(
4050 node, ADDRESS_OBJECT(ads) );
4051 if (newNode == NULL) {
4052 g_message("error adding addressbook object\n");
4054 nodeDS = g_list_next( nodeDS );
4056 gtk_cmctree_expand( ctree, node );
4059 nodeIf = g_list_next( nodeIf );
4064 * Convert the old address book to new format.
4066 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4067 gboolean retVal = FALSE;
4068 gboolean errFlag = TRUE;
4071 /* Read old address book, performing conversion */
4072 debug_print( "Reading and converting old address book...\n" );
4073 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4074 addrindex_read_data( addrIndex );
4075 if( addrIndex->retVal == MGU_NO_FILE ) {
4076 /* We do not have a file - new user */
4077 debug_print( "New user... create new books...\n" );
4078 addrindex_create_new_books( addrIndex );
4079 if( addrIndex->retVal == MGU_SUCCESS ) {
4080 /* Save index file */
4081 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4082 addrindex_save_data( addrIndex );
4083 if( addrIndex->retVal == MGU_SUCCESS ) {
4088 msg = _( "New user, could not save index file." );
4092 msg = _( "New user, could not save address book files." );
4096 /* We have an old file */
4097 if( addrIndex->wasConverted ) {
4098 /* Converted successfully - save address index */
4099 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4100 addrindex_save_data( addrIndex );
4101 if( addrIndex->retVal == MGU_SUCCESS ) {
4102 msg = _( "Old address book converted successfully." );
4107 msg = _("Old address book converted,\n"
4108 "could not save new address index file." );
4112 /* File conversion failed - just create new books */
4113 debug_print( "File conversion failed... just create new books...\n" );
4114 addrindex_create_new_books( addrIndex );
4115 if( addrIndex->retVal == MGU_SUCCESS ) {
4117 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4118 addrindex_save_data( addrIndex );
4119 if( addrIndex->retVal == MGU_SUCCESS ) {
4120 msg = _("Could not convert address book,\n"
4121 "but created empty new address book files." );
4126 msg = _("Could not convert address book,\n"
4127 "could not save new address index file." );
4131 msg = _("Could not convert address book\n"
4132 "and could not create new address book files." );
4137 debug_print( "Error\n%s\n", msg );
4138 alertpanel_full(_("Addressbook conversion error"), msg,
4139 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4140 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4143 debug_print( "Warning\n%s\n", msg );
4144 alertpanel_full(_("Addressbook conversion error"), msg,
4145 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4146 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4152 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4156 gboolean failed = FALSE;
4157 GError *error = NULL;
4159 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4160 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4161 error->code, error->message);
4162 g_error_free(error);
4166 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4167 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4170 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4172 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4174 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4187 /* all copies succeeded, we can remove source files */
4188 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4189 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4190 error->code, error->message);
4191 g_error_free(error);
4194 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4195 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4198 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4200 claws_unlink(orig_file);
4210 void addressbook_read_file( void ) {
4211 AddressIndex *addrIndex = NULL;
4212 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4214 debug_print( "Reading address index...\n" );
4215 if( _addressIndex_ ) {
4216 debug_print( "address book already read!!!\n" );
4220 addrIndex = addrindex_create_index();
4221 addrindex_initialize();
4223 /* Use new address book index. */
4225 if ( !is_dir_exist(indexdir) ) {
4226 if ( make_dir(indexdir) < 0 ) {
4227 addrindex_set_file_path( addrIndex, get_rc_dir() );
4228 g_warning( "couldn't create dir '%s'", indexdir);
4230 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4231 remove_dir_recursive(indexdir);
4232 addrindex_set_file_path( addrIndex, get_rc_dir() );
4233 g_error("couldn't migrate dir %s", indexdir);
4235 addrindex_set_file_path( addrIndex, indexdir);
4239 addrindex_set_file_path( addrIndex, indexdir);
4242 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4243 addrindex_read_data( addrIndex );
4244 if( addrIndex->retVal == MGU_NO_FILE ) {
4245 /* Conversion required */
4246 debug_print( "Converting...\n" );
4247 if( addressbook_convert( addrIndex ) ) {
4248 _addressIndex_ = addrIndex;
4251 else if( addrIndex->retVal == MGU_SUCCESS ) {
4252 _addressIndex_ = addrIndex;
4255 /* Error reading address book */
4256 debug_print( "Could not read address index.\n" );
4257 addrindex_print_index( addrIndex, stdout );
4258 alertpanel_full(_("Addressbook Error"),
4259 _("Could not read address index"),
4260 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4261 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4263 debug_print( "done.\n" );
4267 * Add object into the address index tree widget.
4268 * Enter: node Parent node.
4269 * obj Object to add.
4270 * Return: Node that was added, or NULL if object not added.
4272 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4275 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4276 GtkCMCTreeNode *added;
4277 AddressObject *pobj;
4278 AddressObjectType otype;
4279 AddressTypeControlItem *atci = NULL;
4281 cm_return_val_if_fail(node != NULL, NULL);
4282 cm_return_val_if_fail(obj != NULL, NULL);
4284 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4285 cm_return_val_if_fail(pobj != NULL, NULL);
4287 /* Determine object type to be displayed */
4288 if( obj->type == ADDR_DATASOURCE ) {
4289 otype = ADAPTER_DSOURCE(obj)->subType;
4295 /* Handle any special conditions. */
4297 atci = addrbookctl_lookup( otype );
4299 if( atci->showInTree ) {
4300 /* Add object to tree */
4303 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4304 atci->iconXpm, atci->iconXpmOpen,
4305 atci->treeLeaf, atci->treeExpand );
4306 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4307 addressbook_free_treenode );
4311 gtk_sctree_sort_node(ctree, node);
4317 * Add group into the address index tree.
4318 * \param node Parent node.
4319 * \param ds Data source.
4320 * \param itemGroup Group to add.
4321 * \return Inserted node.
4323 static GtkCMCTreeNode *addressbook_node_add_group(
4324 GtkCMCTreeNode *node, AddressDataSource *ds,
4325 ItemGroup *itemGroup )
4327 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4328 GtkCMCTreeNode *newNode;
4329 AdapterGroup *adapter;
4330 AddressTypeControlItem *atci = NULL;
4333 if( ds == NULL ) return NULL;
4334 if( node == NULL || itemGroup == NULL ) return NULL;
4336 name = &itemGroup->obj.name;
4338 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4340 adapter = g_new0( AdapterGroup, 1 );
4341 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4342 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4343 adapter->itemGroup = itemGroup;
4345 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4346 atci->iconXpm, atci->iconXpm,
4347 atci->treeLeaf, atci->treeExpand );
4348 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4349 addressbook_free_treenode );
4350 gtk_sctree_sort_node( ctree, node );
4355 * Add folder into the address index tree. Only visible folders are loaded into
4356 * the address index tree. Note that the root folder is not inserted into the
4359 * \param node Parent node.
4360 * \param ds Data source.
4361 * \param itemFolder Folder to add.
4362 * \param otype Object type to display.
4363 * \return Inserted node for the folder.
4365 static GtkCMCTreeNode *addressbook_node_add_folder(
4366 GtkCMCTreeNode *node, AddressDataSource *ds,
4367 ItemFolder *itemFolder, AddressObjectType otype )
4369 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4370 GtkCMCTreeNode *newNode = NULL;
4371 AdapterFolder *adapter;
4372 AddressTypeControlItem *atci = NULL;
4373 GList *listItems = NULL;
4375 ItemFolder *rootFolder;
4377 /* Only visible folders */
4378 if( itemFolder == NULL || itemFolder->isHidden )
4383 if( node == NULL || itemFolder == NULL )
4386 /* Determine object type */
4387 atci = addrbookctl_lookup( otype );
4391 rootFolder = addrindex_ds_get_root_folder( ds );
4392 if( itemFolder == rootFolder ) {
4396 adapter = g_new0( AdapterFolder, 1 );
4397 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4398 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4399 adapter->itemFolder = itemFolder;
4401 name = ADDRITEM_NAME(itemFolder);
4402 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4403 atci->iconXpm, atci->iconXpm,
4404 atci->treeLeaf, atci->treeExpand );
4406 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4407 addressbook_free_treenode );
4411 listItems = itemFolder->listFolder;
4412 while( listItems ) {
4413 ItemFolder *item = listItems->data;
4414 addressbook_node_add_folder( newNode, ds, item, otype );
4415 listItems = g_list_next( listItems );
4417 listItems = itemFolder->listGroup;
4418 while( listItems ) {
4419 ItemGroup *item = listItems->data;
4420 addressbook_node_add_group( newNode, ds, item );
4421 listItems = g_list_next( listItems );
4423 gtk_sctree_sort_node( ctree, node );
4427 void addressbook_export_to_file( void ) {
4428 if( _addressIndex_ ) {
4429 /* Save all new address book data */
4430 debug_print( "Saving address books...\n" );
4431 addrindex_save_all_books( _addressIndex_ );
4433 debug_print( "Exporting addressbook to file...\n" );
4434 addrindex_save_data( _addressIndex_ );
4435 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4436 addrindex_print_index( _addressIndex_, stdout );
4439 /* Notify address completion of new data */
4440 invalidate_address_completion();
4444 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4446 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4447 addressbook_lup_clicked(NULL, NULL);
4452 * Comparison using cell contents (text in first column). Used for sort
4453 * address index widget.
4455 static gint addressbook_treenode_compare_func(
4456 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4458 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4459 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4460 gchar *name1 = NULL, *name2 = NULL;
4461 if( cell1 ) name1 = cell1->u.text;
4462 if( cell2 ) name2 = cell2->u.text;
4463 if( ! name1 ) return ( name2 != NULL );
4464 if( ! name2 ) return -1;
4465 return g_utf8_collate( name1, name2 );
4468 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4469 AdapterDSource *ads;
4470 AdapterInterface *adapter;
4471 GtkCMCTreeNode *newNode;
4473 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4474 if( adapter == NULL ) return;
4475 ads = addressbook_edit_book( _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;
4485 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4486 AdapterDSource *ads;
4487 AdapterInterface *adapter;
4488 GtkCMCTreeNode *newNode;
4490 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4491 if( adapter == NULL ) return;
4492 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4494 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4496 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4497 addrbook.treeSelected = newNode;
4503 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4504 AdapterDSource *ads;
4505 AdapterInterface *adapter;
4506 AddressInterface *iface;
4507 GtkCMCTreeNode *newNode;
4509 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4510 if( adapter == NULL ) return;
4511 iface = adapter->interface;
4512 if( ! iface->haveLibrary ) return;
4513 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4515 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4517 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4518 addrbook.treeSelected = newNode;
4525 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4526 AdapterDSource *ads;
4527 AdapterInterface *adapter;
4528 AddressInterface *iface;
4529 GtkCMCTreeNode *newNode;
4531 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4532 if( adapter == NULL ) return;
4533 iface = adapter->interface;
4534 if( ! iface->haveLibrary ) return;
4535 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4537 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4539 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4540 addrbook.treeSelected = newNode;
4547 * Display address search status message.
4548 * \param queryType Query type.
4549 * \param status Status/Error code.
4551 static void addressbook_search_message( gint queryType, gint sts ) {
4553 *addressbook_msgbuf = '\0';
4555 if( sts != MGU_SUCCESS ) {
4556 if( queryType == ADDRQUERY_LDAP ) {
4558 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4563 g_snprintf( addressbook_msgbuf,
4564 sizeof(addressbook_msgbuf), "%s", desc );
4565 addressbook_status_show( addressbook_msgbuf );
4568 addressbook_status_show( "" );
4573 * Refresh addressbook by forcing refresh of current selected object in
4576 static void addressbook_refresh_current( void ) {
4580 ctree = GTK_CMCTREE(addrbook.ctree);
4581 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4582 if( obj == NULL ) return;
4583 addressbook_set_clist( obj, TRUE );
4587 * Message that is displayed whilst a query is executing in a background
4590 static gchar *_tempMessage_ = N_( "Busy searching..." );
4593 * Address search idle function. This function is called during UI idle time
4594 * while a search is in progress.
4596 * \param data Idler data.
4598 static void addressbook_search_idle( gpointer data ) {
4602 queryID = GPOINTER_TO_INT( data );
4603 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4608 * Search completion callback function. This removes the query from the idle
4611 * \param sender Sender of query.
4612 * \param queryID Query ID of search request.
4613 * \param status Search status.
4614 * \param data Query data.
4616 static void addressbook_search_callback_end(
4617 gpointer sender, gint queryID, gint status, gpointer data )
4621 AddrQueryObject *aqo;
4623 /* Remove idler function */
4624 ptrQID = GINT_TO_POINTER( queryID );
4626 g_idle_remove_by_data( ptrQID );
4629 /* Refresh addressbook contents */
4630 addressbook_refresh_current();
4631 req = qrymgr_find_request( queryID );
4633 aqo = ( AddrQueryObject * ) req->queryList->data;
4634 addressbook_search_message( aqo->queryType, status );
4637 /* Stop the search */
4638 addrindex_stop_search( queryID );
4644 * \param ds Data source to search.
4645 * \param searchTerm String to lookup.
4646 * \param pNode Parent data source node.
4648 static void addressbook_perform_search(
4649 AddressDataSource *ds, gchar *searchTerm,
4650 GtkCMCTreeNode *pNode )
4658 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4660 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4662 /* Create a folder for the search results */
4663 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4664 folder = addressbook_setup_subf(ds, name, pNode);
4667 /* Setup the search */
4668 queryID = addrindex_setup_explicit_search(
4669 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4670 if( queryID == 0 ) return;
4672 /* Set up idler function */
4673 idleID = g_idle_add(
4674 (GSourceFunc) addressbook_search_idle,
4675 GINT_TO_POINTER( queryID ) );
4677 g_message("error adding addressbook_search_idle\n");
4680 /* Start search, sit back and wait for something to happen */
4681 addrindex_start_search( queryID );
4683 addressbook_status_show( _tempMessage_ );
4687 * Lookup button handler. Address search is only performed against
4688 * address interfaces for external queries.
4690 * \param button Lookup button widget.
4691 * \param data Data object.
4693 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4696 AddressDataSource *ds;
4697 AddressInterface *iface;
4699 GtkCMCTreeNode *node, *parentNode;
4701 node = addrbook.treeSelected;
4702 if( ! node ) return;
4703 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4705 ctree = GTK_CMCTREE(addrbook.ctree);
4706 obj = gtk_cmctree_node_get_row_data( ctree, node );
4707 if( obj == NULL ) return;
4709 if (obj->type != ADDR_DATASOURCE ||
4710 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4711 addressbook_set_clist(
4712 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4713 addrbook.treeSelected),
4717 ds = addressbook_find_datasource( node );
4718 if( ds == NULL ) return;
4720 /* We must have a datasource that is an external interface */
4721 iface = ds->interface;
4722 if( ! iface->haveLibrary ) return;
4723 if( ! iface->externalQuery ) return;
4726 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4727 g_strchomp( searchTerm );
4729 if( obj->type == ADDR_ITEM_FOLDER ) {
4730 parentNode = GTK_CMCTREE_ROW(node)->parent;
4735 addressbook_perform_search( ds, searchTerm, parentNode );
4737 gtk_widget_grab_focus( addrbook.entry );
4739 g_free( searchTerm );
4742 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4743 addressbook_close();
4748 * Browse address entry for highlighted entry.
4750 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4752 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4754 AddressDataSource *ds;
4755 AddressInterface *iface;
4759 if(addrbook.listSelected == NULL)
4762 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4766 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4770 iface = ds->interface;
4771 if(!iface || !iface->haveLibrary )
4775 if (obj->type == ADDR_ITEM_EMAIL) {
4776 email = ( ItemEMail * ) obj;
4778 person = (ItemPerson *) ADDRITEM_PARENT(email);
4780 else if (obj->type == ADDR_ITEM_PERSON) {
4781 person = (ItemPerson *) obj;
4788 if( iface && iface->type == ADDR_IF_LDAP ) {
4789 browseldap_entry(ds, person->externalID);
4794 /* **********************************************************************
4795 * Build lookup tables.
4796 * ***********************************************************************
4800 * Remap object types.
4801 * Enter: abType AddressObjectType (used in tree node).
4802 * Return: ItemObjectType (used in address cache data).
4804 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4805 ItemObjectType ioType;
4808 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4809 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4810 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4811 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4812 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4813 default: ioType = ITEMTYPE_NONE; break;
4818 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4819 atci = addrbookctl_lookup(id); \
4821 atci->iconXpm = icon; \
4822 atci->iconXpmOpen = iconopen; \
4824 g_warning("can't get atci %d", id); \
4829 * Build table that controls the rendering of object types.
4831 static void addrbookctl_build_icons( GtkWidget *window ) {
4832 AddressTypeControlItem *atci;
4836 g_object_unref(interfacexpm);
4838 g_object_unref(folderxpm);
4840 g_object_unref(folderopenxpm);
4842 g_object_unref(groupxpm);
4844 g_object_unref(vcardxpm);
4846 g_object_unref(bookxpm);
4848 g_object_unref(addressxpm);
4850 g_object_unref(jpilotxpm);
4852 g_object_unref(categoryxpm);
4854 g_object_unref(ldapxpm);
4856 g_object_unref(addrsearchxpm);
4857 stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacexpm );
4858 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4859 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4860 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4861 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4862 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4863 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4864 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4865 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4866 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4867 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4869 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4870 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4871 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4872 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4873 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4874 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4875 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4876 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4877 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4878 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4879 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4884 * Build table that controls the rendering of object types.
4886 static void addrbookctl_build_map( GtkWidget *window ) {
4887 AddressTypeControlItem *atci;
4889 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4890 _addressBookTypeList_ = NULL;
4893 atci = g_new0( AddressTypeControlItem, 1 );
4894 atci->objectType = ADDR_INTERFACE;
4895 atci->interfaceType = ADDR_IF_NONE;
4896 atci->showInTree = TRUE;
4897 atci->treeExpand = TRUE;
4898 atci->treeLeaf = FALSE;
4899 atci->displayName = _( "Interface" );
4900 atci->menuCommand = NULL;
4901 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4902 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4905 atci = g_new0( AddressTypeControlItem, 1 );
4906 atci->objectType = ADDR_BOOK;
4907 atci->interfaceType = ADDR_IF_BOOK;
4908 atci->showInTree = TRUE;
4909 atci->treeExpand = TRUE;
4910 atci->treeLeaf = FALSE;
4911 atci->displayName = _( "Address Book" );
4912 atci->menuCommand = "Menu/Book/NewBook";
4913 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4914 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4917 atci = g_new0( AddressTypeControlItem, 1 );
4918 atci->objectType = ADDR_ITEM_PERSON;
4919 atci->interfaceType = ADDR_IF_NONE;
4920 atci->showInTree = FALSE;
4921 atci->treeExpand = FALSE;
4922 atci->treeLeaf = FALSE;
4923 atci->displayName = _( "Person" );
4924 atci->menuCommand = NULL;
4925 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4926 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4929 atci = g_new0( AddressTypeControlItem, 1 );
4930 atci->objectType = ADDR_ITEM_EMAIL;
4931 atci->interfaceType = ADDR_IF_NONE;
4932 atci->showInTree = FALSE;
4933 atci->treeExpand = FALSE;
4934 atci->treeLeaf = TRUE;
4935 atci->displayName = _( "Email Address" );
4936 atci->menuCommand = NULL;
4937 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4938 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4941 atci = g_new0( AddressTypeControlItem, 1 );
4942 atci->objectType = ADDR_ITEM_GROUP;
4943 atci->interfaceType = ADDR_IF_BOOK;
4944 atci->showInTree = TRUE;
4945 atci->treeExpand = FALSE;
4946 atci->treeLeaf = FALSE;
4947 atci->displayName = _( "Group" );
4948 atci->menuCommand = NULL;
4949 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4950 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4953 atci = g_new0( AddressTypeControlItem, 1 );
4954 atci->objectType = ADDR_ITEM_FOLDER;
4955 atci->interfaceType = ADDR_IF_BOOK;
4956 atci->showInTree = TRUE;
4957 atci->treeExpand = FALSE;
4958 atci->treeLeaf = FALSE;
4959 atci->displayName = _( "Folder" );
4960 atci->menuCommand = NULL;
4961 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4962 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4965 atci = g_new0( AddressTypeControlItem, 1 );
4966 atci->objectType = ADDR_VCARD;
4967 atci->interfaceType = ADDR_IF_VCARD;
4968 atci->showInTree = TRUE;
4969 atci->treeExpand = TRUE;
4970 atci->treeLeaf = TRUE;
4971 atci->displayName = _( "vCard" );
4972 atci->menuCommand = "Menu/Book/NewVCard";
4973 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4974 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4977 atci = g_new0( AddressTypeControlItem, 1 );
4978 atci->objectType = ADDR_JPILOT;
4979 atci->interfaceType = ADDR_IF_JPILOT;
4980 atci->showInTree = TRUE;
4981 atci->treeExpand = TRUE;
4982 atci->treeLeaf = FALSE;
4983 atci->displayName = _( "JPilot" );
4984 atci->menuCommand = "Menu/Book/NewJPilot";
4985 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4986 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4989 atci = g_new0( AddressTypeControlItem, 1 );
4990 atci->objectType = ADDR_CATEGORY;
4991 atci->interfaceType = ADDR_IF_JPILOT;
4992 atci->showInTree = TRUE;
4993 atci->treeExpand = TRUE;
4994 atci->treeLeaf = TRUE;
4995 atci->displayName = _( "JPilot" );
4996 atci->menuCommand = NULL;
4997 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4998 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5001 atci = g_new0( AddressTypeControlItem, 1 );
5002 atci->objectType = ADDR_LDAP;
5003 atci->interfaceType = ADDR_IF_LDAP;
5004 atci->showInTree = TRUE;
5005 atci->treeExpand = TRUE;
5006 atci->treeLeaf = FALSE;
5007 atci->displayName = _( "LDAP servers" );
5008 atci->menuCommand = "Menu/Book/NewLDAPServer";
5009 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5010 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5013 atci = g_new0( AddressTypeControlItem, 1 );
5014 atci->objectType = ADDR_LDAP_QUERY;
5015 atci->interfaceType = ADDR_IF_LDAP;
5016 atci->showInTree = TRUE;
5017 atci->treeExpand = FALSE;
5018 atci->treeLeaf = TRUE;
5019 atci->displayName = _( "LDAP Query" );
5020 atci->menuCommand = NULL;
5021 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5022 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5024 addrbookctl_build_icons(window);
5027 void addressbook_reflect_prefs_pixmap_theme(void)
5029 if (addrbook.window)
5030 addrbookctl_build_icons(addrbook.window);
5034 * Search for specified object type.
5036 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5038 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5042 * Search for specified interface type.
5044 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5045 GList *node = _addressBookTypeList_;
5047 AddressTypeControlItem *atci = node->data;
5048 if( atci->interfaceType == ifType ) return atci;
5049 node = g_list_next( node );
5054 static void addrbookctl_free_address( AddressObject *obj ) {
5055 g_free( obj->name );
5056 obj->type = ADDR_NONE;
5060 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5061 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5062 adapter->interface = NULL;
5063 adapter->interfaceType = ADDR_IF_NONE;
5064 adapter->atci = NULL;
5065 adapter->enabled = FALSE;
5066 adapter->haveLibrary = FALSE;
5067 adapter->treeNode = NULL;
5071 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5072 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5073 adapter->dataSource = NULL;
5074 adapter->subType = ADDR_NONE;
5078 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5079 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5080 adapter->itemFolder = NULL;
5084 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5085 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5086 adapter->itemGroup = NULL;
5091 * Build GUI interface list.
5093 static void addrbookctl_build_iflist( void ) {
5094 AddressTypeControlItem *atci;
5095 AdapterInterface *adapter;
5098 if( _addressIndex_ == NULL ) {
5099 _addressIndex_ = addrindex_create_index();
5100 if( _clipBoard_ == NULL ) {
5101 _clipBoard_ = addrclip_create();
5103 addrclip_set_index( _clipBoard_, _addressIndex_ );
5105 _addressInterfaceList_ = NULL;
5106 list = addrindex_get_interface_list( _addressIndex_ );
5108 AddressInterface *interface = list->data;
5109 atci = addrbookctl_lookup_iface( interface->type );
5111 adapter = g_new0( AdapterInterface, 1 );
5112 adapter->interfaceType = interface->type;
5113 adapter->atci = atci;
5114 adapter->interface = interface;
5115 adapter->treeNode = NULL;
5116 adapter->enabled = TRUE;
5117 adapter->haveLibrary = interface->haveLibrary;
5118 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5119 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5120 _addressInterfaceList_ =
5121 g_list_append( _addressInterfaceList_, adapter );
5123 list = g_list_next( list );
5128 * Find GUI interface type specified interface type.
5129 * \param ifType Interface type.
5130 * \return Interface item, or NULL if not found.
5132 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5133 GList *node = _addressInterfaceList_;
5135 AdapterInterface *adapter = node->data;
5136 if( adapter->interfaceType == ifType ) return adapter;
5137 node = g_list_next( node );
5143 * Build interface list selection.
5145 static void addrbookctl_build_ifselect( void ) {
5146 GList *newList = NULL;
5151 gchar *endptr = NULL;
5152 /* gboolean enabled; */
5153 AdapterInterface *adapter;
5155 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5158 splitStr = g_strsplit( selectStr, ",", -1 );
5159 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5161 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5162 ifType = strtol( splitStr[i], &endptr, 10 );
5165 if( strcmp( endptr, "/n" ) == 0 ) {
5170 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5171 adapter = addrbookctl_find_interface( ifType );
5173 newList = g_list_append( newList, adapter );
5180 /* g_print( "i=%d\n", i ); */
5181 g_strfreev( splitStr );
5182 g_free( selectStr );
5184 /* Replace existing list */
5185 mgu_clear_list( _addressIFaceSelection_ );
5186 g_list_free( _addressIFaceSelection_ );
5187 _addressIFaceSelection_ = newList;
5191 /* ***********************************************************************
5192 * Add sender to address book.
5193 * ***********************************************************************
5197 * This function is used by the Add sender to address book function.
5199 gboolean addressbook_add_contact(
5200 const gchar *name, const gchar *address, const gchar *remarks,
5201 GdkPixbuf *picture )
5203 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5204 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5205 debug_print( "addressbook_add_contact - added\n" );
5206 addressbook_refresh();
5211 /* ***********************************************************************
5212 * Book/folder selection.
5213 * ***********************************************************************
5217 * This function is used by the matcher dialog to select a book/folder.
5219 gchar *addressbook_folder_selection( const gchar *folderpath)
5221 AddressBookFile *book = NULL;
5222 ItemFolder *folder = NULL;
5225 cm_return_val_if_fail( folderpath != NULL, NULL);
5227 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5229 if ( folder != NULL) {
5231 gchar *oldtmp = NULL;
5232 AddrItemObject *obj = NULL;
5234 /* walk thru folder->parent to build the full folder path */
5235 /* TODO: wwp: optimize this */
5237 tmp = g_strdup(obj->uid);
5238 while ( obj->parent ) {
5240 if ( obj->name != NULL ) {
5241 oldtmp = g_strdup(tmp);
5243 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5247 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5250 path = g_strdup_printf("%s", book->fileName);
5252 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5258 /* ***********************************************************************
5259 * Book/folder checking.
5260 * ***********************************************************************
5263 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5265 FolderInfo *fi = g_new0( FolderInfo, 1 );
5267 fi->folder = folder;
5271 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5272 FolderInfo *fiParent, FolderPathMatch *match )
5278 FolderPathMatch *nextmatch = NULL;
5283 list = parentFolder->listFolder;
5285 folder = list->data;
5286 fName = g_strdup( ADDRITEM_NAME(folder) );
5288 /* match folder name, match pointer will be set to NULL if next recursive call
5289 doesn't need to match subfolder name */
5290 if ( match != NULL &&
5291 match->matched == FALSE ) {
5292 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5293 /* folder name matches, prepare next subfolder match */
5294 debug_print("matched folder name '%s'\n", fName);
5296 if ( match->folder_path[match->index] == NULL ) {
5297 /* we've matched all elements */
5298 match->matched = TRUE;
5299 match->folder = folder;
5300 debug_print("book/folder path matched!\n");
5302 /* keep on matching */
5310 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5311 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5313 list = g_list_next( list );
5318 * This function is used by to check if a matcher book/folder path corresponds to an
5319 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5320 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5321 if book AND folder are NULL this means that folderpath was empty or Any.
5322 If folderpath is a simple book name (without folder), book will not be NULL and folder
5323 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5326 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5327 AddressDataSource **book,
5328 ItemFolder **folder )
5330 AddressDataSource *ds;
5331 GList *list, *nodeDS;
5332 ItemFolder *rootFolder;
5333 AddressBookFile *abf;
5335 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5342 if ( folderpath == NULL )
5345 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5348 /* split the folder path we've received, we'll try to match this path, subpath by
5349 subpath against the book/folder structure in order */
5350 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5351 if (!folder_path_match.folder_path)
5354 list = addrindex_get_interface_list( _addressIndex_ );
5355 while ( list && !folder_path_match.matched ) {
5356 AddressInterface *interface = list->data;
5357 if ( interface && interface->type == ADDR_IF_BOOK ) {
5358 nodeDS = interface->listSource;
5359 while ( nodeDS && !folder_path_match.matched ) {
5362 /* Read address book */
5363 if( ! addrindex_ds_get_read_flag( ds ) ) {
5364 addrindex_ds_read_data( ds );
5367 /* Add node for address book */
5368 abf = ds->rawDataSource;
5370 /* match book name */
5371 if ( abf && abf->fileName &&
5372 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5374 debug_print("matched book name '%s'\n", abf->fileName);
5375 folder_path_match.book = ds;
5377 if ( folder_path_match.folder_path[1] == NULL ) {
5378 /* no folder part to match */
5380 folder_path_match.matched = TRUE;
5381 folder_path_match.folder = NULL;
5382 debug_print("book path matched!\n");
5385 /* match folder part */
5387 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5388 rootFolder = addrindex_ds_get_root_folder( ds );
5390 /* prepare for recursive call */
5391 folder_path_match.index = 1;
5392 /* this call will set folder_path_match.matched and folder_path_match.folder */
5393 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5398 nodeDS = g_list_next( nodeDS );
5401 list = g_list_next( list );
5404 g_strfreev( folder_path_match.folder_path );
5407 *book = folder_path_match.book;
5409 *folder = folder_path_match.folder;
5410 return folder_path_match.matched;
5414 /* **********************************************************************
5416 * ***********************************************************************
5422 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5423 AddressDataSource *ds = NULL;
5424 AdapterDSource *ads = NULL;
5425 AddressBookFile *abf = NULL;
5426 AdapterInterface *adapter;
5427 GtkCMCTreeNode *newNode;
5429 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5431 if( adapter->treeNode ) {
5432 abf = addressbook_imp_ldif( _addressIndex_ );
5434 ds = addrindex_index_add_datasource(
5435 _addressIndex_, ADDR_IF_BOOK, abf );
5436 ads = addressbook_create_ds_adapter(
5437 ds, ADDR_BOOK, NULL );
5438 addressbook_ads_set_name(
5439 ads, addrbook_get_name( abf ) );
5440 newNode = addressbook_add_object(
5442 ADDRESS_OBJECT(ads) );
5444 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5446 addrbook.treeSelected = newNode;
5449 /* Notify address completion */
5450 invalidate_address_completion();
5459 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5460 AddressDataSource *ds = NULL;
5461 AdapterDSource *ads = NULL;
5462 AddressBookFile *abf = NULL;
5463 AdapterInterface *adapter;
5464 GtkCMCTreeNode *newNode;
5466 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5468 if( adapter->treeNode ) {
5469 abf = addressbook_imp_mutt( _addressIndex_ );
5471 ds = addrindex_index_add_datasource(
5472 _addressIndex_, ADDR_IF_BOOK, abf );
5473 ads = addressbook_create_ds_adapter(
5474 ds, ADDR_BOOK, NULL );
5475 addressbook_ads_set_name(
5476 ads, addrbook_get_name( abf ) );
5477 newNode = addressbook_add_object(
5479 ADDRESS_OBJECT(ads) );
5481 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5483 addrbook.treeSelected = newNode;
5486 /* Notify address completion */
5487 invalidate_address_completion();
5496 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5497 AddressDataSource *ds = NULL;
5498 AdapterDSource *ads = NULL;
5499 AddressBookFile *abf = NULL;
5500 AdapterInterface *adapter;
5501 GtkCMCTreeNode *newNode;
5503 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5505 if( adapter->treeNode ) {
5506 abf = addressbook_imp_pine( _addressIndex_ );
5508 ds = addrindex_index_add_datasource(
5509 _addressIndex_, ADDR_IF_BOOK, abf );
5510 ads = addressbook_create_ds_adapter(
5511 ds, ADDR_BOOK, NULL );
5512 addressbook_ads_set_name(
5513 ads, addrbook_get_name( abf ) );
5514 newNode = addressbook_add_object(
5516 ADDRESS_OBJECT(ads) );
5518 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5520 addrbook.treeSelected = newNode;
5523 /* Notify address completion */
5524 invalidate_address_completion();
5531 * Harvest addresses.
5532 * \param folderItem Folder to import.
5533 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5534 * \param msgList List of message numbers, or NULL to process folder.
5536 void addressbook_harvest(
5537 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5539 AddressDataSource *ds = NULL;
5540 AdapterDSource *ads = NULL;
5541 AddressBookFile *abf = NULL;
5542 AdapterInterface *adapter;
5543 GtkCMCTreeNode *newNode;
5545 abf = addrgather_dlg_execute(
5546 folderItem, _addressIndex_, sourceInd, msgList );
5548 ds = addrindex_index_add_datasource(
5549 _addressIndex_, ADDR_IF_BOOK, abf );
5551 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5553 if( adapter->treeNode ) {
5554 ads = addressbook_create_ds_adapter(
5555 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5556 newNode = addressbook_add_object(
5558 ADDRESS_OBJECT(ads) );
5559 if (newNode == NULL) {
5560 g_message("error adding addressbook object\n");
5565 /* Notify address completion */
5566 invalidate_address_completion();
5573 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5574 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5576 AddressDataSource *ds = NULL;
5577 AddrBookBase *adbase;
5578 AddressCache *cache;
5579 GtkCMCTreeNode *node = NULL;
5581 if( ! addrbook.treeSelected ) return;
5582 node = addrbook.treeSelected;
5583 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5584 obj = gtk_cmctree_node_get_row_data( ctree, node );
5585 if( obj == NULL ) return;
5587 ds = addressbook_find_datasource( node );
5588 if( ds == NULL ) return;
5589 adbase = ( AddrBookBase * ) ds->rawDataSource;
5590 cache = adbase->addressCache;
5591 addressbook_exp_html( cache );
5597 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5598 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5600 AddressDataSource *ds = NULL;
5601 AddrBookBase *adbase;
5602 AddressCache *cache;
5603 GtkCMCTreeNode *node = NULL;
5605 if( ! addrbook.treeSelected ) return;
5606 node = addrbook.treeSelected;
5607 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5608 obj = gtk_cmctree_node_get_row_data( ctree, node );
5609 if( obj == NULL ) return;
5611 ds = addressbook_find_datasource( node );
5612 if( ds == NULL ) return;
5613 adbase = ( AddrBookBase * ) ds->rawDataSource;
5614 cache = adbase->addressCache;
5615 addressbook_exp_ldif( cache );
5618 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5620 addrduplicates_find(GTK_WINDOW(addrbook.window));
5623 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5625 addressbook_custom_attr_edit();
5628 static void addressbook_start_drag(GtkWidget *widget, gint button,
5632 GdkDragContext *context;
5633 if (addressbook_target_list == NULL)
5634 addressbook_target_list = gtk_target_list_new(
5635 addressbook_drag_types, 1);
5636 context = gtk_drag_begin(widget, addressbook_target_list,
5637 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5638 gtk_drag_set_icon_default(context);
5641 static void addressbook_drag_data_get(GtkWidget *widget,
5642 GdkDragContext *drag_context,
5643 GtkSelectionData *selection_data,
5648 AddrItemObject *aio = NULL;
5649 AddressObject *pobj = NULL;
5650 AdapterDSource *ads = NULL;
5651 AddressDataSource *ds = NULL;
5654 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5656 if( pobj == NULL ) return;
5658 if( pobj->type == ADDR_DATASOURCE ) {
5659 ads = ADAPTER_DSOURCE(pobj);
5660 ds = ads->dataSource;
5661 } else if (pobj->type == ADDR_ITEM_GROUP) {
5666 else if( pobj->type != ADDR_INTERFACE ) {
5667 ds = addressbook_find_datasource( addrbook.treeSelected );
5673 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5674 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5675 GTK_CMCTREE_NODE(cur->data));
5676 while (aio && aio->type != ITEMTYPE_PERSON) {
5681 if (aio && aio->type == ITEMTYPE_PERSON) {
5682 if( ds && ds->interface && ds->interface->readOnly)
5683 gtk_selection_data_set(selection_data,
5684 gtk_selection_data_get_target(selection_data), 8,
5685 (const guchar *)"Dummy_addr_copy", 15);
5687 gtk_selection_data_set(selection_data,
5688 gtk_selection_data_get_target(selection_data), 8,
5689 (const guchar *)"Dummy_addr_move", 15);
5693 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5694 GdkDragContext *context,
5700 GtkAllocation allocation;
5701 GtkRequisition requisition;
5703 GtkCMCTreeNode *node = NULL;
5704 gboolean acceptable = FALSE;
5705 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5706 gint height = allocation.height;
5707 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5708 gint total_height = requisition.height;
5709 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5710 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5711 gfloat vpos = gtk_adjustment_get_value(pos);
5713 if (gtk_cmclist_get_selection_info
5714 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5716 if (y > height - 24 && height + vpos < total_height) {
5717 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5718 gtk_adjustment_changed(pos);
5720 if (y < 24 && y > 0) {
5721 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5722 gtk_adjustment_changed(pos);
5724 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5727 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5728 if( obj->type == ADDR_ITEM_FOLDER
5729 || obj->type == ADDR_ITEM_GROUP)
5732 AdapterDSource *ads = NULL;
5733 AddressDataSource *ds = NULL;
5734 ads = ADAPTER_DSOURCE(obj);
5735 if (ads == NULL ){ return FALSE;}
5736 ds = ads->dataSource;
5737 if (ds == NULL ) { return FALSE;}
5745 g_signal_handlers_block_by_func
5747 G_CALLBACK(addressbook_tree_selected), NULL);
5748 gtk_sctree_select( GTK_SCTREE(widget), node);
5749 g_signal_handlers_unblock_by_func
5751 G_CALLBACK(addressbook_tree_selected), NULL);
5752 gdk_drag_status(context,
5753 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5754 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5756 gdk_drag_status(context, 0, time);
5761 static void addressbook_drag_leave_cb(GtkWidget *widget,
5762 GdkDragContext *context,
5766 if (addrbook.treeSelected) {
5767 g_signal_handlers_block_by_func
5769 G_CALLBACK(addressbook_tree_selected), NULL);
5770 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5771 g_signal_handlers_unblock_by_func
5773 G_CALLBACK(addressbook_tree_selected), NULL);
5778 static void addressbook_drag_received_cb(GtkWidget *widget,
5779 GdkDragContext *drag_context,
5782 GtkSelectionData *data,
5788 GtkCMCTreeNode *node;
5789 GtkCMCTreeNode *lastopened = addrbook.opened;
5791 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5792 if (gtk_cmclist_get_selection_info
5793 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5797 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5798 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5801 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5802 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5803 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5804 addressbook_clip_copy_cb(NULL, NULL);
5806 addressbook_clip_cut_cb(NULL, NULL);
5807 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5808 addressbook_clip_paste_cb(NULL,NULL);
5809 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5810 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5811 gtk_drag_finish(drag_context, TRUE, TRUE, time);