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 ||
2508 obj->type == ADDR_DATASOURCE) {
2510 addressbook_treenode_edit_cb(NULL, NULL);
2512 /* expand pr collapse */
2513 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2514 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2520 addressbook_menubar_set_sensitive( FALSE );
2522 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2523 gtkut_clist_set_focus_row(clist, row);
2524 obj = gtk_cmclist_get_row_data( clist, row );
2527 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2531 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2533 if( ! addrclip_is_empty( _clipBoard_ ) )
2534 canTreePaste = TRUE;
2536 if (obj->type == ADDR_INTERFACE) {
2537 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2538 iface = adapter->interface;
2541 if( !iface->readOnly ) {
2542 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2543 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2545 if( iface->externalQuery )
2548 if (obj->type == ADDR_DATASOURCE) {
2550 ads = ADAPTER_DSOURCE(obj);
2551 ds = ads->dataSource;
2554 iface = ds->interface;
2557 if( !iface->readOnly ) {
2559 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2560 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2561 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2566 else if (obj->type == ADDR_ITEM_FOLDER) {
2568 ds = addressbook_find_datasource( node );
2571 iface = ds->interface;
2574 if( !iface->readOnly ) {
2578 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2579 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2580 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2584 if( iface->externalQuery ) {
2585 /* Enable deletion of LDAP folder */
2589 else if (obj->type == ADDR_ITEM_GROUP) {
2591 ds = addressbook_find_datasource( node );
2594 iface = ds->interface;
2597 if( ! iface->readOnly ) {
2600 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2601 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2605 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2607 if( ! addrselect_test_empty( _addressSelect_ ) )
2609 if( ! addrclip_is_empty( _clipBoard_ ) )
2612 /* Forbid write changes when read-only */
2613 if( iface && iface->readOnly ) {
2615 canTreePaste = FALSE;
2623 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2624 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2625 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2626 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2627 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2629 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2630 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2631 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2632 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2633 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2635 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2636 addrbook.target_compose != NULL);
2638 if( event->button == 3 )
2639 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2640 event->button, event->time);
2645 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2646 GdkEventButton *event,
2649 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2653 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2655 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2656 AddressObject *obj = NULL;
2657 AddressDataSource *ds = NULL;
2658 AddressBookFile *abf = NULL;
2659 ItemFolder *parentFolder = NULL;
2660 ItemFolder *folder = NULL;
2662 if( ! addrbook.treeSelected ) return;
2663 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2664 if( obj == NULL ) return;
2665 ds = addressbook_find_datasource( addrbook.treeSelected );
2666 if( ds == NULL ) return;
2668 if( obj->type == ADDR_DATASOURCE ) {
2669 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2671 else if( obj->type == ADDR_ITEM_FOLDER ) {
2672 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2678 abf = ds->rawDataSource;
2679 if( abf == NULL ) return;
2680 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2683 nn = addressbook_node_add_folder(
2684 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2686 g_message("error adding addressbook folder\n");
2688 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2689 if( addrbook.treeSelected == addrbook.opened )
2690 addressbook_set_clist(obj, TRUE);
2694 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2696 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2697 AddressObject *obj = NULL;
2698 AddressDataSource *ds = NULL;
2699 AddressBookFile *abf = NULL;
2700 ItemFolder *parentFolder = NULL;
2701 ItemGroup *group = NULL;
2703 if( ! addrbook.treeSelected ) return;
2704 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2705 if( obj == NULL ) return;
2706 ds = addressbook_find_datasource( addrbook.treeSelected );
2707 if( ds == NULL ) return;
2709 if( obj->type == ADDR_DATASOURCE ) {
2710 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2712 else if( obj->type == ADDR_ITEM_FOLDER ) {
2713 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2719 abf = ds->rawDataSource;
2720 if( abf == NULL ) return;
2721 group = addressbook_edit_group( abf, parentFolder, NULL );
2724 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2726 g_message("error adding addressbook group\n");
2728 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2729 if( addrbook.treeSelected == addrbook.opened )
2730 addressbook_set_clist(obj, TRUE);
2734 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2736 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2739 GdkPixbuf *pix_cl, *pix_op;
2740 gboolean is_leaf, expanded;
2742 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2744 &is_leaf, &expanded);
2745 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2752 * \param obj Address object to edit.
2753 * \param node Node in tree.
2754 * \return New name of data source.
2756 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2757 gchar *newName = NULL;
2758 AddressDataSource *ds = NULL;
2759 AddressInterface *iface = NULL;
2760 AdapterDSource *ads = NULL;
2762 ds = addressbook_find_datasource( node );
2763 if( ds == NULL ) return NULL;
2764 iface = ds->interface;
2765 if( ! iface->haveLibrary ) return NULL;
2767 /* Read data from data source */
2768 if( addrindex_ds_get_modify_flag( ds ) ) {
2769 addrindex_ds_read_data( ds );
2772 if( ! addrindex_ds_get_read_flag( ds ) ) {
2773 addrindex_ds_read_data( ds );
2777 ads = ADAPTER_DSOURCE(obj);
2778 if( ads->subType == ADDR_BOOK ) {
2779 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2781 else if( ads->subType == ADDR_VCARD ) {
2782 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2785 else if( ads->subType == ADDR_JPILOT ) {
2786 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2790 else if( ads->subType == ADDR_LDAP ) {
2791 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2797 newName = obj->name;
2802 * Edit an object that is in the address tree area.
2804 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2806 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2808 AddressDataSource *ds = NULL;
2809 AddressBookFile *abf = NULL;
2810 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2813 if( ! addrbook.treeSelected ) return;
2814 node = addrbook.treeSelected;
2815 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2816 obj = gtk_cmctree_node_get_row_data( ctree, node );
2817 if( obj == NULL ) return;
2818 parentNode = GTK_CMCTREE_ROW(node)->parent;
2820 ds = addressbook_find_datasource( node );
2821 if( ds == NULL ) return;
2823 if( obj->type == ADDR_DATASOURCE ) {
2824 name = addressbook_edit_datasource( obj, node );
2825 if( name == NULL ) return;
2828 abf = ds->rawDataSource;
2829 if( abf == NULL ) return;
2830 if( obj->type == ADDR_ITEM_FOLDER ) {
2831 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2832 ItemFolder *item = adapter->itemFolder;
2833 ItemFolder *parentFolder = NULL;
2834 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2835 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2836 name = ADDRITEM_NAME(item);
2838 else if( obj->type == ADDR_ITEM_GROUP ) {
2839 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2840 ItemGroup *item = adapter->itemGroup;
2841 ItemFolder *parentFolder = NULL;
2842 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2843 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2844 name = ADDRITEM_NAME(item);
2847 if( name && parentNode ) {
2848 /* Update node in tree view */
2849 addressbook_change_node_name( node, name );
2850 gtk_sctree_sort_node(ctree, parentNode);
2851 gtk_cmctree_expand( ctree, node );
2852 gtk_sctree_select( GTK_SCTREE( ctree), node );
2859 ADDRTREE_DEL_FOLDER_ONLY,
2860 ADDRTREE_DEL_FOLDER_ADDR
2864 * Delete an item from the tree widget.
2865 * \param data Data passed in.
2866 * \param action Action.
2867 * \param widget Widget issuing callback.
2869 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2871 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2872 GtkCMCTreeNode *node = NULL;
2876 AddrBookBase *adbase;
2877 AddressCache *cache;
2878 AdapterDSource *ads = NULL;
2879 AddressInterface *iface = NULL;
2880 AddressDataSource *ds = NULL;
2881 gboolean remFlag = FALSE;
2882 TreeItemDelType delType;
2884 if( ! addrbook.treeSelected ) return;
2885 node = addrbook.treeSelected;
2886 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2888 obj = gtk_cmctree_node_get_row_data( ctree, node );
2889 cm_return_if_fail(obj != NULL);
2891 if( obj->type == ADDR_DATASOURCE ) {
2892 ads = ADAPTER_DSOURCE(obj);
2894 ds = ads->dataSource;
2895 if( ds == NULL ) return;
2898 /* Must be folder or something else */
2899 ds = addressbook_find_datasource( node );
2900 if( ds == NULL ) return;
2902 /* Only allow deletion from non-readOnly */
2903 iface = ds->interface;
2904 if( iface->readOnly ) {
2905 /* Allow deletion of query results */
2906 if( ! iface->externalQuery ) return;
2910 /* Confirm deletion */
2911 delType = ADDRTREE_DEL_NONE;
2912 if( obj->type == ADDR_ITEM_FOLDER ) {
2913 if( iface && iface->externalQuery ) {
2914 message = g_strdup_printf( _(
2915 "Do you want to delete the query " \
2916 "results and addresses in '%s'?" ),
2918 aval = alertpanel( _("Delete"), message,
2919 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2921 if( aval == G_ALERTALTERNATE ) {
2922 delType = ADDRTREE_DEL_FOLDER_ADDR;
2926 message = g_strdup_printf
2927 ( _( "Do you want to delete '%s'? "
2928 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2930 aval = alertpanel( _("Delete folder"), message,
2931 GTK_STOCK_CANCEL, g_strconcat("+",_("Delete _folder only"), NULL), _("Delete folder and _addresses"));
2933 if( aval == G_ALERTALTERNATE ) {
2934 delType = ADDRTREE_DEL_FOLDER_ONLY;
2936 else if( aval == G_ALERTOTHER ) {
2937 delType = ADDRTREE_DEL_FOLDER_ADDR;
2941 else if( obj->type == ADDR_ITEM_GROUP ) {
2942 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2943 "The addresses it contains will not be lost."), obj->name);
2944 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2945 "+" GTK_STOCK_DELETE, NULL);
2947 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2949 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2950 "The addresses it contains will be lost."), obj->name);
2951 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2952 "+" GTK_STOCK_DELETE, NULL);
2954 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2956 if( delType == ADDRTREE_DEL_NONE ) return;
2958 /* Proceed with deletion */
2959 if( obj->type == ADDR_DATASOURCE ) {
2960 /* Remove node from tree */
2961 gtk_cmctree_remove_node( ctree, node );
2963 if (delType == ADDRTREE_DEL_DATA &&
2964 ds->interface && ds->interface->type == ADDR_IF_BOOK)
2965 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
2967 /* Remove data source. */
2968 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2969 addrindex_free_datasource( ds );
2974 /* Get reference to cache */
2975 adbase = ( AddrBookBase * ) ds->rawDataSource;
2976 if( adbase == NULL ) return;
2977 cache = adbase->addressCache;
2979 /* Remove query results folder */
2980 if( iface && iface->externalQuery ) {
2981 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2982 ItemFolder *folder = adapter->itemFolder;
2984 adapter->itemFolder = NULL;
2986 g_print( "remove folder for ::%s::\n", obj->name );
2987 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2988 g_print( "-------------- remove results\n" );
2990 addrindex_remove_results( ds, folder );
2991 /* g_print( "-------------- remove node\n" ); */
2992 gtk_cmctree_remove_node( ctree, node );
2996 /* Code below is valid for regular address book deletion */
2997 if( obj->type == ADDR_ITEM_FOLDER ) {
2998 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2999 ItemFolder *item = adapter->itemFolder;
3001 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3002 /* Remove folder only */
3003 item = addrcache_remove_folder( cache, item );
3005 addritem_free_item_folder( item );
3006 addressbook_move_nodes_up( ctree, node );
3010 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3011 /* Remove folder and addresses */
3012 item = addrcache_remove_folder_delete( cache, item );
3014 addritem_free_item_folder( item );
3019 else if( obj->type == ADDR_ITEM_GROUP ) {
3020 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3021 ItemGroup *item = adapter->itemGroup;
3023 item = addrcache_remove_group( cache, item );
3025 addritem_free_item_group( item );
3032 gtk_cmctree_remove_node(ctree, node );
3036 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3038 if( person && addrbook.treeSelected == addrbook.opened ) {
3039 person->status = ADD_ENTRY;
3040 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3041 addressbook_folder_refresh_one_person(
3042 GTK_CMCTREE(addrbook.clist), person );
3044 addressbook_address_list_set_focus();
3047 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3049 if( person && addrbook.treeSelected == addrbook.opened) {
3050 person->status = ADD_ENTRY;
3051 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3052 addressbook_set_clist(
3053 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3057 addressbook_address_list_set_focus();
3061 * Label (a format string) that is used to name each folder.
3063 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3066 * Search ctree widget callback function.
3067 * \param pA Pointer to node.
3068 * \param pB Pointer to data item being sought.
3069 * \return Zero (0) if folder found.
3071 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3074 aoA = ( AddressObject * ) pA;
3075 if( aoA->type == ADDR_ITEM_FOLDER ) {
3076 ItemFolder *folder, *fld;
3078 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3079 folder = ( ItemFolder * ) pB;
3080 if( fld == folder ) return 0; /* Found folder */
3085 static ItemFolder * addressbook_setup_subf(
3086 AddressDataSource *ds, gchar *title,
3087 GtkCMCTreeNode *pNode )
3089 AddrBookBase *adbase;
3090 AddressCache *cache;
3093 GtkCMCTreeNode *nNode;
3095 AddressObjectType aoType = ADDR_NONE;
3098 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3100 if( ds && ds->type == ADDR_IF_LDAP ) {
3102 aoType = ADDR_LDAP_QUERY;
3109 ctree = GTK_CMCTREE(addrbook.ctree);
3110 /* Get reference to address cache */
3111 adbase = ( AddrBookBase * ) ds->rawDataSource;
3112 cache = adbase->addressCache;
3114 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3115 GList *cur = children;
3116 for (; cur; cur = cur->next) {
3117 ItemFolder *child = (ItemFolder *) cur->data;
3118 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3119 nNode = gtk_cmctree_find_by_row_data_custom(
3121 addressbook_treenode_find_folder_cb );
3123 addrindex_remove_results( ds, child );
3124 while( child->listPerson ) {
3125 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3126 item = addrcache_remove_person( cache, item );
3128 addritem_free_item_person( item );
3132 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3133 addrbook.treeSelected = nNode;
3140 /* Create a folder */
3141 folder = addrcache_add_new_folder( cache, NULL );
3142 name = g_strdup_printf( "%s", title );
3143 addritem_folder_set_name( folder, name );
3144 addritem_folder_set_remarks( folder, "" );
3147 /* Now let's see the folder */
3148 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3149 gtk_cmctree_expand( ctree, pNode );
3151 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3152 addrbook.treeSelected = nNode;
3158 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3159 AddressObject *pobj = NULL;
3160 AddressDataSource *ds = NULL;
3161 AddressBookFile *abf = NULL;
3162 debug_print("adding address\n");
3163 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3164 if( pobj == NULL ) {
3165 debug_print("no row data\n");
3168 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3170 debug_print("no datasource\n");
3174 abf = ds->rawDataSource;
3176 g_print("no addressbook file\n");
3180 if( pobj->type == ADDR_DATASOURCE ) {
3181 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3182 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3184 ItemFolder *folder = NULL;
3186 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3187 GtkCMCTreeNode *parentNode;
3188 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3189 if( ds == NULL ) return;
3191 /* We must have a datasource that is an external interface */
3192 if( ! ds->interface->haveLibrary ) return;
3193 if( ! ds->interface->externalQuery ) return;
3195 if( pobj->type == ADDR_ITEM_FOLDER ) {
3196 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3199 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3201 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3203 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3205 abf = ds->rawDataSource;
3208 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3209 addrbook.editaddress_vbox,
3210 addressbook_new_address_from_book_post_cb,
3213 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3214 LdapServer *server = ds->rawDataSource;
3215 ldapsvr_set_modified(server, TRUE);
3216 ldapsvr_update_book(server, NULL);
3217 if (server->retVal != LDAPRC_SUCCESS) {
3218 alertpanel( _("Add address(es)"),
3219 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3220 GTK_STOCK_CLOSE, NULL, NULL );
3221 server->retVal = LDAPRC_SUCCESS;
3226 if (prefs_common.addressbook_use_editaddress_dialog)
3227 addressbook_new_address_from_book_post_cb( person );
3230 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3232 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3235 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3236 GtkCMCTreeNode *parentNode;
3237 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3238 if( ds == NULL ) return;
3240 /* We must have a datasource that is an external interface */
3241 if( ! ds->interface->haveLibrary ) return;
3242 if( ! ds->interface->externalQuery ) return;
3244 if( pobj->type == ADDR_ITEM_FOLDER ) {
3245 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3248 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3250 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3254 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3256 abf = ds->rawDataSource;
3259 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3260 addrbook.editaddress_vbox,
3261 addressbook_new_address_from_folder_post_cb,
3264 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3265 LdapServer *server = ds->rawDataSource;
3266 ldapsvr_set_modified(server, TRUE);
3267 ldapsvr_update_book(server, NULL);
3268 if (server->retVal != LDAPRC_SUCCESS) {
3269 alertpanel( _("Add address(es)"),
3270 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3271 GTK_STOCK_CLOSE, NULL, NULL );
3276 if (prefs_common.addressbook_use_editaddress_dialog)
3277 addressbook_new_address_from_folder_post_cb( person );
3279 else if( pobj->type == ADDR_ITEM_GROUP ) {
3280 /* New address in group */
3281 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3282 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3283 if (addrbook.treeSelected == addrbook.opened) {
3284 /* Change node name in tree. */
3285 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3286 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3287 addressbook_set_clist(
3288 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3296 * Search for specified child group node in address index tree.
3297 * \param parent Parent node.
3298 * \param group Group to find.
3300 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3301 GtkCMCTreeNode *node = NULL;
3302 GtkCMCTreeRow *currRow;
3304 currRow = GTK_CMCTREE_ROW( parent );
3306 node = currRow->children;
3310 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3311 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3312 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3313 if( g == group ) return node;
3315 currRow = GTK_CMCTREE_ROW(node);
3316 node = currRow->sibling;
3322 static AddressBookFile *addressbook_get_book_file() {
3323 AddressBookFile *abf = NULL;
3324 AddressDataSource *ds = NULL;
3326 ds = addressbook_find_datasource( addrbook.treeSelected );
3327 if( ds == NULL ) return NULL;
3328 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3332 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3333 GtkCMCTreeNode *node;
3336 /* Remove existing folders and groups */
3337 row = GTK_CMCTREE_ROW( parent );
3339 while( (node = row->children) ) {
3340 gtk_cmctree_remove_node( ctree, node );
3345 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3346 GtkCMCTreeNode *parent, *child;
3347 GtkCMCTreeRow *currRow;
3348 currRow = GTK_CMCTREE_ROW( node );
3350 parent = currRow->parent;
3351 while( (child = currRow->children) ) {
3352 gtk_cmctree_move( ctree, child, parent, node );
3354 gtk_sctree_sort_node( ctree, parent );
3358 static void addressbook_edit_address_post_cb( ItemPerson *person )
3362 AddressBookFile *abf = addressbook_get_book_file();
3364 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3365 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3366 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3369 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3370 invalidate_address_completion();
3372 addressbook_address_list_set_focus();
3375 void addressbook_address_list_set_focus( void )
3377 if (!prefs_common.addressbook_use_editaddress_dialog) {
3378 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3379 addressbook_list_menu_setup();
3383 void addressbook_address_list_disable_some_actions(void)
3385 /* disable address copy/pasting when editing contact's detail (embedded form) */
3386 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3387 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3388 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3391 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3392 addressbook_edit_address(data, 0, NULL, TRUE);
3395 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3396 gboolean force_focus ) {
3397 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3399 AddressObject *obj = NULL, *pobj = NULL;
3400 AddressDataSource *ds = NULL;
3401 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3403 AddressBookFile *abf = NULL;
3405 if( addrbook.listSelected == NULL ) return;
3406 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3407 cm_return_if_fail(obj != NULL);
3409 ctree = GTK_CMCTREE( addrbook.ctree );
3410 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3412 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3413 if( ds == NULL ) return;
3415 abf = addressbook_get_book_file();
3417 if( obj->type == ADDR_ITEM_EMAIL ) {
3418 ItemEMail *email = ( ItemEMail * ) obj;
3420 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3421 /* Edit parent group */
3422 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3423 ItemGroup *itemGrp = adapter->itemGroup;
3424 if( abf == NULL ) return;
3425 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3426 name = ADDRITEM_NAME(itemGrp);
3427 node = addrbook.treeSelected;
3428 parentNode = GTK_CMCTREE_ROW(node)->parent;
3431 /* Edit person - email page */
3433 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3434 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3435 addressbook_edit_address_post_cb,
3436 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3439 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3440 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3441 person->status = UPDATE_ENTRY;
3444 if (prefs_common.addressbook_use_editaddress_dialog)
3445 addressbook_edit_address_post_cb( person );
3450 else if( obj->type == ADDR_ITEM_PERSON ) {
3451 /* Edit person - basic page */
3452 ItemPerson *person = ( ItemPerson * ) obj;
3453 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3454 addressbook_edit_address_post_cb,
3455 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3458 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3459 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3460 person->status = UPDATE_ENTRY;
3463 if (prefs_common.addressbook_use_editaddress_dialog)
3464 addressbook_edit_address_post_cb( person );
3468 else if( obj->type == ADDR_ITEM_GROUP ) {
3469 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3470 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3471 parentNode = addrbook.treeSelected;
3472 node = addressbook_find_group_node( parentNode, itemGrp );
3473 name = ADDRITEM_NAME(itemGrp);
3474 invalidate_address_completion();
3480 /* Update tree node with node name */
3481 if( node == NULL ) return;
3482 addressbook_change_node_name( node, name );
3483 gtk_sctree_sort_node( ctree, parentNode );
3484 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3485 addressbook_set_clist(
3486 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3491 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3493 addressbook_del_clicked(NULL, NULL);
3496 static void close_cb(GtkAction *action, gpointer data)
3498 addressbook_close();
3501 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3502 addressbook_export_to_file();
3505 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3507 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3508 if( person ) addritem_person_set_opened( person, TRUE );
3512 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3514 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3515 if( person ) addritem_person_set_opened( person, FALSE );
3519 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3521 gchar *eMailAlias = ADDRITEM_NAME(email);
3522 if( eMailAlias && *eMailAlias != '\0' ) {
3524 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3527 str = g_strdup( eMailAlias );
3533 static gboolean addressbook_match_item(const gchar *name,
3534 const gchar *email_alias,
3536 const gchar *remarks,
3541 if (!str || str[0] == '\0')
3543 if (strcasestr(name, str))
3545 else if (email_alias && strcasestr(email_alias, str))
3547 else if (addr && strcasestr(addr, str))
3549 else if (remarks && strcasestr(remarks, str))
3555 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3556 GList *items = itemGroup->listEMail;
3557 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3558 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3559 for( ; items != NULL; items = g_list_next( items ) ) {
3560 GtkCMCTreeNode *nodeEMail = NULL;
3561 gchar *text[N_LIST_COLS];
3562 ItemEMail *email = items->data;
3566 if( ! email ) continue;
3568 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3570 if( !addressbook_match_item(ADDRITEM_NAME(person),
3571 ADDRITEM_NAME(email),
3572 email->address, email->remarks,
3576 str = addressbook_format_item_clist( person, email );
3578 text[COL_NAME] = addressbook_set_col_name_guard(str);
3581 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3583 text[COL_ADDRESS] = email->address;
3584 text[COL_REMARKS] = email->remarks;
3585 nodeEMail = gtk_sctree_insert_node(
3587 text, FOLDER_SPACING,
3591 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3597 gchar *addressbook_set_col_name_guard(gchar *value)
3599 gchar *ret = "<not set>";
3600 gchar *tmp = g_strdup(value);
3602 if (tmp !=NULL && *tmp != '\0')
3608 static void addressbook_folder_load_one_person(
3609 GtkCMCTree *clist, ItemPerson *person,
3610 AddressTypeControlItem *atci,
3611 AddressTypeControlItem *atciMail )
3613 GtkCMCTreeNode *nodePerson = NULL;
3614 GtkCMCTreeNode *nodeEMail = NULL;
3615 gchar *text[N_LIST_COLS];
3616 gboolean flgFirst = TRUE, haveAddr = FALSE;
3619 AddressBookFile *abf = addressbook_get_book_file();
3622 if( person == NULL ) return;
3624 text[COL_NAME] = "";
3625 node = person->listEMail;
3627 ItemEMail *email = node->data;
3628 gchar *eMailAddr = NULL;
3629 node = g_list_next( node );
3631 text[COL_ADDRESS] = email->address;
3632 text[COL_REMARKS] = email->remarks;
3633 eMailAddr = ADDRITEM_NAME(email);
3634 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3636 /* First email belongs with person */
3637 gchar *str = addressbook_format_item_clist( person, email );
3639 text[COL_NAME] = addressbook_set_col_name_guard(str);
3642 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3643 person && person->nickName ) {
3644 if (person->nickName) {
3645 if (strcmp(person->nickName, "") != 0) {
3646 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3649 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3655 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3657 nodePerson = gtk_sctree_insert_node(
3659 text, FOLDER_SPACING,
3662 FALSE, person->isOpened );
3665 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3668 /* Subsequent email is a child node of person */
3669 text[COL_NAME] = ADDRITEM_NAME(email);
3670 nodeEMail = gtk_sctree_insert_node(
3671 clist, nodePerson, NULL,
3672 text, FOLDER_SPACING,
3674 atciMail->iconXpmOpen,
3676 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3682 /* Have name without EMail */
3683 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3684 text[COL_ADDRESS] = "";
3685 text[COL_REMARKS] = "";
3686 nodePerson = gtk_sctree_insert_node(
3688 text, FOLDER_SPACING,
3691 FALSE, person->isOpened );
3692 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3697 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3699 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3700 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3701 const gchar *search_str;
3703 if( atci == NULL ) return;
3704 if( atciMail == NULL ) return;
3706 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3708 /* Load email addresses */
3709 items = addritem_folder_get_person_list( itemFolder );
3710 for( ; items != NULL; items = g_list_next( items ) ) {
3715 person = (ItemPerson *)items->data;
3718 node = person->listEMail;
3719 if (node && node->data) {
3721 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3724 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3728 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3730 /* Free up the list */
3731 mgu_clear_list( items );
3732 g_list_free( items );
3735 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3736 addrbook.listSelected = NULL;
3737 gtk_cmctree_remove_node( clist, node );
3738 addressbook_menubar_set_sensitive( FALSE );
3739 addressbook_menuitem_set_sensitive(
3740 gtk_cmctree_node_get_row_data(
3741 GTK_CMCTREE(clist), addrbook.treeSelected ),
3742 addrbook.treeSelected );
3745 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3746 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3747 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3748 GtkCMCTreeNode *node;
3749 if( atci == NULL ) return;
3750 if( atciMail == NULL ) return;
3751 if( person == NULL ) return;
3752 /* unload the person */
3754 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3756 addressbook_folder_remove_node( clist, node );
3757 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3758 gtk_sctree_sort_node( clist, NULL );
3759 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3761 gtk_sctree_select( GTK_SCTREE(clist), node );
3762 if (!gtk_cmctree_node_is_visible( clist, node ) )
3763 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3767 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3768 GtkCMCTreeNode *node;
3770 if( person == NULL ) return;
3771 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3773 addressbook_folder_remove_node( clist, node );
3777 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3779 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3780 const gchar *search_str;
3782 /* Load any groups */
3783 if( ! atci ) return;
3785 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3787 items = addritem_folder_get_group_list( itemFolder );
3788 for( ; items != NULL; items = g_list_next( items ) ) {
3789 GtkCMCTreeNode *nodeGroup = NULL;
3790 gchar *text[N_LIST_COLS];
3791 ItemGroup *group = items->data;
3792 if( group == NULL ) continue;
3793 if( !addressbook_match_item(ADDRITEM_NAME(group),
3794 NULL, NULL, NULL, search_str) )
3797 text[COL_NAME] = ADDRITEM_NAME(group);
3798 text[COL_ADDRESS] = "";
3799 text[COL_REMARKS] = "";
3800 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3801 text, FOLDER_SPACING,
3805 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3806 gtk_sctree_sort_node(clist, NULL);
3808 /* Free up the list */
3809 mgu_clear_list( items );
3810 g_list_free( items );
3814 * Search ctree widget callback function.
3815 * \param pA Pointer to node.
3816 * \param pB Pointer to data item being sought.
3817 * \return Zero (0) if group found.
3819 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3822 aoA = ( AddressObject * ) pA;
3823 if( aoA->type == ADDR_ITEM_GROUP ) {
3824 ItemGroup *group, *grp;
3826 grp = ADAPTER_GROUP(aoA)->itemGroup;
3827 group = ( ItemGroup * ) pB;
3828 if( grp == group ) return 0; /* Found group */
3834 * Remove folder and group nodes from tree widget for items contained ("cut")
3837 static void addressbook_treenode_remove_item( void ) {
3839 AddrSelectItem *cutItem;
3840 AddressCache *cache;
3841 AddrItemObject *aio;
3842 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3845 node = _clipBoard_->objectList;
3847 cutItem = node->data;
3848 node = g_list_next( node );
3849 cache = addrindex_get_cache(
3850 _clipBoard_->addressIndex, cutItem->cacheID );
3851 if( cache == NULL ) continue;
3852 aio = addrcache_get_object( cache, cutItem->uid );
3855 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3858 folder = ( ItemFolder * ) aio;
3859 tn = gtk_cmctree_find_by_row_data_custom(
3860 ctree, NULL, folder,
3861 addressbook_treenode_find_folder_cb );
3863 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3866 group = ( ItemGroup * ) aio;
3867 tn = gtk_cmctree_find_by_row_data_custom(
3869 addressbook_treenode_find_group_cb );
3873 /* Free up adapter and remove node. */
3874 gtk_cmctree_remove_node( ctree, tn );
3881 * Find parent datasource for specified tree node.
3882 * \param node Node to test.
3883 * \return Data source, or NULL if not found.
3885 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3886 AddressDataSource *ds = NULL;
3889 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3892 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3893 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3895 /* g_print( "ao->type = %d\n", ao->type ); */
3896 if( ao->type == ADDR_DATASOURCE ) {
3897 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3898 /* g_print( "found it\n" ); */
3899 ds = ads->dataSource;
3903 node = GTK_CMCTREE_ROW(node)->parent;
3909 * Load address list widget with children of specified object.
3910 * \param obj Parent object to be loaded.
3912 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3913 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3914 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3915 AddressDataSource *ds = NULL;
3916 AdapterDSource *ads = NULL;
3917 static AddressObject *last_obj = NULL;
3919 if (addrbook.clist == NULL) {
3922 if (obj == last_obj && !refresh)
3927 gtk_cmclist_clear(clist);
3931 if( obj->type == ADDR_INTERFACE ) {
3932 /* g_print( "set_clist: loading datasource...\n" ); */
3933 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3937 gtk_cmclist_freeze(clist);
3938 gtk_cmclist_clear(clist);
3940 if( obj->type == ADDR_DATASOURCE ) {
3941 ads = ADAPTER_DSOURCE(obj);
3942 ds = ads->dataSource;
3944 /* Load root folder */
3945 ItemFolder *rootFolder = NULL;
3946 rootFolder = addrindex_ds_get_root_folder( ds );
3947 addressbook_folder_load_person(
3948 ctreelist, rootFolder );
3949 addressbook_folder_load_group(
3950 ctreelist, rootFolder );
3954 if( obj->type == ADDR_ITEM_GROUP ) {
3956 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3957 addressbook_load_group( ctreelist, itemGroup );
3959 else if( obj->type == ADDR_ITEM_FOLDER ) {
3961 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3962 addressbook_folder_load_person( ctreelist, itemFolder );
3963 addressbook_folder_load_group( ctreelist, itemFolder );
3966 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3967 clist->focus_row = -1;
3968 gtk_cmclist_thaw(clist);
3972 * Call back function to free adaptor. Call back is setup by function
3973 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3974 * called when the address book tree widget node is removed by calling
3975 * function gtk_cmctree_remove_node().
3977 * \param data Tree node's row data.
3979 static void addressbook_free_treenode( gpointer data ) {
3982 ao = ( AddressObject * ) data;
3983 if( ao == NULL ) return;
3984 if( ao->type == ADDR_INTERFACE ) {
3985 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3986 addrbookctl_free_interface( ai );
3988 else if( ao->type == ADDR_DATASOURCE ) {
3989 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3990 addrbookctl_free_datasource( ads );
3992 else if( ao->type == ADDR_ITEM_FOLDER ) {
3993 AdapterFolder *af = ADAPTER_FOLDER(ao);
3994 addrbookctl_free_folder( af );
3996 else if( ao->type == ADDR_ITEM_GROUP ) {
3997 AdapterGroup *ag = ADAPTER_GROUP(ao);
3998 addrbookctl_free_group( ag );
4003 * Create new adaptor for specified data source.
4005 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4006 AddressObjectType otype, gchar *name )
4008 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4009 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4010 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4011 adapter->dataSource = ds;
4012 adapter->subType = otype;
4016 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4017 ADDRESS_OBJECT_NAME(adapter) =
4018 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4022 * Load tree from address index with the initial data.
4024 static void addressbook_load_tree( void ) {
4025 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4026 GList *nodeIf, *nodeDS;
4027 AdapterInterface *adapter;
4028 AddressInterface *iface;
4029 AddressTypeControlItem *atci;
4030 AddressDataSource *ds;
4031 AdapterDSource *ads;
4032 GtkCMCTreeNode *node, *newNode;
4035 nodeIf = _addressInterfaceList_;
4037 adapter = nodeIf->data;
4038 node = adapter->treeNode;
4039 iface = adapter->interface;
4040 atci = adapter->atci;
4042 if( iface->useInterface ) {
4043 /* Load data sources below interface node */
4044 nodeDS = iface->listSource;
4047 name = addrindex_ds_get_name( ds );
4048 ads = addressbook_create_ds_adapter(
4049 ds, atci->objectType, name );
4050 newNode = addressbook_add_object(
4051 node, ADDRESS_OBJECT(ads) );
4052 if (newNode == NULL) {
4053 g_message("error adding addressbook object\n");
4055 nodeDS = g_list_next( nodeDS );
4057 gtk_cmctree_expand( ctree, node );
4060 nodeIf = g_list_next( nodeIf );
4065 * Convert the old address book to new format.
4067 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4068 gboolean retVal = FALSE;
4069 gboolean errFlag = TRUE;
4072 /* Read old address book, performing conversion */
4073 debug_print( "Reading and converting old address book...\n" );
4074 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4075 addrindex_read_data( addrIndex );
4076 if( addrIndex->retVal == MGU_NO_FILE ) {
4077 /* We do not have a file - new user */
4078 debug_print( "New user... create new books...\n" );
4079 addrindex_create_new_books( addrIndex );
4080 if( addrIndex->retVal == MGU_SUCCESS ) {
4081 /* Save index file */
4082 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4083 addrindex_save_data( addrIndex );
4084 if( addrIndex->retVal == MGU_SUCCESS ) {
4089 msg = _( "New user, could not save index file." );
4093 msg = _( "New user, could not save address book files." );
4097 /* We have an old file */
4098 if( addrIndex->wasConverted ) {
4099 /* Converted successfully - save address index */
4100 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4101 addrindex_save_data( addrIndex );
4102 if( addrIndex->retVal == MGU_SUCCESS ) {
4103 msg = _( "Old address book converted successfully." );
4108 msg = _("Old address book converted,\n"
4109 "could not save new address index file." );
4113 /* File conversion failed - just create new books */
4114 debug_print( "File conversion failed... just create new books...\n" );
4115 addrindex_create_new_books( addrIndex );
4116 if( addrIndex->retVal == MGU_SUCCESS ) {
4118 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4119 addrindex_save_data( addrIndex );
4120 if( addrIndex->retVal == MGU_SUCCESS ) {
4121 msg = _("Could not convert address book,\n"
4122 "but created empty new address book files." );
4127 msg = _("Could not convert address book,\n"
4128 "could not save new address index file." );
4132 msg = _("Could not convert address book\n"
4133 "and could not create new address book files." );
4138 debug_print( "Error\n%s\n", msg );
4139 alertpanel_full(_("Addressbook conversion error"), msg,
4140 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4141 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4144 debug_print( "Warning\n%s\n", msg );
4145 alertpanel_full(_("Addressbook conversion error"), msg,
4146 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4147 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4153 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4157 gboolean failed = FALSE;
4158 GError *error = NULL;
4160 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4161 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4162 error->code, error->message);
4163 g_error_free(error);
4167 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4168 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4171 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4173 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4175 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4188 /* all copies succeeded, we can remove source files */
4189 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4190 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4191 error->code, error->message);
4192 g_error_free(error);
4195 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4196 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4199 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4201 claws_unlink(orig_file);
4211 void addressbook_read_file( void ) {
4212 AddressIndex *addrIndex = NULL;
4213 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4215 debug_print( "Reading address index...\n" );
4216 if( _addressIndex_ ) {
4217 debug_print( "address book already read!!!\n" );
4221 addrIndex = addrindex_create_index();
4222 addrindex_initialize();
4224 /* Use new address book index. */
4226 if ( !is_dir_exist(indexdir) ) {
4227 if ( make_dir(indexdir) < 0 ) {
4228 addrindex_set_file_path( addrIndex, get_rc_dir() );
4229 g_warning( "couldn't create dir '%s'", indexdir);
4231 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4232 remove_dir_recursive(indexdir);
4233 addrindex_set_file_path( addrIndex, get_rc_dir() );
4234 g_error("couldn't migrate dir %s", indexdir);
4236 addrindex_set_file_path( addrIndex, indexdir);
4240 addrindex_set_file_path( addrIndex, indexdir);
4243 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4244 addrindex_read_data( addrIndex );
4245 if( addrIndex->retVal == MGU_NO_FILE ) {
4246 /* Conversion required */
4247 debug_print( "Converting...\n" );
4248 if( addressbook_convert( addrIndex ) ) {
4249 _addressIndex_ = addrIndex;
4252 else if( addrIndex->retVal == MGU_SUCCESS ) {
4253 _addressIndex_ = addrIndex;
4256 /* Error reading address book */
4257 debug_print( "Could not read address index.\n" );
4258 addrindex_print_index( addrIndex, stdout );
4259 alertpanel_full(_("Addressbook Error"),
4260 _("Could not read address index"),
4261 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4262 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4264 debug_print( "done.\n" );
4268 * Add object into the address index tree widget.
4269 * Enter: node Parent node.
4270 * obj Object to add.
4271 * Return: Node that was added, or NULL if object not added.
4273 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4276 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4277 GtkCMCTreeNode *added;
4278 AddressObject *pobj;
4279 AddressObjectType otype;
4280 AddressTypeControlItem *atci = NULL;
4282 cm_return_val_if_fail(node != NULL, NULL);
4283 cm_return_val_if_fail(obj != NULL, NULL);
4285 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4286 cm_return_val_if_fail(pobj != NULL, NULL);
4288 /* Determine object type to be displayed */
4289 if( obj->type == ADDR_DATASOURCE ) {
4290 otype = ADAPTER_DSOURCE(obj)->subType;
4296 /* Handle any special conditions. */
4298 atci = addrbookctl_lookup( otype );
4300 if( atci->showInTree ) {
4301 /* Add object to tree */
4304 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4305 atci->iconXpm, atci->iconXpmOpen,
4306 atci->treeLeaf, atci->treeExpand );
4307 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4308 addressbook_free_treenode );
4312 gtk_sctree_sort_node(ctree, node);
4318 * Add group into the address index tree.
4319 * \param node Parent node.
4320 * \param ds Data source.
4321 * \param itemGroup Group to add.
4322 * \return Inserted node.
4324 static GtkCMCTreeNode *addressbook_node_add_group(
4325 GtkCMCTreeNode *node, AddressDataSource *ds,
4326 ItemGroup *itemGroup )
4328 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4329 GtkCMCTreeNode *newNode;
4330 AdapterGroup *adapter;
4331 AddressTypeControlItem *atci = NULL;
4334 if( ds == NULL ) return NULL;
4335 if( node == NULL || itemGroup == NULL ) return NULL;
4337 name = &itemGroup->obj.name;
4339 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4341 adapter = g_new0( AdapterGroup, 1 );
4342 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4343 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4344 adapter->itemGroup = itemGroup;
4346 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4347 atci->iconXpm, atci->iconXpm,
4348 atci->treeLeaf, atci->treeExpand );
4349 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4350 addressbook_free_treenode );
4351 gtk_sctree_sort_node( ctree, node );
4356 * Add folder into the address index tree. Only visible folders are loaded into
4357 * the address index tree. Note that the root folder is not inserted into the
4360 * \param node Parent node.
4361 * \param ds Data source.
4362 * \param itemFolder Folder to add.
4363 * \param otype Object type to display.
4364 * \return Inserted node for the folder.
4366 static GtkCMCTreeNode *addressbook_node_add_folder(
4367 GtkCMCTreeNode *node, AddressDataSource *ds,
4368 ItemFolder *itemFolder, AddressObjectType otype )
4370 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4371 GtkCMCTreeNode *newNode = NULL;
4372 AdapterFolder *adapter;
4373 AddressTypeControlItem *atci = NULL;
4374 GList *listItems = NULL;
4376 ItemFolder *rootFolder;
4378 /* Only visible folders */
4379 if( itemFolder == NULL || itemFolder->isHidden )
4384 if( node == NULL || itemFolder == NULL )
4387 /* Determine object type */
4388 atci = addrbookctl_lookup( otype );
4392 rootFolder = addrindex_ds_get_root_folder( ds );
4393 if( itemFolder == rootFolder ) {
4397 adapter = g_new0( AdapterFolder, 1 );
4398 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4399 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4400 adapter->itemFolder = itemFolder;
4402 name = ADDRITEM_NAME(itemFolder);
4403 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4404 atci->iconXpm, atci->iconXpm,
4405 atci->treeLeaf, atci->treeExpand );
4407 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4408 addressbook_free_treenode );
4412 listItems = itemFolder->listFolder;
4413 while( listItems ) {
4414 ItemFolder *item = listItems->data;
4415 addressbook_node_add_folder( newNode, ds, item, otype );
4416 listItems = g_list_next( listItems );
4418 listItems = itemFolder->listGroup;
4419 while( listItems ) {
4420 ItemGroup *item = listItems->data;
4421 addressbook_node_add_group( newNode, ds, item );
4422 listItems = g_list_next( listItems );
4424 gtk_sctree_sort_node( ctree, node );
4428 void addressbook_export_to_file( void ) {
4429 if( _addressIndex_ ) {
4430 /* Save all new address book data */
4431 debug_print( "Saving address books...\n" );
4432 addrindex_save_all_books( _addressIndex_ );
4434 debug_print( "Exporting addressbook to file...\n" );
4435 addrindex_save_data( _addressIndex_ );
4436 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4437 addrindex_print_index( _addressIndex_, stdout );
4440 /* Notify address completion of new data */
4441 invalidate_address_completion();
4445 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4447 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4448 addressbook_lup_clicked(NULL, NULL);
4453 * Comparison using cell contents (text in first column). Used for sort
4454 * address index widget.
4456 static gint addressbook_treenode_compare_func(
4457 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4459 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4460 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4461 gchar *name1 = NULL, *name2 = NULL;
4462 if( cell1 ) name1 = cell1->u.text;
4463 if( cell2 ) name2 = cell2->u.text;
4464 if( ! name1 ) return ( name2 != NULL );
4465 if( ! name2 ) return -1;
4466 return g_utf8_collate( name1, name2 );
4469 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4470 AdapterDSource *ads;
4471 AdapterInterface *adapter;
4472 GtkCMCTreeNode *newNode;
4474 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4475 if( adapter == NULL ) return;
4476 ads = addressbook_edit_book( _addressIndex_, NULL );
4478 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4480 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4481 addrbook.treeSelected = newNode;
4486 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4487 AdapterDSource *ads;
4488 AdapterInterface *adapter;
4489 GtkCMCTreeNode *newNode;
4491 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4492 if( adapter == NULL ) return;
4493 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4495 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4497 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4498 addrbook.treeSelected = newNode;
4504 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4505 AdapterDSource *ads;
4506 AdapterInterface *adapter;
4507 AddressInterface *iface;
4508 GtkCMCTreeNode *newNode;
4510 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4511 if( adapter == NULL ) return;
4512 iface = adapter->interface;
4513 if( ! iface->haveLibrary ) return;
4514 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4516 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4518 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4519 addrbook.treeSelected = newNode;
4526 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4527 AdapterDSource *ads;
4528 AdapterInterface *adapter;
4529 AddressInterface *iface;
4530 GtkCMCTreeNode *newNode;
4532 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4533 if( adapter == NULL ) return;
4534 iface = adapter->interface;
4535 if( ! iface->haveLibrary ) return;
4536 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4538 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4540 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4541 addrbook.treeSelected = newNode;
4548 * Display address search status message.
4549 * \param queryType Query type.
4550 * \param status Status/Error code.
4552 static void addressbook_search_message( gint queryType, gint sts ) {
4554 *addressbook_msgbuf = '\0';
4556 if( sts != MGU_SUCCESS ) {
4557 if( queryType == ADDRQUERY_LDAP ) {
4559 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4564 g_snprintf( addressbook_msgbuf,
4565 sizeof(addressbook_msgbuf), "%s", desc );
4566 addressbook_status_show( addressbook_msgbuf );
4569 addressbook_status_show( "" );
4574 * Refresh addressbook by forcing refresh of current selected object in
4577 static void addressbook_refresh_current( void ) {
4581 ctree = GTK_CMCTREE(addrbook.ctree);
4582 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4583 if( obj == NULL ) return;
4584 addressbook_set_clist( obj, TRUE );
4588 * Message that is displayed whilst a query is executing in a background
4591 static gchar *_tempMessage_ = N_( "Busy searching..." );
4594 * Address search idle function. This function is called during UI idle time
4595 * while a search is in progress.
4597 * \param data Idler data.
4599 static void addressbook_search_idle( gpointer data ) {
4603 queryID = GPOINTER_TO_INT( data );
4604 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4609 * Search completion callback function. This removes the query from the idle
4612 * \param sender Sender of query.
4613 * \param queryID Query ID of search request.
4614 * \param status Search status.
4615 * \param data Query data.
4617 static void addressbook_search_callback_end(
4618 gpointer sender, gint queryID, gint status, gpointer data )
4622 AddrQueryObject *aqo;
4624 /* Remove idler function */
4625 ptrQID = GINT_TO_POINTER( queryID );
4627 g_idle_remove_by_data( ptrQID );
4630 /* Refresh addressbook contents */
4631 addressbook_refresh_current();
4632 req = qrymgr_find_request( queryID );
4634 aqo = ( AddrQueryObject * ) req->queryList->data;
4635 addressbook_search_message( aqo->queryType, status );
4638 /* Stop the search */
4639 addrindex_stop_search( queryID );
4645 * \param ds Data source to search.
4646 * \param searchTerm String to lookup.
4647 * \param pNode Parent data source node.
4649 static void addressbook_perform_search(
4650 AddressDataSource *ds, gchar *searchTerm,
4651 GtkCMCTreeNode *pNode )
4659 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4661 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4663 /* Create a folder for the search results */
4664 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4665 folder = addressbook_setup_subf(ds, name, pNode);
4668 /* Setup the search */
4669 queryID = addrindex_setup_explicit_search(
4670 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4671 if( queryID == 0 ) return;
4673 /* Set up idler function */
4674 idleID = g_idle_add(
4675 (GSourceFunc) addressbook_search_idle,
4676 GINT_TO_POINTER( queryID ) );
4678 g_message("error adding addressbook_search_idle\n");
4681 /* Start search, sit back and wait for something to happen */
4682 addrindex_start_search( queryID );
4684 addressbook_status_show( _tempMessage_ );
4688 * Lookup button handler. Address search is only performed against
4689 * address interfaces for external queries.
4691 * \param button Lookup button widget.
4692 * \param data Data object.
4694 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4697 AddressDataSource *ds;
4698 AddressInterface *iface;
4700 GtkCMCTreeNode *node, *parentNode;
4702 node = addrbook.treeSelected;
4703 if( ! node ) return;
4704 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4706 ctree = GTK_CMCTREE(addrbook.ctree);
4707 obj = gtk_cmctree_node_get_row_data( ctree, node );
4708 if( obj == NULL ) return;
4710 if (obj->type != ADDR_DATASOURCE ||
4711 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4712 addressbook_set_clist(
4713 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4714 addrbook.treeSelected),
4718 ds = addressbook_find_datasource( node );
4719 if( ds == NULL ) return;
4721 /* We must have a datasource that is an external interface */
4722 iface = ds->interface;
4723 if( ! iface->haveLibrary ) return;
4724 if( ! iface->externalQuery ) return;
4727 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4728 g_strchomp( searchTerm );
4730 if( obj->type == ADDR_ITEM_FOLDER ) {
4731 parentNode = GTK_CMCTREE_ROW(node)->parent;
4736 addressbook_perform_search( ds, searchTerm, parentNode );
4738 gtk_widget_grab_focus( addrbook.entry );
4740 g_free( searchTerm );
4743 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4744 addressbook_close();
4749 * Browse address entry for highlighted entry.
4751 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4753 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4755 AddressDataSource *ds;
4756 AddressInterface *iface;
4760 if(addrbook.listSelected == NULL)
4763 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4767 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4771 iface = ds->interface;
4772 if(!iface || !iface->haveLibrary )
4776 if (obj->type == ADDR_ITEM_EMAIL) {
4777 email = ( ItemEMail * ) obj;
4779 person = (ItemPerson *) ADDRITEM_PARENT(email);
4781 else if (obj->type == ADDR_ITEM_PERSON) {
4782 person = (ItemPerson *) obj;
4789 if( iface && iface->type == ADDR_IF_LDAP ) {
4790 browseldap_entry(ds, person->externalID);
4795 /* **********************************************************************
4796 * Build lookup tables.
4797 * ***********************************************************************
4801 * Remap object types.
4802 * Enter: abType AddressObjectType (used in tree node).
4803 * Return: ItemObjectType (used in address cache data).
4805 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4806 ItemObjectType ioType;
4809 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4810 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4811 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4812 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4813 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4814 default: ioType = ITEMTYPE_NONE; break;
4819 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4820 atci = addrbookctl_lookup(id); \
4822 atci->iconXpm = icon; \
4823 atci->iconXpmOpen = iconopen; \
4825 g_warning("can't get atci %d", id); \
4830 * Build table that controls the rendering of object types.
4832 static void addrbookctl_build_icons( GtkWidget *window ) {
4833 AddressTypeControlItem *atci;
4837 g_object_unref(interfacexpm);
4839 g_object_unref(folderxpm);
4841 g_object_unref(folderopenxpm);
4843 g_object_unref(groupxpm);
4845 g_object_unref(vcardxpm);
4847 g_object_unref(bookxpm);
4849 g_object_unref(addressxpm);
4851 g_object_unref(jpilotxpm);
4853 g_object_unref(categoryxpm);
4855 g_object_unref(ldapxpm);
4857 g_object_unref(addrsearchxpm);
4858 stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacexpm );
4859 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4860 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4861 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4862 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4863 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4864 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4865 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4866 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4867 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4868 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4870 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4871 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4872 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4873 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4874 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4875 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4876 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4877 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4878 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4879 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4880 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4885 * Build table that controls the rendering of object types.
4887 static void addrbookctl_build_map( GtkWidget *window ) {
4888 AddressTypeControlItem *atci;
4890 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4891 _addressBookTypeList_ = NULL;
4894 atci = g_new0( AddressTypeControlItem, 1 );
4895 atci->objectType = ADDR_INTERFACE;
4896 atci->interfaceType = ADDR_IF_NONE;
4897 atci->showInTree = TRUE;
4898 atci->treeExpand = TRUE;
4899 atci->treeLeaf = FALSE;
4900 atci->displayName = _( "Interface" );
4901 atci->menuCommand = NULL;
4902 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4903 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4906 atci = g_new0( AddressTypeControlItem, 1 );
4907 atci->objectType = ADDR_BOOK;
4908 atci->interfaceType = ADDR_IF_BOOK;
4909 atci->showInTree = TRUE;
4910 atci->treeExpand = TRUE;
4911 atci->treeLeaf = FALSE;
4912 atci->displayName = _( "Address Book" );
4913 atci->menuCommand = "Menu/Book/NewBook";
4914 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4915 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4918 atci = g_new0( AddressTypeControlItem, 1 );
4919 atci->objectType = ADDR_ITEM_PERSON;
4920 atci->interfaceType = ADDR_IF_NONE;
4921 atci->showInTree = FALSE;
4922 atci->treeExpand = FALSE;
4923 atci->treeLeaf = FALSE;
4924 atci->displayName = _( "Person" );
4925 atci->menuCommand = NULL;
4926 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4927 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4930 atci = g_new0( AddressTypeControlItem, 1 );
4931 atci->objectType = ADDR_ITEM_EMAIL;
4932 atci->interfaceType = ADDR_IF_NONE;
4933 atci->showInTree = FALSE;
4934 atci->treeExpand = FALSE;
4935 atci->treeLeaf = TRUE;
4936 atci->displayName = _( "Email Address" );
4937 atci->menuCommand = NULL;
4938 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4939 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4942 atci = g_new0( AddressTypeControlItem, 1 );
4943 atci->objectType = ADDR_ITEM_GROUP;
4944 atci->interfaceType = ADDR_IF_BOOK;
4945 atci->showInTree = TRUE;
4946 atci->treeExpand = FALSE;
4947 atci->treeLeaf = FALSE;
4948 atci->displayName = _( "Group" );
4949 atci->menuCommand = NULL;
4950 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4951 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4954 atci = g_new0( AddressTypeControlItem, 1 );
4955 atci->objectType = ADDR_ITEM_FOLDER;
4956 atci->interfaceType = ADDR_IF_BOOK;
4957 atci->showInTree = TRUE;
4958 atci->treeExpand = FALSE;
4959 atci->treeLeaf = FALSE;
4960 atci->displayName = _( "Folder" );
4961 atci->menuCommand = NULL;
4962 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4963 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4966 atci = g_new0( AddressTypeControlItem, 1 );
4967 atci->objectType = ADDR_VCARD;
4968 atci->interfaceType = ADDR_IF_VCARD;
4969 atci->showInTree = TRUE;
4970 atci->treeExpand = TRUE;
4971 atci->treeLeaf = TRUE;
4972 atci->displayName = _( "vCard" );
4973 atci->menuCommand = "Menu/Book/NewVCard";
4974 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4975 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4978 atci = g_new0( AddressTypeControlItem, 1 );
4979 atci->objectType = ADDR_JPILOT;
4980 atci->interfaceType = ADDR_IF_JPILOT;
4981 atci->showInTree = TRUE;
4982 atci->treeExpand = TRUE;
4983 atci->treeLeaf = FALSE;
4984 atci->displayName = _( "JPilot" );
4985 atci->menuCommand = "Menu/Book/NewJPilot";
4986 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4987 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4990 atci = g_new0( AddressTypeControlItem, 1 );
4991 atci->objectType = ADDR_CATEGORY;
4992 atci->interfaceType = ADDR_IF_JPILOT;
4993 atci->showInTree = TRUE;
4994 atci->treeExpand = TRUE;
4995 atci->treeLeaf = TRUE;
4996 atci->displayName = _( "JPilot" );
4997 atci->menuCommand = NULL;
4998 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4999 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5002 atci = g_new0( AddressTypeControlItem, 1 );
5003 atci->objectType = ADDR_LDAP;
5004 atci->interfaceType = ADDR_IF_LDAP;
5005 atci->showInTree = TRUE;
5006 atci->treeExpand = TRUE;
5007 atci->treeLeaf = FALSE;
5008 atci->displayName = _( "LDAP servers" );
5009 atci->menuCommand = "Menu/Book/NewLDAPServer";
5010 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5011 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5014 atci = g_new0( AddressTypeControlItem, 1 );
5015 atci->objectType = ADDR_LDAP_QUERY;
5016 atci->interfaceType = ADDR_IF_LDAP;
5017 atci->showInTree = TRUE;
5018 atci->treeExpand = FALSE;
5019 atci->treeLeaf = TRUE;
5020 atci->displayName = _( "LDAP Query" );
5021 atci->menuCommand = NULL;
5022 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5023 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5025 addrbookctl_build_icons(window);
5028 void addressbook_reflect_prefs_pixmap_theme(void)
5030 if (addrbook.window)
5031 addrbookctl_build_icons(addrbook.window);
5035 * Search for specified object type.
5037 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5039 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5043 * Search for specified interface type.
5045 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5046 GList *node = _addressBookTypeList_;
5048 AddressTypeControlItem *atci = node->data;
5049 if( atci->interfaceType == ifType ) return atci;
5050 node = g_list_next( node );
5055 static void addrbookctl_free_address( AddressObject *obj ) {
5056 g_free( obj->name );
5057 obj->type = ADDR_NONE;
5061 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5062 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5063 adapter->interface = NULL;
5064 adapter->interfaceType = ADDR_IF_NONE;
5065 adapter->atci = NULL;
5066 adapter->enabled = FALSE;
5067 adapter->haveLibrary = FALSE;
5068 adapter->treeNode = NULL;
5072 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5073 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5074 adapter->dataSource = NULL;
5075 adapter->subType = ADDR_NONE;
5079 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5080 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5081 adapter->itemFolder = NULL;
5085 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5086 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5087 adapter->itemGroup = NULL;
5092 * Build GUI interface list.
5094 static void addrbookctl_build_iflist( void ) {
5095 AddressTypeControlItem *atci;
5096 AdapterInterface *adapter;
5099 if( _addressIndex_ == NULL ) {
5100 _addressIndex_ = addrindex_create_index();
5101 if( _clipBoard_ == NULL ) {
5102 _clipBoard_ = addrclip_create();
5104 addrclip_set_index( _clipBoard_, _addressIndex_ );
5106 _addressInterfaceList_ = NULL;
5107 list = addrindex_get_interface_list( _addressIndex_ );
5109 AddressInterface *interface = list->data;
5110 atci = addrbookctl_lookup_iface( interface->type );
5112 adapter = g_new0( AdapterInterface, 1 );
5113 adapter->interfaceType = interface->type;
5114 adapter->atci = atci;
5115 adapter->interface = interface;
5116 adapter->treeNode = NULL;
5117 adapter->enabled = TRUE;
5118 adapter->haveLibrary = interface->haveLibrary;
5119 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5120 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5121 _addressInterfaceList_ =
5122 g_list_append( _addressInterfaceList_, adapter );
5124 list = g_list_next( list );
5129 * Find GUI interface type specified interface type.
5130 * \param ifType Interface type.
5131 * \return Interface item, or NULL if not found.
5133 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5134 GList *node = _addressInterfaceList_;
5136 AdapterInterface *adapter = node->data;
5137 if( adapter->interfaceType == ifType ) return adapter;
5138 node = g_list_next( node );
5144 * Build interface list selection.
5146 static void addrbookctl_build_ifselect( void ) {
5147 GList *newList = NULL;
5152 gchar *endptr = NULL;
5153 /* gboolean enabled; */
5154 AdapterInterface *adapter;
5156 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5159 splitStr = g_strsplit( selectStr, ",", -1 );
5160 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5162 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5163 ifType = strtol( splitStr[i], &endptr, 10 );
5166 if( strcmp( endptr, "/n" ) == 0 ) {
5171 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5172 adapter = addrbookctl_find_interface( ifType );
5174 newList = g_list_append( newList, adapter );
5181 /* g_print( "i=%d\n", i ); */
5182 g_strfreev( splitStr );
5183 g_free( selectStr );
5185 /* Replace existing list */
5186 mgu_clear_list( _addressIFaceSelection_ );
5187 g_list_free( _addressIFaceSelection_ );
5188 _addressIFaceSelection_ = newList;
5192 /* ***********************************************************************
5193 * Add sender to address book.
5194 * ***********************************************************************
5198 * This function is used by the Add sender to address book function.
5200 gboolean addressbook_add_contact(
5201 const gchar *name, const gchar *address, const gchar *remarks,
5202 GdkPixbuf *picture )
5204 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5205 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5206 debug_print( "addressbook_add_contact - added\n" );
5207 addressbook_refresh();
5212 /* ***********************************************************************
5213 * Book/folder selection.
5214 * ***********************************************************************
5218 * This function is used by the matcher dialog to select a book/folder.
5220 gchar *addressbook_folder_selection( const gchar *folderpath)
5222 AddressBookFile *book = NULL;
5223 ItemFolder *folder = NULL;
5226 cm_return_val_if_fail( folderpath != NULL, NULL);
5228 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5230 if ( folder != NULL) {
5232 gchar *oldtmp = NULL;
5233 AddrItemObject *obj = NULL;
5235 /* walk thru folder->parent to build the full folder path */
5236 /* TODO: wwp: optimize this */
5238 tmp = g_strdup(obj->uid);
5239 while ( obj->parent ) {
5241 if ( obj->name != NULL ) {
5242 oldtmp = g_strdup(tmp);
5244 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5248 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5251 path = g_strdup_printf("%s", book->fileName);
5253 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5259 /* ***********************************************************************
5260 * Book/folder checking.
5261 * ***********************************************************************
5264 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5266 FolderInfo *fi = g_new0( FolderInfo, 1 );
5268 fi->folder = folder;
5272 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5273 FolderInfo *fiParent, FolderPathMatch *match )
5279 FolderPathMatch *nextmatch = NULL;
5284 list = parentFolder->listFolder;
5286 folder = list->data;
5287 fName = g_strdup( ADDRITEM_NAME(folder) );
5289 /* match folder name, match pointer will be set to NULL if next recursive call
5290 doesn't need to match subfolder name */
5291 if ( match != NULL &&
5292 match->matched == FALSE ) {
5293 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5294 /* folder name matches, prepare next subfolder match */
5295 debug_print("matched folder name '%s'\n", fName);
5297 if ( match->folder_path[match->index] == NULL ) {
5298 /* we've matched all elements */
5299 match->matched = TRUE;
5300 match->folder = folder;
5301 debug_print("book/folder path matched!\n");
5303 /* keep on matching */
5311 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5312 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5314 list = g_list_next( list );
5319 * This function is used by to check if a matcher book/folder path corresponds to an
5320 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5321 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5322 if book AND folder are NULL this means that folderpath was empty or Any.
5323 If folderpath is a simple book name (without folder), book will not be NULL and folder
5324 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5327 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5328 AddressDataSource **book,
5329 ItemFolder **folder )
5331 AddressDataSource *ds;
5332 GList *list, *nodeDS;
5333 ItemFolder *rootFolder;
5334 AddressBookFile *abf;
5336 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5343 if ( folderpath == NULL )
5346 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5349 /* split the folder path we've received, we'll try to match this path, subpath by
5350 subpath against the book/folder structure in order */
5351 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5352 if (!folder_path_match.folder_path)
5355 list = addrindex_get_interface_list( _addressIndex_ );
5356 while ( list && !folder_path_match.matched ) {
5357 AddressInterface *interface = list->data;
5358 if ( interface && interface->type == ADDR_IF_BOOK ) {
5359 nodeDS = interface->listSource;
5360 while ( nodeDS && !folder_path_match.matched ) {
5363 /* Read address book */
5364 if( ! addrindex_ds_get_read_flag( ds ) ) {
5365 addrindex_ds_read_data( ds );
5368 /* Add node for address book */
5369 abf = ds->rawDataSource;
5371 /* match book name */
5372 if ( abf && abf->fileName &&
5373 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5375 debug_print("matched book name '%s'\n", abf->fileName);
5376 folder_path_match.book = ds;
5378 if ( folder_path_match.folder_path[1] == NULL ) {
5379 /* no folder part to match */
5381 folder_path_match.matched = TRUE;
5382 folder_path_match.folder = NULL;
5383 debug_print("book path matched!\n");
5386 /* match folder part */
5388 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5389 rootFolder = addrindex_ds_get_root_folder( ds );
5391 /* prepare for recursive call */
5392 folder_path_match.index = 1;
5393 /* this call will set folder_path_match.matched and folder_path_match.folder */
5394 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5399 nodeDS = g_list_next( nodeDS );
5402 list = g_list_next( list );
5405 g_strfreev( folder_path_match.folder_path );
5408 *book = folder_path_match.book;
5410 *folder = folder_path_match.folder;
5411 return folder_path_match.matched;
5415 /* **********************************************************************
5417 * ***********************************************************************
5423 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5424 AddressDataSource *ds = NULL;
5425 AdapterDSource *ads = NULL;
5426 AddressBookFile *abf = NULL;
5427 AdapterInterface *adapter;
5428 GtkCMCTreeNode *newNode;
5430 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5432 if( adapter->treeNode ) {
5433 abf = addressbook_imp_ldif( _addressIndex_ );
5435 ds = addrindex_index_add_datasource(
5436 _addressIndex_, ADDR_IF_BOOK, abf );
5437 ads = addressbook_create_ds_adapter(
5438 ds, ADDR_BOOK, NULL );
5439 addressbook_ads_set_name(
5440 ads, addrbook_get_name( abf ) );
5441 newNode = addressbook_add_object(
5443 ADDRESS_OBJECT(ads) );
5445 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5447 addrbook.treeSelected = newNode;
5450 /* Notify address completion */
5451 invalidate_address_completion();
5460 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5461 AddressDataSource *ds = NULL;
5462 AdapterDSource *ads = NULL;
5463 AddressBookFile *abf = NULL;
5464 AdapterInterface *adapter;
5465 GtkCMCTreeNode *newNode;
5467 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5469 if( adapter->treeNode ) {
5470 abf = addressbook_imp_mutt( _addressIndex_ );
5472 ds = addrindex_index_add_datasource(
5473 _addressIndex_, ADDR_IF_BOOK, abf );
5474 ads = addressbook_create_ds_adapter(
5475 ds, ADDR_BOOK, NULL );
5476 addressbook_ads_set_name(
5477 ads, addrbook_get_name( abf ) );
5478 newNode = addressbook_add_object(
5480 ADDRESS_OBJECT(ads) );
5482 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5484 addrbook.treeSelected = newNode;
5487 /* Notify address completion */
5488 invalidate_address_completion();
5497 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5498 AddressDataSource *ds = NULL;
5499 AdapterDSource *ads = NULL;
5500 AddressBookFile *abf = NULL;
5501 AdapterInterface *adapter;
5502 GtkCMCTreeNode *newNode;
5504 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5506 if( adapter->treeNode ) {
5507 abf = addressbook_imp_pine( _addressIndex_ );
5509 ds = addrindex_index_add_datasource(
5510 _addressIndex_, ADDR_IF_BOOK, abf );
5511 ads = addressbook_create_ds_adapter(
5512 ds, ADDR_BOOK, NULL );
5513 addressbook_ads_set_name(
5514 ads, addrbook_get_name( abf ) );
5515 newNode = addressbook_add_object(
5517 ADDRESS_OBJECT(ads) );
5519 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5521 addrbook.treeSelected = newNode;
5524 /* Notify address completion */
5525 invalidate_address_completion();
5532 * Harvest addresses.
5533 * \param folderItem Folder to import.
5534 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5535 * \param msgList List of message numbers, or NULL to process folder.
5537 void addressbook_harvest(
5538 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5540 AddressDataSource *ds = NULL;
5541 AdapterDSource *ads = NULL;
5542 AddressBookFile *abf = NULL;
5543 AdapterInterface *adapter;
5544 GtkCMCTreeNode *newNode;
5546 abf = addrgather_dlg_execute(
5547 folderItem, _addressIndex_, sourceInd, msgList );
5549 ds = addrindex_index_add_datasource(
5550 _addressIndex_, ADDR_IF_BOOK, abf );
5552 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5554 if( adapter->treeNode ) {
5555 ads = addressbook_create_ds_adapter(
5556 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5557 newNode = addressbook_add_object(
5559 ADDRESS_OBJECT(ads) );
5560 if (newNode == NULL) {
5561 g_message("error adding addressbook object\n");
5566 /* Notify address completion */
5567 invalidate_address_completion();
5574 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5575 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5577 AddressDataSource *ds = NULL;
5578 AddrBookBase *adbase;
5579 AddressCache *cache;
5580 GtkCMCTreeNode *node = NULL;
5582 if( ! addrbook.treeSelected ) return;
5583 node = addrbook.treeSelected;
5584 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5585 obj = gtk_cmctree_node_get_row_data( ctree, node );
5586 if( obj == NULL ) return;
5588 ds = addressbook_find_datasource( node );
5589 if( ds == NULL ) return;
5590 adbase = ( AddrBookBase * ) ds->rawDataSource;
5591 cache = adbase->addressCache;
5592 addressbook_exp_html( cache );
5598 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5599 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5601 AddressDataSource *ds = NULL;
5602 AddrBookBase *adbase;
5603 AddressCache *cache;
5604 GtkCMCTreeNode *node = NULL;
5606 if( ! addrbook.treeSelected ) return;
5607 node = addrbook.treeSelected;
5608 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5609 obj = gtk_cmctree_node_get_row_data( ctree, node );
5610 if( obj == NULL ) return;
5612 ds = addressbook_find_datasource( node );
5613 if( ds == NULL ) return;
5614 adbase = ( AddrBookBase * ) ds->rawDataSource;
5615 cache = adbase->addressCache;
5616 addressbook_exp_ldif( cache );
5619 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5621 addrduplicates_find(GTK_WINDOW(addrbook.window));
5624 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5626 addressbook_custom_attr_edit();
5629 static void addressbook_start_drag(GtkWidget *widget, gint button,
5633 GdkDragContext *context;
5634 if (addressbook_target_list == NULL)
5635 addressbook_target_list = gtk_target_list_new(
5636 addressbook_drag_types, 1);
5637 context = gtk_drag_begin(widget, addressbook_target_list,
5638 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5639 gtk_drag_set_icon_default(context);
5642 static void addressbook_drag_data_get(GtkWidget *widget,
5643 GdkDragContext *drag_context,
5644 GtkSelectionData *selection_data,
5649 AddrItemObject *aio = NULL;
5650 AddressObject *pobj = NULL;
5651 AdapterDSource *ads = NULL;
5652 AddressDataSource *ds = NULL;
5655 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5657 if( pobj == NULL ) return;
5659 if( pobj->type == ADDR_DATASOURCE ) {
5660 ads = ADAPTER_DSOURCE(pobj);
5661 ds = ads->dataSource;
5662 } else if (pobj->type == ADDR_ITEM_GROUP) {
5667 else if( pobj->type != ADDR_INTERFACE ) {
5668 ds = addressbook_find_datasource( addrbook.treeSelected );
5674 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5675 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5676 GTK_CMCTREE_NODE(cur->data));
5677 while (aio && aio->type != ITEMTYPE_PERSON) {
5682 if (aio && aio->type == ITEMTYPE_PERSON) {
5683 if( ds && ds->interface && ds->interface->readOnly)
5684 gtk_selection_data_set(selection_data,
5685 gtk_selection_data_get_target(selection_data), 8,
5686 (const guchar *)"Dummy_addr_copy", 15);
5688 gtk_selection_data_set(selection_data,
5689 gtk_selection_data_get_target(selection_data), 8,
5690 (const guchar *)"Dummy_addr_move", 15);
5694 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5695 GdkDragContext *context,
5701 GtkAllocation allocation;
5702 GtkRequisition requisition;
5704 GtkCMCTreeNode *node = NULL;
5705 gboolean acceptable = FALSE;
5706 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5707 gint height = allocation.height;
5708 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5709 gint total_height = requisition.height;
5710 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5711 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5712 gfloat vpos = gtk_adjustment_get_value(pos);
5714 if (gtk_cmclist_get_selection_info
5715 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5717 if (y > height - 24 && height + vpos < total_height) {
5718 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5719 gtk_adjustment_changed(pos);
5721 if (y < 24 && y > 0) {
5722 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5723 gtk_adjustment_changed(pos);
5725 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5728 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5729 if( obj->type == ADDR_ITEM_FOLDER
5730 || obj->type == ADDR_ITEM_GROUP)
5733 AdapterDSource *ads = NULL;
5734 AddressDataSource *ds = NULL;
5735 ads = ADAPTER_DSOURCE(obj);
5736 if (ads == NULL ){ return FALSE;}
5737 ds = ads->dataSource;
5738 if (ds == NULL ) { return FALSE;}
5746 g_signal_handlers_block_by_func
5748 G_CALLBACK(addressbook_tree_selected), NULL);
5749 gtk_sctree_select( GTK_SCTREE(widget), node);
5750 g_signal_handlers_unblock_by_func
5752 G_CALLBACK(addressbook_tree_selected), NULL);
5753 gdk_drag_status(context,
5754 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5755 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5757 gdk_drag_status(context, 0, time);
5762 static void addressbook_drag_leave_cb(GtkWidget *widget,
5763 GdkDragContext *context,
5767 if (addrbook.treeSelected) {
5768 g_signal_handlers_block_by_func
5770 G_CALLBACK(addressbook_tree_selected), NULL);
5771 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5772 g_signal_handlers_unblock_by_func
5774 G_CALLBACK(addressbook_tree_selected), NULL);
5779 static void addressbook_drag_received_cb(GtkWidget *widget,
5780 GdkDragContext *drag_context,
5783 GtkSelectionData *data,
5789 GtkCMCTreeNode *node;
5790 GtkCMCTreeNode *lastopened = addrbook.opened;
5792 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5793 if (gtk_cmclist_get_selection_info
5794 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5798 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5799 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5802 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5803 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5804 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5805 addressbook_clip_copy_cb(NULL, NULL);
5807 addressbook_clip_cut_cb(NULL, NULL);
5808 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5809 addressbook_clip_paste_cb(NULL,NULL);
5810 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5811 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5812 gtk_drag_finish(drag_context, TRUE, TRUE, time);