2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2020 the Claws Mail team and Hiroyuki Yamamoto
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"
47 #include "file-utils.h"
52 #include "addr_compl.h"
56 #include "addressitem.h"
58 #include "addrcache.h"
60 #include "addrindex.h"
61 #include "addrmerge.h"
62 #include "addressadd.h"
63 #include "addrduplicates.h"
64 #include "addressbook_foldersel.h"
66 #include "editvcard.h"
67 #include "editgroup.h"
68 #include "editaddress.h"
70 #include "importldif.h"
71 #include "importmutt.h"
72 #include "importpine.h"
77 #include "editjpilot.h"
82 #include "ldapserver.h"
84 #include "ldapupdate.h"
86 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
89 #include "addrquery.h"
90 #include "addrselect.h"
92 #include "addrgather.h"
93 #include "adbookbase.h"
94 #include "exphtmldlg.h"
95 #include "expldifdlg.h"
96 #include "browseldap.h"
97 #include "addrcustomattr.h"
105 } AddressIndexColumns;
113 } AddressListColumns;
116 AddressBookFile *book;
124 AddressDataSource *book;
128 static gchar *list_titles[] = { N_("Name"),
132 #define COL_NAME_WIDTH 164
133 #define COL_ADDRESS_WIDTH 156
135 #define COL_FOLDER_WIDTH 170
136 #define ADDRESSBOOK_WIDTH 640
137 #define ADDRESSBOOK_HEIGHT 360
139 #define ADDRESSBOOK_MSGBUF_SIZE 2048
141 static GdkPixbuf *folderxpm = NULL;
142 static GdkPixbuf *folderopenxpm = NULL;
143 static GdkPixbuf *groupxpm = NULL;
144 static GdkPixbuf *interfacexpm = NULL;
145 static GdkPixbuf *bookxpm = NULL;
146 static GdkPixbuf *addressxpm = NULL;
147 static GdkPixbuf *vcardxpm = NULL;
148 static GdkPixbuf *jpilotxpm = NULL;
149 static GdkPixbuf *categoryxpm = NULL;
150 static GdkPixbuf *ldapxpm = NULL;
151 static GdkPixbuf *addrsearchxpm = NULL;
154 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
156 /* Address list selection */
157 static AddrSelectList *_addressSelect_ = NULL;
158 static AddressClipboard *_clipBoard_ = NULL;
160 /* Address index file and interfaces */
161 static AddressIndex *_addressIndex_ = NULL;
162 static GList *_addressInterfaceList_ = NULL;
163 static GList *_addressIFaceSelection_ = NULL;
164 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
166 static AddressBook_win addrbook;
168 static GHashTable *_addressBookTypeHash_ = NULL;
169 static GList *_addressBookTypeList_ = NULL;
171 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
172 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
173 static void addressbook_edit_address_post_cb( ItemPerson *person );
175 static void addressbook_create (void);
176 static gint addressbook_close (void);
178 static gboolean address_index_has_focus = FALSE;
179 static gboolean address_list_has_focus = FALSE;
181 /* callback functions */
182 static void addressbook_del_clicked (GtkButton *button,
184 static void addressbook_reg_clicked (GtkButton *button,
186 static void addressbook_to_clicked (GtkButton *button,
188 static void addressbook_lup_clicked (GtkButton *button,
190 static void addressbook_close_clicked (GtkButton *button,
193 static void addressbook_tree_selected (GtkCMCTree *ctree,
194 GtkCMCTreeNode *node,
197 static void addressbook_select_row_tree (GtkCMCTree *ctree,
198 GtkCMCTreeNode *node,
201 static void addressbook_list_row_selected (GtkCMCTree *clist,
202 GtkCMCTreeNode *node,
205 static void addressbook_list_row_unselected (GtkCMCTree *clist,
206 GtkCMCTreeNode *node,
209 static void addressbook_person_expand_node (GtkCMCTree *ctree,
212 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
216 static void addressbook_entry_activated (GtkWidget *widget,
219 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
220 GdkEventButton *event,
222 static gboolean addressbook_list_button_released(GtkWidget *widget,
223 GdkEventButton *event,
225 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
226 GdkEventButton *event,
228 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
229 GdkEventButton *event,
232 static void addressbook_new_folder_cb (GtkAction *action,
234 static void addressbook_new_group_cb (GtkAction *action,
236 static void addressbook_treenode_edit_cb (GtkAction *action,
238 static void addressbook_treenode_delete_cb (GtkAction *action,
241 static void addressbook_change_node_name (GtkCMCTreeNode *node,
244 static void addressbook_new_address_cb (GtkAction *action,
246 static void addressbook_edit_address_cb (GtkAction *action,
248 static void addressbook_delete_address_cb (GtkAction *action,
251 static void close_cb (GtkAction *action,
253 static void addressbook_file_save_cb (GtkAction *action,
256 /* Data source edit stuff */
257 static void addressbook_new_book_cb (GtkAction *action,
259 static void addressbook_new_vcard_cb (GtkAction *action,
263 static void addressbook_new_jpilot_cb (GtkAction *action,
268 static void addressbook_new_ldap_cb (GtkAction *action,
272 static void addressbook_set_clist (AddressObject *obj,
275 static void addressbook_load_tree (void);
276 void addressbook_read_file (void);
278 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
280 static void addressbook_treenode_remove_item ( void );
282 static AddressDataSource *addressbook_find_datasource
283 (GtkCMCTreeNode *node );
285 static AddressBookFile *addressbook_get_book_file(void);
287 static GtkCMCTreeNode *addressbook_node_add_folder
288 (GtkCMCTreeNode *node,
289 AddressDataSource *ds,
290 ItemFolder *itemFolder,
291 AddressObjectType otype);
292 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
293 AddressDataSource *ds,
294 ItemGroup *itemGroup);
295 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
296 GtkCMCTreeNode *parent);
297 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
298 GtkCMCTreeNode *node);
299 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
301 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
304 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
307 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
309 AddressTypeControlItem *atci,
310 AddressTypeControlItem *atciMail);
311 static void addressbook_folder_remove_node (GtkCMCTree *clist,
312 GtkCMCTreeNode *node);
314 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
315 gboolean force_focus );
317 /* LUT's and IF stuff */
318 static void addressbook_free_treenode ( gpointer data );
319 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
320 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
322 static void addrbookctl_build_map (GtkWidget *window);
323 static void addrbookctl_build_iflist (void);
324 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
325 static void addrbookctl_build_ifselect (void);
327 static void addrbookctl_free_interface (AdapterInterface *adapter);
328 static void addrbookctl_free_datasource (AdapterDSource *adapter);
329 static void addrbookctl_free_folder (AdapterFolder *adapter);
330 static void addrbookctl_free_group (AdapterGroup *adapter);
332 static void addressbook_list_select_clear ( void );
333 static void addressbook_list_select_add ( AddrItemObject *aio,
334 AddressDataSource *ds );
335 static void addressbook_list_select_remove ( AddrItemObject *aio );
337 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
338 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
339 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
340 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
341 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
342 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
343 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
344 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
345 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
346 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
347 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
348 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
349 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
350 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
352 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
353 static void addressbook_merge_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", NULL, NULL, NULL },
405 {"Book", NULL, N_("_Book"), NULL, NULL, NULL },
406 {"Edit", NULL, N_("_Edit"), NULL, NULL, NULL },
407 {"Tools", NULL, N_("_Tools"), NULL, NULL, NULL },
410 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
411 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
412 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
416 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
419 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
421 {"Book/---", NULL, "---", NULL, NULL, NULL },
423 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
424 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
425 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
426 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
427 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
430 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
431 {"Address/---", NULL, "---", NULL, NULL, NULL },
432 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
433 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
434 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
435 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
436 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
437 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
438 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
439 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
440 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
441 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
442 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
443 {"Address/Merge", NULL, N_("_Merge"), "<control>E", NULL, G_CALLBACK(addressbook_merge_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 static GtkActionEntry addressbook_tree_popup_entries[] =
460 {"ABTreePopup", NULL, "ABTreePopup", NULL, NULL, NULL },
461 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
462 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
463 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
464 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
465 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
466 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
467 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
468 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
469 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
470 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
473 static GtkActionEntry addressbook_list_popup_entries[] =
475 {"ABListPopup", NULL, "ABListPopup", NULL, NULL, NULL },
476 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
477 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
478 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
479 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
480 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
481 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
482 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
483 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
484 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
485 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
486 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
487 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
488 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
490 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
492 {"ABListPopup/Merge", NULL, N_("_Merge"), NULL, NULL, G_CALLBACK(addressbook_merge_cb) },
496 * Structure of error message table.
498 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
499 struct _ErrMsgTableEntry {
504 static gchar *_errMsgUnknown_ = N_( "Unknown" );
507 * Lookup table of error messages for general errors. Note that a NULL
508 * description signifies the end of the table.
510 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
511 { MGU_SUCCESS, N_("Success") },
512 { MGU_BAD_ARGS, N_("Bad arguments") },
513 { MGU_NO_FILE, N_("File not specified") },
514 { MGU_OPEN_FILE, N_("Error opening file") },
515 { MGU_ERROR_READ, N_("Error reading file") },
516 { MGU_EOF, N_("End of file encountered") },
517 { MGU_OO_MEMORY, N_("Error allocating memory") },
518 { MGU_BAD_FORMAT, N_("Bad file format") },
519 { MGU_ERROR_WRITE, N_("Error writing to file") },
520 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
521 { MGU_NO_PATH, N_("No path specified") },
527 * Lookup table of error messages for LDAP errors.
529 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
530 { LDAPRC_SUCCESS, N_("Success") },
531 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
532 { LDAPRC_INIT, N_("Error initializing LDAP") },
533 { LDAPRC_BIND, N_("Error binding to LDAP server") },
534 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
535 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
536 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
537 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
538 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
539 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
540 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
541 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
542 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
543 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
549 * Lookup message for specified error code.
550 * \param lut Lookup table.
551 * \param code Code to lookup.
552 * \return Description associated to code.
554 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
556 ErrMsgTableEntry entry;
559 for( i = 0; ; i++ ) {
561 if( entry.description == NULL ) break;
562 if( entry.code == code ) {
563 desc = entry.description;
568 desc = _errMsgUnknown_;
573 static gboolean lastCanLookup = FALSE;
575 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
577 if (add_and_delete) {
578 gtk_widget_show(addrbook.edit_btn);
579 gtk_widget_show(addrbook.del_btn);
580 gtk_widget_show(addrbook.reg_btn);
582 gtk_widget_hide(addrbook.edit_btn);
583 gtk_widget_hide(addrbook.del_btn);
584 gtk_widget_hide(addrbook.reg_btn);
588 gtk_widget_show(addrbook.lup_btn);
589 gtk_widget_show(addrbook.entry);
590 gtk_widget_show(addrbook.label);
592 gtk_widget_hide(addrbook.lup_btn);
593 gtk_widget_hide(addrbook.entry);
594 gtk_widget_hide(addrbook.label);
597 lastCanLookup = lookup;
600 gtk_widget_show(addrbook.to_btn);
601 gtk_widget_show(addrbook.cc_btn);
602 gtk_widget_show(addrbook.bcc_btn);
604 gtk_widget_hide(addrbook.to_btn);
605 gtk_widget_hide(addrbook.cc_btn);
606 gtk_widget_hide(addrbook.bcc_btn);
610 void addressbook_open(Compose *target)
612 /* Initialize all static members */
613 if( _clipBoard_ == NULL ) {
614 _clipBoard_ = addrclip_create();
616 if( _addressIndex_ != NULL ) {
617 addrclip_set_index( _clipBoard_, _addressIndex_ );
619 if( _addressSelect_ == NULL ) {
620 _addressSelect_ = addrselect_list_create();
622 if (!addrbook.window) {
623 addressbook_read_file();
624 addressbook_create();
625 addressbook_load_tree();
626 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
627 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
630 gtk_widget_hide(addrbook.window);
633 gtk_widget_show_all(addrbook.window);
635 if (!prefs_common.addressbook_use_editaddress_dialog)
636 addressbook_edit_person_widgetset_hide();
638 address_completion_start(addrbook.window);
640 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
641 addressbook_set_target_compose(target);
645 * Destroy addressbook.
647 void addressbook_destroy( void ) {
648 /* Free up address stuff */
649 if( _addressSelect_ != NULL ) {
650 addrselect_list_free( _addressSelect_ );
652 if( _clipBoard_ != NULL ) {
653 addrclip_free( _clipBoard_ );
656 if( _addressIndex_ != NULL ) {
657 addrindex_free_index( _addressIndex_ );
658 addrindex_teardown();
660 _addressSelect_ = NULL;
662 _addressIndex_ = NULL;
665 void addressbook_set_target_compose(Compose *target)
667 addrbook.target_compose = target;
670 Compose *addressbook_get_target_compose(void)
672 return addrbook.target_compose;
676 * Refresh addressbook and save to file(s).
678 void addressbook_refresh( void )
680 if (addrbook.window) {
681 if (addrbook.treeSelected) {
682 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
683 addrbook.treeSelected);
684 addressbook_set_clist(
685 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
686 addrbook.treeSelected),
691 addressbook_export_to_file();
694 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
696 if (event && event->keyval == GDK_KEY_Escape)
698 else if (event && event->keyval == GDK_KEY_Delete) {
699 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
700 if ( /* address_index_has_focus || */ address_list_has_focus )
701 addressbook_del_clicked(NULL, NULL);
707 *\brief Save Gtk object size to prefs dataset
709 static void addressbook_size_allocate_cb(GtkWidget *widget,
710 GtkAllocation *allocation)
712 cm_return_if_fail(allocation != NULL);
714 prefs_common.addressbookwin_width = allocation->width;
715 prefs_common.addressbookwin_height = allocation->height;
718 static gint sort_column_number = 0;
719 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
721 static gint list_case_sort(
722 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
724 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
725 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
726 gchar *name1 = NULL, *name2 = NULL;
727 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
728 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
730 if( aio1->type == aio2->type ) {
732 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
734 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
735 if( ! name1 ) return ( name2 != NULL );
736 if( ! name2 ) return -1;
737 return g_utf8_collate( name1, name2 );
739 /* Order groups before person */
740 if( aio1->type == ITEMTYPE_GROUP ) {
741 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
742 } else if( aio2->type == ITEMTYPE_GROUP ) {
743 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
749 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
750 const GtkSortType sort_type)
753 GtkWidget *hbox, *label, *arrow;
755 sort_column_number = col;
756 sort_column_type = sort_type;
757 gtk_cmclist_set_compare_func(clist, list_case_sort);
758 gtk_cmclist_set_sort_type(clist, sort_type);
759 gtk_cmclist_set_sort_column(clist, col);
761 gtk_cmclist_freeze(clist);
762 gtk_cmclist_sort(clist);
764 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
765 hbox = gtk_hbox_new(FALSE, 4);
766 label = gtk_label_new(gettext(list_titles[pos]));
767 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
770 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
771 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
772 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
775 gtk_widget_show_all(hbox);
776 gtk_cmclist_set_column_widget(clist, pos, hbox);
779 gtk_cmclist_thaw(clist);
782 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
784 static GtkSortType sort_type = GTK_SORT_ASCENDING;
786 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
788 addressbook_sort_list(clist, COL_NAME, sort_type);
791 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
793 static GtkSortType sort_type = GTK_SORT_ASCENDING;
795 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
797 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
800 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
802 static GtkSortType sort_type = GTK_SORT_ASCENDING;
804 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
806 addressbook_sort_list(clist, COL_REMARKS, sort_type);
809 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
812 address_index_has_focus = TRUE;
816 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
819 address_index_has_focus = FALSE;
820 if (!prefs_common.addressbook_use_editaddress_dialog
821 && !address_list_has_focus)
822 addressbook_address_list_disable_some_actions();
826 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
829 address_list_has_focus = TRUE;
833 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
836 address_list_has_focus = FALSE;
837 if (!prefs_common.addressbook_use_editaddress_dialog
838 && !address_index_has_focus)
839 addressbook_address_list_disable_some_actions();
843 /* save hpane and vpane's handle position when it moves */
844 static void addressbook_pane_save_position(void)
847 prefs_common.addressbook_hpaned_pos =
848 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
850 prefs_common.addressbook_vpaned_pos =
851 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
855 * Create the address book widgets. The address book contains two CTree widgets: the
856 * address index tree on the left and the address list on the right.
858 * The address index tree displays a hierarchy of interfaces and groups. Each node in
859 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
860 * data sources and folder objects.
862 * The address list displays group, person and email objects. These items are linked
863 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
866 * In the tradition of MVC architecture, the data stores have been separated from the
867 * GUI components. The addrindex.c file provides the interface to all data stores.
869 static void addressbook_create(void)
875 GtkWidget *ctree_swin;
877 GtkWidget *editaddress_vbox;
878 GtkWidget *clist_vbox;
879 GtkWidget *clist_swin;
886 GtkWidget *statusbar;
897 GtkWidget *close_btn;
898 GtkWidget *tree_popup;
899 GtkWidget *list_popup;
901 GtkUIManager *ui_manager;
902 GtkActionGroup *action_group;
903 gchar *index_titles[N_INDEX_COLS];
907 static GdkGeometry geometry;
909 debug_print("Creating addressbook window...\n");
911 index_titles[COL_SOURCES] = _("Sources");
913 /* Address book window */
914 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
915 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
916 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
917 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
918 gtk_widget_realize(window);
920 g_signal_connect(G_OBJECT(window), "delete_event",
921 G_CALLBACK(addressbook_close), NULL);
922 g_signal_connect(G_OBJECT(window), "size_allocate",
923 G_CALLBACK(addressbook_size_allocate_cb), NULL);
924 g_signal_connect(G_OBJECT(window), "key_press_event",
925 G_CALLBACK(key_pressed), NULL);
926 MANAGE_WINDOW_SIGNALS_CONNECT(window);
928 vbox = gtk_vbox_new(FALSE, 0);
929 gtk_container_add(GTK_CONTAINER(window), vbox);
932 ui_manager = gtk_ui_manager_new();
933 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
934 G_N_ELEMENTS(addressbook_entries), NULL);
935 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
936 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
937 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
938 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
940 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
942 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
957 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
990 gtk_window_add_accel_group(GTK_WINDOW(window),
991 gtk_ui_manager_get_accel_group(ui_manager));
993 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
995 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
997 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
998 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
999 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1001 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1002 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1003 GTK_POLICY_AUTOMATIC,
1004 GTK_POLICY_AUTOMATIC);
1005 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1008 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1009 gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1011 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1012 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1013 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1014 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1015 GTK_CMCTREE_EXPANDER_TRIANGLE);
1016 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1017 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1018 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1019 addressbook_treenode_compare_func);
1021 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1022 G_CALLBACK(addressbook_tree_selected), NULL);
1023 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1024 G_CALLBACK(addressbook_tree_button_pressed),
1026 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1027 G_CALLBACK(addressbook_tree_button_released),
1030 g_signal_connect(G_OBJECT(ctree), "select_row",
1031 G_CALLBACK(addressbook_select_row_tree), NULL);
1033 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1034 addressbook_drag_types, 1,
1035 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1036 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1037 G_CALLBACK(addressbook_drag_motion_cb),
1039 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1040 G_CALLBACK(addressbook_drag_leave_cb),
1042 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1043 G_CALLBACK(addressbook_drag_received_cb),
1045 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1046 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1047 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1048 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1050 clist_vbox = gtk_vbox_new(FALSE, 4);
1052 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1053 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1054 GTK_POLICY_AUTOMATIC,
1055 GTK_POLICY_AUTOMATIC);
1056 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1059 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1060 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1061 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1062 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1063 GTK_CMCTREE_EXPANDER_TRIANGLE);
1064 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1065 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1066 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1068 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1070 gtk_widget_set_size_request(clist, -1, 80);
1072 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1073 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1074 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1075 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1076 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1077 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1078 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1079 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1080 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1081 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1082 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1084 for (i = 0; i < N_LIST_COLS; i++)
1085 gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1088 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1089 G_CALLBACK(addressbook_list_row_selected), NULL);
1090 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1091 G_CALLBACK(addressbook_list_row_unselected), NULL);
1092 g_signal_connect(G_OBJECT(clist), "button_press_event",
1093 G_CALLBACK(addressbook_list_button_pressed),
1095 g_signal_connect(G_OBJECT(clist), "button_release_event",
1096 G_CALLBACK(addressbook_list_button_released),
1098 g_signal_connect(G_OBJECT(clist), "tree_expand",
1099 G_CALLBACK(addressbook_person_expand_node), NULL );
1100 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1101 G_CALLBACK(addressbook_person_collapse_node), NULL );
1102 g_signal_connect(G_OBJECT(clist), "start_drag",
1103 G_CALLBACK(addressbook_start_drag), NULL);
1104 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1105 G_CALLBACK(addressbook_drag_data_get), NULL);
1106 hbox = gtk_hbox_new(FALSE, 4);
1107 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1109 label = gtk_label_new(_("Search"));
1110 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1112 entry = gtk_entry_new();
1113 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1115 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1117 g_signal_connect(G_OBJECT(entry), "key_press_event",
1118 G_CALLBACK(addressbook_entry_key_pressed),
1120 g_signal_connect(G_OBJECT(entry), "activate",
1121 G_CALLBACK(addressbook_entry_activated), NULL);
1123 if (!prefs_common.addressbook_use_editaddress_dialog) {
1124 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1125 vpaned = gtk_vpaned_new();
1126 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1127 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1130 editaddress_vbox = NULL;
1132 hpaned = gtk_hpaned_new();
1133 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1134 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1135 if (prefs_common.addressbook_use_editaddress_dialog)
1136 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1138 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1141 hsbox = gtk_hbox_new(FALSE, 0);
1142 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1143 statusbar = gtk_statusbar_new();
1144 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1147 hbbox = gtk_hbutton_box_new();
1148 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1149 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1150 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1151 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1153 gtkut_stock_button_add_help(hbbox, &help_btn);
1155 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1156 gtk_widget_set_can_default(edit_btn, TRUE);
1157 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1158 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1159 gtk_widget_set_can_default(del_btn, TRUE);
1160 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1161 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1162 gtk_widget_set_can_default(reg_btn, TRUE);
1163 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1166 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1167 gtk_widget_set_can_default(lup_btn, TRUE);
1168 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1170 g_signal_connect(G_OBJECT(help_btn), "clicked",
1171 G_CALLBACK(manual_open_with_anchor_cb),
1172 MANUAL_ANCHOR_ADDRBOOK);
1174 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1175 G_CALLBACK(addressbook_edit_clicked), NULL);
1176 g_signal_connect(G_OBJECT(del_btn), "clicked",
1177 G_CALLBACK(addressbook_del_clicked), NULL);
1178 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1179 G_CALLBACK(addressbook_reg_clicked), NULL);
1180 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1181 G_CALLBACK(addressbook_lup_clicked), NULL);
1183 to_btn = gtk_button_new_with_label
1184 (prefs_common_translated_header_name("To:"));
1185 gtk_widget_set_can_default(to_btn, TRUE);
1186 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1187 cc_btn = gtk_button_new_with_label
1188 (prefs_common_translated_header_name("Cc:"));
1189 gtk_widget_set_can_default(cc_btn, TRUE);
1190 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1191 bcc_btn = gtk_button_new_with_label
1192 (prefs_common_translated_header_name("Bcc:"));
1193 gtk_widget_set_can_default(bcc_btn, TRUE);
1194 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1196 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1197 gtk_widget_set_can_default(close_btn, TRUE);
1198 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1200 g_signal_connect(G_OBJECT(to_btn), "clicked",
1201 G_CALLBACK(addressbook_to_clicked),
1202 GINT_TO_POINTER(COMPOSE_TO));
1203 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1204 G_CALLBACK(addressbook_to_clicked),
1205 GINT_TO_POINTER(COMPOSE_CC));
1206 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1207 G_CALLBACK(addressbook_to_clicked),
1208 GINT_TO_POINTER(COMPOSE_BCC));
1209 g_signal_connect(G_OBJECT(close_btn), "clicked",
1210 G_CALLBACK(addressbook_close_clicked), NULL);
1212 /* Build icons for interface */
1214 /* Build control tables */
1215 addrbookctl_build_map(window);
1216 addrbookctl_build_iflist();
1217 addrbookctl_build_ifselect();
1219 addrbook.clist = NULL;
1221 /* Add each interface into the tree as a root level folder */
1222 nodeIf = _addressInterfaceList_;
1224 AdapterInterface *adapter = nodeIf->data;
1225 AddressInterface *iface = adapter->interface;
1226 nodeIf = g_list_next(nodeIf);
1228 if(iface->useInterface) {
1229 AddressTypeControlItem *atci = adapter->atci;
1230 text = atci->displayName;
1232 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1233 NULL, NULL, &text, FOLDER_SPACING,
1237 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1238 gtk_cmctree_node_set_row_data_full(
1239 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1240 addressbook_free_treenode );
1246 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1247 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1248 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1249 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1250 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1259 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1260 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
1280 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1281 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1283 addrbook.window = window;
1284 addrbook.hpaned = hpaned;
1285 addrbook.vpaned = vpaned;
1286 addrbook.menubar = menubar;
1287 addrbook.ctree = ctree;
1290 addrbook.editaddress_vbox = editaddress_vbox;
1291 addrbook.clist = clist;
1292 addrbook.label = label;
1293 addrbook.entry = entry;
1294 addrbook.statusbar = statusbar;
1295 addrbook.status_cid = gtk_statusbar_get_context_id(
1296 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1298 addrbook.help_btn = help_btn;
1299 addrbook.edit_btn = edit_btn;
1300 addrbook.del_btn = del_btn;
1301 addrbook.reg_btn = reg_btn;
1302 addrbook.lup_btn = lup_btn;
1303 addrbook.to_btn = to_btn;
1304 addrbook.cc_btn = cc_btn;
1305 addrbook.bcc_btn = bcc_btn;
1307 addrbook.tree_popup = tree_popup;
1308 addrbook.list_popup = list_popup;
1309 addrbook.ui_manager = ui_manager;
1311 addrbook.listSelected = NULL;
1313 if (!geometry.min_height) {
1314 geometry.min_width = ADDRESSBOOK_WIDTH;
1315 geometry.min_height = ADDRESSBOOK_HEIGHT;
1318 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1320 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1321 prefs_common.addressbookwin_height);
1323 gtk_window_move(GTK_WINDOW(window), 48, 48);
1326 if (!prefs_common.addressbook_use_editaddress_dialog) {
1327 if (prefs_common.addressbook_vpaned_pos > 0)
1328 gtk_paned_set_position(GTK_PANED(vpaned),
1329 prefs_common.addressbook_vpaned_pos);
1331 if (prefs_common.addressbook_hpaned_pos > 0)
1332 gtk_paned_set_position(GTK_PANED(hpaned),
1333 prefs_common.addressbook_hpaned_pos);
1336 gtk_widget_show_all(window);
1340 * Close address book window and save to file(s).
1342 static gint addressbook_close( void ) {
1343 address_completion_end(addrbook.window);
1344 if (!prefs_common.addressbook_use_editaddress_dialog)
1345 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1347 addressbook_pane_save_position();
1349 gtk_widget_hide(addrbook.window);
1350 addressbook_export_to_file();
1355 * Display message in status line.
1356 * \param msg Message to display.
1358 static void addressbook_status_show( gchar *msg ) {
1359 if( addrbook.statusbar != NULL ) {
1361 GTK_STATUSBAR(addrbook.statusbar),
1362 addrbook.status_cid );
1365 GTK_STATUSBAR(addrbook.statusbar),
1366 addrbook.status_cid, msg );
1371 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1375 *addressbook_msgbuf = '\0';
1377 name = addrindex_ds_get_name( ds );
1378 retVal = addrindex_ds_get_status_code( ds );
1379 if( retVal == MGU_SUCCESS ) {
1380 g_snprintf( addressbook_msgbuf,
1381 sizeof(addressbook_msgbuf), "%s", name );
1384 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1385 g_snprintf( addressbook_msgbuf,
1386 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1389 addressbook_status_show( addressbook_msgbuf );
1392 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1394 addressbook_edit_address_cb(NULL, NULL);
1397 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1399 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1403 * Delete one or more objects from address list.
1405 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1407 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1408 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1409 AddressObject *pobj;
1410 AdapterDSource *ads = NULL;
1411 GtkCMCTreeNode *nodeList;
1414 AddressBookFile *abf = NULL;
1415 AddressDataSource *ds = NULL;
1416 AddressInterface *iface;
1417 AddrItemObject *aio;
1418 AddrSelectItem *item;
1420 gboolean refreshList = FALSE;
1422 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1423 cm_return_if_fail(pobj != NULL);
1425 /* Test whether anything selected for deletion */
1426 nodeList = addrbook.listSelected;
1428 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1429 if( aio == NULL) return;
1430 ds = addressbook_find_datasource( addrbook.treeSelected );
1431 if( ds == NULL ) return;
1433 /* Test for read only */
1434 iface = ds->interface;
1435 if( iface->readOnly ) {
1436 alertpanel( _("Delete address(es)"),
1437 _("This address data is read-only and cannot be deleted."),
1438 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST);
1442 /* Test whether Ok to proceed */
1444 if( pobj->type == ADDR_DATASOURCE ) {
1445 ads = ADAPTER_DSOURCE(pobj);
1446 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1448 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1451 else if( pobj->type == ADDR_ITEM_GROUP ) {
1454 if( ! procFlag ) return;
1455 abf = ds->rawDataSource;
1456 if( abf == NULL ) return;
1458 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1459 g_signal_handlers_block_by_func
1460 (G_OBJECT(addrbook.clist),
1461 G_CALLBACK(addressbook_list_row_unselected), NULL);
1463 /* Process deletions */
1464 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1465 GList *groups = NULL, *persons = NULL, *emails = NULL;
1466 gboolean group_delete = TRUE;
1467 /* Items inside folders */
1468 list = addrselect_get_list( _addressSelect_ );
1469 /* Confirm deletion */
1473 node = g_list_next( node );
1474 aio = ( AddrItemObject * ) item->addressItem;
1475 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1476 group_delete = FALSE;
1481 aval = alertpanel( _("Delete group"),
1482 _("Really delete the group(s)?\n"
1483 "The addresses it contains will not be lost."),
1484 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1485 if( aval != G_ALERTALTERNATE ) {
1489 aval = alertpanel( _("Delete address(es)"),
1490 _("Really delete the address(es)?"),
1491 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1492 if( aval != G_ALERTALTERNATE ) {
1497 /* first, set lists of groups and persons to remove */
1501 node = g_list_next( node );
1502 aio = ( AddrItemObject * ) item->addressItem;
1505 if( aio->type == ITEMTYPE_GROUP ) {
1506 groups = g_list_prepend(groups, item);
1508 else if( aio->type == ITEMTYPE_PERSON ) {
1509 persons = g_list_prepend(persons, item);
1512 /* then set list of emails to remove *if* they're not children of
1513 * persons to remove */
1517 node = g_list_next( node );
1518 aio = ( AddrItemObject * ) item->addressItem;
1521 if( aio->type == ITEMTYPE_EMAIL ) {
1522 ItemEMail *sitem = ( ItemEMail * ) aio;
1523 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1524 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1525 emails = g_list_prepend(emails, item);
1527 /* else, the email will be removed via the parent person */
1530 /* then delete groups */
1534 node = g_list_next( node );
1535 aio = ( AddrItemObject * ) item->addressItem;
1538 if( aio->type == ITEMTYPE_GROUP ) {
1539 ItemGroup *item = ( ItemGroup * ) aio;
1540 GtkCMCTreeNode *nd = NULL;
1541 nd = addressbook_find_group_node( addrbook.opened, item );
1542 item = addrbook_remove_group( abf, item );
1544 addritem_free_item_group( item );
1546 /* Remove group from parent node */
1547 gtk_cmctree_remove_node( ctree, nd );
1551 /* then delete persons */
1555 node = g_list_next( node );
1556 aio = ( AddrItemObject * ) item->addressItem;
1559 if( aio->type == ITEMTYPE_PERSON ) {
1560 ItemPerson *item = ( ItemPerson * ) aio;
1561 item->status = DELETE_ENTRY;
1562 addressbook_folder_remove_one_person( clist, item );
1563 if (pobj->type == ADDR_ITEM_FOLDER)
1564 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1565 item = addrbook_remove_person( abf, item );
1567 if (ds && ds->type == ADDR_IF_LDAP) {
1568 LdapServer *server = ds->rawDataSource;
1569 ldapsvr_set_modified(server, TRUE);
1570 ldapsvr_update_book(server, item);
1574 addritem_person_remove_picture(item);
1575 addritem_free_item_person( item );
1579 /* then delete emails */
1583 node = g_list_next( node );
1584 aio = ( AddrItemObject * ) item->addressItem;
1588 if( aio->type == ITEMTYPE_EMAIL ) {
1589 ItemEMail *sitem = ( ItemEMail * ) aio;
1590 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1591 sitem = addrbook_person_remove_email( abf, person, sitem );
1593 addrcache_remove_email(abf->addressCache, sitem);
1594 addritem_free_item_email( sitem );
1596 addressbook_folder_refresh_one_person( clist, person );
1599 g_list_free( groups );
1600 g_list_free( persons );
1601 g_list_free( emails );
1602 g_list_free( list );
1603 addressbook_list_select_clear();
1605 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1606 addressbook_set_clist(
1607 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1611 addrbook_set_dirty(abf, TRUE);
1612 addressbook_export_to_file();
1613 addressbook_list_menu_setup();
1616 else if( pobj->type == ADDR_ITEM_GROUP ) {
1617 /* Items inside groups */
1618 list = addrselect_get_list( _addressSelect_ );
1622 node = g_list_next( node );
1623 aio = ( AddrItemObject * ) item->addressItem;
1624 if( aio->type == ITEMTYPE_EMAIL ) {
1625 ItemEMail *item = ( ItemEMail * ) aio;
1626 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1627 item = addrbook_person_remove_email( abf, person, item );
1629 addritem_free_item_email( item );
1633 g_list_free( list );
1634 addressbook_list_select_clear();
1635 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1636 addressbook_set_clist(
1637 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1641 addrbook_set_dirty(abf, TRUE);
1642 addressbook_export_to_file();
1643 addressbook_list_menu_setup();
1647 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1648 gtk_cmctree_remove_node( clist, nodeList );
1650 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1651 g_signal_handlers_unblock_by_func
1652 (G_OBJECT(addrbook.clist),
1653 G_CALLBACK(addressbook_list_row_unselected), NULL);
1656 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1658 addressbook_new_address_cb( NULL, NULL );
1661 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1664 gchar *address = NULL;
1666 if( aio->type == ITEMTYPE_EMAIL ) {
1667 ItemPerson *person = NULL;
1668 ItemEMail *email = ( ItemEMail * ) aio;
1670 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1671 if( email->address ) {
1672 if( ADDRITEM_NAME(email) ) {
1673 name = ADDRITEM_NAME(email);
1674 if( *name == '\0' ) {
1675 name = ADDRITEM_NAME(person);
1678 else if( ADDRITEM_NAME(person) ) {
1679 name = ADDRITEM_NAME(person);
1682 buf = g_strdup( email->address );
1684 address = email->address;
1687 else if( aio->type == ITEMTYPE_PERSON ) {
1688 ItemPerson *person = ( ItemPerson * ) aio;
1689 GList *node = person->listEMail;
1691 name = ADDRITEM_NAME(person);
1693 ItemEMail *email = ( ItemEMail * ) node->data;
1694 address = email->address;
1698 if( name && name[0] != '\0' ) {
1699 if( strchr_with_skip_quote( name, '"', ',' ) )
1700 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1702 buf = g_strdup_printf( "%s <%s>", name, address );
1705 buf = g_strdup( address );
1712 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1716 AddrSelectItem *item;
1717 AddrItemObject *aio;
1720 compose = addrbook.target_compose;
1721 if( ! compose ) return;
1723 /* Nothing selected, but maybe there is something in text entry */
1724 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1726 compose_entry_append(
1727 compose, addr, (ComposeEntryType)data , PREF_NONE);
1730 /* Select from address list */
1731 list = addrselect_get_list( _addressSelect_ );
1736 node = g_list_next( node );
1737 aio = item->addressItem;
1738 if( aio->type == ITEMTYPE_PERSON ||
1739 aio->type == ITEMTYPE_EMAIL ) {
1740 addr = addressbook_format_address( aio );
1741 compose_entry_append(
1742 compose, addr, (ComposeEntryType) data, PREF_NONE );
1745 else if( aio->type == ITEMTYPE_GROUP ) {
1746 ItemGroup *group = ( ItemGroup * ) aio;
1747 GList *nodeMail = group->listEMail;
1749 ItemEMail *email = nodeMail->data;
1751 addr = addressbook_format_address(
1752 ( AddrItemObject * ) email );
1753 compose_entry_append(
1754 compose, addr, (ComposeEntryType) data, PREF_NONE );
1756 nodeMail = g_list_next( nodeMail );
1761 AddressObject *obj = NULL;
1763 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1765 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1766 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1767 GList *nodeMail = itemGroup->listEMail;
1769 ItemEMail *email = nodeMail->data;
1771 addr = addressbook_format_address(
1772 ( AddrItemObject * ) email );
1773 compose_entry_append(
1774 compose, addr, (ComposeEntryType) data, PREF_NONE );
1776 nodeMail = g_list_next( nodeMail );
1780 g_list_free( list );
1783 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1784 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1785 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1786 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1788 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/SelectAll", TRUE );
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", sensitive );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", sensitive );
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", sensitive );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", sensitive );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", sensitive );
1797 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1798 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1801 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1802 gboolean canEdit = FALSE;
1803 gboolean canDelete = TRUE;
1804 gboolean canAdd = FALSE;
1805 gboolean canEditTr = TRUE;
1806 gboolean editAddress = FALSE;
1807 gboolean canExport = TRUE;
1808 AddressTypeControlItem *atci = NULL;
1809 AddressDataSource *ds = NULL;
1810 AddressInterface *iface = NULL;
1812 if( obj == NULL ) return;
1813 if( obj->type == ADDR_INTERFACE ) {
1814 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1815 iface = adapter->interface;
1817 if( iface->haveLibrary ) {
1818 /* Enable appropriate File / New command */
1819 atci = adapter->atci;
1820 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1823 canEditTr = canExport = FALSE;
1825 else if( obj->type == ADDR_DATASOURCE ) {
1826 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1827 ds = ads->dataSource;
1828 iface = ds->interface;
1829 if( ! iface->readOnly ) {
1830 canAdd = canEdit = editAddress = canDelete = TRUE;
1832 if( ! iface->haveLibrary ) {
1833 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1836 else if( obj->type == ADDR_ITEM_FOLDER ) {
1837 ds = addressbook_find_datasource( addrbook.treeSelected );
1839 iface = ds->interface;
1840 if( iface->readOnly ) {
1845 canAdd = editAddress = TRUE;
1849 else if( obj->type == ADDR_ITEM_GROUP ) {
1850 ds = addressbook_find_datasource( addrbook.treeSelected );
1852 iface = ds->interface;
1853 if( ! iface->readOnly ) {
1859 if( addrbook.listSelected == NULL )
1863 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", editAddress );
1864 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", canAdd );
1865 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1866 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1869 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
1870 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
1871 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1872 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1875 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1878 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1879 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1883 * Address book tree callback function that responds to selection of tree
1886 * \param ctree Tree widget.
1887 * \param node Node that was selected.
1888 * \param column Column number where selected occurred.
1889 * \param data Pointer to user data.
1891 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1892 gint column, gpointer data)
1894 AddressObject *obj = NULL;
1895 AdapterDSource *ads = NULL;
1896 AddressDataSource *ds = NULL;
1897 ItemFolder *rootFolder = NULL;
1898 AddressObjectType aot;
1900 addrbook.treeSelected = node;
1901 addrbook.listSelected = NULL;
1902 addressbook_status_show( "" );
1903 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1905 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1907 addressbook_set_clist(NULL, TRUE);
1910 addrbook.opened = node;
1912 if( obj->type == ADDR_DATASOURCE ) {
1913 /* Read from file */
1914 static gboolean tVal = TRUE;
1916 ads = ADAPTER_DSOURCE(obj);
1918 ds = ads->dataSource;
1919 if( ds == NULL ) return;
1921 if( addrindex_ds_get_modify_flag( ds ) ) {
1922 addrindex_ds_read_data( ds );
1925 if( ! addrindex_ds_get_read_flag( ds ) ) {
1926 addrindex_ds_read_data( ds );
1928 addressbook_ds_show_message( ds );
1930 if( ! addrindex_ds_get_access_flag( ds ) ) {
1931 /* Remove existing folders and groups */
1932 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1933 addressbook_tree_remove_children( ctree, node );
1934 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1936 /* Load folders into the tree */
1937 rootFolder = addrindex_ds_get_root_folder( ds );
1938 if( ds && ds->type == ADDR_IF_JPILOT ) {
1939 aot = ADDR_CATEGORY;
1941 else if( ds && ds->type == ADDR_IF_LDAP ) {
1942 aot = ADDR_LDAP_QUERY;
1945 aot = ADDR_ITEM_FOLDER;
1947 addressbook_node_add_folder( node, ds, rootFolder, aot );
1948 addrindex_ds_set_access_flag( ds, &tVal );
1949 gtk_cmctree_expand( ctree, node );
1952 addressbook_set_clist(NULL, TRUE);
1955 /* Update address list */
1956 g_signal_handlers_block_by_func
1958 G_CALLBACK(addressbook_tree_selected), NULL);
1959 addressbook_set_clist( obj, FALSE );
1960 g_signal_handlers_unblock_by_func
1962 G_CALLBACK(addressbook_tree_selected), NULL);
1963 if (!prefs_common.addressbook_use_editaddress_dialog)
1964 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1966 /* Setup main menu selections */
1967 addressbook_menubar_set_sensitive( FALSE );
1968 addressbook_menuitem_set_sensitive( obj, node );
1969 addressbook_list_select_clear();
1970 addressbook_list_menu_setup();
1975 * Setup address list popup menu items. Items are enabled or disabled as
1978 static void addressbook_list_menu_setup( void ) {
1979 GtkCMCTree *clist = NULL;
1980 AddressObject *pobj = NULL;
1981 AddressObject *obj = NULL;
1982 AdapterDSource *ads = NULL;
1983 AddressInterface *iface = NULL;
1984 AddressDataSource *ds = NULL;
1986 AddrItemObject *aio;
1987 AddrSelectItem *item;
1988 gboolean canEdit = FALSE;
1989 gboolean canDelete = FALSE;
1990 gboolean canCut = FALSE;
1991 gboolean canCopy = FALSE;
1992 gboolean canPaste = FALSE;
1993 gboolean canBrowse = FALSE;
1994 gboolean canMerge = 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 /* Allow merging persons or emails are selected */
2073 list = _addressSelect_->listSelect;
2074 if (list && list->next ) {
2076 aio = ( AddrItemObject * ) item->addressItem;
2077 if( aio->type == ITEMTYPE_EMAIL ||
2078 aio->type == ITEMTYPE_PERSON ) {
2083 /* Forbid write changes when read-only */
2084 if( iface && iface->readOnly ) {
2091 /* Now go finalize menu items */
2092 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2093 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2095 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2096 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2097 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2099 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge", canMerge );
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2103 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2104 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2106 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
2107 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
2108 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", canCopy );
2109 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", canMerge );
2111 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2112 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2114 if (addrbook.target_compose) {
2115 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2116 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2117 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2120 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2124 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2125 GtkCMCTreeNode *node,
2132 * Add list of items into tree node below specified tree node.
2133 * \param treeNode Tree node.
2134 * \param ds Data source.
2135 * \param listItems List of items.
2137 static void addressbook_treenode_add_list(
2138 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2144 AddrItemObject *aio;
2148 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2151 group = ( ItemGroup * ) aio;
2152 nn = addressbook_node_add_group( treeNode, ds, group );
2154 g_message("error adding addressbook group\n");
2157 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2160 folder = ( ItemFolder * ) aio;
2161 nn = addressbook_node_add_folder(
2162 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2164 g_message("error adding addressbook folder\n");
2167 node = g_list_next( node );
2171 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2172 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2176 * Cut from address list widget.
2178 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2179 _clipBoard_->cutFlag = TRUE;
2180 addrclip_clear( _clipBoard_ );
2181 addrclip_add( _clipBoard_, _addressSelect_ );
2182 /* addrclip_list_show( _clipBoard_, stdout ); */
2186 * Copy from address list widget.
2188 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2189 _clipBoard_->cutFlag = FALSE;
2190 addrclip_clear( _clipBoard_ );
2191 addrclip_add( _clipBoard_, _addressSelect_ );
2192 /* addrclip_list_show( _clipBoard_, stdout ); */
2196 * Paste clipboard into address list widget.
2198 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2199 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2200 AddressObject *pobj = NULL;
2201 AddressDataSource *ds = NULL;
2202 AddressBookFile *abf = NULL;
2203 ItemFolder *folder = NULL;
2204 GList *folderGroup = NULL;
2206 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2207 if( ds == NULL ) return;
2208 if( addrindex_ds_get_readonly( ds ) ) {
2209 alertpanel_error( _("Cannot paste. Target address book is read-only.") );
2213 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2215 if( pobj->type == ADDR_ITEM_FOLDER ) {
2216 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2218 else if( pobj->type == ADDR_ITEM_GROUP ) {
2219 alertpanel_error( _("Cannot paste into an address group.") );
2224 /* Get an address book */
2225 abf = addressbook_get_book_file();
2226 if( abf == NULL ) return;
2228 if( _clipBoard_->cutFlag ) {
2230 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2232 /* Remove all groups and folders in clipboard from tree node */
2233 addressbook_treenode_remove_item();
2235 /* Remove all "cut" items */
2236 addrclip_delete_item( _clipBoard_ );
2238 /* Clear clipboard - cut items??? */
2239 addrclip_clear( _clipBoard_ );
2243 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2246 /* addrclip_list_show( _clipBoard_, stdout ); */
2248 /* Update tree by inserting node for each folder or group */
2249 addressbook_treenode_add_list(
2250 addrbook.treeSelected, ds, folderGroup );
2251 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2252 g_list_free( folderGroup );
2256 /* Display items pasted */
2257 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2258 addressbook_set_clist(
2259 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2267 * Add current treenode object to clipboard. Note that widget only allows
2268 * one entry from the tree list to be selected.
2270 static void addressbook_treenode_to_clipboard( void ) {
2271 AddressObject *obj = NULL;
2272 AddressDataSource *ds = NULL;
2273 AddrSelectItem *item;
2274 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2275 GtkCMCTreeNode *node;
2277 node = addrbook.treeSelected;
2278 if( node == NULL ) return;
2279 obj = gtk_cmctree_node_get_row_data( ctree, node );
2280 if( obj == NULL ) return;
2282 ds = addressbook_find_datasource( node );
2283 if( ds == NULL ) return;
2286 if( obj->type == ADDR_ITEM_FOLDER ) {
2287 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2288 ItemFolder *folder = adapter->itemFolder;
2290 item = addrselect_create_node( obj );
2291 item->uid = g_strdup( ADDRITEM_ID(folder) );
2293 else if( obj->type == ADDR_ITEM_GROUP ) {
2294 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2295 ItemGroup *group = adapter->itemGroup;
2297 item = addrselect_create_node( obj );
2298 item->uid = g_strdup( ADDRITEM_ID(group) );
2300 else if( obj->type == ADDR_DATASOURCE ) {
2302 item = addrselect_create_node( obj );
2307 /* Clear existing list and add item into list */
2310 addressbook_list_select_clear();
2311 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2312 addrselect_list_add( _addressSelect_, item, cacheID );
2318 * Cut from tree widget.
2320 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2321 _clipBoard_->cutFlag = TRUE;
2322 addressbook_treenode_to_clipboard();
2323 addrclip_clear( _clipBoard_ );
2324 addrclip_add( _clipBoard_, _addressSelect_ );
2325 /* addrclip_list_show( _clipBoard_, stdout ); */
2329 * Copy from tree widget.
2331 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2332 _clipBoard_->cutFlag = FALSE;
2333 addressbook_treenode_to_clipboard();
2334 addrclip_clear( _clipBoard_ );
2335 addrclip_add( _clipBoard_, _addressSelect_ );
2336 /* addrclip_list_show( _clipBoard_, stdout ); */
2340 * Paste clipboard into address tree widget.
2342 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2343 addressbook_clip_paste_cb(NULL,NULL);
2347 * Clear selected entries in clipboard.
2349 static void addressbook_list_select_clear( void ) {
2350 addrselect_list_clear( _addressSelect_ );
2354 * Add specified address item to selected address list.
2355 * \param aio Address item object.
2356 * \param ds Datasource.
2358 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2361 if( ds == NULL ) return;
2362 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2363 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2368 * Remove specified address item from selected address list.
2369 * \param aio Address item object.
2371 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2372 addrselect_list_remove( _addressSelect_, aio );
2376 * Invoke EMail compose window with addresses in selected address list.
2378 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2381 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2382 listAddress = addrselect_build_list( _addressSelect_ );
2383 compose_new_with_list( NULL, listAddress );
2384 g_list_free_full( listAddress, g_free );
2389 static void addressbook_merge_list( AddrSelectList *list ) {
2390 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2391 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2392 AddressObject *pobj;
2393 AddressDataSource *ds = NULL;
2395 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
2396 cm_return_if_fail(pobj != NULL);
2398 ds = addressbook_find_datasource( addrbook.treeSelected );
2399 if( ds == NULL ) return;
2401 addrmerge_merge(clist, pobj, ds, list);
2405 * Merge selected entries in the address list
2407 static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
2408 if( addrselect_test_empty( _addressSelect_ ) )
2411 addressbook_merge_list( _addressSelect_ );
2414 static void addressbook_list_row_selected( GtkCMCTree *clist,
2415 GtkCMCTreeNode *node,
2419 AddrItemObject *aio = NULL;
2420 AddressObject *pobj = NULL;
2421 AdapterDSource *ads = NULL;
2422 AddressDataSource *ds = NULL;
2424 addrbook.listSelected = node;
2426 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2427 if( pobj == NULL ) return;
2429 if( pobj->type == ADDR_DATASOURCE ) {
2430 ads = ADAPTER_DSOURCE(pobj);
2431 ds = ads->dataSource;
2433 else if( pobj->type != ADDR_INTERFACE ) {
2434 ds = addressbook_find_datasource( addrbook.treeSelected );
2437 aio = gtk_cmctree_node_get_row_data( clist, node );
2439 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2440 addressbook_list_select_add( aio, ds );
2443 addressbook_list_menu_setup();
2445 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2446 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2448 if (obj && obj->type != ADDR_ITEM_GROUP)
2449 addressbook_edit_address(NULL, 0, NULL, FALSE);
2453 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2454 GtkCMCTreeNode *node,
2458 AddrItemObject *aio;
2460 aio = gtk_cmctree_node_get_row_data( ctree, node );
2462 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2463 addressbook_list_select_remove( aio );
2466 if (!prefs_common.addressbook_use_editaddress_dialog)
2467 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2470 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2472 addressbook_lup_clicked(NULL, NULL);
2475 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2476 GdkEventButton *event,
2479 if( ! event ) return FALSE;
2480 if( event->window != GTK_CMCLIST(widget)->clist_window ) return FALSE;
2482 addressbook_list_menu_setup();
2484 if( event->button == 3 ) {
2485 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2486 event->button, event->time );
2487 } else if (event->button == 1) {
2488 if (event->type == GDK_2BUTTON_PRESS) {
2489 if (prefs_common.add_address_by_click &&
2490 addrbook.target_compose)
2491 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2493 if (prefs_common.addressbook_use_editaddress_dialog)
2494 addressbook_edit_address_cb(NULL, NULL);
2496 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2497 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2498 if( obj && obj->type == ADDR_ITEM_GROUP )
2499 addressbook_edit_address_cb(NULL, NULL);
2507 static gboolean addressbook_list_button_released(GtkWidget *widget,
2508 GdkEventButton *event,
2514 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2515 GdkEventButton *event,
2518 GtkCMCList *clist = GTK_CMCLIST(ctree);
2520 AddressObject *obj = NULL;
2521 AdapterDSource *ads = NULL;
2522 AddressInterface *iface = NULL;
2523 AddressDataSource *ds = NULL;
2524 gboolean canEdit = FALSE;
2525 gboolean canDelete = FALSE;
2526 gboolean canCut = FALSE;
2527 gboolean canCopy = FALSE;
2528 gboolean canPaste = FALSE;
2529 gboolean canTreeCut = FALSE;
2530 gboolean canTreeCopy = FALSE;
2531 gboolean canTreePaste = FALSE;
2532 gboolean canLookup = FALSE;
2533 GtkCMCTreeNode *node = NULL;
2535 if( ! event ) return FALSE;
2536 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2538 if( event->window != clist->clist_window )
2541 if (event->button == 1) {
2542 if (event->type == GDK_2BUTTON_PRESS) {
2543 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2544 gtkut_clist_set_focus_row(clist, row);
2545 obj = gtk_cmclist_get_row_data( clist, row );
2550 if (obj->type == ADDR_ITEM_GROUP ||
2551 obj->type == ADDR_DATASOURCE) {
2553 addressbook_treenode_edit_cb(NULL, NULL);
2555 /* expand pr collapse */
2556 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2557 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2563 addressbook_menubar_set_sensitive( FALSE );
2565 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2566 gtkut_clist_set_focus_row(clist, row);
2567 obj = gtk_cmclist_get_row_data( clist, row );
2570 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2574 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2576 if( ! addrclip_is_empty( _clipBoard_ ) )
2577 canTreePaste = TRUE;
2579 if (obj->type == ADDR_INTERFACE) {
2580 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2581 iface = adapter->interface;
2584 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2585 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2587 if( iface->externalQuery )
2590 if (obj->type == ADDR_DATASOURCE) {
2592 ads = ADAPTER_DSOURCE(obj);
2593 ds = ads->dataSource;
2596 iface = ds->interface;
2599 if( !iface->readOnly ) {
2600 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2601 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2602 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2608 else if (obj->type == ADDR_ITEM_FOLDER) {
2610 ds = addressbook_find_datasource( node );
2613 iface = ds->interface;
2616 if( !iface->readOnly ) {
2620 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2621 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2622 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2626 if( iface->externalQuery ) {
2627 /* Enable deletion of LDAP folder */
2631 else if (obj->type == ADDR_ITEM_GROUP) {
2633 ds = addressbook_find_datasource( node );
2636 iface = ds->interface;
2639 if( ! iface->readOnly ) {
2642 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2643 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2647 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2649 if( ! addrselect_test_empty( _addressSelect_ ) )
2651 if( ! addrclip_is_empty( _clipBoard_ ) )
2654 /* Forbid write changes when read-only */
2655 if( iface && iface->readOnly ) {
2657 canTreePaste = FALSE;
2664 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2665 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2666 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2667 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2668 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2670 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2671 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2672 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2673 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2674 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2676 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2677 addrbook.target_compose != NULL);
2679 if( event->button == 3 )
2680 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2681 event->button, event->time);
2686 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2687 GdkEventButton *event,
2690 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2694 static void addressbook_new_folder_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 ItemFolder *folder = 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 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2724 nn = addressbook_node_add_folder(
2725 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2727 g_message("error adding addressbook folder\n");
2729 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2730 if( addrbook.treeSelected == addrbook.opened )
2731 addressbook_set_clist(obj, TRUE);
2735 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2737 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2738 AddressObject *obj = NULL;
2739 AddressDataSource *ds = NULL;
2740 AddressBookFile *abf = NULL;
2741 ItemFolder *parentFolder = NULL;
2742 ItemGroup *group = NULL;
2744 if( ! addrbook.treeSelected ) return;
2745 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2746 if( obj == NULL ) return;
2747 ds = addressbook_find_datasource( addrbook.treeSelected );
2748 if( ds == NULL ) return;
2750 if( obj->type == ADDR_DATASOURCE ) {
2751 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2753 else if( obj->type == ADDR_ITEM_FOLDER ) {
2754 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2760 abf = ds->rawDataSource;
2761 if( abf == NULL ) return;
2762 group = addressbook_edit_group( abf, parentFolder, NULL );
2765 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2767 g_message("error adding addressbook group\n");
2769 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2770 if( addrbook.treeSelected == addrbook.opened )
2771 addressbook_set_clist(obj, TRUE);
2775 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2777 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2780 GdkPixbuf *pix_cl, *pix_op;
2781 gboolean is_leaf, expanded;
2783 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2785 &is_leaf, &expanded);
2786 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2793 * \param obj Address object to edit.
2794 * \param node Node in tree.
2795 * \return New name of data source.
2797 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2798 gchar *newName = NULL;
2799 AddressDataSource *ds = NULL;
2800 AddressInterface *iface = NULL;
2801 AdapterDSource *ads = NULL;
2803 ds = addressbook_find_datasource( node );
2804 if( ds == NULL ) return NULL;
2805 iface = ds->interface;
2806 if( ! iface->haveLibrary ) return NULL;
2808 /* Read data from data source */
2809 if( addrindex_ds_get_modify_flag( ds ) ) {
2810 addrindex_ds_read_data( ds );
2813 if( ! addrindex_ds_get_read_flag( ds ) ) {
2814 addrindex_ds_read_data( ds );
2818 ads = ADAPTER_DSOURCE(obj);
2819 if( ads->subType == ADDR_BOOK ) {
2820 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2822 else if( ads->subType == ADDR_VCARD ) {
2823 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2826 else if( ads->subType == ADDR_JPILOT ) {
2827 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2831 else if( ads->subType == ADDR_LDAP ) {
2832 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2838 newName = obj->name;
2843 * Edit an object that is in the address tree area.
2845 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2847 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2849 AddressDataSource *ds = NULL;
2850 AddressBookFile *abf = NULL;
2851 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2854 if( ! addrbook.treeSelected ) return;
2855 node = addrbook.treeSelected;
2856 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2857 obj = gtk_cmctree_node_get_row_data( ctree, node );
2858 if( obj == NULL ) return;
2859 parentNode = GTK_CMCTREE_ROW(node)->parent;
2861 ds = addressbook_find_datasource( node );
2862 if( ds == NULL ) return;
2864 if( obj->type == ADDR_DATASOURCE ) {
2865 name = addressbook_edit_datasource( obj, node );
2866 if( name == NULL ) return;
2869 abf = ds->rawDataSource;
2870 if( abf == NULL ) return;
2871 if( obj->type == ADDR_ITEM_FOLDER ) {
2872 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2873 ItemFolder *item = adapter->itemFolder;
2874 ItemFolder *parentFolder = NULL;
2875 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2876 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2877 name = ADDRITEM_NAME(item);
2879 else if( obj->type == ADDR_ITEM_GROUP ) {
2880 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2881 ItemGroup *item = adapter->itemGroup;
2882 ItemFolder *parentFolder = NULL;
2883 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2884 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2885 name = ADDRITEM_NAME(item);
2888 if( name && parentNode ) {
2889 /* Update node in tree view */
2890 addressbook_change_node_name( node, name );
2891 gtk_sctree_sort_node(ctree, parentNode);
2892 gtk_cmctree_expand( ctree, node );
2893 gtk_sctree_select( GTK_SCTREE( ctree), node );
2900 ADDRTREE_DEL_FOLDER_ONLY,
2901 ADDRTREE_DEL_FOLDER_ADDR
2905 * Delete an item from the tree widget.
2906 * \param data Data passed in.
2907 * \param action Action.
2908 * \param widget Widget issuing callback.
2910 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2912 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2913 GtkCMCTreeNode *node = NULL;
2917 AddrBookBase *adbase;
2918 AddressCache *cache;
2919 AdapterDSource *ads = NULL;
2920 AddressInterface *iface = NULL;
2921 AddressDataSource *ds = NULL;
2922 gboolean remFlag = FALSE;
2923 TreeItemDelType delType;
2925 if( ! addrbook.treeSelected ) return;
2926 node = addrbook.treeSelected;
2927 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2929 obj = gtk_cmctree_node_get_row_data( ctree, node );
2930 cm_return_if_fail(obj != NULL);
2932 if( obj->type == ADDR_DATASOURCE ) {
2933 ads = ADAPTER_DSOURCE(obj);
2935 ds = ads->dataSource;
2936 if( ds == NULL ) return;
2939 /* Must be folder or something else */
2940 ds = addressbook_find_datasource( node );
2941 if( ds == NULL ) return;
2943 /* Only allow deletion from non-readOnly */
2944 iface = ds->interface;
2945 if( iface->readOnly ) {
2946 /* Allow deletion of query results */
2947 if( ! iface->externalQuery ) return;
2951 /* Confirm deletion */
2952 delType = ADDRTREE_DEL_NONE;
2953 if( obj->type == ADDR_ITEM_FOLDER ) {
2954 if( iface && iface->externalQuery ) {
2955 message = g_strdup_printf( _(
2956 "Do you want to delete the query " \
2957 "results and addresses in '%s'?" ),
2959 aval = alertpanel( _("Delete"), message,
2960 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
2962 if( aval == G_ALERTALTERNATE ) {
2963 delType = ADDRTREE_DEL_FOLDER_ADDR;
2967 message = g_strdup_printf
2968 ( _( "Do you want to delete '%s'? "
2969 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2971 aval = alertpanel( _("Delete folder"), message,
2972 GTK_STOCK_CANCEL, _("Delete _folder only"), _("Delete folder and _addresses"), ALERTFOCUS_SECOND);
2974 if( aval == G_ALERTALTERNATE ) {
2975 delType = ADDRTREE_DEL_FOLDER_ONLY;
2977 else if( aval == G_ALERTOTHER ) {
2978 delType = ADDRTREE_DEL_FOLDER_ADDR;
2982 else if( obj->type == ADDR_ITEM_GROUP ) {
2983 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2984 "The addresses it contains will not be lost."), obj->name);
2985 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2986 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2988 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2990 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2991 "The addresses it contains will be lost."), obj->name);
2992 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2993 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2995 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2997 if( delType == ADDRTREE_DEL_NONE ) return;
2999 /* Proceed with deletion */
3000 if( obj->type == ADDR_DATASOURCE ) {
3001 /* Remove node from tree */
3002 gtk_cmctree_remove_node( ctree, node );
3004 if (delType == ADDRTREE_DEL_DATA &&
3005 ds->interface && ds->interface->type == ADDR_IF_BOOK)
3006 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
3008 /* Remove data source. */
3009 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3010 addrindex_free_datasource( ds );
3015 /* Get reference to cache */
3016 adbase = ( AddrBookBase * ) ds->rawDataSource;
3017 if( adbase == NULL ) return;
3018 cache = adbase->addressCache;
3020 /* Remove query results folder */
3021 if( iface && iface->externalQuery ) {
3022 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3023 ItemFolder *folder = adapter->itemFolder;
3025 adapter->itemFolder = NULL;
3027 g_print( "remove folder for ::%s::\n", obj->name );
3028 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3029 g_print( "-------------- remove results\n" );
3031 addrindex_remove_results( ds, folder );
3032 /* g_print( "-------------- remove node\n" ); */
3033 gtk_cmctree_remove_node( ctree, node );
3037 /* Code below is valid for regular address book deletion */
3038 if( obj->type == ADDR_ITEM_FOLDER ) {
3039 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3040 ItemFolder *item = adapter->itemFolder;
3042 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3043 /* Remove folder only */
3044 item = addrcache_remove_folder( cache, item );
3046 addritem_free_item_folder( item );
3047 addressbook_move_nodes_up( ctree, node );
3051 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3052 /* Remove folder and addresses */
3053 item = addrcache_remove_folder_delete( cache, item );
3055 addritem_free_item_folder( item );
3060 else if( obj->type == ADDR_ITEM_GROUP ) {
3061 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3062 ItemGroup *item = adapter->itemGroup;
3064 item = addrcache_remove_group( cache, item );
3066 addritem_free_item_group( item );
3073 gtk_cmctree_remove_node(ctree, node );
3077 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3079 if( person && addrbook.treeSelected == addrbook.opened ) {
3080 person->status = ADD_ENTRY;
3081 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3082 addressbook_folder_refresh_one_person(
3083 GTK_CMCTREE(addrbook.clist), person );
3085 addressbook_address_list_set_focus();
3088 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3090 if( person && addrbook.treeSelected == addrbook.opened) {
3091 person->status = ADD_ENTRY;
3092 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3093 addressbook_set_clist(
3094 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3098 addressbook_address_list_set_focus();
3102 * Label (a format string) that is used to name each folder.
3104 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3107 * Search ctree widget callback function.
3108 * \param pA Pointer to node.
3109 * \param pB Pointer to data item being sought.
3110 * \return Zero (0) if folder found.
3112 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3115 aoA = ( AddressObject * ) pA;
3116 if( aoA->type == ADDR_ITEM_FOLDER ) {
3117 ItemFolder *folder, *fld;
3119 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3120 folder = ( ItemFolder * ) pB;
3121 if( fld == folder ) return 0; /* Found folder */
3126 static ItemFolder * addressbook_setup_subf(
3127 AddressDataSource *ds, gchar *title,
3128 GtkCMCTreeNode *pNode )
3130 AddrBookBase *adbase;
3131 AddressCache *cache;
3134 GtkCMCTreeNode *nNode;
3136 AddressObjectType aoType = ADDR_NONE;
3139 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3141 if( ds && ds->type == ADDR_IF_LDAP ) {
3143 aoType = ADDR_LDAP_QUERY;
3150 ctree = GTK_CMCTREE(addrbook.ctree);
3151 /* Get reference to address cache */
3152 adbase = ( AddrBookBase * ) ds->rawDataSource;
3153 cache = adbase->addressCache;
3155 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3156 GList *cur = children;
3157 for (; cur; cur = cur->next) {
3158 ItemFolder *child = (ItemFolder *) cur->data;
3159 if (!g_strcmp0(ADDRITEM_NAME(child), title)) {
3160 nNode = gtk_cmctree_find_by_row_data_custom(
3162 addressbook_treenode_find_folder_cb );
3164 addrindex_remove_results( ds, child );
3165 while( child->listPerson ) {
3166 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3167 item = addrcache_remove_person( cache, item );
3169 addritem_free_item_person( item );
3173 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3174 addrbook.treeSelected = nNode;
3181 /* Create a folder */
3182 folder = addrcache_add_new_folder( cache, NULL );
3183 name = g_strdup_printf( "%s", title );
3184 addritem_folder_set_name( folder, name );
3185 addritem_folder_set_remarks( folder, "" );
3188 /* Now let's see the folder */
3189 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3190 gtk_cmctree_expand( ctree, pNode );
3192 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3193 addrbook.treeSelected = nNode;
3199 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3200 AddressObject *pobj = NULL;
3201 AddressDataSource *ds = NULL;
3202 AddressBookFile *abf = NULL;
3203 debug_print("adding address\n");
3204 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3205 if( pobj == NULL ) {
3206 debug_print("no row data\n");
3209 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3211 debug_print("no datasource\n");
3215 abf = ds->rawDataSource;
3217 g_print("no addressbook file\n");
3221 if( pobj->type == ADDR_DATASOURCE ) {
3222 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3223 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3225 ItemFolder *folder = NULL;
3227 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3228 GtkCMCTreeNode *parentNode;
3229 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3230 if( ds == NULL ) return;
3232 /* We must have a datasource that is an external interface */
3233 if( ! ds->interface->haveLibrary ) return;
3234 if( ! ds->interface->externalQuery ) return;
3236 if( pobj->type == ADDR_ITEM_FOLDER ) {
3237 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3240 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3242 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3244 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3246 abf = ds->rawDataSource;
3249 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3250 addrbook.editaddress_vbox,
3251 addressbook_new_address_from_book_post_cb,
3254 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3255 LdapServer *server = ds->rawDataSource;
3256 ldapsvr_set_modified(server, TRUE);
3257 ldapsvr_update_book(server, NULL);
3258 if (server->retVal != LDAPRC_SUCCESS) {
3259 alertpanel( _("Add address(es)"),
3260 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3261 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3262 server->retVal = LDAPRC_SUCCESS;
3267 if (prefs_common.addressbook_use_editaddress_dialog)
3268 addressbook_new_address_from_book_post_cb( person );
3271 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3273 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3276 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3277 GtkCMCTreeNode *parentNode;
3278 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3279 if( ds == NULL ) return;
3281 /* We must have a datasource that is an external interface */
3282 if( ! ds->interface->haveLibrary ) return;
3283 if( ! ds->interface->externalQuery ) return;
3285 if( pobj->type == ADDR_ITEM_FOLDER ) {
3286 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3289 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3291 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3295 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3297 abf = ds->rawDataSource;
3300 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3301 addrbook.editaddress_vbox,
3302 addressbook_new_address_from_folder_post_cb,
3305 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3306 LdapServer *server = ds->rawDataSource;
3307 ldapsvr_set_modified(server, TRUE);
3308 ldapsvr_update_book(server, NULL);
3309 if (server->retVal != LDAPRC_SUCCESS) {
3310 alertpanel( _("Add address(es)"),
3311 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3312 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3317 if (prefs_common.addressbook_use_editaddress_dialog)
3318 addressbook_new_address_from_folder_post_cb( person );
3320 else if( pobj->type == ADDR_ITEM_GROUP ) {
3321 /* New address in group */
3322 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3323 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3324 if (addrbook.treeSelected == addrbook.opened) {
3325 /* Change node name in tree. */
3326 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3327 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3328 addressbook_set_clist(
3329 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3337 * Search for specified child group node in address index tree.
3338 * \param parent Parent node.
3339 * \param group Group to find.
3341 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3342 GtkCMCTreeNode *node = NULL;
3343 GtkCMCTreeRow *currRow;
3345 currRow = GTK_CMCTREE_ROW( parent );
3347 node = currRow->children;
3351 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3352 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3353 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3354 if( g == group ) return node;
3356 currRow = GTK_CMCTREE_ROW(node);
3357 node = currRow->sibling;
3363 static AddressBookFile *addressbook_get_book_file() {
3364 AddressBookFile *abf = NULL;
3365 AddressDataSource *ds = NULL;
3367 ds = addressbook_find_datasource( addrbook.treeSelected );
3368 if( ds == NULL ) return NULL;
3369 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3373 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3374 GtkCMCTreeNode *node;
3377 /* Remove existing folders and groups */
3378 row = GTK_CMCTREE_ROW( parent );
3380 while( (node = row->children) ) {
3381 gtk_cmctree_remove_node( ctree, node );
3386 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3387 GtkCMCTreeNode *parent, *child;
3388 GtkCMCTreeRow *currRow;
3389 currRow = GTK_CMCTREE_ROW( node );
3391 parent = currRow->parent;
3392 while( (child = currRow->children) ) {
3393 gtk_cmctree_move( ctree, child, parent, node );
3395 gtk_sctree_sort_node( ctree, parent );
3399 static void addressbook_edit_address_post_cb( ItemPerson *person )
3403 AddressBookFile *abf = addressbook_get_book_file();
3405 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3406 if (g_strcmp0(person->nickName, ADDRITEM_NAME(person)))
3407 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3410 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3411 invalidate_address_completion();
3413 addressbook_address_list_set_focus();
3416 void addressbook_address_list_set_focus( void )
3418 if (!prefs_common.addressbook_use_editaddress_dialog) {
3419 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3420 addressbook_list_menu_setup();
3424 void addressbook_address_list_disable_some_actions(void)
3426 /* disable address copy/pasting when editing contact's detail (embedded form) */
3427 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", FALSE );
3428 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", FALSE );
3429 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", FALSE );
3432 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3433 addressbook_edit_address(data, 0, NULL, TRUE);
3436 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3437 gboolean force_focus ) {
3438 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3440 AddressObject *obj = NULL, *pobj = NULL;
3441 AddressDataSource *ds = NULL;
3442 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3444 AddressBookFile *abf = NULL;
3446 if( addrbook.listSelected == NULL ) return;
3447 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3448 cm_return_if_fail(obj != NULL);
3450 ctree = GTK_CMCTREE( addrbook.ctree );
3451 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3453 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3454 if( ds == NULL ) return;
3456 abf = addressbook_get_book_file();
3458 if( obj->type == ADDR_ITEM_EMAIL ) {
3459 ItemEMail *email = ( ItemEMail * ) obj;
3461 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3462 /* Edit parent group */
3463 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3464 ItemGroup *itemGrp = adapter->itemGroup;
3465 if( abf == NULL ) return;
3466 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3467 name = ADDRITEM_NAME(itemGrp);
3468 node = addrbook.treeSelected;
3469 parentNode = GTK_CMCTREE_ROW(node)->parent;
3472 /* Edit person - email page */
3474 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3475 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3476 addressbook_edit_address_post_cb,
3477 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3480 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3481 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3482 person->status = UPDATE_ENTRY;
3485 if (prefs_common.addressbook_use_editaddress_dialog)
3486 addressbook_edit_address_post_cb( person );
3491 else if( obj->type == ADDR_ITEM_PERSON ) {
3492 /* Edit person - basic page */
3493 ItemPerson *person = ( ItemPerson * ) obj;
3494 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3495 addressbook_edit_address_post_cb,
3496 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3499 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3500 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3501 person->status = UPDATE_ENTRY;
3504 if (prefs_common.addressbook_use_editaddress_dialog)
3505 addressbook_edit_address_post_cb( person );
3509 else if( obj->type == ADDR_ITEM_GROUP ) {
3510 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3511 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3512 parentNode = addrbook.treeSelected;
3513 node = addressbook_find_group_node( parentNode, itemGrp );
3514 name = ADDRITEM_NAME(itemGrp);
3515 invalidate_address_completion();
3521 /* Update tree node with node name */
3522 if( node == NULL ) return;
3523 addressbook_change_node_name( node, name );
3524 gtk_sctree_sort_node( ctree, parentNode );
3525 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3526 addressbook_set_clist(
3527 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3532 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3534 addressbook_del_clicked(NULL, NULL);
3537 static void close_cb(GtkAction *action, gpointer data)
3539 addressbook_close();
3542 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3543 addressbook_export_to_file();
3546 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3548 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3549 if( person ) addritem_person_set_opened( person, TRUE );
3553 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3555 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3556 if( person ) addritem_person_set_opened( person, FALSE );
3560 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3562 gchar *eMailAlias = ADDRITEM_NAME(email);
3563 if( eMailAlias && *eMailAlias != '\0' ) {
3565 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3568 str = g_strdup( eMailAlias );
3574 static gboolean addressbook_match_item(const gchar *name,
3575 const gchar *email_alias,
3577 const gchar *remarks,
3582 if (!str || str[0] == '\0')
3584 if (strcasestr(name, str))
3586 else if (email_alias && strcasestr(email_alias, str))
3588 else if (addr && strcasestr(addr, str))
3590 else if (remarks && strcasestr(remarks, str))
3596 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3597 GList *items = itemGroup->listEMail;
3598 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3599 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3600 for( ; items != NULL; items = g_list_next( items ) ) {
3601 GtkCMCTreeNode *nodeEMail = NULL;
3602 gchar *text[N_LIST_COLS];
3603 ItemEMail *email = items->data;
3607 if( ! email ) continue;
3609 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3611 if( !addressbook_match_item(ADDRITEM_NAME(person),
3612 ADDRITEM_NAME(email),
3613 email->address, email->remarks,
3617 str = addressbook_format_item_clist( person, email );
3619 text[COL_NAME] = addressbook_set_col_name_guard(str);
3622 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3624 text[COL_ADDRESS] = email->address;
3625 text[COL_REMARKS] = email->remarks;
3626 nodeEMail = gtk_sctree_insert_node(
3628 text, FOLDER_SPACING,
3632 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3638 gchar *addressbook_set_col_name_guard(gchar *value)
3640 gchar *ret = "<not set>";
3641 gchar *tmp = g_strdup(value);
3651 static void addressbook_folder_load_one_person(
3652 GtkCMCTree *clist, ItemPerson *person,
3653 AddressTypeControlItem *atci,
3654 AddressTypeControlItem *atciMail )
3656 GtkCMCTreeNode *nodePerson = NULL;
3657 GtkCMCTreeNode *nodeEMail = NULL;
3658 gchar *text[N_LIST_COLS];
3659 gboolean flgFirst = TRUE, haveAddr = FALSE;
3662 AddressBookFile *abf = addressbook_get_book_file();
3665 if( person == NULL ) return;
3667 text[COL_NAME] = "";
3668 node = person->listEMail;
3670 ItemEMail *email = node->data;
3671 gchar *eMailAddr = NULL;
3672 node = g_list_next( node );
3674 text[COL_ADDRESS] = email->address;
3675 text[COL_REMARKS] = email->remarks;
3676 eMailAddr = ADDRITEM_NAME(email);
3677 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3679 /* First email belongs with person */
3680 gchar *str = addressbook_format_item_clist( person, email );
3682 text[COL_NAME] = addressbook_set_col_name_guard(str);
3685 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3686 person && person->nickName ) {
3687 if (person->nickName) {
3688 if (strcmp(person->nickName, "") != 0) {
3689 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3692 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3698 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3700 nodePerson = gtk_sctree_insert_node(
3702 text, FOLDER_SPACING,
3705 FALSE, person->isOpened );
3708 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3711 /* Subsequent email is a child node of person */
3712 text[COL_NAME] = ADDRITEM_NAME(email);
3713 nodeEMail = gtk_sctree_insert_node(
3714 clist, nodePerson, NULL,
3715 text, FOLDER_SPACING,
3717 atciMail->iconXpmOpen,
3719 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3725 /* Have name without EMail */
3726 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3727 text[COL_ADDRESS] = "";
3728 text[COL_REMARKS] = "";
3729 nodePerson = gtk_sctree_insert_node(
3731 text, FOLDER_SPACING,
3734 FALSE, person->isOpened );
3735 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3740 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3742 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3743 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3744 const gchar *search_str;
3746 if( atci == NULL ) return;
3747 if( atciMail == NULL ) return;
3749 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3751 /* Load email addresses */
3752 items = addritem_folder_get_person_list( itemFolder );
3753 for(cur = items ; cur != NULL; cur = g_list_next( cur ) ) {
3758 person = (ItemPerson *)cur->data;
3761 node = person->listEMail;
3762 if (node && node->data) {
3764 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3767 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3771 addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
3773 /* Free up the list */
3774 g_list_free( items );
3777 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3778 addrbook.listSelected = NULL;
3779 gtk_cmctree_remove_node( clist, node );
3780 addressbook_menubar_set_sensitive( FALSE );
3781 addressbook_menuitem_set_sensitive(
3782 gtk_cmctree_node_get_row_data(
3783 GTK_CMCTREE(clist), addrbook.treeSelected ),
3784 addrbook.treeSelected );
3787 void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3788 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3789 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3790 GtkCMCTreeNode *node;
3791 if( atci == NULL ) return;
3792 if( atciMail == NULL ) return;
3793 if( person == NULL ) return;
3794 /* unload the person */
3796 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3798 addressbook_folder_remove_node( clist, node );
3799 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3800 gtk_sctree_sort_node( clist, NULL );
3801 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3803 gtk_sctree_select( GTK_SCTREE(clist), node );
3804 if (!gtk_cmctree_node_is_visible( clist, node ) )
3805 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3809 void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3810 GtkCMCTreeNode *node;
3812 if( person == NULL ) return;
3813 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3815 addressbook_folder_remove_node( clist, node );
3819 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3821 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3822 const gchar *search_str;
3824 /* Load any groups */
3825 if( ! atci ) return;
3827 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3829 items = addritem_folder_get_group_list( itemFolder );
3830 for( ; items != NULL; items = g_list_next( items ) ) {
3831 GtkCMCTreeNode *nodeGroup = NULL;
3832 gchar *text[N_LIST_COLS];
3833 ItemGroup *group = items->data;
3834 if( group == NULL ) continue;
3835 if( !addressbook_match_item(ADDRITEM_NAME(group),
3836 NULL, NULL, NULL, search_str) )
3839 text[COL_NAME] = ADDRITEM_NAME(group);
3840 text[COL_ADDRESS] = "";
3841 text[COL_REMARKS] = "";
3842 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3843 text, FOLDER_SPACING,
3847 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3848 gtk_sctree_sort_node(clist, NULL);
3850 /* Free up the list */
3851 g_list_free( items );
3855 * Search ctree widget callback function.
3856 * \param pA Pointer to node.
3857 * \param pB Pointer to data item being sought.
3858 * \return Zero (0) if group found.
3860 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3863 aoA = ( AddressObject * ) pA;
3864 if( aoA->type == ADDR_ITEM_GROUP ) {
3865 ItemGroup *group, *grp;
3867 grp = ADAPTER_GROUP(aoA)->itemGroup;
3868 group = ( ItemGroup * ) pB;
3869 if( grp == group ) return 0; /* Found group */
3875 * Remove folder and group nodes from tree widget for items contained ("cut")
3878 static void addressbook_treenode_remove_item( void ) {
3880 AddrSelectItem *cutItem;
3881 AddressCache *cache;
3882 AddrItemObject *aio;
3883 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3886 node = _clipBoard_->objectList;
3888 cutItem = node->data;
3889 node = g_list_next( node );
3890 cache = addrindex_get_cache(
3891 _clipBoard_->addressIndex, cutItem->cacheID );
3892 if( cache == NULL ) continue;
3893 aio = addrcache_get_object( cache, cutItem->uid );
3896 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3899 folder = ( ItemFolder * ) aio;
3900 tn = gtk_cmctree_find_by_row_data_custom(
3901 ctree, NULL, folder,
3902 addressbook_treenode_find_folder_cb );
3904 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3907 group = ( ItemGroup * ) aio;
3908 tn = gtk_cmctree_find_by_row_data_custom(
3910 addressbook_treenode_find_group_cb );
3914 /* Free up adapter and remove node. */
3915 gtk_cmctree_remove_node( ctree, tn );
3922 * Find parent datasource for specified tree node.
3923 * \param node Node to test.
3924 * \return Data source, or NULL if not found.
3926 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3927 AddressDataSource *ds = NULL;
3930 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3933 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3934 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3936 /* g_print( "ao->type = %d\n", ao->type ); */
3937 if( ao->type == ADDR_DATASOURCE ) {
3938 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3939 /* g_print( "found it\n" ); */
3940 ds = ads->dataSource;
3944 node = GTK_CMCTREE_ROW(node)->parent;
3950 * Load address list widget with children of specified object.
3951 * \param obj Parent object to be loaded.
3953 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3954 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3955 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3956 AddressDataSource *ds = NULL;
3957 AdapterDSource *ads = NULL;
3958 static AddressObject *last_obj = NULL;
3960 if (addrbook.clist == NULL) {
3963 if (obj == last_obj && !refresh)
3968 gtk_cmclist_clear(clist);
3972 if( obj->type == ADDR_INTERFACE ) {
3973 /* g_print( "set_clist: loading datasource...\n" ); */
3974 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3978 gtk_cmclist_freeze(clist);
3979 gtk_cmclist_clear(clist);
3981 if( obj->type == ADDR_DATASOURCE ) {
3982 ads = ADAPTER_DSOURCE(obj);
3983 ds = ads->dataSource;
3985 /* Load root folder */
3986 ItemFolder *rootFolder = NULL;
3987 rootFolder = addrindex_ds_get_root_folder( ds );
3988 addressbook_folder_load_person(
3989 ctreelist, rootFolder );
3990 addressbook_folder_load_group(
3991 ctreelist, rootFolder );
3995 if( obj->type == ADDR_ITEM_GROUP ) {
3997 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3998 addressbook_load_group( ctreelist, itemGroup );
4000 else if( obj->type == ADDR_ITEM_FOLDER ) {
4002 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
4003 addressbook_folder_load_person( ctreelist, itemFolder );
4004 addressbook_folder_load_group( ctreelist, itemFolder );
4007 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
4008 clist->focus_row = -1;
4009 gtk_cmclist_thaw(clist);
4013 * Call back function to free adaptor. Call back is setup by function
4014 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4015 * called when the address book tree widget node is removed by calling
4016 * function gtk_cmctree_remove_node().
4018 * \param data Tree node's row data.
4020 static void addressbook_free_treenode( gpointer data ) {
4023 ao = ( AddressObject * ) data;
4024 if( ao == NULL ) return;
4025 if( ao->type == ADDR_INTERFACE ) {
4026 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
4027 addrbookctl_free_interface( ai );
4029 else if( ao->type == ADDR_DATASOURCE ) {
4030 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
4031 addrbookctl_free_datasource( ads );
4033 else if( ao->type == ADDR_ITEM_FOLDER ) {
4034 AdapterFolder *af = ADAPTER_FOLDER(ao);
4035 addrbookctl_free_folder( af );
4037 else if( ao->type == ADDR_ITEM_GROUP ) {
4038 AdapterGroup *ag = ADAPTER_GROUP(ao);
4039 addrbookctl_free_group( ag );
4044 * Create new adaptor for specified data source.
4046 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4047 AddressObjectType otype, gchar *name )
4049 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4050 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4051 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4052 adapter->dataSource = ds;
4053 adapter->subType = otype;
4057 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4058 ADDRESS_OBJECT_NAME(adapter) =
4059 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4063 * Load tree from address index with the initial data.
4065 static void addressbook_load_tree( void ) {
4066 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4067 GList *nodeIf, *nodeDS;
4068 AdapterInterface *adapter;
4069 AddressInterface *iface;
4070 AddressTypeControlItem *atci;
4071 AddressDataSource *ds;
4072 AdapterDSource *ads;
4073 GtkCMCTreeNode *node, *newNode;
4076 nodeIf = _addressInterfaceList_;
4078 adapter = nodeIf->data;
4079 node = adapter->treeNode;
4080 iface = adapter->interface;
4081 atci = adapter->atci;
4083 if( iface->useInterface ) {
4084 /* Load data sources below interface node */
4085 nodeDS = iface->listSource;
4088 name = addrindex_ds_get_name( ds );
4089 ads = addressbook_create_ds_adapter(
4090 ds, atci->objectType, name );
4091 newNode = addressbook_add_object(
4092 node, ADDRESS_OBJECT(ads) );
4093 if (newNode == NULL) {
4094 g_message("error adding addressbook object\n");
4096 nodeDS = g_list_next( nodeDS );
4098 gtk_cmctree_expand( ctree, node );
4101 nodeIf = g_list_next( nodeIf );
4106 * Convert the old address book to new format.
4108 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4109 gboolean retVal = FALSE;
4110 gboolean errFlag = TRUE;
4113 /* Read old address book, performing conversion */
4114 debug_print( "Reading and converting old address book...\n" );
4115 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4116 addrindex_read_data( addrIndex );
4117 if( addrIndex->retVal == MGU_NO_FILE ) {
4118 /* We do not have a file - new user */
4119 debug_print( "New user... create new books...\n" );
4120 addrindex_create_new_books( addrIndex );
4121 if( addrIndex->retVal == MGU_SUCCESS ) {
4122 /* Save index file */
4123 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4124 addrindex_save_data( addrIndex );
4125 if( addrIndex->retVal == MGU_SUCCESS ) {
4130 msg = _( "New user, could not save index file." );
4134 msg = _( "New user, could not save address book files." );
4138 /* We have an old file */
4139 if( addrIndex->wasConverted ) {
4140 /* Converted successfully - save address index */
4141 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4142 addrindex_save_data( addrIndex );
4143 if( addrIndex->retVal == MGU_SUCCESS ) {
4144 msg = _( "Old address book converted successfully." );
4149 msg = _("Old address book converted,\n"
4150 "could not save new address index file." );
4154 /* File conversion failed - just create new books */
4155 debug_print( "File conversion failed... just create new books...\n" );
4156 addrindex_create_new_books( addrIndex );
4157 if( addrIndex->retVal == MGU_SUCCESS ) {
4159 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4160 addrindex_save_data( addrIndex );
4161 if( addrIndex->retVal == MGU_SUCCESS ) {
4162 msg = _("Could not convert address book,\n"
4163 "but created empty new address book files." );
4168 msg = _("Could not convert address book,\n"
4169 "could not save new address index file." );
4173 msg = _("Could not convert address book\n"
4174 "and could not create new address book files." );
4179 debug_print( "Error\n%s\n", msg );
4180 alertpanel_full(_("Addressbook conversion error"), msg,
4181 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4185 debug_print( "Warning\n%s\n", msg );
4186 alertpanel_full(_("Addressbook conversion error"), msg,
4187 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4188 NULL, ALERT_WARNING);
4194 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4198 gboolean failed = FALSE;
4199 GError *error = NULL;
4201 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4202 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4203 error->code, error->message);
4204 g_error_free(error);
4208 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4209 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4212 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4214 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4216 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4229 /* all copies succeeded, we can remove source files */
4230 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4231 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4232 error->code, error->message);
4233 g_error_free(error);
4236 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4237 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4240 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4242 claws_unlink(orig_file);
4252 void addressbook_read_file( void ) {
4253 AddressIndex *addrIndex = NULL;
4254 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4256 debug_print( "Reading address index...\n" );
4257 if( _addressIndex_ ) {
4258 debug_print( "address book already read!!!\n" );
4263 addrIndex = addrindex_create_index();
4264 addrindex_initialize();
4266 /* Use new address book index. */
4268 if ( !is_dir_exist(indexdir) ) {
4269 if ( make_dir(indexdir) < 0 ) {
4270 addrindex_set_file_path( addrIndex, get_rc_dir() );
4271 g_warning("couldn't create dir '%s'", indexdir);
4273 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4274 remove_dir_recursive(indexdir);
4275 addrindex_set_file_path( addrIndex, get_rc_dir() );
4276 g_error("couldn't migrate dir %s", indexdir);
4278 addrindex_set_file_path( addrIndex, indexdir);
4282 addrindex_set_file_path( addrIndex, indexdir);
4285 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4286 addrindex_read_data( addrIndex );
4287 if( addrIndex->retVal == MGU_NO_FILE ) {
4288 /* Conversion required */
4289 debug_print( "Converting...\n" );
4290 if( addressbook_convert( addrIndex ) ) {
4291 _addressIndex_ = addrIndex;
4294 else if( addrIndex->retVal == MGU_SUCCESS ) {
4295 _addressIndex_ = addrIndex;
4298 /* Error reading address book */
4299 debug_print( "Could not read address index.\n" );
4300 addrindex_print_index( addrIndex, stdout );
4301 alertpanel_full(_("Addressbook Error"),
4302 _("Could not read address index"),
4303 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4306 debug_print( "done.\n" );
4310 * Add object into the address index tree widget.
4311 * Enter: node Parent node.
4312 * obj Object to add.
4313 * Return: Node that was added, or NULL if object not added.
4315 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4318 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4319 GtkCMCTreeNode *added;
4320 AddressObject *pobj;
4321 AddressObjectType otype;
4322 AddressTypeControlItem *atci = NULL;
4324 cm_return_val_if_fail(node != NULL, NULL);
4325 cm_return_val_if_fail(obj != NULL, NULL);
4327 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4328 cm_return_val_if_fail(pobj != NULL, NULL);
4330 /* Determine object type to be displayed */
4331 if( obj->type == ADDR_DATASOURCE ) {
4332 otype = ADAPTER_DSOURCE(obj)->subType;
4338 /* Handle any special conditions. */
4340 atci = addrbookctl_lookup( otype );
4342 if( atci->showInTree ) {
4343 /* Add object to tree */
4346 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4347 atci->iconXpm, atci->iconXpmOpen,
4348 atci->treeLeaf, atci->treeExpand );
4349 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4350 addressbook_free_treenode );
4354 gtk_sctree_sort_node(ctree, node);
4360 * Add group into the address index tree.
4361 * \param node Parent node.
4362 * \param ds Data source.
4363 * \param itemGroup Group to add.
4364 * \return Inserted node.
4366 static GtkCMCTreeNode *addressbook_node_add_group(
4367 GtkCMCTreeNode *node, AddressDataSource *ds,
4368 ItemGroup *itemGroup )
4370 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4371 GtkCMCTreeNode *newNode;
4372 AdapterGroup *adapter;
4373 AddressTypeControlItem *atci = NULL;
4376 if( ds == NULL ) return NULL;
4377 if( node == NULL || itemGroup == NULL ) return NULL;
4379 name = &itemGroup->obj.name;
4381 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4383 adapter = g_new0( AdapterGroup, 1 );
4384 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4385 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4386 adapter->itemGroup = itemGroup;
4388 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4389 atci->iconXpm, atci->iconXpm,
4390 atci->treeLeaf, atci->treeExpand );
4391 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4392 addressbook_free_treenode );
4393 gtk_sctree_sort_node( ctree, node );
4398 * Add folder into the address index tree. Only visible folders are loaded into
4399 * the address index tree. Note that the root folder is not inserted into the
4402 * \param node Parent node.
4403 * \param ds Data source.
4404 * \param itemFolder Folder to add.
4405 * \param otype Object type to display.
4406 * \return Inserted node for the folder.
4408 static GtkCMCTreeNode *addressbook_node_add_folder(
4409 GtkCMCTreeNode *node, AddressDataSource *ds,
4410 ItemFolder *itemFolder, AddressObjectType otype )
4412 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4413 GtkCMCTreeNode *newNode = NULL;
4414 AddressTypeControlItem *atci = NULL;
4415 GList *listItems = NULL;
4417 ItemFolder *rootFolder;
4419 /* Only visible folders */
4420 if( itemFolder == NULL || itemFolder->isHidden )
4425 if( node == NULL || itemFolder == NULL )
4428 /* Determine object type */
4429 atci = addrbookctl_lookup( otype );
4433 rootFolder = addrindex_ds_get_root_folder( ds );
4434 if( itemFolder == rootFolder ) {
4438 AdapterFolder *adapter = g_new0( AdapterFolder, 1 );
4439 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4440 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4441 adapter->itemFolder = itemFolder;
4443 name = ADDRITEM_NAME(itemFolder);
4444 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4445 atci->iconXpm, atci->iconXpm,
4446 atci->treeLeaf, atci->treeExpand );
4448 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4449 addressbook_free_treenode );
4451 addrbookctl_free_folder(adapter);
4455 listItems = itemFolder->listFolder;
4456 while( listItems ) {
4457 ItemFolder *item = listItems->data;
4458 addressbook_node_add_folder( newNode, ds, item, otype );
4459 listItems = g_list_next( listItems );
4461 listItems = itemFolder->listGroup;
4462 while( listItems ) {
4463 ItemGroup *item = listItems->data;
4464 addressbook_node_add_group( newNode, ds, item );
4465 listItems = g_list_next( listItems );
4467 gtk_sctree_sort_node( ctree, node );
4471 void addressbook_export_to_file( void ) {
4472 if( _addressIndex_ ) {
4473 /* Save all new address book data */
4474 debug_print( "Saving address books...\n" );
4475 addrindex_save_all_books( _addressIndex_ );
4477 debug_print( "Exporting addressbook to file...\n" );
4478 addrindex_save_data( _addressIndex_ );
4479 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4480 addrindex_print_index( _addressIndex_, stdout );
4483 /* Notify address completion of new data */
4484 invalidate_address_completion();
4488 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4490 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4491 addressbook_lup_clicked(NULL, NULL);
4496 * Comparison using cell contents (text in first column). Used for sort
4497 * address index widget.
4499 static gint addressbook_treenode_compare_func(
4500 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4502 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4503 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4504 gchar *name1 = NULL, *name2 = NULL;
4505 if( cell1 ) name1 = cell1->u.text;
4506 if( cell2 ) name2 = cell2->u.text;
4507 if( ! name1 ) return ( name2 != NULL );
4508 if( ! name2 ) return -1;
4509 return g_utf8_collate( name1, name2 );
4512 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4513 AdapterDSource *ads;
4514 AdapterInterface *adapter;
4515 GtkCMCTreeNode *newNode;
4517 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4518 if( adapter == NULL ) return;
4519 ads = addressbook_edit_book( _addressIndex_, NULL );
4521 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4523 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4524 addrbook.treeSelected = newNode;
4529 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4530 AdapterDSource *ads;
4531 AdapterInterface *adapter;
4532 GtkCMCTreeNode *newNode;
4534 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4535 if( adapter == NULL ) return;
4536 ads = addressbook_edit_vcard( _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;
4547 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4548 AdapterDSource *ads;
4549 AdapterInterface *adapter;
4550 AddressInterface *iface;
4551 GtkCMCTreeNode *newNode;
4553 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4554 if( adapter == NULL ) return;
4555 iface = adapter->interface;
4556 if( ! iface->haveLibrary ) return;
4557 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4559 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4561 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4562 addrbook.treeSelected = newNode;
4569 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4570 AdapterDSource *ads;
4571 AdapterInterface *adapter;
4572 AddressInterface *iface;
4573 GtkCMCTreeNode *newNode;
4575 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4576 if( adapter == NULL ) return;
4577 iface = adapter->interface;
4578 if( ! iface->haveLibrary ) return;
4579 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4581 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4583 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4584 addrbook.treeSelected = newNode;
4591 * Display address search status message.
4592 * \param queryType Query type.
4593 * \param status Status/Error code.
4595 static void addressbook_search_message( gint queryType, gint sts ) {
4597 *addressbook_msgbuf = '\0';
4599 if( sts != MGU_SUCCESS ) {
4600 if( queryType == ADDRQUERY_LDAP ) {
4602 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4607 g_snprintf( addressbook_msgbuf,
4608 sizeof(addressbook_msgbuf), "%s", desc );
4609 addressbook_status_show( addressbook_msgbuf );
4612 addressbook_status_show( "" );
4617 * Refresh addressbook by forcing refresh of current selected object in
4620 static void addressbook_refresh_current( void ) {
4624 ctree = GTK_CMCTREE(addrbook.ctree);
4625 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4626 if( obj == NULL ) return;
4627 addressbook_set_clist( obj, TRUE );
4631 * Message that is displayed whilst a query is executing in a background
4634 static gchar *_tempMessage_ = N_( "Busy searching..." );
4637 * Address search idle function. This function is called during UI idle time
4638 * while a search is in progress.
4640 * \param data Idler data.
4642 static void addressbook_search_idle( gpointer data ) {
4646 queryID = GPOINTER_TO_INT( data );
4647 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4652 * Search completion callback function. This removes the query from the idle
4655 * \param sender Sender of query.
4656 * \param queryID Query ID of search request.
4657 * \param status Search status.
4658 * \param data Query data.
4660 static void addressbook_search_callback_end(
4661 gpointer sender, gint queryID, gint status, gpointer data )
4665 AddrQueryObject *aqo;
4667 /* Remove idler function */
4668 ptrQID = GINT_TO_POINTER( queryID );
4670 g_idle_remove_by_data( ptrQID );
4673 /* Refresh addressbook contents */
4674 addressbook_refresh_current();
4675 req = qrymgr_find_request( queryID );
4677 aqo = ( AddrQueryObject * ) req->queryList->data;
4678 addressbook_search_message( aqo->queryType, status );
4681 /* Stop the search */
4682 addrindex_stop_search( queryID );
4688 * \param ds Data source to search.
4689 * \param searchTerm String to lookup.
4690 * \param pNode Parent data source node.
4692 static void addressbook_perform_search(
4693 AddressDataSource *ds, gchar *searchTerm,
4694 GtkCMCTreeNode *pNode )
4702 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4704 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4706 /* Create a folder for the search results */
4707 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4708 folder = addressbook_setup_subf(ds, name, pNode);
4711 /* Setup the search */
4712 queryID = addrindex_setup_explicit_search(
4713 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4714 if( queryID == 0 ) return;
4716 /* Set up idler function */
4717 idleID = g_idle_add(
4718 (GSourceFunc) addressbook_search_idle,
4719 GINT_TO_POINTER( queryID ) );
4721 g_message("error adding addressbook_search_idle\n");
4724 /* Start search, sit back and wait for something to happen */
4725 addrindex_start_search( queryID );
4727 addressbook_status_show( _tempMessage_ );
4731 * Lookup button handler. Address search is only performed against
4732 * address interfaces for external queries.
4734 * \param button Lookup button widget.
4735 * \param data Data object.
4737 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4740 AddressDataSource *ds;
4741 AddressInterface *iface;
4743 GtkCMCTreeNode *node, *parentNode;
4745 LdapServer *ldap_server;
4746 LdapControl *ldap_ctl;
4749 node = addrbook.treeSelected;
4750 if( ! node ) return;
4751 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4753 ctree = GTK_CMCTREE(addrbook.ctree);
4754 obj = gtk_cmctree_node_get_row_data( ctree, node );
4755 if( obj == NULL ) return;
4757 if (obj->type != ADDR_DATASOURCE ||
4758 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4759 addressbook_set_clist(
4760 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4761 addrbook.treeSelected),
4765 ds = addressbook_find_datasource( node );
4766 if( ds == NULL ) return;
4768 /* We must have a datasource that is an external interface */
4769 iface = ds->interface;
4770 if( ! iface->haveLibrary ) return;
4771 if( ! iface->externalQuery ) return;
4774 if (iface->type == ADDR_IF_LDAP) {
4775 ldap_server = ds->rawDataSource;
4776 ldap_ctl = ldap_server->control;
4777 if (ldap_ctl != NULL &&
4778 ldap_ctl->bindDN != NULL && strlen(ldap_ctl->bindDN) > 0) {
4779 #ifndef PASSWORD_CRYPTO_OLD
4780 /* LDAP server is password-protected. */
4781 if (master_passphrase() == NULL) {
4782 /* User did not enter master passphrase, do not start a search. */
4785 #endif /* PASSWORD_CRYPTO_OLD */
4788 #endif /* USE_LDAP */
4791 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4792 g_strchomp( searchTerm );
4794 if( obj->type == ADDR_ITEM_FOLDER ) {
4795 parentNode = GTK_CMCTREE_ROW(node)->parent;
4800 addressbook_perform_search( ds, searchTerm, parentNode );
4802 gtk_widget_grab_focus( addrbook.entry );
4804 g_free( searchTerm );
4807 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4808 addressbook_close();
4813 * Browse address entry for highlighted entry.
4815 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4817 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4819 AddressDataSource *ds;
4820 AddressInterface *iface;
4824 if(addrbook.listSelected == NULL)
4827 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4831 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4835 iface = ds->interface;
4836 if(!iface || !iface->haveLibrary )
4840 if (obj->type == ADDR_ITEM_EMAIL) {
4841 email = ( ItemEMail * ) obj;
4843 person = (ItemPerson *) ADDRITEM_PARENT(email);
4845 else if (obj->type == ADDR_ITEM_PERSON) {
4846 person = (ItemPerson *) obj;
4853 if( iface && iface->type == ADDR_IF_LDAP ) {
4854 browseldap_entry(ds, person->externalID);
4859 /* **********************************************************************
4860 * Build lookup tables.
4861 * ***********************************************************************
4865 * Remap object types.
4866 * Enter: abType AddressObjectType (used in tree node).
4867 * Return: ItemObjectType (used in address cache data).
4869 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4870 ItemObjectType ioType;
4873 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4874 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4875 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4876 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4877 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4878 default: ioType = ITEMTYPE_NONE; break;
4883 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4884 atci = addrbookctl_lookup(id); \
4886 atci->iconXpm = icon; \
4887 atci->iconXpmOpen = iconopen; \
4889 g_warning("can't get atci %d", id); \
4894 * Build table that controls the rendering of object types.
4896 static void addrbookctl_build_icons( GtkWidget *window ) {
4897 AddressTypeControlItem *atci;
4901 g_object_unref(interfacexpm);
4903 g_object_unref(folderxpm);
4905 g_object_unref(folderopenxpm);
4907 g_object_unref(groupxpm);
4909 g_object_unref(vcardxpm);
4911 g_object_unref(bookxpm);
4913 g_object_unref(addressxpm);
4915 g_object_unref(jpilotxpm);
4917 g_object_unref(categoryxpm);
4919 g_object_unref(ldapxpm);
4921 g_object_unref(addrsearchxpm);
4922 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4923 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4924 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4925 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4926 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4927 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4928 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4929 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4930 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4931 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4932 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4934 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4935 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4936 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4937 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4938 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4939 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4940 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4941 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4942 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4943 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4944 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4949 * Build table that controls the rendering of object types.
4951 static void addrbookctl_build_map( GtkWidget *window ) {
4952 AddressTypeControlItem *atci;
4954 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4955 _addressBookTypeList_ = NULL;
4958 atci = g_new0( AddressTypeControlItem, 1 );
4959 atci->objectType = ADDR_INTERFACE;
4960 atci->interfaceType = ADDR_IF_NONE;
4961 atci->showInTree = TRUE;
4962 atci->treeExpand = TRUE;
4963 atci->treeLeaf = FALSE;
4964 atci->displayName = _( "Interface" );
4965 atci->menuCommand = NULL;
4966 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4967 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4970 atci = g_new0( AddressTypeControlItem, 1 );
4971 atci->objectType = ADDR_BOOK;
4972 atci->interfaceType = ADDR_IF_BOOK;
4973 atci->showInTree = TRUE;
4974 atci->treeExpand = TRUE;
4975 atci->treeLeaf = FALSE;
4976 atci->displayName = _("Address Books");
4977 atci->menuCommand = "Menu/Book/NewBook";
4978 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4979 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4982 atci = g_new0( AddressTypeControlItem, 1 );
4983 atci->objectType = ADDR_ITEM_PERSON;
4984 atci->interfaceType = ADDR_IF_NONE;
4985 atci->showInTree = FALSE;
4986 atci->treeExpand = FALSE;
4987 atci->treeLeaf = FALSE;
4988 atci->displayName = _( "Person" );
4989 atci->menuCommand = NULL;
4990 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4991 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4994 atci = g_new0( AddressTypeControlItem, 1 );
4995 atci->objectType = ADDR_ITEM_EMAIL;
4996 atci->interfaceType = ADDR_IF_NONE;
4997 atci->showInTree = FALSE;
4998 atci->treeExpand = FALSE;
4999 atci->treeLeaf = TRUE;
5000 atci->displayName = _( "Email Address" );
5001 atci->menuCommand = NULL;
5002 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5003 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5006 atci = g_new0( AddressTypeControlItem, 1 );
5007 atci->objectType = ADDR_ITEM_GROUP;
5008 atci->interfaceType = ADDR_IF_BOOK;
5009 atci->showInTree = TRUE;
5010 atci->treeExpand = FALSE;
5011 atci->treeLeaf = FALSE;
5012 atci->displayName = _( "Group" );
5013 atci->menuCommand = NULL;
5014 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5015 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5018 atci = g_new0( AddressTypeControlItem, 1 );
5019 atci->objectType = ADDR_ITEM_FOLDER;
5020 atci->interfaceType = ADDR_IF_BOOK;
5021 atci->showInTree = TRUE;
5022 atci->treeExpand = FALSE;
5023 atci->treeLeaf = FALSE;
5024 atci->displayName = _( "Folder" );
5025 atci->menuCommand = NULL;
5026 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5027 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5030 atci = g_new0( AddressTypeControlItem, 1 );
5031 atci->objectType = ADDR_VCARD;
5032 atci->interfaceType = ADDR_IF_VCARD;
5033 atci->showInTree = TRUE;
5034 atci->treeExpand = TRUE;
5035 atci->treeLeaf = TRUE;
5036 atci->displayName = _( "vCard" );
5037 atci->menuCommand = "Menu/Book/NewVCard";
5038 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5039 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5042 atci = g_new0( AddressTypeControlItem, 1 );
5043 atci->objectType = ADDR_JPILOT;
5044 atci->interfaceType = ADDR_IF_JPILOT;
5045 atci->showInTree = TRUE;
5046 atci->treeExpand = TRUE;
5047 atci->treeLeaf = FALSE;
5048 atci->displayName = _( "JPilot" );
5049 atci->menuCommand = "Menu/Book/NewJPilot";
5050 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5051 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5054 atci = g_new0( AddressTypeControlItem, 1 );
5055 atci->objectType = ADDR_CATEGORY;
5056 atci->interfaceType = ADDR_IF_JPILOT;
5057 atci->showInTree = TRUE;
5058 atci->treeExpand = TRUE;
5059 atci->treeLeaf = TRUE;
5060 atci->displayName = _( "JPilot" );
5061 atci->menuCommand = NULL;
5062 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5063 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5066 atci = g_new0( AddressTypeControlItem, 1 );
5067 atci->objectType = ADDR_LDAP;
5068 atci->interfaceType = ADDR_IF_LDAP;
5069 atci->showInTree = TRUE;
5070 atci->treeExpand = TRUE;
5071 atci->treeLeaf = FALSE;
5072 atci->displayName = _( "LDAP servers" );
5073 atci->menuCommand = "Menu/Book/NewLDAPServer";
5074 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5075 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5078 atci = g_new0( AddressTypeControlItem, 1 );
5079 atci->objectType = ADDR_LDAP_QUERY;
5080 atci->interfaceType = ADDR_IF_LDAP;
5081 atci->showInTree = TRUE;
5082 atci->treeExpand = FALSE;
5083 atci->treeLeaf = TRUE;
5084 atci->displayName = _( "LDAP Query" );
5085 atci->menuCommand = NULL;
5086 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5087 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5089 addrbookctl_build_icons(window);
5092 void addressbook_reflect_prefs_pixmap_theme(void)
5094 if (addrbook.window)
5095 addrbookctl_build_icons(addrbook.window);
5099 * Search for specified object type.
5101 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5103 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5107 * Search for specified interface type.
5109 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5110 GList *node = _addressBookTypeList_;
5112 AddressTypeControlItem *atci = node->data;
5113 if( atci->interfaceType == ifType ) return atci;
5114 node = g_list_next( node );
5119 static void addrbookctl_free_address( AddressObject *obj ) {
5120 g_free( obj->name );
5121 obj->type = ADDR_NONE;
5125 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5126 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5127 adapter->interface = NULL;
5128 adapter->interfaceType = ADDR_IF_NONE;
5129 adapter->atci = NULL;
5130 adapter->enabled = FALSE;
5131 adapter->haveLibrary = FALSE;
5132 adapter->treeNode = NULL;
5136 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5137 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5138 adapter->dataSource = NULL;
5139 adapter->subType = ADDR_NONE;
5143 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5144 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5145 adapter->itemFolder = NULL;
5149 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5150 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5151 adapter->itemGroup = NULL;
5156 * Build GUI interface list.
5158 static void addrbookctl_build_iflist( void ) {
5159 AddressTypeControlItem *atci;
5160 AdapterInterface *adapter;
5163 if( _addressIndex_ == NULL ) {
5164 _addressIndex_ = addrindex_create_index();
5165 if( _clipBoard_ == NULL ) {
5166 _clipBoard_ = addrclip_create();
5168 addrclip_set_index( _clipBoard_, _addressIndex_ );
5170 _addressInterfaceList_ = NULL;
5171 list = addrindex_get_interface_list( _addressIndex_ );
5173 AddressInterface *interface = list->data;
5174 atci = addrbookctl_lookup_iface( interface->type );
5176 adapter = g_new0( AdapterInterface, 1 );
5177 adapter->interfaceType = interface->type;
5178 adapter->atci = atci;
5179 adapter->interface = interface;
5180 adapter->treeNode = NULL;
5181 adapter->enabled = TRUE;
5182 adapter->haveLibrary = interface->haveLibrary;
5183 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5184 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5185 _addressInterfaceList_ =
5186 g_list_append( _addressInterfaceList_, adapter );
5188 list = g_list_next( list );
5193 * Find GUI interface type specified interface type.
5194 * \param ifType Interface type.
5195 * \return Interface item, or NULL if not found.
5197 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5198 GList *node = _addressInterfaceList_;
5200 AdapterInterface *adapter = node->data;
5201 if( adapter->interfaceType == ifType ) return adapter;
5202 node = g_list_next( node );
5208 * Build interface list selection.
5210 static void addrbookctl_build_ifselect( void ) {
5211 GList *newList = NULL;
5216 gchar *endptr = NULL;
5217 /* gboolean enabled; */
5218 AdapterInterface *adapter;
5220 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5223 splitStr = g_strsplit( selectStr, ",", -1 );
5224 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5226 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5227 ifType = strtol( splitStr[i], &endptr, 10 );
5230 if( strcmp( endptr, "/n" ) == 0 ) {
5235 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5236 adapter = addrbookctl_find_interface( ifType );
5238 newList = g_list_append( newList, adapter );
5245 /* g_print( "i=%d\n", i ); */
5246 g_strfreev( splitStr );
5247 g_free( selectStr );
5249 /* Replace existing list */
5250 g_list_free( _addressIFaceSelection_ );
5251 _addressIFaceSelection_ = newList;
5255 /* ***********************************************************************
5256 * Add sender to address book.
5257 * ***********************************************************************
5261 * This function is used by the Add sender to address book function.
5263 gboolean addressbook_add_contact(
5264 const gchar *name, const gchar *address, const gchar *remarks,
5265 GdkPixbuf *picture )
5267 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5268 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5269 debug_print( "addressbook_add_contact - added\n" );
5270 addressbook_refresh();
5275 /* ***********************************************************************
5276 * Book/folder selection.
5277 * ***********************************************************************
5281 * This function is used by the matcher dialog to select a book/folder.
5283 gchar *addressbook_folder_selection( const gchar *folderpath)
5285 AddressBookFile *book = NULL;
5286 ItemFolder *folder = NULL;
5289 cm_return_val_if_fail( folderpath != NULL, NULL);
5291 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5293 if ( folder != NULL) {
5295 gchar *oldtmp = NULL;
5296 AddrItemObject *obj = NULL;
5298 /* walk thru folder->parent to build the full folder path */
5299 /* TODO: wwp: optimize this */
5301 tmp = g_strdup(obj->uid);
5302 while ( obj->parent ) {
5304 if ( obj->name != NULL ) {
5305 oldtmp = g_strdup(tmp);
5307 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5311 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5314 path = g_strdup_printf("%s", book->fileName);
5316 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5322 /* ***********************************************************************
5323 * Book/folder checking.
5324 * ***********************************************************************
5327 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5329 FolderInfo *fi = g_new0( FolderInfo, 1 );
5331 fi->folder = folder;
5335 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5336 FolderInfo *fiParent, FolderPathMatch *match )
5342 FolderPathMatch *nextmatch = NULL;
5347 list = parentFolder->listFolder;
5349 folder = list->data;
5350 fName = g_strdup( ADDRITEM_NAME(folder) );
5352 /* match folder name, match pointer will be set to NULL if next recursive call
5353 doesn't need to match subfolder name */
5354 if ( match != NULL &&
5355 match->matched == FALSE ) {
5356 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5357 /* folder name matches, prepare next subfolder match */
5358 debug_print("matched folder name '%s'\n", fName);
5360 if ( match->folder_path[match->index] == NULL ) {
5361 /* we've matched all elements */
5362 match->matched = TRUE;
5363 match->folder = folder;
5364 debug_print("book/folder path matched!\n");
5366 /* keep on matching */
5374 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5375 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5377 list = g_list_next( list );
5382 * This function is used by to check if a matcher book/folder path corresponds to an
5383 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5384 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5385 if book AND folder are NULL this means that folderpath was empty or Any.
5386 If folderpath is a simple book name (without folder), book will not be NULL and folder
5387 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5390 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5391 AddressDataSource **book,
5392 ItemFolder **folder )
5394 AddressDataSource *ds;
5395 GList *list, *nodeDS;
5396 ItemFolder *rootFolder;
5397 AddressBookFile *abf;
5399 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5406 if ( folderpath == NULL )
5409 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5412 /* split the folder path we've received, we'll try to match this path, subpath by
5413 subpath against the book/folder structure in order */
5414 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5415 if (!folder_path_match.folder_path)
5418 list = addrindex_get_interface_list( _addressIndex_ );
5419 while ( list && !folder_path_match.matched ) {
5420 AddressInterface *interface = list->data;
5421 if ( interface && interface->type == ADDR_IF_BOOK ) {
5422 nodeDS = interface->listSource;
5423 while ( nodeDS && !folder_path_match.matched ) {
5426 /* Read address book */
5427 if( ! addrindex_ds_get_read_flag( ds ) ) {
5428 addrindex_ds_read_data( ds );
5431 /* Add node for address book */
5432 abf = ds->rawDataSource;
5434 /* match book name */
5435 if ( abf && abf->fileName &&
5436 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5438 debug_print("matched book name '%s'\n", abf->fileName);
5439 folder_path_match.book = ds;
5441 if ( folder_path_match.folder_path[1] == NULL ) {
5442 /* no folder part to match */
5444 folder_path_match.matched = TRUE;
5445 folder_path_match.folder = NULL;
5446 debug_print("book path matched!\n");
5449 /* match folder part */
5451 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5452 rootFolder = addrindex_ds_get_root_folder( ds );
5454 /* prepare for recursive call */
5455 folder_path_match.index = 1;
5456 /* this call will set folder_path_match.matched and folder_path_match.folder */
5457 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5462 nodeDS = g_list_next( nodeDS );
5465 list = g_list_next( list );
5468 g_strfreev( folder_path_match.folder_path );
5471 *book = folder_path_match.book;
5473 *folder = folder_path_match.folder;
5474 return folder_path_match.matched;
5478 /* **********************************************************************
5480 * ***********************************************************************
5486 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5487 AddressDataSource *ds = NULL;
5488 AdapterDSource *ads = NULL;
5489 AddressBookFile *abf = NULL;
5490 AdapterInterface *adapter;
5491 GtkCMCTreeNode *newNode;
5493 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5495 if( adapter->treeNode ) {
5496 abf = addressbook_imp_ldif( _addressIndex_ );
5498 ds = addrindex_index_add_datasource(
5499 _addressIndex_, ADDR_IF_BOOK, abf );
5500 ads = addressbook_create_ds_adapter(
5501 ds, ADDR_BOOK, NULL );
5502 addressbook_ads_set_name(
5503 ads, addrbook_get_name( abf ) );
5504 newNode = addressbook_add_object(
5506 ADDRESS_OBJECT(ads) );
5508 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5510 addrbook.treeSelected = newNode;
5513 /* Notify address completion */
5514 invalidate_address_completion();
5523 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5524 AddressDataSource *ds = NULL;
5525 AdapterDSource *ads = NULL;
5526 AddressBookFile *abf = NULL;
5527 AdapterInterface *adapter;
5528 GtkCMCTreeNode *newNode;
5530 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5532 if( adapter->treeNode ) {
5533 abf = addressbook_imp_mutt( _addressIndex_ );
5535 ds = addrindex_index_add_datasource(
5536 _addressIndex_, ADDR_IF_BOOK, abf );
5537 ads = addressbook_create_ds_adapter(
5538 ds, ADDR_BOOK, NULL );
5539 addressbook_ads_set_name(
5540 ads, addrbook_get_name( abf ) );
5541 newNode = addressbook_add_object(
5543 ADDRESS_OBJECT(ads) );
5545 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5547 addrbook.treeSelected = newNode;
5550 /* Notify address completion */
5551 invalidate_address_completion();
5560 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5561 AddressDataSource *ds = NULL;
5562 AdapterDSource *ads = NULL;
5563 AddressBookFile *abf = NULL;
5564 AdapterInterface *adapter;
5565 GtkCMCTreeNode *newNode;
5567 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5569 if( adapter->treeNode ) {
5570 abf = addressbook_imp_pine( _addressIndex_ );
5572 ds = addrindex_index_add_datasource(
5573 _addressIndex_, ADDR_IF_BOOK, abf );
5574 ads = addressbook_create_ds_adapter(
5575 ds, ADDR_BOOK, NULL );
5576 addressbook_ads_set_name(
5577 ads, addrbook_get_name( abf ) );
5578 newNode = addressbook_add_object(
5580 ADDRESS_OBJECT(ads) );
5582 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5584 addrbook.treeSelected = newNode;
5587 /* Notify address completion */
5588 invalidate_address_completion();
5595 * Harvest addresses.
5596 * \param folderItem Folder to import.
5597 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5598 * \param msgList List of message numbers, or NULL to process folder.
5600 void addressbook_harvest(
5601 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5603 AddressDataSource *ds = NULL;
5604 AdapterDSource *ads = NULL;
5605 AddressBookFile *abf = NULL;
5606 AdapterInterface *adapter;
5607 GtkCMCTreeNode *newNode;
5609 abf = addrgather_dlg_execute(
5610 folderItem, _addressIndex_, sourceInd, msgList );
5612 ds = addrindex_index_add_datasource(
5613 _addressIndex_, ADDR_IF_BOOK, abf );
5615 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5617 if( adapter->treeNode ) {
5618 ads = addressbook_create_ds_adapter(
5619 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5620 newNode = addressbook_add_object(
5622 ADDRESS_OBJECT(ads) );
5623 if (newNode == NULL) {
5624 g_message("error adding addressbook object\n");
5629 /* Notify address completion */
5630 invalidate_address_completion();
5637 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5638 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5640 AddressDataSource *ds = NULL;
5641 AddrBookBase *adbase;
5642 AddressCache *cache;
5643 GtkCMCTreeNode *node = NULL;
5645 if( ! addrbook.treeSelected ) return;
5646 node = addrbook.treeSelected;
5647 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5648 obj = gtk_cmctree_node_get_row_data( ctree, node );
5649 if( obj == NULL ) return;
5651 ds = addressbook_find_datasource( node );
5652 if( ds == NULL ) return;
5653 adbase = ( AddrBookBase * ) ds->rawDataSource;
5654 cache = adbase->addressCache;
5655 addressbook_exp_html( cache );
5661 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5662 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5664 AddressDataSource *ds = NULL;
5665 AddrBookBase *adbase;
5666 AddressCache *cache;
5667 GtkCMCTreeNode *node = NULL;
5669 if( ! addrbook.treeSelected ) return;
5670 node = addrbook.treeSelected;
5671 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5672 obj = gtk_cmctree_node_get_row_data( ctree, node );
5673 if( obj == NULL ) return;
5675 ds = addressbook_find_datasource( node );
5676 if( ds == NULL ) return;
5677 adbase = ( AddrBookBase * ) ds->rawDataSource;
5678 cache = adbase->addressCache;
5679 addressbook_exp_ldif( cache );
5682 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5684 addrduplicates_find(GTK_WINDOW(addrbook.window));
5687 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5689 addressbook_custom_attr_edit();
5692 static void addressbook_start_drag(GtkWidget *widget, gint button,
5696 GdkDragContext *context;
5697 if (addressbook_target_list == NULL)
5698 addressbook_target_list = gtk_target_list_new(
5699 addressbook_drag_types, 1);
5700 context = gtk_drag_begin(widget, addressbook_target_list,
5701 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5702 gtk_drag_set_icon_default(context);
5705 static void addressbook_drag_data_get(GtkWidget *widget,
5706 GdkDragContext *drag_context,
5707 GtkSelectionData *selection_data,
5712 AddrItemObject *aio = NULL;
5713 AddressObject *pobj = NULL;
5714 AdapterDSource *ads = NULL;
5715 AddressDataSource *ds = NULL;
5718 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5720 if( pobj == NULL ) return;
5722 if( pobj->type == ADDR_DATASOURCE ) {
5723 ads = ADAPTER_DSOURCE(pobj);
5724 ds = ads->dataSource;
5725 } else if (pobj->type == ADDR_ITEM_GROUP) {
5730 else if( pobj->type != ADDR_INTERFACE ) {
5731 ds = addressbook_find_datasource( addrbook.treeSelected );
5737 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5738 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5739 GTK_CMCTREE_NODE(cur->data));
5740 while (aio && aio->type != ITEMTYPE_PERSON) {
5745 if (aio && aio->type == ITEMTYPE_PERSON) {
5746 if( ds && ds->interface && ds->interface->readOnly)
5747 gtk_selection_data_set(selection_data,
5748 gtk_selection_data_get_target(selection_data), 8,
5749 (const guchar *)"Dummy_addr_copy", 15);
5751 gtk_selection_data_set(selection_data,
5752 gtk_selection_data_get_target(selection_data), 8,
5753 (const guchar *)"Dummy_addr_move", 15);
5757 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5758 GdkDragContext *context,
5764 GtkAllocation allocation;
5765 GtkRequisition requisition;
5767 GtkCMCTreeNode *node = NULL;
5768 gboolean acceptable = FALSE;
5769 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5770 gint height = allocation.height;
5771 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5772 gint total_height = requisition.height;
5773 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5774 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5775 gfloat vpos = gtk_adjustment_get_value(pos);
5777 if (gtk_cmclist_get_selection_info
5778 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5780 if (y > height - 24 && height + vpos < total_height) {
5781 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5782 gtk_adjustment_changed(pos);
5784 if (y < 24 && y > 0) {
5785 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5786 gtk_adjustment_changed(pos);
5788 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5791 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5794 if( obj->type == ADDR_ITEM_FOLDER
5795 || obj->type == ADDR_ITEM_GROUP)
5798 AdapterDSource *ads = NULL;
5799 AddressDataSource *ds = NULL;
5800 ads = ADAPTER_DSOURCE(obj);
5801 if (ads == NULL ){ return FALSE;}
5802 ds = ads->dataSource;
5803 if (ds == NULL ) { return FALSE;}
5811 g_signal_handlers_block_by_func
5813 G_CALLBACK(addressbook_tree_selected), NULL);
5814 gtk_sctree_select( GTK_SCTREE(widget), node);
5815 g_signal_handlers_unblock_by_func
5817 G_CALLBACK(addressbook_tree_selected), NULL);
5818 gdk_drag_status(context,
5819 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5820 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5822 gdk_drag_status(context, 0, time);
5827 static void addressbook_drag_leave_cb(GtkWidget *widget,
5828 GdkDragContext *context,
5832 if (addrbook.treeSelected) {
5833 g_signal_handlers_block_by_func
5835 G_CALLBACK(addressbook_tree_selected), NULL);
5836 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5837 g_signal_handlers_unblock_by_func
5839 G_CALLBACK(addressbook_tree_selected), NULL);
5844 static void addressbook_drag_received_cb(GtkWidget *widget,
5845 GdkDragContext *drag_context,
5848 GtkSelectionData *data,
5854 GtkCMCTreeNode *node;
5855 GtkCMCTreeNode *lastopened = addrbook.opened;
5857 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5858 if (gtk_cmclist_get_selection_info
5859 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5863 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5864 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5867 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5868 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5869 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5870 addressbook_clip_copy_cb(NULL, NULL);
5872 addressbook_clip_cut_cb(NULL, NULL);
5873 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5874 addressbook_clip_paste_cb(NULL,NULL);
5875 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5876 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5877 gtk_drag_finish(drag_context, TRUE, TRUE, time);