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 GtkActionEntry addressbook_entries[] =
398 {"Menu", NULL, "Menu", NULL, NULL, NULL },
400 {"Book", NULL, N_("_Book"), NULL, NULL, NULL },
401 {"Edit", NULL, N_("_Edit"), NULL, NULL, NULL },
402 {"Tools", NULL, N_("_Tools"), NULL, NULL, NULL },
405 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
406 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
407 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
411 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
414 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
416 {"Book/---", NULL, "---", NULL, NULL, NULL },
418 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
419 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
420 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
421 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
422 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
425 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
426 {"Address/---", NULL, "---", NULL, NULL, NULL },
427 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
428 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
429 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
430 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
431 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
432 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
433 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
434 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
435 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
436 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
437 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
438 {"Address/Merge", NULL, N_("_Merge"), "<control>E", NULL, G_CALLBACK(addressbook_merge_cb) },
442 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
443 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
444 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
445 {"Tools/---", NULL, "---", NULL, NULL, NULL },
446 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
447 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
448 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
449 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
450 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
453 static GtkActionEntry addressbook_tree_popup_entries[] =
455 {"ABTreePopup", NULL, "ABTreePopup", NULL, NULL, NULL },
456 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
457 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
458 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
459 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
460 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
461 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
462 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
463 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
464 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
465 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
468 static GtkActionEntry addressbook_list_popup_entries[] =
470 {"ABListPopup", NULL, "ABListPopup", NULL, NULL, NULL },
471 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
472 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
473 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
474 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
475 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
476 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
477 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
478 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
479 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
480 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
481 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
482 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
483 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
485 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
487 {"ABListPopup/Merge", NULL, N_("_Merge"), NULL, NULL, G_CALLBACK(addressbook_merge_cb) },
491 * Structure of error message table.
493 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
494 struct _ErrMsgTableEntry {
499 static gchar *_errMsgUnknown_ = N_( "Unknown" );
502 * Lookup table of error messages for general errors. Note that a NULL
503 * description signifies the end of the table.
505 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
506 { MGU_SUCCESS, N_("Success") },
507 { MGU_BAD_ARGS, N_("Bad arguments") },
508 { MGU_NO_FILE, N_("File not specified") },
509 { MGU_OPEN_FILE, N_("Error opening file") },
510 { MGU_ERROR_READ, N_("Error reading file") },
511 { MGU_EOF, N_("End of file encountered") },
512 { MGU_OO_MEMORY, N_("Error allocating memory") },
513 { MGU_BAD_FORMAT, N_("Bad file format") },
514 { MGU_ERROR_WRITE, N_("Error writing to file") },
515 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
516 { MGU_NO_PATH, N_("No path specified") },
522 * Lookup table of error messages for LDAP errors.
524 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
525 { LDAPRC_SUCCESS, N_("Success") },
526 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
527 { LDAPRC_INIT, N_("Error initializing LDAP") },
528 { LDAPRC_BIND, N_("Error binding to LDAP server") },
529 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
530 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
531 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
532 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
533 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
534 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
535 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
536 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
537 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
538 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
544 * Lookup message for specified error code.
545 * \param lut Lookup table.
546 * \param code Code to lookup.
547 * \return Description associated to code.
549 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
551 ErrMsgTableEntry entry;
554 for( i = 0; ; i++ ) {
556 if( entry.description == NULL ) break;
557 if( entry.code == code ) {
558 desc = entry.description;
563 desc = _errMsgUnknown_;
568 static gboolean lastCanLookup = FALSE;
570 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
572 if (add_and_delete) {
573 gtk_widget_show(addrbook.edit_btn);
574 gtk_widget_show(addrbook.del_btn);
575 gtk_widget_show(addrbook.reg_btn);
577 gtk_widget_hide(addrbook.edit_btn);
578 gtk_widget_hide(addrbook.del_btn);
579 gtk_widget_hide(addrbook.reg_btn);
583 gtk_widget_show(addrbook.lup_btn);
584 gtk_widget_show(addrbook.entry);
585 gtk_widget_show(addrbook.label);
587 gtk_widget_hide(addrbook.lup_btn);
588 gtk_widget_hide(addrbook.entry);
589 gtk_widget_hide(addrbook.label);
592 lastCanLookup = lookup;
595 gtk_widget_show(addrbook.to_btn);
596 gtk_widget_show(addrbook.cc_btn);
597 gtk_widget_show(addrbook.bcc_btn);
599 gtk_widget_hide(addrbook.to_btn);
600 gtk_widget_hide(addrbook.cc_btn);
601 gtk_widget_hide(addrbook.bcc_btn);
605 void addressbook_open(Compose *target)
607 /* Initialize all static members */
608 if( _clipBoard_ == NULL ) {
609 _clipBoard_ = addrclip_create();
611 if( _addressIndex_ != NULL ) {
612 addrclip_set_index( _clipBoard_, _addressIndex_ );
614 if( _addressSelect_ == NULL ) {
615 _addressSelect_ = addrselect_list_create();
617 if (!addrbook.window) {
618 addressbook_read_file();
619 addressbook_create();
620 addressbook_load_tree();
621 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
622 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
625 gtk_widget_hide(addrbook.window);
628 gtk_widget_show_all(addrbook.window);
630 if (!prefs_common.addressbook_use_editaddress_dialog)
631 addressbook_edit_person_widgetset_hide();
633 address_completion_start(addrbook.window);
635 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
636 addressbook_set_target_compose(target);
640 * Destroy addressbook.
642 void addressbook_destroy( void ) {
643 /* Free up address stuff */
644 if( _addressSelect_ != NULL ) {
645 addrselect_list_free( _addressSelect_ );
647 if( _clipBoard_ != NULL ) {
648 addrclip_free( _clipBoard_ );
651 if( _addressIndex_ != NULL ) {
652 addrindex_free_index( _addressIndex_ );
653 addrindex_teardown();
655 _addressSelect_ = NULL;
657 _addressIndex_ = NULL;
660 void addressbook_set_target_compose(Compose *target)
662 addrbook.target_compose = target;
665 Compose *addressbook_get_target_compose(void)
667 return addrbook.target_compose;
671 * Refresh addressbook and save to file(s).
673 void addressbook_refresh( void )
675 if (addrbook.window) {
676 if (addrbook.treeSelected) {
677 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
678 addrbook.treeSelected);
679 addressbook_set_clist(
680 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
681 addrbook.treeSelected),
686 addressbook_export_to_file();
689 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
691 if (event && event->keyval == GDK_KEY_Escape)
693 else if (event && event->keyval == GDK_KEY_Delete) {
694 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
695 if ( /* address_index_has_focus || */ address_list_has_focus )
696 addressbook_del_clicked(NULL, NULL);
702 *\brief Save Gtk object size to prefs dataset
704 static void addressbook_size_allocate_cb(GtkWidget *widget,
705 GtkAllocation *allocation)
707 cm_return_if_fail(allocation != NULL);
709 prefs_common.addressbookwin_width = allocation->width;
710 prefs_common.addressbookwin_height = allocation->height;
713 static gint sort_column_number = 0;
714 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
716 static gint list_case_sort(
717 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
719 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
720 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
721 gchar *name1 = NULL, *name2 = NULL;
722 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
723 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
725 if( aio1->type == aio2->type ) {
727 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
729 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
730 if( ! name1 ) return ( name2 != NULL );
731 if( ! name2 ) return -1;
732 return g_utf8_collate( name1, name2 );
734 /* Order groups before person */
735 if( aio1->type == ITEMTYPE_GROUP ) {
736 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
737 } else if( aio2->type == ITEMTYPE_GROUP ) {
738 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
744 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
745 const GtkSortType sort_type)
748 GtkWidget *hbox, *label, *arrow;
750 sort_column_number = col;
751 sort_column_type = sort_type;
752 gtk_cmclist_set_compare_func(clist, list_case_sort);
753 gtk_cmclist_set_sort_type(clist, sort_type);
754 gtk_cmclist_set_sort_column(clist, col);
756 gtk_cmclist_freeze(clist);
757 gtk_cmclist_sort(clist);
759 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
760 hbox = gtk_hbox_new(FALSE, 4);
761 label = gtk_label_new(gettext(list_titles[pos]));
762 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
765 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
766 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
767 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
770 gtk_widget_show_all(hbox);
771 gtk_cmclist_set_column_widget(clist, pos, hbox);
774 gtk_cmclist_thaw(clist);
777 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
779 static GtkSortType sort_type = GTK_SORT_ASCENDING;
781 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
783 addressbook_sort_list(clist, COL_NAME, sort_type);
786 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
788 static GtkSortType sort_type = GTK_SORT_ASCENDING;
790 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
792 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
795 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
797 static GtkSortType sort_type = GTK_SORT_ASCENDING;
799 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
801 addressbook_sort_list(clist, COL_REMARKS, sort_type);
804 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
807 address_index_has_focus = TRUE;
811 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
814 address_index_has_focus = FALSE;
815 if (!prefs_common.addressbook_use_editaddress_dialog
816 && !address_list_has_focus)
817 addressbook_address_list_disable_some_actions();
821 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
824 address_list_has_focus = TRUE;
828 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
831 address_list_has_focus = FALSE;
832 if (!prefs_common.addressbook_use_editaddress_dialog
833 && !address_index_has_focus)
834 addressbook_address_list_disable_some_actions();
838 /* save hpane and vpane's handle position when it moves */
839 static void addressbook_pane_save_position(void)
842 prefs_common.addressbook_hpaned_pos =
843 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
845 prefs_common.addressbook_vpaned_pos =
846 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
850 * Create the address book widgets. The address book contains two CTree widgets: the
851 * address index tree on the left and the address list on the right.
853 * The address index tree displays a hierarchy of interfaces and groups. Each node in
854 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
855 * data sources and folder objects.
857 * The address list displays group, person and email objects. These items are linked
858 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
861 * In the tradition of MVC architecture, the data stores have been separated from the
862 * GUI components. The addrindex.c file provides the interface to all data stores.
864 static void addressbook_create(void)
870 GtkWidget *ctree_swin;
872 GtkWidget *editaddress_vbox;
873 GtkWidget *clist_vbox;
874 GtkWidget *clist_swin;
881 GtkWidget *statusbar;
892 GtkWidget *close_btn;
893 GtkWidget *tree_popup;
894 GtkWidget *list_popup;
896 GtkUIManager *ui_manager;
897 GtkActionGroup *action_group;
898 gchar *index_titles[N_INDEX_COLS];
902 static GdkGeometry geometry;
904 debug_print("Creating addressbook window...\n");
906 index_titles[COL_SOURCES] = _("Sources");
908 /* Address book window */
909 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
910 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
911 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
912 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
913 gtk_widget_realize(window);
915 g_signal_connect(G_OBJECT(window), "delete_event",
916 G_CALLBACK(addressbook_close), NULL);
917 g_signal_connect(G_OBJECT(window), "size_allocate",
918 G_CALLBACK(addressbook_size_allocate_cb), NULL);
919 g_signal_connect(G_OBJECT(window), "key_press_event",
920 G_CALLBACK(key_pressed), NULL);
921 MANAGE_WINDOW_SIGNALS_CONNECT(window);
923 vbox = gtk_vbox_new(FALSE, 0);
924 gtk_container_add(GTK_CONTAINER(window), vbox);
927 ui_manager = gtk_ui_manager_new();
928 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
929 G_N_ELEMENTS(addressbook_entries), NULL);
930 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
931 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
932 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
933 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
935 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
937 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
938 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
939 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
942 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
955 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
985 gtk_window_add_accel_group(GTK_WINDOW(window),
986 gtk_ui_manager_get_accel_group(ui_manager));
988 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
990 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
992 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
993 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
994 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
996 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
997 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
998 GTK_POLICY_AUTOMATIC,
999 GTK_POLICY_AUTOMATIC);
1000 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1003 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1004 gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1006 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1007 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1008 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1009 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1010 GTK_CMCTREE_EXPANDER_TRIANGLE);
1011 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1012 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1013 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1014 addressbook_treenode_compare_func);
1016 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1017 G_CALLBACK(addressbook_tree_selected), NULL);
1018 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1019 G_CALLBACK(addressbook_tree_button_pressed),
1021 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1022 G_CALLBACK(addressbook_tree_button_released),
1025 g_signal_connect(G_OBJECT(ctree), "select_row",
1026 G_CALLBACK(addressbook_select_row_tree), NULL);
1028 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1029 addressbook_drag_types, 1,
1030 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1031 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1032 G_CALLBACK(addressbook_drag_motion_cb),
1034 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1035 G_CALLBACK(addressbook_drag_leave_cb),
1037 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1038 G_CALLBACK(addressbook_drag_received_cb),
1040 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1041 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1042 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1043 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1045 clist_vbox = gtk_vbox_new(FALSE, 4);
1047 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1048 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1049 GTK_POLICY_AUTOMATIC,
1050 GTK_POLICY_AUTOMATIC);
1051 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1054 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1055 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1056 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1057 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1058 GTK_CMCTREE_EXPANDER_TRIANGLE);
1059 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1060 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1061 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1063 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1065 gtk_widget_set_size_request(clist, -1, 80);
1067 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1068 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1069 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1070 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1071 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1072 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1073 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1074 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1075 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1076 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1077 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1079 for (i = 0; i < N_LIST_COLS; i++)
1080 gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1083 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1084 G_CALLBACK(addressbook_list_row_selected), NULL);
1085 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1086 G_CALLBACK(addressbook_list_row_unselected), NULL);
1087 g_signal_connect(G_OBJECT(clist), "button_press_event",
1088 G_CALLBACK(addressbook_list_button_pressed),
1090 g_signal_connect(G_OBJECT(clist), "button_release_event",
1091 G_CALLBACK(addressbook_list_button_released),
1093 g_signal_connect(G_OBJECT(clist), "tree_expand",
1094 G_CALLBACK(addressbook_person_expand_node), NULL );
1095 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1096 G_CALLBACK(addressbook_person_collapse_node), NULL );
1097 g_signal_connect(G_OBJECT(clist), "start_drag",
1098 G_CALLBACK(addressbook_start_drag), NULL);
1099 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1100 G_CALLBACK(addressbook_drag_data_get), NULL);
1101 hbox = gtk_hbox_new(FALSE, 4);
1102 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1104 label = gtk_label_new(_("Search"));
1105 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1107 entry = gtk_entry_new();
1108 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1110 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1112 g_signal_connect(G_OBJECT(entry), "key_press_event",
1113 G_CALLBACK(addressbook_entry_key_pressed),
1115 g_signal_connect(G_OBJECT(entry), "activate",
1116 G_CALLBACK(addressbook_entry_activated), NULL);
1118 if (!prefs_common.addressbook_use_editaddress_dialog) {
1119 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1120 vpaned = gtk_vpaned_new();
1121 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1122 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1125 editaddress_vbox = NULL;
1127 hpaned = gtk_hpaned_new();
1128 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1129 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1130 if (prefs_common.addressbook_use_editaddress_dialog)
1131 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1133 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1136 hsbox = gtk_hbox_new(FALSE, 0);
1137 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1138 statusbar = gtk_statusbar_new();
1139 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1142 hbbox = gtk_hbutton_box_new();
1143 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1144 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1145 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1146 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1148 gtkut_stock_button_add_help(hbbox, &help_btn);
1150 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1151 gtk_widget_set_can_default(edit_btn, TRUE);
1152 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1153 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1154 gtk_widget_set_can_default(del_btn, TRUE);
1155 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1156 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1157 gtk_widget_set_can_default(reg_btn, TRUE);
1158 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1161 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1162 gtk_widget_set_can_default(lup_btn, TRUE);
1163 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1165 g_signal_connect(G_OBJECT(help_btn), "clicked",
1166 G_CALLBACK(manual_open_with_anchor_cb),
1167 MANUAL_ANCHOR_ADDRBOOK);
1169 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1170 G_CALLBACK(addressbook_edit_clicked), NULL);
1171 g_signal_connect(G_OBJECT(del_btn), "clicked",
1172 G_CALLBACK(addressbook_del_clicked), NULL);
1173 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1174 G_CALLBACK(addressbook_reg_clicked), NULL);
1175 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1176 G_CALLBACK(addressbook_lup_clicked), NULL);
1178 to_btn = gtk_button_new_with_label
1179 (prefs_common_translated_header_name("To:"));
1180 gtk_widget_set_can_default(to_btn, TRUE);
1181 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1182 cc_btn = gtk_button_new_with_label
1183 (prefs_common_translated_header_name("Cc:"));
1184 gtk_widget_set_can_default(cc_btn, TRUE);
1185 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1186 bcc_btn = gtk_button_new_with_label
1187 (prefs_common_translated_header_name("Bcc:"));
1188 gtk_widget_set_can_default(bcc_btn, TRUE);
1189 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1191 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1192 gtk_widget_set_can_default(close_btn, TRUE);
1193 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1195 g_signal_connect(G_OBJECT(to_btn), "clicked",
1196 G_CALLBACK(addressbook_to_clicked),
1197 GINT_TO_POINTER(COMPOSE_TO));
1198 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1199 G_CALLBACK(addressbook_to_clicked),
1200 GINT_TO_POINTER(COMPOSE_CC));
1201 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1202 G_CALLBACK(addressbook_to_clicked),
1203 GINT_TO_POINTER(COMPOSE_BCC));
1204 g_signal_connect(G_OBJECT(close_btn), "clicked",
1205 G_CALLBACK(addressbook_close_clicked), NULL);
1207 /* Build icons for interface */
1209 /* Build control tables */
1210 addrbookctl_build_map(window);
1211 addrbookctl_build_iflist();
1212 addrbookctl_build_ifselect();
1214 addrbook.clist = NULL;
1216 /* Add each interface into the tree as a root level folder */
1217 nodeIf = _addressInterfaceList_;
1219 AdapterInterface *adapter = nodeIf->data;
1220 AddressInterface *iface = adapter->interface;
1221 nodeIf = g_list_next(nodeIf);
1223 if(iface->useInterface) {
1224 AddressTypeControlItem *atci = adapter->atci;
1225 text = atci->displayName;
1227 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1228 NULL, NULL, &text, FOLDER_SPACING,
1232 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1233 gtk_cmctree_node_set_row_data_full(
1234 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1235 addressbook_free_treenode );
1241 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1242 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1243 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1244 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1245 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1246 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1247 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1248 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1249 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1250 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1254 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1255 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
1275 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1276 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1278 addrbook.window = window;
1279 addrbook.hpaned = hpaned;
1280 addrbook.vpaned = vpaned;
1281 addrbook.menubar = menubar;
1282 addrbook.ctree = ctree;
1285 addrbook.editaddress_vbox = editaddress_vbox;
1286 addrbook.clist = clist;
1287 addrbook.label = label;
1288 addrbook.entry = entry;
1289 addrbook.statusbar = statusbar;
1290 addrbook.status_cid = gtk_statusbar_get_context_id(
1291 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1293 addrbook.help_btn = help_btn;
1294 addrbook.edit_btn = edit_btn;
1295 addrbook.del_btn = del_btn;
1296 addrbook.reg_btn = reg_btn;
1297 addrbook.lup_btn = lup_btn;
1298 addrbook.to_btn = to_btn;
1299 addrbook.cc_btn = cc_btn;
1300 addrbook.bcc_btn = bcc_btn;
1302 addrbook.tree_popup = tree_popup;
1303 addrbook.list_popup = list_popup;
1304 addrbook.ui_manager = ui_manager;
1306 addrbook.listSelected = NULL;
1308 if (!geometry.min_height) {
1309 geometry.min_width = ADDRESSBOOK_WIDTH;
1310 geometry.min_height = ADDRESSBOOK_HEIGHT;
1313 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1315 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1316 prefs_common.addressbookwin_height);
1318 gtk_window_move(GTK_WINDOW(window), 48, 48);
1321 if (!prefs_common.addressbook_use_editaddress_dialog) {
1322 if (prefs_common.addressbook_vpaned_pos > 0)
1323 gtk_paned_set_position(GTK_PANED(vpaned),
1324 prefs_common.addressbook_vpaned_pos);
1326 if (prefs_common.addressbook_hpaned_pos > 0)
1327 gtk_paned_set_position(GTK_PANED(hpaned),
1328 prefs_common.addressbook_hpaned_pos);
1331 gtk_widget_show_all(window);
1335 * Close address book window and save to file(s).
1337 static gint addressbook_close( void ) {
1338 address_completion_end(addrbook.window);
1339 if (!prefs_common.addressbook_use_editaddress_dialog)
1340 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1342 addressbook_pane_save_position();
1344 gtk_widget_hide(addrbook.window);
1345 addressbook_export_to_file();
1350 * Display message in status line.
1351 * \param msg Message to display.
1353 static void addressbook_status_show( gchar *msg ) {
1354 if( addrbook.statusbar != NULL ) {
1356 GTK_STATUSBAR(addrbook.statusbar),
1357 addrbook.status_cid );
1360 GTK_STATUSBAR(addrbook.statusbar),
1361 addrbook.status_cid, msg );
1366 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1370 *addressbook_msgbuf = '\0';
1372 name = addrindex_ds_get_name( ds );
1373 retVal = addrindex_ds_get_status_code( ds );
1374 if( retVal == MGU_SUCCESS ) {
1375 g_snprintf( addressbook_msgbuf,
1376 sizeof(addressbook_msgbuf), "%s", name );
1379 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1380 g_snprintf( addressbook_msgbuf,
1381 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1384 addressbook_status_show( addressbook_msgbuf );
1387 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1389 addressbook_edit_address_cb(NULL, NULL);
1392 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1394 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1398 * Delete one or more objects from address list.
1400 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1402 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1403 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1404 AddressObject *pobj;
1405 AdapterDSource *ads = NULL;
1406 GtkCMCTreeNode *nodeList;
1409 AddressBookFile *abf = NULL;
1410 AddressDataSource *ds = NULL;
1411 AddressInterface *iface;
1412 AddrItemObject *aio;
1413 AddrSelectItem *item;
1415 gboolean refreshList = FALSE;
1417 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1418 cm_return_if_fail(pobj != NULL);
1420 /* Test whether anything selected for deletion */
1421 nodeList = addrbook.listSelected;
1423 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1424 if( aio == NULL) return;
1425 ds = addressbook_find_datasource( addrbook.treeSelected );
1426 if( ds == NULL ) return;
1428 /* Test for read only */
1429 iface = ds->interface;
1430 if( iface->readOnly ) {
1431 alertpanel( _("Delete address(es)"),
1432 _("This address data is read-only and cannot be deleted."),
1433 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST);
1437 /* Test whether Ok to proceed */
1439 if( pobj->type == ADDR_DATASOURCE ) {
1440 ads = ADAPTER_DSOURCE(pobj);
1441 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1443 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1446 else if( pobj->type == ADDR_ITEM_GROUP ) {
1449 if( ! procFlag ) return;
1450 abf = ds->rawDataSource;
1451 if( abf == NULL ) return;
1453 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1454 g_signal_handlers_block_by_func
1455 (G_OBJECT(addrbook.clist),
1456 G_CALLBACK(addressbook_list_row_unselected), NULL);
1458 /* Process deletions */
1459 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1460 GList *groups = NULL, *persons = NULL, *emails = NULL;
1461 gboolean group_delete = TRUE;
1462 /* Items inside folders */
1463 list = addrselect_get_list( _addressSelect_ );
1464 /* Confirm deletion */
1468 node = g_list_next( node );
1469 aio = ( AddrItemObject * ) item->addressItem;
1470 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1471 group_delete = FALSE;
1476 aval = alertpanel( _("Delete group"),
1477 _("Really delete the group(s)?\n"
1478 "The addresses it contains will not be lost."),
1479 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1480 if( aval != G_ALERTALTERNATE ) {
1484 aval = alertpanel( _("Delete address(es)"),
1485 _("Really delete the address(es)?"),
1486 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1487 if( aval != G_ALERTALTERNATE ) {
1492 /* first, set lists of groups and persons to remove */
1496 node = g_list_next( node );
1497 aio = ( AddrItemObject * ) item->addressItem;
1500 if( aio->type == ITEMTYPE_GROUP ) {
1501 groups = g_list_prepend(groups, item);
1503 else if( aio->type == ITEMTYPE_PERSON ) {
1504 persons = g_list_prepend(persons, item);
1507 /* then set list of emails to remove *if* they're not children of
1508 * persons to remove */
1512 node = g_list_next( node );
1513 aio = ( AddrItemObject * ) item->addressItem;
1516 if( aio->type == ITEMTYPE_EMAIL ) {
1517 ItemEMail *sitem = ( ItemEMail * ) aio;
1518 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1519 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1520 emails = g_list_prepend(emails, item);
1522 /* else, the email will be removed via the parent person */
1525 /* then delete groups */
1529 node = g_list_next( node );
1530 aio = ( AddrItemObject * ) item->addressItem;
1533 if( aio->type == ITEMTYPE_GROUP ) {
1534 ItemGroup *item = ( ItemGroup * ) aio;
1535 GtkCMCTreeNode *nd = NULL;
1536 nd = addressbook_find_group_node( addrbook.opened, item );
1537 item = addrbook_remove_group( abf, item );
1539 addritem_free_item_group( item );
1541 /* Remove group from parent node */
1542 gtk_cmctree_remove_node( ctree, nd );
1546 /* then delete persons */
1550 node = g_list_next( node );
1551 aio = ( AddrItemObject * ) item->addressItem;
1554 if( aio->type == ITEMTYPE_PERSON ) {
1555 ItemPerson *item = ( ItemPerson * ) aio;
1556 item->status = DELETE_ENTRY;
1557 addressbook_folder_remove_one_person( clist, item );
1558 if (pobj->type == ADDR_ITEM_FOLDER)
1559 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1560 item = addrbook_remove_person( abf, item );
1562 if (ds && ds->type == ADDR_IF_LDAP) {
1563 LdapServer *server = ds->rawDataSource;
1564 ldapsvr_set_modified(server, TRUE);
1565 ldapsvr_update_book(server, item);
1569 addritem_person_remove_picture(item);
1570 addritem_free_item_person( item );
1574 /* then delete emails */
1578 node = g_list_next( node );
1579 aio = ( AddrItemObject * ) item->addressItem;
1583 if( aio->type == ITEMTYPE_EMAIL ) {
1584 ItemEMail *sitem = ( ItemEMail * ) aio;
1585 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1586 sitem = addrbook_person_remove_email( abf, person, sitem );
1588 addrcache_remove_email(abf->addressCache, sitem);
1589 addritem_free_item_email( sitem );
1591 addressbook_folder_refresh_one_person( clist, person );
1594 g_list_free( groups );
1595 g_list_free( persons );
1596 g_list_free( emails );
1597 g_list_free( list );
1598 addressbook_list_select_clear();
1600 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1601 addressbook_set_clist(
1602 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1606 addrbook_set_dirty(abf, TRUE);
1607 addressbook_export_to_file();
1608 addressbook_list_menu_setup();
1611 else if( pobj->type == ADDR_ITEM_GROUP ) {
1612 /* Items inside groups */
1613 list = addrselect_get_list( _addressSelect_ );
1617 node = g_list_next( node );
1618 aio = ( AddrItemObject * ) item->addressItem;
1619 if( aio->type == ITEMTYPE_EMAIL ) {
1620 ItemEMail *item = ( ItemEMail * ) aio;
1621 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1622 item = addrbook_person_remove_email( abf, person, item );
1624 addritem_free_item_email( item );
1628 g_list_free( list );
1629 addressbook_list_select_clear();
1630 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1631 addressbook_set_clist(
1632 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1636 addrbook_set_dirty(abf, TRUE);
1637 addressbook_export_to_file();
1638 addressbook_list_menu_setup();
1642 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1643 gtk_cmctree_remove_node( clist, nodeList );
1645 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1646 g_signal_handlers_unblock_by_func
1647 (G_OBJECT(addrbook.clist),
1648 G_CALLBACK(addressbook_list_row_unselected), NULL);
1651 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1653 addressbook_new_address_cb( NULL, NULL );
1656 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1659 gchar *address = NULL;
1661 if( aio->type == ITEMTYPE_EMAIL ) {
1662 ItemPerson *person = NULL;
1663 ItemEMail *email = ( ItemEMail * ) aio;
1665 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1666 if( email->address ) {
1667 if( ADDRITEM_NAME(email) ) {
1668 name = ADDRITEM_NAME(email);
1669 if( *name == '\0' ) {
1670 name = ADDRITEM_NAME(person);
1673 else if( ADDRITEM_NAME(person) ) {
1674 name = ADDRITEM_NAME(person);
1677 buf = g_strdup( email->address );
1679 address = email->address;
1682 else if( aio->type == ITEMTYPE_PERSON ) {
1683 ItemPerson *person = ( ItemPerson * ) aio;
1684 GList *node = person->listEMail;
1686 name = ADDRITEM_NAME(person);
1688 ItemEMail *email = ( ItemEMail * ) node->data;
1689 address = email->address;
1693 if( name && name[0] != '\0' ) {
1694 if( strchr_with_skip_quote( name, '"', ',' ) )
1695 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1697 buf = g_strdup_printf( "%s <%s>", name, address );
1700 buf = g_strdup( address );
1707 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1711 AddrSelectItem *item;
1712 AddrItemObject *aio;
1715 compose = addrbook.target_compose;
1716 if( ! compose ) return;
1718 /* Nothing selected, but maybe there is something in text entry */
1719 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1721 compose_entry_append(
1722 compose, addr, (ComposeEntryType)data , PREF_NONE);
1725 /* Select from address list */
1726 list = addrselect_get_list( _addressSelect_ );
1731 node = g_list_next( node );
1732 aio = item->addressItem;
1733 if( aio->type == ITEMTYPE_PERSON ||
1734 aio->type == ITEMTYPE_EMAIL ) {
1735 addr = addressbook_format_address( aio );
1736 compose_entry_append(
1737 compose, addr, (ComposeEntryType) data, PREF_NONE );
1740 else if( aio->type == ITEMTYPE_GROUP ) {
1741 ItemGroup *group = ( ItemGroup * ) aio;
1742 GList *nodeMail = group->listEMail;
1744 ItemEMail *email = nodeMail->data;
1746 addr = addressbook_format_address(
1747 ( AddrItemObject * ) email );
1748 compose_entry_append(
1749 compose, addr, (ComposeEntryType) data, PREF_NONE );
1751 nodeMail = g_list_next( nodeMail );
1756 AddressObject *obj = NULL;
1758 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1760 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1761 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1762 GList *nodeMail = itemGroup->listEMail;
1764 ItemEMail *email = nodeMail->data;
1766 addr = addressbook_format_address(
1767 ( AddrItemObject * ) email );
1768 compose_entry_append(
1769 compose, addr, (ComposeEntryType) data, PREF_NONE );
1771 nodeMail = g_list_next( nodeMail );
1775 g_list_free( list );
1778 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1779 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1780 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1781 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1783 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/SelectAll", TRUE );
1784 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", sensitive );
1785 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", sensitive );
1786 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", sensitive );
1788 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", sensitive );
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", sensitive );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", sensitive );
1792 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1793 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1796 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1797 gboolean canEdit = FALSE;
1798 gboolean canDelete = TRUE;
1799 gboolean canAdd = FALSE;
1800 gboolean canEditTr = TRUE;
1801 gboolean editAddress = FALSE;
1802 gboolean canExport = TRUE;
1803 AddressTypeControlItem *atci = NULL;
1804 AddressDataSource *ds = NULL;
1805 AddressInterface *iface = NULL;
1807 if( obj == NULL ) return;
1808 if( obj->type == ADDR_INTERFACE ) {
1809 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1810 iface = adapter->interface;
1812 if( iface->haveLibrary ) {
1813 /* Enable appropriate File / New command */
1814 atci = adapter->atci;
1815 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1818 canEditTr = canExport = FALSE;
1820 else if( obj->type == ADDR_DATASOURCE ) {
1821 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1822 ds = ads->dataSource;
1823 iface = ds->interface;
1824 if( ! iface->readOnly ) {
1825 canAdd = canEdit = editAddress = canDelete = TRUE;
1827 if( ! iface->haveLibrary ) {
1828 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1831 else if( obj->type == ADDR_ITEM_FOLDER ) {
1832 ds = addressbook_find_datasource( addrbook.treeSelected );
1834 iface = ds->interface;
1835 if( iface->readOnly ) {
1840 canAdd = editAddress = TRUE;
1844 else if( obj->type == ADDR_ITEM_GROUP ) {
1845 ds = addressbook_find_datasource( addrbook.treeSelected );
1847 iface = ds->interface;
1848 if( ! iface->readOnly ) {
1854 if( addrbook.listSelected == NULL )
1858 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", editAddress );
1859 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", canAdd );
1860 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1861 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1864 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
1865 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
1866 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1867 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1869 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1870 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1873 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1878 * Address book tree callback function that responds to selection of tree
1881 * \param ctree Tree widget.
1882 * \param node Node that was selected.
1883 * \param column Column number where selected occurred.
1884 * \param data Pointer to user data.
1886 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1887 gint column, gpointer data)
1889 AddressObject *obj = NULL;
1890 AdapterDSource *ads = NULL;
1891 AddressDataSource *ds = NULL;
1892 ItemFolder *rootFolder = NULL;
1893 AddressObjectType aot;
1895 addrbook.treeSelected = node;
1896 addrbook.listSelected = NULL;
1897 addressbook_status_show( "" );
1898 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1900 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1902 addressbook_set_clist(NULL, TRUE);
1905 addrbook.opened = node;
1907 if( obj->type == ADDR_DATASOURCE ) {
1908 /* Read from file */
1909 static gboolean tVal = TRUE;
1911 ads = ADAPTER_DSOURCE(obj);
1913 ds = ads->dataSource;
1914 if( ds == NULL ) return;
1916 if( addrindex_ds_get_modify_flag( ds ) ) {
1917 addrindex_ds_read_data( ds );
1920 if( ! addrindex_ds_get_read_flag( ds ) ) {
1921 addrindex_ds_read_data( ds );
1923 addressbook_ds_show_message( ds );
1925 if( ! addrindex_ds_get_access_flag( ds ) ) {
1926 /* Remove existing folders and groups */
1927 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1928 addressbook_tree_remove_children( ctree, node );
1929 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1931 /* Load folders into the tree */
1932 rootFolder = addrindex_ds_get_root_folder( ds );
1933 if( ds && ds->type == ADDR_IF_JPILOT ) {
1934 aot = ADDR_CATEGORY;
1936 else if( ds && ds->type == ADDR_IF_LDAP ) {
1937 aot = ADDR_LDAP_QUERY;
1940 aot = ADDR_ITEM_FOLDER;
1942 addressbook_node_add_folder( node, ds, rootFolder, aot );
1943 addrindex_ds_set_access_flag( ds, &tVal );
1944 gtk_cmctree_expand( ctree, node );
1947 addressbook_set_clist(NULL, TRUE);
1950 /* Update address list */
1951 g_signal_handlers_block_by_func
1953 G_CALLBACK(addressbook_tree_selected), NULL);
1954 addressbook_set_clist( obj, FALSE );
1955 g_signal_handlers_unblock_by_func
1957 G_CALLBACK(addressbook_tree_selected), NULL);
1958 if (!prefs_common.addressbook_use_editaddress_dialog)
1959 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1961 /* Setup main menu selections */
1962 addressbook_menubar_set_sensitive( FALSE );
1963 addressbook_menuitem_set_sensitive( obj, node );
1964 addressbook_list_select_clear();
1965 addressbook_list_menu_setup();
1970 * Setup address list popup menu items. Items are enabled or disabled as
1973 static void addressbook_list_menu_setup( void ) {
1974 GtkCMCTree *clist = NULL;
1975 AddressObject *pobj = NULL;
1976 AddressObject *obj = NULL;
1977 AdapterDSource *ads = NULL;
1978 AddressInterface *iface = NULL;
1979 AddressDataSource *ds = NULL;
1981 AddrItemObject *aio;
1982 AddrSelectItem *item;
1983 gboolean canEdit = FALSE;
1984 gboolean canDelete = FALSE;
1985 gboolean canCut = FALSE;
1986 gboolean canCopy = FALSE;
1987 gboolean canPaste = FALSE;
1988 gboolean canBrowse = FALSE;
1989 gboolean canMerge = FALSE;
1991 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1992 if( pobj == NULL ) return;
1994 clist = GTK_CMCTREE(addrbook.clist);
1995 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
1996 if( obj == NULL ) canEdit = FALSE;
1998 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
1999 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2001 if( pobj->type == ADDR_DATASOURCE ) {
2002 /* Parent object is a data source */
2003 ads = ADAPTER_DSOURCE(pobj);
2004 ds = ads->dataSource;
2007 iface = ds->interface;
2010 if( ! iface->readOnly ) {
2011 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2012 if (iface->type != ADDR_IF_LDAP)
2013 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2014 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2017 canDelete = canEdit;
2020 else if( pobj->type != ADDR_INTERFACE ) {
2021 /* Parent object is not an interface */
2022 ds = addressbook_find_datasource( addrbook.treeSelected );
2025 iface = ds->interface;
2028 if( ! iface->readOnly ) {
2029 /* Folder or group */
2030 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2031 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2032 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2033 if( obj ) canEdit = TRUE;
2036 if( pobj->type == ADDR_ITEM_FOLDER ) {
2037 if (iface->type != ADDR_IF_LDAP)
2038 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2039 if( obj ) canEdit = TRUE;
2041 canDelete = canEdit;
2043 if( iface->type == ADDR_IF_LDAP ) {
2044 if( obj ) canBrowse = TRUE;
2051 /* Enable cut and paste */
2052 if( ! addrclip_is_empty( _clipBoard_ ) )
2054 if( ! addrselect_test_empty( _addressSelect_ ) )
2056 /* Enable copy if something is selected */
2057 if( ! addrselect_test_empty( _addressSelect_ ) )
2061 /* Disable edit or browse if more than one row selected */
2062 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2067 /* Allow merging persons or emails are selected */
2068 list = _addressSelect_->listSelect;
2069 if (list && list->next ) {
2071 aio = ( AddrItemObject * ) item->addressItem;
2072 if( aio->type == ITEMTYPE_EMAIL ||
2073 aio->type == ITEMTYPE_PERSON ) {
2078 /* Forbid write changes when read-only */
2079 if( iface && iface->readOnly ) {
2086 /* Now go finalize menu items */
2087 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2088 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2090 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2091 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2092 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2094 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2095 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge", canMerge );
2097 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2098 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2099 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2101 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
2103 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", canCopy );
2104 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", canMerge );
2106 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2107 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2109 if (addrbook.target_compose) {
2110 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2111 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2112 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2115 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2119 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2120 GtkCMCTreeNode *node,
2127 * Add list of items into tree node below specified tree node.
2128 * \param treeNode Tree node.
2129 * \param ds Data source.
2130 * \param listItems List of items.
2132 static void addressbook_treenode_add_list(
2133 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2139 AddrItemObject *aio;
2143 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2146 group = ( ItemGroup * ) aio;
2147 nn = addressbook_node_add_group( treeNode, ds, group );
2149 g_message("error adding addressbook group\n");
2152 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2155 folder = ( ItemFolder * ) aio;
2156 nn = addressbook_node_add_folder(
2157 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2159 g_message("error adding addressbook folder\n");
2162 node = g_list_next( node );
2166 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2167 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2171 * Cut from address list widget.
2173 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2174 _clipBoard_->cutFlag = TRUE;
2175 addrclip_clear( _clipBoard_ );
2176 addrclip_add( _clipBoard_, _addressSelect_ );
2177 /* addrclip_list_show( _clipBoard_, stdout ); */
2181 * Copy from address list widget.
2183 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2184 _clipBoard_->cutFlag = FALSE;
2185 addrclip_clear( _clipBoard_ );
2186 addrclip_add( _clipBoard_, _addressSelect_ );
2187 /* addrclip_list_show( _clipBoard_, stdout ); */
2191 * Paste clipboard into address list widget.
2193 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2194 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2195 AddressObject *pobj = NULL;
2196 AddressDataSource *ds = NULL;
2197 AddressBookFile *abf = NULL;
2198 ItemFolder *folder = NULL;
2199 GList *folderGroup = NULL;
2201 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2202 if( ds == NULL ) return;
2203 if( addrindex_ds_get_readonly( ds ) ) {
2204 alertpanel_error( _("Cannot paste. Target address book is read-only.") );
2208 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2210 if( pobj->type == ADDR_ITEM_FOLDER ) {
2211 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2213 else if( pobj->type == ADDR_ITEM_GROUP ) {
2214 alertpanel_error( _("Cannot paste into an address group.") );
2219 /* Get an address book */
2220 abf = addressbook_get_book_file();
2221 if( abf == NULL ) return;
2223 if( _clipBoard_->cutFlag ) {
2225 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2227 /* Remove all groups and folders in clipboard from tree node */
2228 addressbook_treenode_remove_item();
2230 /* Remove all "cut" items */
2231 addrclip_delete_item( _clipBoard_ );
2233 /* Clear clipboard - cut items??? */
2234 addrclip_clear( _clipBoard_ );
2238 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2241 /* addrclip_list_show( _clipBoard_, stdout ); */
2243 /* Update tree by inserting node for each folder or group */
2244 addressbook_treenode_add_list(
2245 addrbook.treeSelected, ds, folderGroup );
2246 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2247 g_list_free( folderGroup );
2251 /* Display items pasted */
2252 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2253 addressbook_set_clist(
2254 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2262 * Add current treenode object to clipboard. Note that widget only allows
2263 * one entry from the tree list to be selected.
2265 static void addressbook_treenode_to_clipboard( void ) {
2266 AddressObject *obj = NULL;
2267 AddressDataSource *ds = NULL;
2268 AddrSelectItem *item;
2269 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2270 GtkCMCTreeNode *node;
2272 node = addrbook.treeSelected;
2273 if( node == NULL ) return;
2274 obj = gtk_cmctree_node_get_row_data( ctree, node );
2275 if( obj == NULL ) return;
2277 ds = addressbook_find_datasource( node );
2278 if( ds == NULL ) return;
2281 if( obj->type == ADDR_ITEM_FOLDER ) {
2282 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2283 ItemFolder *folder = adapter->itemFolder;
2285 item = addrselect_create_node( obj );
2286 item->uid = g_strdup( ADDRITEM_ID(folder) );
2288 else if( obj->type == ADDR_ITEM_GROUP ) {
2289 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2290 ItemGroup *group = adapter->itemGroup;
2292 item = addrselect_create_node( obj );
2293 item->uid = g_strdup( ADDRITEM_ID(group) );
2295 else if( obj->type == ADDR_DATASOURCE ) {
2297 item = addrselect_create_node( obj );
2302 /* Clear existing list and add item into list */
2305 addressbook_list_select_clear();
2306 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2307 addrselect_list_add( _addressSelect_, item, cacheID );
2313 * Cut from tree widget.
2315 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2316 _clipBoard_->cutFlag = TRUE;
2317 addressbook_treenode_to_clipboard();
2318 addrclip_clear( _clipBoard_ );
2319 addrclip_add( _clipBoard_, _addressSelect_ );
2320 /* addrclip_list_show( _clipBoard_, stdout ); */
2324 * Copy from tree widget.
2326 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2327 _clipBoard_->cutFlag = FALSE;
2328 addressbook_treenode_to_clipboard();
2329 addrclip_clear( _clipBoard_ );
2330 addrclip_add( _clipBoard_, _addressSelect_ );
2331 /* addrclip_list_show( _clipBoard_, stdout ); */
2335 * Paste clipboard into address tree widget.
2337 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2338 addressbook_clip_paste_cb(NULL,NULL);
2342 * Clear selected entries in clipboard.
2344 static void addressbook_list_select_clear( void ) {
2345 addrselect_list_clear( _addressSelect_ );
2349 * Add specified address item to selected address list.
2350 * \param aio Address item object.
2351 * \param ds Datasource.
2353 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2356 if( ds == NULL ) return;
2357 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2358 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2363 * Remove specified address item from selected address list.
2364 * \param aio Address item object.
2366 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2367 addrselect_list_remove( _addressSelect_, aio );
2371 * Invoke EMail compose window with addresses in selected address list.
2373 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2376 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2377 listAddress = addrselect_build_list( _addressSelect_ );
2378 compose_new_with_list( NULL, listAddress );
2379 g_list_free_full( listAddress, g_free );
2384 static void addressbook_merge_list( AddrSelectList *list ) {
2385 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2386 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2387 AddressObject *pobj;
2388 AddressDataSource *ds = NULL;
2390 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
2391 cm_return_if_fail(pobj != NULL);
2393 ds = addressbook_find_datasource( addrbook.treeSelected );
2394 if( ds == NULL ) return;
2396 addrmerge_merge(clist, pobj, ds, list);
2400 * Merge selected entries in the address list
2402 static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
2403 if( addrselect_test_empty( _addressSelect_ ) )
2406 addressbook_merge_list( _addressSelect_ );
2409 static void addressbook_list_row_selected( GtkCMCTree *clist,
2410 GtkCMCTreeNode *node,
2414 AddrItemObject *aio = NULL;
2415 AddressObject *pobj = NULL;
2416 AdapterDSource *ads = NULL;
2417 AddressDataSource *ds = NULL;
2419 addrbook.listSelected = node;
2421 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2422 if( pobj == NULL ) return;
2424 if( pobj->type == ADDR_DATASOURCE ) {
2425 ads = ADAPTER_DSOURCE(pobj);
2426 ds = ads->dataSource;
2428 else if( pobj->type != ADDR_INTERFACE ) {
2429 ds = addressbook_find_datasource( addrbook.treeSelected );
2432 aio = gtk_cmctree_node_get_row_data( clist, node );
2434 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2435 addressbook_list_select_add( aio, ds );
2438 addressbook_list_menu_setup();
2440 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2441 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2443 if (obj && obj->type != ADDR_ITEM_GROUP)
2444 addressbook_edit_address(NULL, 0, NULL, FALSE);
2448 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2449 GtkCMCTreeNode *node,
2453 AddrItemObject *aio;
2455 aio = gtk_cmctree_node_get_row_data( ctree, node );
2457 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2458 addressbook_list_select_remove( aio );
2461 if (!prefs_common.addressbook_use_editaddress_dialog)
2462 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2465 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2467 addressbook_lup_clicked(NULL, NULL);
2470 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2471 GdkEventButton *event,
2474 if( ! event ) return FALSE;
2475 if( event->window != GTK_CMCLIST(widget)->clist_window ) return FALSE;
2477 addressbook_list_menu_setup();
2479 if( event->button == 3 ) {
2480 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2481 event->button, event->time );
2482 } else if (event->button == 1) {
2483 if (event->type == GDK_2BUTTON_PRESS) {
2484 if (prefs_common.add_address_by_click &&
2485 addrbook.target_compose)
2486 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2488 if (prefs_common.addressbook_use_editaddress_dialog)
2489 addressbook_edit_address_cb(NULL, NULL);
2491 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2492 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2493 if( obj && obj->type == ADDR_ITEM_GROUP )
2494 addressbook_edit_address_cb(NULL, NULL);
2502 static gboolean addressbook_list_button_released(GtkWidget *widget,
2503 GdkEventButton *event,
2509 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2510 GdkEventButton *event,
2513 GtkCMCList *clist = GTK_CMCLIST(ctree);
2515 AddressObject *obj = NULL;
2516 AdapterDSource *ads = NULL;
2517 AddressInterface *iface = NULL;
2518 AddressDataSource *ds = NULL;
2519 gboolean canEdit = FALSE;
2520 gboolean canDelete = FALSE;
2521 gboolean canCut = FALSE;
2522 gboolean canCopy = FALSE;
2523 gboolean canPaste = FALSE;
2524 gboolean canTreeCut = FALSE;
2525 gboolean canTreeCopy = FALSE;
2526 gboolean canTreePaste = FALSE;
2527 gboolean canLookup = FALSE;
2528 GtkCMCTreeNode *node = NULL;
2530 if( ! event ) return FALSE;
2531 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2533 if( event->window != clist->clist_window )
2536 if (event->button == 1) {
2537 if (event->type == GDK_2BUTTON_PRESS) {
2538 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2539 gtkut_clist_set_focus_row(clist, row);
2540 obj = gtk_cmclist_get_row_data( clist, row );
2545 if (obj->type == ADDR_ITEM_GROUP ||
2546 obj->type == ADDR_DATASOURCE) {
2548 addressbook_treenode_edit_cb(NULL, NULL);
2550 /* expand pr collapse */
2551 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2552 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2558 addressbook_menubar_set_sensitive( FALSE );
2560 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2561 gtkut_clist_set_focus_row(clist, row);
2562 obj = gtk_cmclist_get_row_data( clist, row );
2565 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2569 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2571 if( ! addrclip_is_empty( _clipBoard_ ) )
2572 canTreePaste = TRUE;
2574 if (obj->type == ADDR_INTERFACE) {
2575 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2576 iface = adapter->interface;
2579 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2580 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2582 if( iface->externalQuery )
2585 if (obj->type == ADDR_DATASOURCE) {
2587 ads = ADAPTER_DSOURCE(obj);
2588 ds = ads->dataSource;
2591 iface = ds->interface;
2594 if( !iface->readOnly ) {
2595 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2596 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2597 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2603 else if (obj->type == ADDR_ITEM_FOLDER) {
2605 ds = addressbook_find_datasource( node );
2608 iface = ds->interface;
2611 if( !iface->readOnly ) {
2615 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2616 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2617 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2621 if( iface->externalQuery ) {
2622 /* Enable deletion of LDAP folder */
2626 else if (obj->type == ADDR_ITEM_GROUP) {
2628 ds = addressbook_find_datasource( node );
2631 iface = ds->interface;
2634 if( ! iface->readOnly ) {
2637 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2638 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2642 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2644 if( ! addrselect_test_empty( _addressSelect_ ) )
2646 if( ! addrclip_is_empty( _clipBoard_ ) )
2649 /* Forbid write changes when read-only */
2650 if( iface && iface->readOnly ) {
2652 canTreePaste = FALSE;
2659 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2660 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2661 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2662 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2663 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2665 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2666 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2667 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2668 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2669 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2671 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2672 addrbook.target_compose != NULL);
2674 if( event->button == 3 )
2675 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2676 event->button, event->time);
2681 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2682 GdkEventButton *event,
2685 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2689 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2691 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2692 AddressObject *obj = NULL;
2693 AddressDataSource *ds = NULL;
2694 AddressBookFile *abf = NULL;
2695 ItemFolder *parentFolder = NULL;
2696 ItemFolder *folder = NULL;
2698 if( ! addrbook.treeSelected ) return;
2699 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2700 if( obj == NULL ) return;
2701 ds = addressbook_find_datasource( addrbook.treeSelected );
2702 if( ds == NULL ) return;
2704 if( obj->type == ADDR_DATASOURCE ) {
2705 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2707 else if( obj->type == ADDR_ITEM_FOLDER ) {
2708 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2714 abf = ds->rawDataSource;
2715 if( abf == NULL ) return;
2716 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2719 nn = addressbook_node_add_folder(
2720 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2722 g_message("error adding addressbook folder\n");
2724 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2725 if( addrbook.treeSelected == addrbook.opened )
2726 addressbook_set_clist(obj, TRUE);
2730 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2732 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2733 AddressObject *obj = NULL;
2734 AddressDataSource *ds = NULL;
2735 AddressBookFile *abf = NULL;
2736 ItemFolder *parentFolder = NULL;
2737 ItemGroup *group = NULL;
2739 if( ! addrbook.treeSelected ) return;
2740 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2741 if( obj == NULL ) return;
2742 ds = addressbook_find_datasource( addrbook.treeSelected );
2743 if( ds == NULL ) return;
2745 if( obj->type == ADDR_DATASOURCE ) {
2746 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2748 else if( obj->type == ADDR_ITEM_FOLDER ) {
2749 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2755 abf = ds->rawDataSource;
2756 if( abf == NULL ) return;
2757 group = addressbook_edit_group( abf, parentFolder, NULL );
2760 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2762 g_message("error adding addressbook group\n");
2764 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2765 if( addrbook.treeSelected == addrbook.opened )
2766 addressbook_set_clist(obj, TRUE);
2770 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2772 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2775 GdkPixbuf *pix_cl, *pix_op;
2776 gboolean is_leaf, expanded;
2778 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2780 &is_leaf, &expanded);
2781 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2788 * \param obj Address object to edit.
2789 * \param node Node in tree.
2790 * \return New name of data source.
2792 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2793 gchar *newName = NULL;
2794 AddressDataSource *ds = NULL;
2795 AddressInterface *iface = NULL;
2796 AdapterDSource *ads = NULL;
2798 ds = addressbook_find_datasource( node );
2799 if( ds == NULL ) return NULL;
2800 iface = ds->interface;
2801 if( ! iface->haveLibrary ) return NULL;
2803 /* Read data from data source */
2804 if( addrindex_ds_get_modify_flag( ds ) ) {
2805 addrindex_ds_read_data( ds );
2808 if( ! addrindex_ds_get_read_flag( ds ) ) {
2809 addrindex_ds_read_data( ds );
2813 ads = ADAPTER_DSOURCE(obj);
2814 if( ads->subType == ADDR_BOOK ) {
2815 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2817 else if( ads->subType == ADDR_VCARD ) {
2818 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2821 else if( ads->subType == ADDR_JPILOT ) {
2822 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2826 else if( ads->subType == ADDR_LDAP ) {
2827 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2833 newName = obj->name;
2838 * Edit an object that is in the address tree area.
2840 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2842 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2844 AddressDataSource *ds = NULL;
2845 AddressBookFile *abf = NULL;
2846 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2849 if( ! addrbook.treeSelected ) return;
2850 node = addrbook.treeSelected;
2851 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2852 obj = gtk_cmctree_node_get_row_data( ctree, node );
2853 if( obj == NULL ) return;
2854 parentNode = GTK_CMCTREE_ROW(node)->parent;
2856 ds = addressbook_find_datasource( node );
2857 if( ds == NULL ) return;
2859 if( obj->type == ADDR_DATASOURCE ) {
2860 name = addressbook_edit_datasource( obj, node );
2861 if( name == NULL ) return;
2864 abf = ds->rawDataSource;
2865 if( abf == NULL ) return;
2866 if( obj->type == ADDR_ITEM_FOLDER ) {
2867 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2868 ItemFolder *item = adapter->itemFolder;
2869 ItemFolder *parentFolder = NULL;
2870 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2871 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2872 name = ADDRITEM_NAME(item);
2874 else if( obj->type == ADDR_ITEM_GROUP ) {
2875 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2876 ItemGroup *item = adapter->itemGroup;
2877 ItemFolder *parentFolder = NULL;
2878 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2879 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2880 name = ADDRITEM_NAME(item);
2883 if( name && parentNode ) {
2884 /* Update node in tree view */
2885 addressbook_change_node_name( node, name );
2886 gtk_sctree_sort_node(ctree, parentNode);
2887 gtk_cmctree_expand( ctree, node );
2888 gtk_sctree_select( GTK_SCTREE( ctree), node );
2895 ADDRTREE_DEL_FOLDER_ONLY,
2896 ADDRTREE_DEL_FOLDER_ADDR
2900 * Delete an item from the tree widget.
2901 * \param data Data passed in.
2902 * \param action Action.
2903 * \param widget Widget issuing callback.
2905 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2907 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2908 GtkCMCTreeNode *node = NULL;
2912 AddrBookBase *adbase;
2913 AddressCache *cache;
2914 AdapterDSource *ads = NULL;
2915 AddressInterface *iface = NULL;
2916 AddressDataSource *ds = NULL;
2917 gboolean remFlag = FALSE;
2918 TreeItemDelType delType;
2920 if( ! addrbook.treeSelected ) return;
2921 node = addrbook.treeSelected;
2922 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2924 obj = gtk_cmctree_node_get_row_data( ctree, node );
2925 cm_return_if_fail(obj != NULL);
2927 if( obj->type == ADDR_DATASOURCE ) {
2928 ads = ADAPTER_DSOURCE(obj);
2930 ds = ads->dataSource;
2931 if( ds == NULL ) return;
2934 /* Must be folder or something else */
2935 ds = addressbook_find_datasource( node );
2936 if( ds == NULL ) return;
2938 /* Only allow deletion from non-readOnly */
2939 iface = ds->interface;
2940 if( iface->readOnly ) {
2941 /* Allow deletion of query results */
2942 if( ! iface->externalQuery ) return;
2946 /* Confirm deletion */
2947 delType = ADDRTREE_DEL_NONE;
2948 if( obj->type == ADDR_ITEM_FOLDER ) {
2949 if( iface && iface->externalQuery ) {
2950 message = g_strdup_printf( _(
2951 "Do you want to delete the query " \
2952 "results and addresses in '%s'?" ),
2954 aval = alertpanel( _("Delete"), message,
2955 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
2957 if( aval == G_ALERTALTERNATE ) {
2958 delType = ADDRTREE_DEL_FOLDER_ADDR;
2962 message = g_strdup_printf
2963 ( _( "Do you want to delete '%s'? "
2964 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2966 aval = alertpanel( _("Delete folder"), message,
2967 GTK_STOCK_CANCEL, _("Delete _folder only"), _("Delete folder and _addresses"), ALERTFOCUS_SECOND);
2969 if( aval == G_ALERTALTERNATE ) {
2970 delType = ADDRTREE_DEL_FOLDER_ONLY;
2972 else if( aval == G_ALERTOTHER ) {
2973 delType = ADDRTREE_DEL_FOLDER_ADDR;
2977 else if( obj->type == ADDR_ITEM_GROUP ) {
2978 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2979 "The addresses it contains will not be lost."), obj->name);
2980 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2981 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2983 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2985 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2986 "The addresses it contains will be lost."), obj->name);
2987 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2988 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2990 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2992 if( delType == ADDRTREE_DEL_NONE ) return;
2994 /* Proceed with deletion */
2995 if( obj->type == ADDR_DATASOURCE ) {
2996 /* Remove node from tree */
2997 gtk_cmctree_remove_node( ctree, node );
2999 if (delType == ADDRTREE_DEL_DATA &&
3000 ds->interface && ds->interface->type == ADDR_IF_BOOK)
3001 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
3003 /* Remove data source. */
3004 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3005 addrindex_free_datasource( ds );
3010 /* Get reference to cache */
3011 adbase = ( AddrBookBase * ) ds->rawDataSource;
3012 if( adbase == NULL ) return;
3013 cache = adbase->addressCache;
3015 /* Remove query results folder */
3016 if( iface && iface->externalQuery ) {
3017 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3018 ItemFolder *folder = adapter->itemFolder;
3020 adapter->itemFolder = NULL;
3022 g_print( "remove folder for ::%s::\n", obj->name );
3023 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3024 g_print( "-------------- remove results\n" );
3026 addrindex_remove_results( ds, folder );
3027 /* g_print( "-------------- remove node\n" ); */
3028 gtk_cmctree_remove_node( ctree, node );
3032 /* Code below is valid for regular address book deletion */
3033 if( obj->type == ADDR_ITEM_FOLDER ) {
3034 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3035 ItemFolder *item = adapter->itemFolder;
3037 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3038 /* Remove folder only */
3039 item = addrcache_remove_folder( cache, item );
3041 addritem_free_item_folder( item );
3042 addressbook_move_nodes_up( ctree, node );
3046 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3047 /* Remove folder and addresses */
3048 item = addrcache_remove_folder_delete( cache, item );
3050 addritem_free_item_folder( item );
3055 else if( obj->type == ADDR_ITEM_GROUP ) {
3056 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3057 ItemGroup *item = adapter->itemGroup;
3059 item = addrcache_remove_group( cache, item );
3061 addritem_free_item_group( item );
3068 gtk_cmctree_remove_node(ctree, node );
3072 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3074 if( person && addrbook.treeSelected == addrbook.opened ) {
3075 person->status = ADD_ENTRY;
3076 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3077 addressbook_folder_refresh_one_person(
3078 GTK_CMCTREE(addrbook.clist), person );
3080 addressbook_address_list_set_focus();
3083 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3085 if( person && addrbook.treeSelected == addrbook.opened) {
3086 person->status = ADD_ENTRY;
3087 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3088 addressbook_set_clist(
3089 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3093 addressbook_address_list_set_focus();
3097 * Label (a format string) that is used to name each folder.
3099 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3102 * Search ctree widget callback function.
3103 * \param pA Pointer to node.
3104 * \param pB Pointer to data item being sought.
3105 * \return Zero (0) if folder found.
3107 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3110 aoA = ( AddressObject * ) pA;
3111 if( aoA->type == ADDR_ITEM_FOLDER ) {
3112 ItemFolder *folder, *fld;
3114 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3115 folder = ( ItemFolder * ) pB;
3116 if( fld == folder ) return 0; /* Found folder */
3121 static ItemFolder * addressbook_setup_subf(
3122 AddressDataSource *ds, gchar *title,
3123 GtkCMCTreeNode *pNode )
3125 AddrBookBase *adbase;
3126 AddressCache *cache;
3129 GtkCMCTreeNode *nNode;
3131 AddressObjectType aoType = ADDR_NONE;
3134 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3136 if( ds && ds->type == ADDR_IF_LDAP ) {
3138 aoType = ADDR_LDAP_QUERY;
3145 ctree = GTK_CMCTREE(addrbook.ctree);
3146 /* Get reference to address cache */
3147 adbase = ( AddrBookBase * ) ds->rawDataSource;
3148 cache = adbase->addressCache;
3150 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3151 GList *cur = children;
3152 for (; cur; cur = cur->next) {
3153 ItemFolder *child = (ItemFolder *) cur->data;
3154 if (!g_strcmp0(ADDRITEM_NAME(child), title)) {
3155 nNode = gtk_cmctree_find_by_row_data_custom(
3157 addressbook_treenode_find_folder_cb );
3159 addrindex_remove_results( ds, child );
3160 while( child->listPerson ) {
3161 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3162 item = addrcache_remove_person( cache, item );
3164 addritem_free_item_person( item );
3168 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3169 addrbook.treeSelected = nNode;
3176 /* Create a folder */
3177 folder = addrcache_add_new_folder( cache, NULL );
3178 name = g_strdup_printf( "%s", title );
3179 addritem_folder_set_name( folder, name );
3180 addritem_folder_set_remarks( folder, "" );
3183 /* Now let's see the folder */
3184 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3185 gtk_cmctree_expand( ctree, pNode );
3187 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3188 addrbook.treeSelected = nNode;
3194 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3195 AddressObject *pobj = NULL;
3196 AddressDataSource *ds = NULL;
3197 AddressBookFile *abf = NULL;
3198 debug_print("adding address\n");
3199 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3200 if( pobj == NULL ) {
3201 debug_print("no row data\n");
3204 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3206 debug_print("no datasource\n");
3210 abf = ds->rawDataSource;
3212 g_print("no addressbook file\n");
3216 if( pobj->type == ADDR_DATASOURCE ) {
3217 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3218 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3220 ItemFolder *folder = NULL;
3222 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3223 GtkCMCTreeNode *parentNode;
3224 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3225 if( ds == NULL ) return;
3227 /* We must have a datasource that is an external interface */
3228 if( ! ds->interface->haveLibrary ) return;
3229 if( ! ds->interface->externalQuery ) return;
3231 if( pobj->type == ADDR_ITEM_FOLDER ) {
3232 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3235 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3237 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3239 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3241 abf = ds->rawDataSource;
3244 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3245 addrbook.editaddress_vbox,
3246 addressbook_new_address_from_book_post_cb,
3249 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3250 LdapServer *server = ds->rawDataSource;
3251 ldapsvr_set_modified(server, TRUE);
3252 ldapsvr_update_book(server, NULL);
3253 if (server->retVal != LDAPRC_SUCCESS) {
3254 alertpanel( _("Add address(es)"),
3255 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3256 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3257 server->retVal = LDAPRC_SUCCESS;
3262 if (prefs_common.addressbook_use_editaddress_dialog)
3263 addressbook_new_address_from_book_post_cb( person );
3266 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3268 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3271 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3272 GtkCMCTreeNode *parentNode;
3273 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3274 if( ds == NULL ) return;
3276 /* We must have a datasource that is an external interface */
3277 if( ! ds->interface->haveLibrary ) return;
3278 if( ! ds->interface->externalQuery ) return;
3280 if( pobj->type == ADDR_ITEM_FOLDER ) {
3281 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3284 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3286 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3290 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3292 abf = ds->rawDataSource;
3295 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3296 addrbook.editaddress_vbox,
3297 addressbook_new_address_from_folder_post_cb,
3300 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3301 LdapServer *server = ds->rawDataSource;
3302 ldapsvr_set_modified(server, TRUE);
3303 ldapsvr_update_book(server, NULL);
3304 if (server->retVal != LDAPRC_SUCCESS) {
3305 alertpanel( _("Add address(es)"),
3306 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3307 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3312 if (prefs_common.addressbook_use_editaddress_dialog)
3313 addressbook_new_address_from_folder_post_cb( person );
3315 else if( pobj->type == ADDR_ITEM_GROUP ) {
3316 /* New address in group */
3317 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3318 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3319 if (addrbook.treeSelected == addrbook.opened) {
3320 /* Change node name in tree. */
3321 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3322 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3323 addressbook_set_clist(
3324 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3332 * Search for specified child group node in address index tree.
3333 * \param parent Parent node.
3334 * \param group Group to find.
3336 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3337 GtkCMCTreeNode *node = NULL;
3338 GtkCMCTreeRow *currRow;
3340 currRow = GTK_CMCTREE_ROW( parent );
3342 node = currRow->children;
3346 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3347 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3348 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3349 if( g == group ) return node;
3351 currRow = GTK_CMCTREE_ROW(node);
3352 node = currRow->sibling;
3358 static AddressBookFile *addressbook_get_book_file() {
3359 AddressBookFile *abf = NULL;
3360 AddressDataSource *ds = NULL;
3362 ds = addressbook_find_datasource( addrbook.treeSelected );
3363 if( ds == NULL ) return NULL;
3364 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3368 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3369 GtkCMCTreeNode *node;
3372 /* Remove existing folders and groups */
3373 row = GTK_CMCTREE_ROW( parent );
3375 while( (node = row->children) ) {
3376 gtk_cmctree_remove_node( ctree, node );
3381 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3382 GtkCMCTreeNode *parent, *child;
3383 GtkCMCTreeRow *currRow;
3384 currRow = GTK_CMCTREE_ROW( node );
3386 parent = currRow->parent;
3387 while( (child = currRow->children) ) {
3388 gtk_cmctree_move( ctree, child, parent, node );
3390 gtk_sctree_sort_node( ctree, parent );
3394 static void addressbook_edit_address_post_cb( ItemPerson *person )
3398 AddressBookFile *abf = addressbook_get_book_file();
3400 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3401 if (g_strcmp0(person->nickName, ADDRITEM_NAME(person)))
3402 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3405 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3406 invalidate_address_completion();
3408 addressbook_address_list_set_focus();
3411 void addressbook_address_list_set_focus( void )
3413 if (!prefs_common.addressbook_use_editaddress_dialog) {
3414 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3415 addressbook_list_menu_setup();
3419 void addressbook_address_list_disable_some_actions(void)
3421 /* disable address copy/pasting when editing contact's detail (embedded form) */
3422 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", FALSE );
3423 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", FALSE );
3424 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", FALSE );
3427 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3428 addressbook_edit_address(data, 0, NULL, TRUE);
3431 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3432 gboolean force_focus ) {
3433 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3435 AddressObject *obj = NULL, *pobj = NULL;
3436 AddressDataSource *ds = NULL;
3437 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3439 AddressBookFile *abf = NULL;
3441 if( addrbook.listSelected == NULL ) return;
3442 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3443 cm_return_if_fail(obj != NULL);
3445 ctree = GTK_CMCTREE( addrbook.ctree );
3446 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3448 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3449 if( ds == NULL ) return;
3451 abf = addressbook_get_book_file();
3453 if( obj->type == ADDR_ITEM_EMAIL ) {
3454 ItemEMail *email = ( ItemEMail * ) obj;
3456 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3457 /* Edit parent group */
3458 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3459 ItemGroup *itemGrp = adapter->itemGroup;
3460 if( abf == NULL ) return;
3461 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3462 name = ADDRITEM_NAME(itemGrp);
3463 node = addrbook.treeSelected;
3464 parentNode = GTK_CMCTREE_ROW(node)->parent;
3467 /* Edit person - email page */
3469 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3470 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3471 addressbook_edit_address_post_cb,
3472 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3475 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3476 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3477 person->status = UPDATE_ENTRY;
3480 if (prefs_common.addressbook_use_editaddress_dialog)
3481 addressbook_edit_address_post_cb( person );
3486 else if( obj->type == ADDR_ITEM_PERSON ) {
3487 /* Edit person - basic page */
3488 ItemPerson *person = ( ItemPerson * ) obj;
3489 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3490 addressbook_edit_address_post_cb,
3491 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3494 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3495 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3496 person->status = UPDATE_ENTRY;
3499 if (prefs_common.addressbook_use_editaddress_dialog)
3500 addressbook_edit_address_post_cb( person );
3504 else if( obj->type == ADDR_ITEM_GROUP ) {
3505 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3506 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3507 parentNode = addrbook.treeSelected;
3508 node = addressbook_find_group_node( parentNode, itemGrp );
3509 name = ADDRITEM_NAME(itemGrp);
3510 invalidate_address_completion();
3516 /* Update tree node with node name */
3517 if( node == NULL ) return;
3518 addressbook_change_node_name( node, name );
3519 gtk_sctree_sort_node( ctree, parentNode );
3520 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3521 addressbook_set_clist(
3522 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3527 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3529 addressbook_del_clicked(NULL, NULL);
3532 static void close_cb(GtkAction *action, gpointer data)
3534 addressbook_close();
3537 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3538 addressbook_export_to_file();
3541 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3543 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3544 if( person ) addritem_person_set_opened( person, TRUE );
3548 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3550 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3551 if( person ) addritem_person_set_opened( person, FALSE );
3555 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3557 gchar *eMailAlias = ADDRITEM_NAME(email);
3558 if( eMailAlias && *eMailAlias != '\0' ) {
3560 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3563 str = g_strdup( eMailAlias );
3569 static gboolean addressbook_match_item(const gchar *name,
3570 const gchar *email_alias,
3572 const gchar *remarks,
3577 if (!str || str[0] == '\0')
3579 if (strcasestr(name, str))
3581 else if (email_alias && strcasestr(email_alias, str))
3583 else if (addr && strcasestr(addr, str))
3585 else if (remarks && strcasestr(remarks, str))
3591 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3592 GList *items = itemGroup->listEMail;
3593 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3594 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3595 for( ; items != NULL; items = g_list_next( items ) ) {
3596 GtkCMCTreeNode *nodeEMail = NULL;
3597 gchar *text[N_LIST_COLS];
3598 ItemEMail *email = items->data;
3602 if( ! email ) continue;
3604 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3606 if( !addressbook_match_item(ADDRITEM_NAME(person),
3607 ADDRITEM_NAME(email),
3608 email->address, email->remarks,
3612 str = addressbook_format_item_clist( person, email );
3614 text[COL_NAME] = addressbook_set_col_name_guard(str);
3617 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3619 text[COL_ADDRESS] = email->address;
3620 text[COL_REMARKS] = email->remarks;
3621 nodeEMail = gtk_sctree_insert_node(
3623 text, FOLDER_SPACING,
3627 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3633 gchar *addressbook_set_col_name_guard(gchar *value)
3635 gchar *ret = "<not set>";
3636 gchar *tmp = g_strdup(value);
3646 static void addressbook_folder_load_one_person(
3647 GtkCMCTree *clist, ItemPerson *person,
3648 AddressTypeControlItem *atci,
3649 AddressTypeControlItem *atciMail )
3651 GtkCMCTreeNode *nodePerson = NULL;
3652 GtkCMCTreeNode *nodeEMail = NULL;
3653 gchar *text[N_LIST_COLS];
3654 gboolean flgFirst = TRUE, haveAddr = FALSE;
3657 AddressBookFile *abf = addressbook_get_book_file();
3660 if( person == NULL ) return;
3662 text[COL_NAME] = "";
3663 node = person->listEMail;
3665 ItemEMail *email = node->data;
3666 gchar *eMailAddr = NULL;
3667 node = g_list_next( node );
3669 text[COL_ADDRESS] = email->address;
3670 text[COL_REMARKS] = email->remarks;
3671 eMailAddr = ADDRITEM_NAME(email);
3672 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3674 /* First email belongs with person */
3675 gchar *str = addressbook_format_item_clist( person, email );
3677 text[COL_NAME] = addressbook_set_col_name_guard(str);
3680 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3681 person && person->nickName ) {
3682 if (person->nickName) {
3683 if (strcmp(person->nickName, "") != 0) {
3684 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3687 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3693 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3695 nodePerson = gtk_sctree_insert_node(
3697 text, FOLDER_SPACING,
3700 FALSE, person->isOpened );
3703 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3706 /* Subsequent email is a child node of person */
3707 text[COL_NAME] = ADDRITEM_NAME(email);
3708 nodeEMail = gtk_sctree_insert_node(
3709 clist, nodePerson, NULL,
3710 text, FOLDER_SPACING,
3712 atciMail->iconXpmOpen,
3714 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3720 /* Have name without EMail */
3721 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3722 text[COL_ADDRESS] = "";
3723 text[COL_REMARKS] = "";
3724 nodePerson = gtk_sctree_insert_node(
3726 text, FOLDER_SPACING,
3729 FALSE, person->isOpened );
3730 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3735 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3737 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3738 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3739 const gchar *search_str;
3741 if( atci == NULL ) return;
3742 if( atciMail == NULL ) return;
3744 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3746 /* Load email addresses */
3747 items = addritem_folder_get_person_list( itemFolder );
3748 for(cur = items ; cur != NULL; cur = g_list_next( cur ) ) {
3753 person = (ItemPerson *)cur->data;
3756 node = person->listEMail;
3757 if (node && node->data) {
3759 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3762 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3766 addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
3768 /* Free up the list */
3769 g_list_free( items );
3772 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3773 addrbook.listSelected = NULL;
3774 gtk_cmctree_remove_node( clist, node );
3775 addressbook_menubar_set_sensitive( FALSE );
3776 addressbook_menuitem_set_sensitive(
3777 gtk_cmctree_node_get_row_data(
3778 GTK_CMCTREE(clist), addrbook.treeSelected ),
3779 addrbook.treeSelected );
3782 void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3783 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3784 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3785 GtkCMCTreeNode *node;
3786 if( atci == NULL ) return;
3787 if( atciMail == NULL ) return;
3788 if( person == NULL ) return;
3789 /* unload the person */
3791 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3793 addressbook_folder_remove_node( clist, node );
3794 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3795 gtk_sctree_sort_node( clist, NULL );
3796 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3798 gtk_sctree_select( GTK_SCTREE(clist), node );
3799 if (!gtk_cmctree_node_is_visible( clist, node ) )
3800 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3804 void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3805 GtkCMCTreeNode *node;
3807 if( person == NULL ) return;
3808 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3810 addressbook_folder_remove_node( clist, node );
3814 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3816 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3817 const gchar *search_str;
3819 /* Load any groups */
3820 if( ! atci ) return;
3822 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3824 items = addritem_folder_get_group_list( itemFolder );
3825 for( ; items != NULL; items = g_list_next( items ) ) {
3826 GtkCMCTreeNode *nodeGroup = NULL;
3827 gchar *text[N_LIST_COLS];
3828 ItemGroup *group = items->data;
3829 if( group == NULL ) continue;
3830 if( !addressbook_match_item(ADDRITEM_NAME(group),
3831 NULL, NULL, NULL, search_str) )
3834 text[COL_NAME] = ADDRITEM_NAME(group);
3835 text[COL_ADDRESS] = "";
3836 text[COL_REMARKS] = "";
3837 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3838 text, FOLDER_SPACING,
3842 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3843 gtk_sctree_sort_node(clist, NULL);
3845 /* Free up the list */
3846 g_list_free( items );
3850 * Search ctree widget callback function.
3851 * \param pA Pointer to node.
3852 * \param pB Pointer to data item being sought.
3853 * \return Zero (0) if group found.
3855 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3858 aoA = ( AddressObject * ) pA;
3859 if( aoA->type == ADDR_ITEM_GROUP ) {
3860 ItemGroup *group, *grp;
3862 grp = ADAPTER_GROUP(aoA)->itemGroup;
3863 group = ( ItemGroup * ) pB;
3864 if( grp == group ) return 0; /* Found group */
3870 * Remove folder and group nodes from tree widget for items contained ("cut")
3873 static void addressbook_treenode_remove_item( void ) {
3875 AddrSelectItem *cutItem;
3876 AddressCache *cache;
3877 AddrItemObject *aio;
3878 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3881 node = _clipBoard_->objectList;
3883 cutItem = node->data;
3884 node = g_list_next( node );
3885 cache = addrindex_get_cache(
3886 _clipBoard_->addressIndex, cutItem->cacheID );
3887 if( cache == NULL ) continue;
3888 aio = addrcache_get_object( cache, cutItem->uid );
3891 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3894 folder = ( ItemFolder * ) aio;
3895 tn = gtk_cmctree_find_by_row_data_custom(
3896 ctree, NULL, folder,
3897 addressbook_treenode_find_folder_cb );
3899 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3902 group = ( ItemGroup * ) aio;
3903 tn = gtk_cmctree_find_by_row_data_custom(
3905 addressbook_treenode_find_group_cb );
3909 /* Free up adapter and remove node. */
3910 gtk_cmctree_remove_node( ctree, tn );
3917 * Find parent datasource for specified tree node.
3918 * \param node Node to test.
3919 * \return Data source, or NULL if not found.
3921 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3922 AddressDataSource *ds = NULL;
3925 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3928 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3929 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3931 /* g_print( "ao->type = %d\n", ao->type ); */
3932 if( ao->type == ADDR_DATASOURCE ) {
3933 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3934 /* g_print( "found it\n" ); */
3935 ds = ads->dataSource;
3939 node = GTK_CMCTREE_ROW(node)->parent;
3945 * Load address list widget with children of specified object.
3946 * \param obj Parent object to be loaded.
3948 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3949 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3950 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3951 AddressDataSource *ds = NULL;
3952 AdapterDSource *ads = NULL;
3953 static AddressObject *last_obj = NULL;
3955 if (addrbook.clist == NULL) {
3958 if (obj == last_obj && !refresh)
3963 gtk_cmclist_clear(clist);
3967 if( obj->type == ADDR_INTERFACE ) {
3968 /* g_print( "set_clist: loading datasource...\n" ); */
3969 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3973 gtk_cmclist_freeze(clist);
3974 gtk_cmclist_clear(clist);
3976 if( obj->type == ADDR_DATASOURCE ) {
3977 ads = ADAPTER_DSOURCE(obj);
3978 ds = ads->dataSource;
3980 /* Load root folder */
3981 ItemFolder *rootFolder = NULL;
3982 rootFolder = addrindex_ds_get_root_folder( ds );
3983 addressbook_folder_load_person(
3984 ctreelist, rootFolder );
3985 addressbook_folder_load_group(
3986 ctreelist, rootFolder );
3990 if( obj->type == ADDR_ITEM_GROUP ) {
3992 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3993 addressbook_load_group( ctreelist, itemGroup );
3995 else if( obj->type == ADDR_ITEM_FOLDER ) {
3997 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3998 addressbook_folder_load_person( ctreelist, itemFolder );
3999 addressbook_folder_load_group( ctreelist, itemFolder );
4002 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
4003 clist->focus_row = -1;
4004 gtk_cmclist_thaw(clist);
4008 * Call back function to free adaptor. Call back is setup by function
4009 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4010 * called when the address book tree widget node is removed by calling
4011 * function gtk_cmctree_remove_node().
4013 * \param data Tree node's row data.
4015 static void addressbook_free_treenode( gpointer data ) {
4018 ao = ( AddressObject * ) data;
4019 if( ao == NULL ) return;
4020 if( ao->type == ADDR_INTERFACE ) {
4021 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
4022 addrbookctl_free_interface( ai );
4024 else if( ao->type == ADDR_DATASOURCE ) {
4025 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
4026 addrbookctl_free_datasource( ads );
4028 else if( ao->type == ADDR_ITEM_FOLDER ) {
4029 AdapterFolder *af = ADAPTER_FOLDER(ao);
4030 addrbookctl_free_folder( af );
4032 else if( ao->type == ADDR_ITEM_GROUP ) {
4033 AdapterGroup *ag = ADAPTER_GROUP(ao);
4034 addrbookctl_free_group( ag );
4039 * Create new adaptor for specified data source.
4041 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4042 AddressObjectType otype, gchar *name )
4044 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4045 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4046 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4047 adapter->dataSource = ds;
4048 adapter->subType = otype;
4052 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4053 ADDRESS_OBJECT_NAME(adapter) =
4054 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4058 * Load tree from address index with the initial data.
4060 static void addressbook_load_tree( void ) {
4061 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4062 GList *nodeIf, *nodeDS;
4063 AdapterInterface *adapter;
4064 AddressInterface *iface;
4065 AddressTypeControlItem *atci;
4066 AddressDataSource *ds;
4067 AdapterDSource *ads;
4068 GtkCMCTreeNode *node, *newNode;
4071 nodeIf = _addressInterfaceList_;
4073 adapter = nodeIf->data;
4074 node = adapter->treeNode;
4075 iface = adapter->interface;
4076 atci = adapter->atci;
4078 if( iface->useInterface ) {
4079 /* Load data sources below interface node */
4080 nodeDS = iface->listSource;
4083 name = addrindex_ds_get_name( ds );
4084 ads = addressbook_create_ds_adapter(
4085 ds, atci->objectType, name );
4086 newNode = addressbook_add_object(
4087 node, ADDRESS_OBJECT(ads) );
4088 if (newNode == NULL) {
4089 g_message("error adding addressbook object\n");
4091 nodeDS = g_list_next( nodeDS );
4093 gtk_cmctree_expand( ctree, node );
4096 nodeIf = g_list_next( nodeIf );
4101 * Convert the old address book to new format.
4103 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4104 gboolean retVal = FALSE;
4105 gboolean errFlag = TRUE;
4108 /* Read old address book, performing conversion */
4109 debug_print( "Reading and converting old address book...\n" );
4110 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4111 addrindex_read_data( addrIndex );
4112 if( addrIndex->retVal == MGU_NO_FILE ) {
4113 /* We do not have a file - new user */
4114 debug_print( "New user... create new books...\n" );
4115 addrindex_create_new_books( addrIndex );
4116 if( addrIndex->retVal == MGU_SUCCESS ) {
4117 /* Save index file */
4118 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4119 addrindex_save_data( addrIndex );
4120 if( addrIndex->retVal == MGU_SUCCESS ) {
4125 msg = _( "New user, could not save index file." );
4129 msg = _( "New user, could not save address book files." );
4133 /* We have an old file */
4134 if( addrIndex->wasConverted ) {
4135 /* Converted successfully - save address index */
4136 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4137 addrindex_save_data( addrIndex );
4138 if( addrIndex->retVal == MGU_SUCCESS ) {
4139 msg = _( "Old address book converted successfully." );
4144 msg = _("Old address book converted,\n"
4145 "could not save new address index file." );
4149 /* File conversion failed - just create new books */
4150 debug_print( "File conversion failed... just create new books...\n" );
4151 addrindex_create_new_books( addrIndex );
4152 if( addrIndex->retVal == MGU_SUCCESS ) {
4154 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4155 addrindex_save_data( addrIndex );
4156 if( addrIndex->retVal == MGU_SUCCESS ) {
4157 msg = _("Could not convert address book,\n"
4158 "but created empty new address book files." );
4163 msg = _("Could not convert address book,\n"
4164 "could not save new address index file." );
4168 msg = _("Could not convert address book\n"
4169 "and could not create new address book files." );
4174 debug_print( "Error\n%s\n", msg );
4175 alertpanel_full(_("Addressbook conversion error"), msg,
4176 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4180 debug_print( "Warning\n%s\n", msg );
4181 alertpanel_full(_("Addressbook conversion error"), msg,
4182 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4183 NULL, ALERT_WARNING);
4189 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4193 gboolean failed = FALSE;
4194 GError *error = NULL;
4196 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4197 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4198 error->code, error->message);
4199 g_error_free(error);
4203 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4204 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4207 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4209 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4211 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4224 /* all copies succeeded, we can remove source files */
4225 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4226 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4227 error->code, error->message);
4228 g_error_free(error);
4231 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4232 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4235 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4237 claws_unlink(orig_file);
4247 void addressbook_read_file( void ) {
4248 AddressIndex *addrIndex = NULL;
4249 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4251 debug_print( "Reading address index...\n" );
4252 if( _addressIndex_ ) {
4253 debug_print( "address book already read!!!\n" );
4258 addrIndex = addrindex_create_index();
4259 addrindex_initialize();
4261 /* Use new address book index. */
4263 if ( !is_dir_exist(indexdir) ) {
4264 if ( make_dir(indexdir) < 0 ) {
4265 addrindex_set_file_path( addrIndex, get_rc_dir() );
4266 g_warning("couldn't create dir '%s'", indexdir);
4268 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4269 remove_dir_recursive(indexdir);
4270 addrindex_set_file_path( addrIndex, get_rc_dir() );
4271 g_error("couldn't migrate dir %s", indexdir);
4273 addrindex_set_file_path( addrIndex, indexdir);
4277 addrindex_set_file_path( addrIndex, indexdir);
4280 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4281 addrindex_read_data( addrIndex );
4282 if( addrIndex->retVal == MGU_NO_FILE ) {
4283 /* Conversion required */
4284 debug_print( "Converting...\n" );
4285 if( addressbook_convert( addrIndex ) ) {
4286 _addressIndex_ = addrIndex;
4289 else if( addrIndex->retVal == MGU_SUCCESS ) {
4290 _addressIndex_ = addrIndex;
4293 /* Error reading address book */
4294 debug_print( "Could not read address index.\n" );
4295 addrindex_print_index( addrIndex, stdout );
4296 alertpanel_full(_("Addressbook Error"),
4297 _("Could not read address index"),
4298 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4301 debug_print( "done.\n" );
4305 * Add object into the address index tree widget.
4306 * Enter: node Parent node.
4307 * obj Object to add.
4308 * Return: Node that was added, or NULL if object not added.
4310 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4313 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4314 GtkCMCTreeNode *added;
4315 AddressObject *pobj;
4316 AddressObjectType otype;
4317 AddressTypeControlItem *atci = NULL;
4319 cm_return_val_if_fail(node != NULL, NULL);
4320 cm_return_val_if_fail(obj != NULL, NULL);
4322 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4323 cm_return_val_if_fail(pobj != NULL, NULL);
4325 /* Determine object type to be displayed */
4326 if( obj->type == ADDR_DATASOURCE ) {
4327 otype = ADAPTER_DSOURCE(obj)->subType;
4333 /* Handle any special conditions. */
4335 atci = addrbookctl_lookup( otype );
4337 if( atci->showInTree ) {
4338 /* Add object to tree */
4341 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4342 atci->iconXpm, atci->iconXpmOpen,
4343 atci->treeLeaf, atci->treeExpand );
4344 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4345 addressbook_free_treenode );
4349 gtk_sctree_sort_node(ctree, node);
4355 * Add group into the address index tree.
4356 * \param node Parent node.
4357 * \param ds Data source.
4358 * \param itemGroup Group to add.
4359 * \return Inserted node.
4361 static GtkCMCTreeNode *addressbook_node_add_group(
4362 GtkCMCTreeNode *node, AddressDataSource *ds,
4363 ItemGroup *itemGroup )
4365 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4366 GtkCMCTreeNode *newNode;
4367 AdapterGroup *adapter;
4368 AddressTypeControlItem *atci = NULL;
4371 if( ds == NULL ) return NULL;
4372 if( node == NULL || itemGroup == NULL ) return NULL;
4374 name = &itemGroup->obj.name;
4376 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4378 adapter = g_new0( AdapterGroup, 1 );
4379 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4380 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4381 adapter->itemGroup = itemGroup;
4383 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4384 atci->iconXpm, atci->iconXpm,
4385 atci->treeLeaf, atci->treeExpand );
4386 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4387 addressbook_free_treenode );
4388 gtk_sctree_sort_node( ctree, node );
4393 * Add folder into the address index tree. Only visible folders are loaded into
4394 * the address index tree. Note that the root folder is not inserted into the
4397 * \param node Parent node.
4398 * \param ds Data source.
4399 * \param itemFolder Folder to add.
4400 * \param otype Object type to display.
4401 * \return Inserted node for the folder.
4403 static GtkCMCTreeNode *addressbook_node_add_folder(
4404 GtkCMCTreeNode *node, AddressDataSource *ds,
4405 ItemFolder *itemFolder, AddressObjectType otype )
4407 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4408 GtkCMCTreeNode *newNode = NULL;
4409 AddressTypeControlItem *atci = NULL;
4410 GList *listItems = NULL;
4412 ItemFolder *rootFolder;
4414 /* Only visible folders */
4415 if( itemFolder == NULL || itemFolder->isHidden )
4420 if( node == NULL || itemFolder == NULL )
4423 /* Determine object type */
4424 atci = addrbookctl_lookup( otype );
4428 rootFolder = addrindex_ds_get_root_folder( ds );
4429 if( itemFolder == rootFolder ) {
4433 AdapterFolder *adapter = g_new0( AdapterFolder, 1 );
4434 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4435 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4436 adapter->itemFolder = itemFolder;
4438 name = ADDRITEM_NAME(itemFolder);
4439 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4440 atci->iconXpm, atci->iconXpm,
4441 atci->treeLeaf, atci->treeExpand );
4443 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4444 addressbook_free_treenode );
4446 addrbookctl_free_folder(adapter);
4450 listItems = itemFolder->listFolder;
4451 while( listItems ) {
4452 ItemFolder *item = listItems->data;
4453 addressbook_node_add_folder( newNode, ds, item, otype );
4454 listItems = g_list_next( listItems );
4456 listItems = itemFolder->listGroup;
4457 while( listItems ) {
4458 ItemGroup *item = listItems->data;
4459 addressbook_node_add_group( newNode, ds, item );
4460 listItems = g_list_next( listItems );
4462 gtk_sctree_sort_node( ctree, node );
4466 void addressbook_export_to_file( void ) {
4467 if( _addressIndex_ ) {
4468 /* Save all new address book data */
4469 debug_print( "Saving address books...\n" );
4470 addrindex_save_all_books( _addressIndex_ );
4472 debug_print( "Exporting addressbook to file...\n" );
4473 addrindex_save_data( _addressIndex_ );
4474 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4475 addrindex_print_index( _addressIndex_, stdout );
4478 /* Notify address completion of new data */
4479 invalidate_address_completion();
4483 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4485 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4486 addressbook_lup_clicked(NULL, NULL);
4491 * Comparison using cell contents (text in first column). Used for sort
4492 * address index widget.
4494 static gint addressbook_treenode_compare_func(
4495 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4497 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4498 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4499 gchar *name1 = NULL, *name2 = NULL;
4500 if( cell1 ) name1 = cell1->u.text;
4501 if( cell2 ) name2 = cell2->u.text;
4502 if( ! name1 ) return ( name2 != NULL );
4503 if( ! name2 ) return -1;
4504 return g_utf8_collate( name1, name2 );
4507 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4508 AdapterDSource *ads;
4509 AdapterInterface *adapter;
4510 GtkCMCTreeNode *newNode;
4512 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4513 if( adapter == NULL ) return;
4514 ads = addressbook_edit_book( _addressIndex_, NULL );
4516 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4518 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4519 addrbook.treeSelected = newNode;
4524 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4525 AdapterDSource *ads;
4526 AdapterInterface *adapter;
4527 GtkCMCTreeNode *newNode;
4529 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4530 if( adapter == NULL ) return;
4531 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4533 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4535 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4536 addrbook.treeSelected = newNode;
4542 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4543 AdapterDSource *ads;
4544 AdapterInterface *adapter;
4545 AddressInterface *iface;
4546 GtkCMCTreeNode *newNode;
4548 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4549 if( adapter == NULL ) return;
4550 iface = adapter->interface;
4551 if( ! iface->haveLibrary ) return;
4552 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4554 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4556 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4557 addrbook.treeSelected = newNode;
4564 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4565 AdapterDSource *ads;
4566 AdapterInterface *adapter;
4567 AddressInterface *iface;
4568 GtkCMCTreeNode *newNode;
4570 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4571 if( adapter == NULL ) return;
4572 iface = adapter->interface;
4573 if( ! iface->haveLibrary ) return;
4574 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4576 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4578 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4579 addrbook.treeSelected = newNode;
4586 * Display address search status message.
4587 * \param queryType Query type.
4588 * \param status Status/Error code.
4590 static void addressbook_search_message( gint queryType, gint sts ) {
4592 *addressbook_msgbuf = '\0';
4594 if( sts != MGU_SUCCESS ) {
4595 if( queryType == ADDRQUERY_LDAP ) {
4597 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4602 g_snprintf( addressbook_msgbuf,
4603 sizeof(addressbook_msgbuf), "%s", desc );
4604 addressbook_status_show( addressbook_msgbuf );
4607 addressbook_status_show( "" );
4612 * Refresh addressbook by forcing refresh of current selected object in
4615 static void addressbook_refresh_current( void ) {
4619 ctree = GTK_CMCTREE(addrbook.ctree);
4620 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4621 if( obj == NULL ) return;
4622 addressbook_set_clist( obj, TRUE );
4626 * Message that is displayed whilst a query is executing in a background
4629 static gchar *_tempMessage_ = N_( "Busy searching..." );
4632 * Address search idle function. This function is called during UI idle time
4633 * while a search is in progress.
4635 * \param data Idler data.
4637 static void addressbook_search_idle( gpointer data ) {
4641 queryID = GPOINTER_TO_INT( data );
4642 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4647 * Search completion callback function. This removes the query from the idle
4650 * \param sender Sender of query.
4651 * \param queryID Query ID of search request.
4652 * \param status Search status.
4653 * \param data Query data.
4655 static void addressbook_search_callback_end(
4656 gpointer sender, gint queryID, gint status, gpointer data )
4660 AddrQueryObject *aqo;
4662 /* Remove idler function */
4663 ptrQID = GINT_TO_POINTER( queryID );
4665 g_idle_remove_by_data( ptrQID );
4668 /* Refresh addressbook contents */
4669 addressbook_refresh_current();
4670 req = qrymgr_find_request( queryID );
4672 aqo = ( AddrQueryObject * ) req->queryList->data;
4673 addressbook_search_message( aqo->queryType, status );
4676 /* Stop the search */
4677 addrindex_stop_search( queryID );
4683 * \param ds Data source to search.
4684 * \param searchTerm String to lookup.
4685 * \param pNode Parent data source node.
4687 static void addressbook_perform_search(
4688 AddressDataSource *ds, gchar *searchTerm,
4689 GtkCMCTreeNode *pNode )
4697 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4699 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4701 /* Create a folder for the search results */
4702 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4703 folder = addressbook_setup_subf(ds, name, pNode);
4706 /* Setup the search */
4707 queryID = addrindex_setup_explicit_search(
4708 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4709 if( queryID == 0 ) return;
4711 /* Set up idler function */
4712 idleID = g_idle_add(
4713 (GSourceFunc) addressbook_search_idle,
4714 GINT_TO_POINTER( queryID ) );
4716 g_message("error adding addressbook_search_idle\n");
4719 /* Start search, sit back and wait for something to happen */
4720 addrindex_start_search( queryID );
4722 addressbook_status_show( _tempMessage_ );
4726 * Lookup button handler. Address search is only performed against
4727 * address interfaces for external queries.
4729 * \param button Lookup button widget.
4730 * \param data Data object.
4732 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4735 AddressDataSource *ds;
4736 AddressInterface *iface;
4738 GtkCMCTreeNode *node, *parentNode;
4740 LdapServer *ldap_server;
4741 LdapControl *ldap_ctl;
4744 node = addrbook.treeSelected;
4745 if( ! node ) return;
4746 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4748 ctree = GTK_CMCTREE(addrbook.ctree);
4749 obj = gtk_cmctree_node_get_row_data( ctree, node );
4750 if( obj == NULL ) return;
4752 if (obj->type != ADDR_DATASOURCE ||
4753 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4754 addressbook_set_clist(
4755 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4756 addrbook.treeSelected),
4760 ds = addressbook_find_datasource( node );
4761 if( ds == NULL ) return;
4763 /* We must have a datasource that is an external interface */
4764 iface = ds->interface;
4765 if( ! iface->haveLibrary ) return;
4766 if( ! iface->externalQuery ) return;
4769 if (iface->type == ADDR_IF_LDAP) {
4770 ldap_server = ds->rawDataSource;
4771 ldap_ctl = ldap_server->control;
4772 if (ldap_ctl != NULL &&
4773 ldap_ctl->bindDN != NULL && strlen(ldap_ctl->bindDN) > 0) {
4774 #ifndef PASSWORD_CRYPTO_OLD
4775 /* LDAP server is password-protected. */
4776 if (master_passphrase() == NULL) {
4777 /* User did not enter master passphrase, do not start a search. */
4780 #endif /* PASSWORD_CRYPTO_OLD */
4783 #endif /* USE_LDAP */
4786 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4787 g_strchomp( searchTerm );
4789 if( obj->type == ADDR_ITEM_FOLDER ) {
4790 parentNode = GTK_CMCTREE_ROW(node)->parent;
4795 addressbook_perform_search( ds, searchTerm, parentNode );
4797 gtk_widget_grab_focus( addrbook.entry );
4799 g_free( searchTerm );
4802 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4803 addressbook_close();
4808 * Browse address entry for highlighted entry.
4810 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4812 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4814 AddressDataSource *ds;
4815 AddressInterface *iface;
4819 if(addrbook.listSelected == NULL)
4822 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4826 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4830 iface = ds->interface;
4831 if(!iface || !iface->haveLibrary )
4835 if (obj->type == ADDR_ITEM_EMAIL) {
4836 email = ( ItemEMail * ) obj;
4838 person = (ItemPerson *) ADDRITEM_PARENT(email);
4840 else if (obj->type == ADDR_ITEM_PERSON) {
4841 person = (ItemPerson *) obj;
4848 if( iface && iface->type == ADDR_IF_LDAP ) {
4849 browseldap_entry(ds, person->externalID);
4854 /* **********************************************************************
4855 * Build lookup tables.
4856 * ***********************************************************************
4860 * Remap object types.
4861 * Enter: abType AddressObjectType (used in tree node).
4862 * Return: ItemObjectType (used in address cache data).
4864 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4865 ItemObjectType ioType;
4868 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4869 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4870 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4871 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4872 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4873 default: ioType = ITEMTYPE_NONE; break;
4878 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4879 atci = addrbookctl_lookup(id); \
4881 atci->iconXpm = icon; \
4882 atci->iconXpmOpen = iconopen; \
4884 g_warning("can't get atci %d", id); \
4889 * Build table that controls the rendering of object types.
4891 static void addrbookctl_build_icons( GtkWidget *window ) {
4892 AddressTypeControlItem *atci;
4896 g_object_unref(interfacexpm);
4898 g_object_unref(folderxpm);
4900 g_object_unref(folderopenxpm);
4902 g_object_unref(groupxpm);
4904 g_object_unref(vcardxpm);
4906 g_object_unref(bookxpm);
4908 g_object_unref(addressxpm);
4910 g_object_unref(jpilotxpm);
4912 g_object_unref(categoryxpm);
4914 g_object_unref(ldapxpm);
4916 g_object_unref(addrsearchxpm);
4917 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4918 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4919 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4920 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4921 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4922 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4923 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4924 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4925 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4926 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4927 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4929 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4930 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4931 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4932 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4933 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4934 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4935 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4936 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4937 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4938 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4939 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4944 * Build table that controls the rendering of object types.
4946 static void addrbookctl_build_map( GtkWidget *window ) {
4947 AddressTypeControlItem *atci;
4949 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4950 _addressBookTypeList_ = NULL;
4953 atci = g_new0( AddressTypeControlItem, 1 );
4954 atci->objectType = ADDR_INTERFACE;
4955 atci->interfaceType = ADDR_IF_NONE;
4956 atci->showInTree = TRUE;
4957 atci->treeExpand = TRUE;
4958 atci->treeLeaf = FALSE;
4959 atci->displayName = _( "Interface" );
4960 atci->menuCommand = NULL;
4961 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4962 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4965 atci = g_new0( AddressTypeControlItem, 1 );
4966 atci->objectType = ADDR_BOOK;
4967 atci->interfaceType = ADDR_IF_BOOK;
4968 atci->showInTree = TRUE;
4969 atci->treeExpand = TRUE;
4970 atci->treeLeaf = FALSE;
4971 atci->displayName = _("Address Books");
4972 atci->menuCommand = "Menu/Book/NewBook";
4973 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4974 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4977 atci = g_new0( AddressTypeControlItem, 1 );
4978 atci->objectType = ADDR_ITEM_PERSON;
4979 atci->interfaceType = ADDR_IF_NONE;
4980 atci->showInTree = FALSE;
4981 atci->treeExpand = FALSE;
4982 atci->treeLeaf = FALSE;
4983 atci->displayName = _( "Person" );
4984 atci->menuCommand = NULL;
4985 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4986 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4989 atci = g_new0( AddressTypeControlItem, 1 );
4990 atci->objectType = ADDR_ITEM_EMAIL;
4991 atci->interfaceType = ADDR_IF_NONE;
4992 atci->showInTree = FALSE;
4993 atci->treeExpand = FALSE;
4994 atci->treeLeaf = TRUE;
4995 atci->displayName = _( "Email Address" );
4996 atci->menuCommand = NULL;
4997 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4998 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5001 atci = g_new0( AddressTypeControlItem, 1 );
5002 atci->objectType = ADDR_ITEM_GROUP;
5003 atci->interfaceType = ADDR_IF_BOOK;
5004 atci->showInTree = TRUE;
5005 atci->treeExpand = FALSE;
5006 atci->treeLeaf = FALSE;
5007 atci->displayName = _( "Group" );
5008 atci->menuCommand = NULL;
5009 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5010 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5013 atci = g_new0( AddressTypeControlItem, 1 );
5014 atci->objectType = ADDR_ITEM_FOLDER;
5015 atci->interfaceType = ADDR_IF_BOOK;
5016 atci->showInTree = TRUE;
5017 atci->treeExpand = FALSE;
5018 atci->treeLeaf = FALSE;
5019 atci->displayName = _( "Folder" );
5020 atci->menuCommand = NULL;
5021 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5022 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5025 atci = g_new0( AddressTypeControlItem, 1 );
5026 atci->objectType = ADDR_VCARD;
5027 atci->interfaceType = ADDR_IF_VCARD;
5028 atci->showInTree = TRUE;
5029 atci->treeExpand = TRUE;
5030 atci->treeLeaf = TRUE;
5031 atci->displayName = _( "vCard" );
5032 atci->menuCommand = "Menu/Book/NewVCard";
5033 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5034 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5037 atci = g_new0( AddressTypeControlItem, 1 );
5038 atci->objectType = ADDR_JPILOT;
5039 atci->interfaceType = ADDR_IF_JPILOT;
5040 atci->showInTree = TRUE;
5041 atci->treeExpand = TRUE;
5042 atci->treeLeaf = FALSE;
5043 atci->displayName = _( "JPilot" );
5044 atci->menuCommand = "Menu/Book/NewJPilot";
5045 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5046 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5049 atci = g_new0( AddressTypeControlItem, 1 );
5050 atci->objectType = ADDR_CATEGORY;
5051 atci->interfaceType = ADDR_IF_JPILOT;
5052 atci->showInTree = TRUE;
5053 atci->treeExpand = TRUE;
5054 atci->treeLeaf = TRUE;
5055 atci->displayName = _( "JPilot" );
5056 atci->menuCommand = NULL;
5057 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5058 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5061 atci = g_new0( AddressTypeControlItem, 1 );
5062 atci->objectType = ADDR_LDAP;
5063 atci->interfaceType = ADDR_IF_LDAP;
5064 atci->showInTree = TRUE;
5065 atci->treeExpand = TRUE;
5066 atci->treeLeaf = FALSE;
5067 atci->displayName = _( "LDAP servers" );
5068 atci->menuCommand = "Menu/Book/NewLDAPServer";
5069 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5070 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5073 atci = g_new0( AddressTypeControlItem, 1 );
5074 atci->objectType = ADDR_LDAP_QUERY;
5075 atci->interfaceType = ADDR_IF_LDAP;
5076 atci->showInTree = TRUE;
5077 atci->treeExpand = FALSE;
5078 atci->treeLeaf = TRUE;
5079 atci->displayName = _( "LDAP Query" );
5080 atci->menuCommand = NULL;
5081 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5082 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5084 addrbookctl_build_icons(window);
5087 void addressbook_reflect_prefs_pixmap_theme(void)
5089 if (addrbook.window)
5090 addrbookctl_build_icons(addrbook.window);
5094 * Search for specified object type.
5096 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5098 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5102 * Search for specified interface type.
5104 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5105 GList *node = _addressBookTypeList_;
5107 AddressTypeControlItem *atci = node->data;
5108 if( atci->interfaceType == ifType ) return atci;
5109 node = g_list_next( node );
5114 static void addrbookctl_free_address( AddressObject *obj ) {
5115 g_free( obj->name );
5116 obj->type = ADDR_NONE;
5120 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5121 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5122 adapter->interface = NULL;
5123 adapter->interfaceType = ADDR_IF_NONE;
5124 adapter->atci = NULL;
5125 adapter->enabled = FALSE;
5126 adapter->haveLibrary = FALSE;
5127 adapter->treeNode = NULL;
5131 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5132 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5133 adapter->dataSource = NULL;
5134 adapter->subType = ADDR_NONE;
5138 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5139 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5140 adapter->itemFolder = NULL;
5144 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5145 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5146 adapter->itemGroup = NULL;
5151 * Build GUI interface list.
5153 static void addrbookctl_build_iflist( void ) {
5154 AddressTypeControlItem *atci;
5155 AdapterInterface *adapter;
5158 if( _addressIndex_ == NULL ) {
5159 _addressIndex_ = addrindex_create_index();
5160 if( _clipBoard_ == NULL ) {
5161 _clipBoard_ = addrclip_create();
5163 addrclip_set_index( _clipBoard_, _addressIndex_ );
5165 _addressInterfaceList_ = NULL;
5166 list = addrindex_get_interface_list( _addressIndex_ );
5168 AddressInterface *interface = list->data;
5169 atci = addrbookctl_lookup_iface( interface->type );
5171 adapter = g_new0( AdapterInterface, 1 );
5172 adapter->interfaceType = interface->type;
5173 adapter->atci = atci;
5174 adapter->interface = interface;
5175 adapter->treeNode = NULL;
5176 adapter->enabled = TRUE;
5177 adapter->haveLibrary = interface->haveLibrary;
5178 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5179 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5180 _addressInterfaceList_ =
5181 g_list_append( _addressInterfaceList_, adapter );
5183 list = g_list_next( list );
5188 * Find GUI interface type specified interface type.
5189 * \param ifType Interface type.
5190 * \return Interface item, or NULL if not found.
5192 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5193 GList *node = _addressInterfaceList_;
5195 AdapterInterface *adapter = node->data;
5196 if( adapter->interfaceType == ifType ) return adapter;
5197 node = g_list_next( node );
5203 * Build interface list selection.
5205 static void addrbookctl_build_ifselect( void ) {
5206 GList *newList = NULL;
5211 gchar *endptr = NULL;
5212 /* gboolean enabled; */
5213 AdapterInterface *adapter;
5215 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5218 splitStr = g_strsplit( selectStr, ",", -1 );
5219 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5221 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5222 ifType = strtol( splitStr[i], &endptr, 10 );
5225 if( strcmp( endptr, "/n" ) == 0 ) {
5230 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5231 adapter = addrbookctl_find_interface( ifType );
5233 newList = g_list_append( newList, adapter );
5240 /* g_print( "i=%d\n", i ); */
5241 g_strfreev( splitStr );
5242 g_free( selectStr );
5244 /* Replace existing list */
5245 g_list_free( _addressIFaceSelection_ );
5246 _addressIFaceSelection_ = newList;
5250 /* ***********************************************************************
5251 * Add sender to address book.
5252 * ***********************************************************************
5256 * This function is used by the Add sender to address book function.
5258 gboolean addressbook_add_contact(
5259 const gchar *name, const gchar *address, const gchar *remarks,
5260 GdkPixbuf *picture )
5262 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5263 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5264 debug_print( "addressbook_add_contact - added\n" );
5265 addressbook_refresh();
5270 /* ***********************************************************************
5271 * Book/folder selection.
5272 * ***********************************************************************
5276 * This function is used by the matcher dialog to select a book/folder.
5278 gchar *addressbook_folder_selection( const gchar *folderpath)
5280 AddressBookFile *book = NULL;
5281 ItemFolder *folder = NULL;
5284 cm_return_val_if_fail( folderpath != NULL, NULL);
5286 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5288 if ( folder != NULL) {
5290 gchar *oldtmp = NULL;
5291 AddrItemObject *obj = NULL;
5293 /* walk thru folder->parent to build the full folder path */
5294 /* TODO: wwp: optimize this */
5296 tmp = g_strdup(obj->uid);
5297 while ( obj->parent ) {
5299 if ( obj->name != NULL ) {
5300 oldtmp = g_strdup(tmp);
5302 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5306 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5309 path = g_strdup_printf("%s", book->fileName);
5311 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5317 /* ***********************************************************************
5318 * Book/folder checking.
5319 * ***********************************************************************
5322 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5324 FolderInfo *fi = g_new0( FolderInfo, 1 );
5326 fi->folder = folder;
5330 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5331 FolderInfo *fiParent, FolderPathMatch *match )
5337 FolderPathMatch *nextmatch = NULL;
5342 list = parentFolder->listFolder;
5344 folder = list->data;
5345 fName = g_strdup( ADDRITEM_NAME(folder) );
5347 /* match folder name, match pointer will be set to NULL if next recursive call
5348 doesn't need to match subfolder name */
5349 if ( match != NULL &&
5350 match->matched == FALSE ) {
5351 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5352 /* folder name matches, prepare next subfolder match */
5353 debug_print("matched folder name '%s'\n", fName);
5355 if ( match->folder_path[match->index] == NULL ) {
5356 /* we've matched all elements */
5357 match->matched = TRUE;
5358 match->folder = folder;
5359 debug_print("book/folder path matched!\n");
5361 /* keep on matching */
5369 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5370 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5372 list = g_list_next( list );
5377 * This function is used by to check if a matcher book/folder path corresponds to an
5378 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5379 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5380 if book AND folder are NULL this means that folderpath was empty or Any.
5381 If folderpath is a simple book name (without folder), book will not be NULL and folder
5382 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5385 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5386 AddressDataSource **book,
5387 ItemFolder **folder )
5389 AddressDataSource *ds;
5390 GList *list, *nodeDS;
5391 ItemFolder *rootFolder;
5392 AddressBookFile *abf;
5394 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5401 if ( folderpath == NULL )
5404 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5407 /* split the folder path we've received, we'll try to match this path, subpath by
5408 subpath against the book/folder structure in order */
5409 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5410 if (!folder_path_match.folder_path)
5413 list = addrindex_get_interface_list( _addressIndex_ );
5414 while ( list && !folder_path_match.matched ) {
5415 AddressInterface *interface = list->data;
5416 if ( interface && interface->type == ADDR_IF_BOOK ) {
5417 nodeDS = interface->listSource;
5418 while ( nodeDS && !folder_path_match.matched ) {
5421 /* Read address book */
5422 if( ! addrindex_ds_get_read_flag( ds ) ) {
5423 addrindex_ds_read_data( ds );
5426 /* Add node for address book */
5427 abf = ds->rawDataSource;
5429 /* match book name */
5430 if ( abf && abf->fileName &&
5431 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5433 debug_print("matched book name '%s'\n", abf->fileName);
5434 folder_path_match.book = ds;
5436 if ( folder_path_match.folder_path[1] == NULL ) {
5437 /* no folder part to match */
5439 folder_path_match.matched = TRUE;
5440 folder_path_match.folder = NULL;
5441 debug_print("book path matched!\n");
5444 /* match folder part */
5446 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5447 rootFolder = addrindex_ds_get_root_folder( ds );
5449 /* prepare for recursive call */
5450 folder_path_match.index = 1;
5451 /* this call will set folder_path_match.matched and folder_path_match.folder */
5452 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5457 nodeDS = g_list_next( nodeDS );
5460 list = g_list_next( list );
5463 g_strfreev( folder_path_match.folder_path );
5466 *book = folder_path_match.book;
5468 *folder = folder_path_match.folder;
5469 return folder_path_match.matched;
5473 /* **********************************************************************
5475 * ***********************************************************************
5481 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5482 AddressDataSource *ds = NULL;
5483 AdapterDSource *ads = NULL;
5484 AddressBookFile *abf = NULL;
5485 AdapterInterface *adapter;
5486 GtkCMCTreeNode *newNode;
5488 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5490 if( adapter->treeNode ) {
5491 abf = addressbook_imp_ldif( _addressIndex_ );
5493 ds = addrindex_index_add_datasource(
5494 _addressIndex_, ADDR_IF_BOOK, abf );
5495 ads = addressbook_create_ds_adapter(
5496 ds, ADDR_BOOK, NULL );
5497 addressbook_ads_set_name(
5498 ads, addrbook_get_name( abf ) );
5499 newNode = addressbook_add_object(
5501 ADDRESS_OBJECT(ads) );
5503 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5505 addrbook.treeSelected = newNode;
5508 /* Notify address completion */
5509 invalidate_address_completion();
5518 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5519 AddressDataSource *ds = NULL;
5520 AdapterDSource *ads = NULL;
5521 AddressBookFile *abf = NULL;
5522 AdapterInterface *adapter;
5523 GtkCMCTreeNode *newNode;
5525 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5527 if( adapter->treeNode ) {
5528 abf = addressbook_imp_mutt( _addressIndex_ );
5530 ds = addrindex_index_add_datasource(
5531 _addressIndex_, ADDR_IF_BOOK, abf );
5532 ads = addressbook_create_ds_adapter(
5533 ds, ADDR_BOOK, NULL );
5534 addressbook_ads_set_name(
5535 ads, addrbook_get_name( abf ) );
5536 newNode = addressbook_add_object(
5538 ADDRESS_OBJECT(ads) );
5540 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5542 addrbook.treeSelected = newNode;
5545 /* Notify address completion */
5546 invalidate_address_completion();
5555 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5556 AddressDataSource *ds = NULL;
5557 AdapterDSource *ads = NULL;
5558 AddressBookFile *abf = NULL;
5559 AdapterInterface *adapter;
5560 GtkCMCTreeNode *newNode;
5562 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5564 if( adapter->treeNode ) {
5565 abf = addressbook_imp_pine( _addressIndex_ );
5567 ds = addrindex_index_add_datasource(
5568 _addressIndex_, ADDR_IF_BOOK, abf );
5569 ads = addressbook_create_ds_adapter(
5570 ds, ADDR_BOOK, NULL );
5571 addressbook_ads_set_name(
5572 ads, addrbook_get_name( abf ) );
5573 newNode = addressbook_add_object(
5575 ADDRESS_OBJECT(ads) );
5577 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5579 addrbook.treeSelected = newNode;
5582 /* Notify address completion */
5583 invalidate_address_completion();
5590 * Harvest addresses.
5591 * \param folderItem Folder to import.
5592 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5593 * \param msgList List of message numbers, or NULL to process folder.
5595 void addressbook_harvest(
5596 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5598 AddressDataSource *ds = NULL;
5599 AdapterDSource *ads = NULL;
5600 AddressBookFile *abf = NULL;
5601 AdapterInterface *adapter;
5602 GtkCMCTreeNode *newNode;
5604 abf = addrgather_dlg_execute(
5605 folderItem, _addressIndex_, sourceInd, msgList );
5607 ds = addrindex_index_add_datasource(
5608 _addressIndex_, ADDR_IF_BOOK, abf );
5610 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5612 if( adapter->treeNode ) {
5613 ads = addressbook_create_ds_adapter(
5614 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5615 newNode = addressbook_add_object(
5617 ADDRESS_OBJECT(ads) );
5618 if (newNode == NULL) {
5619 g_message("error adding addressbook object\n");
5624 /* Notify address completion */
5625 invalidate_address_completion();
5632 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5633 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5635 AddressDataSource *ds = NULL;
5636 AddrBookBase *adbase;
5637 AddressCache *cache;
5638 GtkCMCTreeNode *node = NULL;
5640 if( ! addrbook.treeSelected ) return;
5641 node = addrbook.treeSelected;
5642 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5643 obj = gtk_cmctree_node_get_row_data( ctree, node );
5644 if( obj == NULL ) return;
5646 ds = addressbook_find_datasource( node );
5647 if( ds == NULL ) return;
5648 adbase = ( AddrBookBase * ) ds->rawDataSource;
5649 cache = adbase->addressCache;
5650 addressbook_exp_html( cache );
5656 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5657 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5659 AddressDataSource *ds = NULL;
5660 AddrBookBase *adbase;
5661 AddressCache *cache;
5662 GtkCMCTreeNode *node = NULL;
5664 if( ! addrbook.treeSelected ) return;
5665 node = addrbook.treeSelected;
5666 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5667 obj = gtk_cmctree_node_get_row_data( ctree, node );
5668 if( obj == NULL ) return;
5670 ds = addressbook_find_datasource( node );
5671 if( ds == NULL ) return;
5672 adbase = ( AddrBookBase * ) ds->rawDataSource;
5673 cache = adbase->addressCache;
5674 addressbook_exp_ldif( cache );
5677 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5679 addrduplicates_find(GTK_WINDOW(addrbook.window));
5682 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5684 addressbook_custom_attr_edit();
5687 static void addressbook_start_drag(GtkWidget *widget, gint button,
5691 GdkDragContext *context;
5692 if (addressbook_target_list == NULL)
5693 addressbook_target_list = gtk_target_list_new(
5694 addressbook_drag_types, 1);
5695 context = gtk_drag_begin(widget, addressbook_target_list,
5696 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5697 gtk_drag_set_icon_default(context);
5700 static void addressbook_drag_data_get(GtkWidget *widget,
5701 GdkDragContext *drag_context,
5702 GtkSelectionData *selection_data,
5707 AddrItemObject *aio = NULL;
5708 AddressObject *pobj = NULL;
5709 AdapterDSource *ads = NULL;
5710 AddressDataSource *ds = NULL;
5713 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5715 if( pobj == NULL ) return;
5717 if( pobj->type == ADDR_DATASOURCE ) {
5718 ads = ADAPTER_DSOURCE(pobj);
5719 ds = ads->dataSource;
5720 } else if (pobj->type == ADDR_ITEM_GROUP) {
5725 else if( pobj->type != ADDR_INTERFACE ) {
5726 ds = addressbook_find_datasource( addrbook.treeSelected );
5732 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5733 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5734 GTK_CMCTREE_NODE(cur->data));
5735 while (aio && aio->type != ITEMTYPE_PERSON) {
5740 if (aio && aio->type == ITEMTYPE_PERSON) {
5741 if( ds && ds->interface && ds->interface->readOnly)
5742 gtk_selection_data_set(selection_data,
5743 gtk_selection_data_get_target(selection_data), 8,
5744 (const guchar *)"Dummy_addr_copy", 15);
5746 gtk_selection_data_set(selection_data,
5747 gtk_selection_data_get_target(selection_data), 8,
5748 (const guchar *)"Dummy_addr_move", 15);
5752 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5753 GdkDragContext *context,
5759 GtkAllocation allocation;
5760 GtkRequisition requisition;
5762 GtkCMCTreeNode *node = NULL;
5763 gboolean acceptable = FALSE;
5764 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5765 gint height = allocation.height;
5766 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5767 gint total_height = requisition.height;
5768 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5769 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5770 gfloat vpos = gtk_adjustment_get_value(pos);
5772 if (gtk_cmclist_get_selection_info
5773 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5775 if (y > height - 24 && height + vpos < total_height) {
5776 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5777 gtk_adjustment_changed(pos);
5779 if (y < 24 && y > 0) {
5780 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5781 gtk_adjustment_changed(pos);
5783 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5786 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5789 if( obj->type == ADDR_ITEM_FOLDER
5790 || obj->type == ADDR_ITEM_GROUP)
5793 AdapterDSource *ads = NULL;
5794 AddressDataSource *ds = NULL;
5795 ads = ADAPTER_DSOURCE(obj);
5796 ds = ads->dataSource;
5797 if (ds == NULL ) { return FALSE;}
5805 g_signal_handlers_block_by_func
5807 G_CALLBACK(addressbook_tree_selected), NULL);
5808 gtk_sctree_select( GTK_SCTREE(widget), node);
5809 g_signal_handlers_unblock_by_func
5811 G_CALLBACK(addressbook_tree_selected), NULL);
5812 gdk_drag_status(context,
5813 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5814 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5816 gdk_drag_status(context, 0, time);
5821 static void addressbook_drag_leave_cb(GtkWidget *widget,
5822 GdkDragContext *context,
5826 if (addrbook.treeSelected) {
5827 g_signal_handlers_block_by_func
5829 G_CALLBACK(addressbook_tree_selected), NULL);
5830 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5831 g_signal_handlers_unblock_by_func
5833 G_CALLBACK(addressbook_tree_selected), NULL);
5838 static void addressbook_drag_received_cb(GtkWidget *widget,
5839 GdkDragContext *drag_context,
5842 GtkSelectionData *data,
5848 GtkCMCTreeNode *node;
5849 GtkCMCTreeNode *lastopened = addrbook.opened;
5851 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5852 if (gtk_cmclist_get_selection_info
5853 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5857 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5858 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5861 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5862 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5863 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5864 addressbook_clip_copy_cb(NULL, NULL);
5866 addressbook_clip_cut_cb(NULL, NULL);
5867 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5868 addressbook_clip_paste_cb(NULL,NULL);
5869 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5870 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5871 gtk_drag_finish(drag_context, TRUE, TRUE, time);