2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2013 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "claws-features.h"
28 #include <glib/gi18n.h>
29 #include <gdk/gdkkeysyms.h>
33 #include <sys/types.h>
37 #include "addressbook.h"
38 #include "manage_window.h"
39 #include "prefs_common.h"
40 #include "alertpanel.h"
41 #include "inputdialog.h"
43 #include "stock_pixmap.h"
45 #include "prefs_gtk.h"
51 #include "addr_compl.h"
55 #include "addressitem.h"
57 #include "addrcache.h"
59 #include "addrindex.h"
60 #include "addrmerge.h"
61 #include "addressadd.h"
62 #include "addrduplicates.h"
63 #include "addressbook_foldersel.h"
65 #include "editvcard.h"
66 #include "editgroup.h"
67 #include "editaddress.h"
69 #include "importldif.h"
70 #include "importmutt.h"
71 #include "importpine.h"
76 #include "editjpilot.h"
81 #include "ldapserver.h"
83 #include "ldapupdate.h"
85 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
88 #include "addrquery.h"
89 #include "addrselect.h"
91 #include "addrgather.h"
92 #include "adbookbase.h"
93 #include "exphtmldlg.h"
94 #include "expldifdlg.h"
95 #include "browseldap.h"
96 #include "addrcustomattr.h"
104 } AddressIndexColumns;
112 } AddressListColumns;
115 AddressBookFile *book;
123 AddressDataSource *book;
127 static gchar *list_titles[] = { N_("Name"),
131 #define COL_NAME_WIDTH 164
132 #define COL_ADDRESS_WIDTH 156
134 #define COL_FOLDER_WIDTH 170
135 #define ADDRESSBOOK_WIDTH 640
136 #define ADDRESSBOOK_HEIGHT 360
138 #define ADDRESSBOOK_MSGBUF_SIZE 2048
140 static GdkPixbuf *folderxpm = NULL;
141 static GdkPixbuf *folderopenxpm = NULL;
142 static GdkPixbuf *groupxpm = NULL;
143 static GdkPixbuf *interfacexpm = NULL;
144 static GdkPixbuf *bookxpm = NULL;
145 static GdkPixbuf *addressxpm = NULL;
146 static GdkPixbuf *vcardxpm = NULL;
147 static GdkPixbuf *jpilotxpm = NULL;
148 static GdkPixbuf *categoryxpm = NULL;
149 static GdkPixbuf *ldapxpm = NULL;
150 static GdkPixbuf *addrsearchxpm = NULL;
153 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
155 /* Address list selection */
156 static AddrSelectList *_addressSelect_ = NULL;
157 static AddressClipboard *_clipBoard_ = NULL;
159 /* Address index file and interfaces */
160 static AddressIndex *_addressIndex_ = NULL;
161 static GList *_addressInterfaceList_ = NULL;
162 static GList *_addressIFaceSelection_ = NULL;
163 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
165 static AddressBook_win addrbook;
167 static GHashTable *_addressBookTypeHash_ = NULL;
168 static GList *_addressBookTypeList_ = NULL;
170 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
171 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
172 static void addressbook_edit_address_post_cb( ItemPerson *person );
174 static void addressbook_create (void);
175 static gint addressbook_close (void);
177 static gboolean address_index_has_focus = FALSE;
178 static gboolean address_list_has_focus = FALSE;
180 /* callback functions */
181 static void addressbook_del_clicked (GtkButton *button,
183 static void addressbook_reg_clicked (GtkButton *button,
185 static void addressbook_to_clicked (GtkButton *button,
187 static void addressbook_lup_clicked (GtkButton *button,
189 static void addressbook_close_clicked (GtkButton *button,
192 static void addressbook_tree_selected (GtkCMCTree *ctree,
193 GtkCMCTreeNode *node,
196 static void addressbook_select_row_tree (GtkCMCTree *ctree,
197 GtkCMCTreeNode *node,
200 static void addressbook_list_row_selected (GtkCMCTree *clist,
201 GtkCMCTreeNode *node,
204 static void addressbook_list_row_unselected (GtkCMCTree *clist,
205 GtkCMCTreeNode *node,
208 static void addressbook_person_expand_node (GtkCMCTree *ctree,
211 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
215 static void addressbook_entry_activated (GtkWidget *widget,
218 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
219 GdkEventButton *event,
221 static gboolean addressbook_list_button_released(GtkWidget *widget,
222 GdkEventButton *event,
224 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
225 GdkEventButton *event,
227 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
228 GdkEventButton *event,
231 static void addressbook_new_folder_cb (GtkAction *action,
233 static void addressbook_new_group_cb (GtkAction *action,
235 static void addressbook_treenode_edit_cb (GtkAction *action,
237 static void addressbook_treenode_delete_cb (GtkAction *action,
240 static void addressbook_change_node_name (GtkCMCTreeNode *node,
243 static void addressbook_new_address_cb (GtkAction *action,
245 static void addressbook_edit_address_cb (GtkAction *action,
247 static void addressbook_delete_address_cb (GtkAction *action,
250 static void close_cb (GtkAction *action,
252 static void addressbook_file_save_cb (GtkAction *action,
255 /* Data source edit stuff */
256 static void addressbook_new_book_cb (GtkAction *action,
258 static void addressbook_new_vcard_cb (GtkAction *action,
262 static void addressbook_new_jpilot_cb (GtkAction *action,
267 static void addressbook_new_ldap_cb (GtkAction *action,
271 static void addressbook_set_clist (AddressObject *obj,
274 static void addressbook_load_tree (void);
275 void addressbook_read_file (void);
277 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
279 static void addressbook_treenode_remove_item ( void );
281 static AddressDataSource *addressbook_find_datasource
282 (GtkCMCTreeNode *node );
284 static AddressBookFile *addressbook_get_book_file(void);
286 static GtkCMCTreeNode *addressbook_node_add_folder
287 (GtkCMCTreeNode *node,
288 AddressDataSource *ds,
289 ItemFolder *itemFolder,
290 AddressObjectType otype);
291 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
292 AddressDataSource *ds,
293 ItemGroup *itemGroup);
294 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
295 GtkCMCTreeNode *parent);
296 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
297 GtkCMCTreeNode *node);
298 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
300 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
303 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
306 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
308 AddressTypeControlItem *atci,
309 AddressTypeControlItem *atciMail);
310 static void addressbook_folder_remove_node (GtkCMCTree *clist,
311 GtkCMCTreeNode *node);
313 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
314 gboolean force_focus );
316 /* LUT's and IF stuff */
317 static void addressbook_free_treenode ( gpointer data );
318 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
319 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
321 static void addrbookctl_build_map (GtkWidget *window);
322 static void addrbookctl_build_iflist (void);
323 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
324 static void addrbookctl_build_ifselect (void);
326 static void addrbookctl_free_interface (AdapterInterface *adapter);
327 static void addrbookctl_free_datasource (AdapterDSource *adapter);
328 static void addrbookctl_free_folder (AdapterFolder *adapter);
329 static void addrbookctl_free_group (AdapterGroup *adapter);
331 static void addressbook_list_select_clear ( void );
332 static void addressbook_list_select_add ( AddrItemObject *aio,
333 AddressDataSource *ds );
334 static void addressbook_list_select_remove ( AddrItemObject *aio );
336 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
337 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
338 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
339 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
340 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
341 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
342 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
343 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
344 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
345 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
346 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
347 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
348 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
349 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
351 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
352 static void addressbook_merge_cb ( GtkAction *action, gpointer data );
355 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
357 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
359 static void addressbook_start_drag(GtkWidget *widget, gint button,
362 static void addressbook_drag_data_get(GtkWidget *widget,
363 GdkDragContext *drag_context,
364 GtkSelectionData *selection_data,
368 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
369 GdkDragContext *context,
374 static void addressbook_drag_leave_cb(GtkWidget *widget,
375 GdkDragContext *context,
378 static void addressbook_drag_received_cb(GtkWidget *widget,
379 GdkDragContext *drag_context,
382 GtkSelectionData *data,
386 static void addressbook_list_menu_setup( void );
388 static GtkTargetEntry addressbook_drag_types[] =
390 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
393 static GtkTargetList *addressbook_target_list = NULL;
395 static void about_show_cb(GtkAction *action, gpointer data)
400 static GtkActionEntry addressbook_entries[] =
402 {"Menu", NULL, "Menu", NULL, NULL, NULL },
404 {"Book", NULL, N_("_Book"), NULL, NULL, NULL },
405 {"Address", NULL, N_("_Edit"), NULL, NULL, NULL },
406 {"Tools", NULL, N_("_Tools"), NULL, NULL, NULL },
407 {"Help", NULL, N_("_Help"), NULL, NULL, NULL },
410 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
411 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
412 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
416 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
419 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
421 {"Book/---", NULL, "---", NULL, NULL, NULL },
423 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
424 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
425 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
426 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
427 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
430 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
431 {"Address/---", NULL, "---", NULL, NULL, NULL },
432 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
433 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
434 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
435 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
436 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
437 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
438 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
439 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
440 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
441 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
442 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
443 {"Address/Merge", NULL, N_("_Merge"), "<control>E", NULL, G_CALLBACK(addressbook_merge_cb) },
447 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
448 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
449 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
450 {"Tools/---", NULL, "---", NULL, NULL, NULL },
451 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
452 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
453 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
454 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
455 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
458 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
462 static GtkActionEntry addressbook_tree_popup_entries[] =
464 {"ABTreePopup", NULL, "ABTreePopup", NULL, NULL, NULL },
465 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
466 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
467 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
468 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
469 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
470 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
471 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
472 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
473 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
474 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
477 static GtkActionEntry addressbook_list_popup_entries[] =
479 {"ABListPopup", NULL, "ABListPopup", NULL, NULL, NULL },
480 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
481 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
482 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
483 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
484 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
485 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
486 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
487 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
488 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
489 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
490 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
491 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
492 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
494 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
496 {"ABListPopup/Merge", NULL, N_("_Merge"), NULL, NULL, G_CALLBACK(addressbook_merge_cb) },
500 * Structure of error message table.
502 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
503 struct _ErrMsgTableEntry {
508 static gchar *_errMsgUnknown_ = N_( "Unknown" );
511 * Lookup table of error messages for general errors. Note that a NULL
512 * description signifies the end of the table.
514 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
515 { MGU_SUCCESS, N_("Success") },
516 { MGU_BAD_ARGS, N_("Bad arguments") },
517 { MGU_NO_FILE, N_("File not specified") },
518 { MGU_OPEN_FILE, N_("Error opening file") },
519 { MGU_ERROR_READ, N_("Error reading file") },
520 { MGU_EOF, N_("End of file encountered") },
521 { MGU_OO_MEMORY, N_("Error allocating memory") },
522 { MGU_BAD_FORMAT, N_("Bad file format") },
523 { MGU_ERROR_WRITE, N_("Error writing to file") },
524 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
525 { MGU_NO_PATH, N_("No path specified") },
531 * Lookup table of error messages for LDAP errors.
533 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
534 { LDAPRC_SUCCESS, N_("Success") },
535 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
536 { LDAPRC_INIT, N_("Error initializing LDAP") },
537 { LDAPRC_BIND, N_("Error binding to LDAP server") },
538 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
539 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
540 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
541 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
542 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
543 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
544 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
545 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
546 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
547 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
553 * Lookup message for specified error code.
554 * \param lut Lookup table.
555 * \param code Code to lookup.
556 * \return Description associated to code.
558 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
560 ErrMsgTableEntry entry;
563 for( i = 0; ; i++ ) {
565 if( entry.description == NULL ) break;
566 if( entry.code == code ) {
567 desc = entry.description;
572 desc = _errMsgUnknown_;
577 static gboolean lastCanLookup = FALSE;
579 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
581 if (add_and_delete) {
582 gtk_widget_show(addrbook.edit_btn);
583 gtk_widget_show(addrbook.del_btn);
584 gtk_widget_show(addrbook.reg_btn);
586 gtk_widget_hide(addrbook.edit_btn);
587 gtk_widget_hide(addrbook.del_btn);
588 gtk_widget_hide(addrbook.reg_btn);
592 gtk_widget_show(addrbook.lup_btn);
593 gtk_widget_show(addrbook.entry);
594 gtk_widget_show(addrbook.label);
596 gtk_widget_hide(addrbook.lup_btn);
597 gtk_widget_hide(addrbook.entry);
598 gtk_widget_hide(addrbook.label);
601 lastCanLookup = lookup;
604 gtk_widget_show(addrbook.to_btn);
605 gtk_widget_show(addrbook.cc_btn);
606 gtk_widget_show(addrbook.bcc_btn);
608 gtk_widget_hide(addrbook.to_btn);
609 gtk_widget_hide(addrbook.cc_btn);
610 gtk_widget_hide(addrbook.bcc_btn);
614 void addressbook_open(Compose *target)
616 /* Initialize all static members */
617 if( _clipBoard_ == NULL ) {
618 _clipBoard_ = addrclip_create();
620 if( _addressIndex_ != NULL ) {
621 addrclip_set_index( _clipBoard_, _addressIndex_ );
623 if( _addressSelect_ == NULL ) {
624 _addressSelect_ = addrselect_list_create();
626 if (!addrbook.window) {
627 addressbook_read_file();
628 addressbook_create();
629 addressbook_load_tree();
630 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
631 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
634 gtk_widget_hide(addrbook.window);
637 gtk_widget_show_all(addrbook.window);
639 if (!prefs_common.addressbook_use_editaddress_dialog)
640 addressbook_edit_person_widgetset_hide();
642 address_completion_start(addrbook.window);
644 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
645 addressbook_set_target_compose(target);
649 * Destroy addressbook.
651 void addressbook_destroy( void ) {
652 /* Free up address stuff */
653 if( _addressSelect_ != NULL ) {
654 addrselect_list_free( _addressSelect_ );
656 if( _clipBoard_ != NULL ) {
657 addrclip_free( _clipBoard_ );
660 if( _addressIndex_ != NULL ) {
661 addrindex_free_index( _addressIndex_ );
662 addrindex_teardown();
664 _addressSelect_ = NULL;
666 _addressIndex_ = NULL;
669 void addressbook_set_target_compose(Compose *target)
671 addrbook.target_compose = target;
674 Compose *addressbook_get_target_compose(void)
676 return addrbook.target_compose;
680 * Refresh addressbook and save to file(s).
682 void addressbook_refresh( void )
684 if (addrbook.window) {
685 if (addrbook.treeSelected) {
686 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
687 addrbook.treeSelected);
688 addressbook_set_clist(
689 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
690 addrbook.treeSelected),
695 addressbook_export_to_file();
698 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
700 if (event && event->keyval == GDK_KEY_Escape)
702 else if (event && event->keyval == GDK_KEY_Delete) {
703 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
704 if ( /* address_index_has_focus || */ address_list_has_focus )
705 addressbook_del_clicked(NULL, NULL);
711 *\brief Save Gtk object size to prefs dataset
713 static void addressbook_size_allocate_cb(GtkWidget *widget,
714 GtkAllocation *allocation)
716 cm_return_if_fail(allocation != NULL);
718 prefs_common.addressbookwin_width = allocation->width;
719 prefs_common.addressbookwin_height = allocation->height;
722 static gint sort_column_number = 0;
723 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
725 static gint list_case_sort(
726 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
728 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
729 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
730 gchar *name1 = NULL, *name2 = NULL;
731 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
732 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
734 if( aio1->type == aio2->type ) {
736 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
738 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
739 if( ! name1 ) return ( name2 != NULL );
740 if( ! name2 ) return -1;
741 return g_utf8_collate( name1, name2 );
743 /* Order groups before person */
744 if( aio1->type == ITEMTYPE_GROUP ) {
745 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
746 } else if( aio2->type == ITEMTYPE_GROUP ) {
747 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
753 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
754 const GtkSortType sort_type)
757 GtkWidget *hbox, *label, *arrow;
759 sort_column_number = col;
760 sort_column_type = sort_type;
761 gtk_cmclist_set_compare_func(clist, list_case_sort);
762 gtk_cmclist_set_sort_type(clist, sort_type);
763 gtk_cmclist_set_sort_column(clist, col);
765 gtk_cmclist_freeze(clist);
766 gtk_cmclist_sort(clist);
768 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
769 hbox = gtk_hbox_new(FALSE, 4);
770 label = gtk_label_new(gettext(list_titles[pos]));
771 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
774 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
775 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
776 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
779 gtk_widget_show_all(hbox);
780 gtk_cmclist_set_column_widget(clist, pos, hbox);
783 gtk_cmclist_thaw(clist);
786 static void addressbook_name_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_NAME, sort_type);
795 static void addressbook_address_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_ADDRESS, sort_type);
804 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
806 static GtkSortType sort_type = GTK_SORT_ASCENDING;
808 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
810 addressbook_sort_list(clist, COL_REMARKS, sort_type);
813 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
816 address_index_has_focus = TRUE;
820 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
823 address_index_has_focus = FALSE;
824 if (!prefs_common.addressbook_use_editaddress_dialog
825 && !address_list_has_focus)
826 addressbook_address_list_disable_some_actions();
830 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
833 address_list_has_focus = TRUE;
837 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
840 address_list_has_focus = FALSE;
841 if (!prefs_common.addressbook_use_editaddress_dialog
842 && !address_index_has_focus)
843 addressbook_address_list_disable_some_actions();
847 /* save hpane and vpane's handle position when it moves */
848 static void addressbook_pane_save_position(void)
851 prefs_common.addressbook_hpaned_pos =
852 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
854 prefs_common.addressbook_vpaned_pos =
855 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
859 * Create the address book widgets. The address book contains two CTree widgets: the
860 * address index tree on the left and the address list on the right.
862 * The address index tree displays a hierarchy of interfaces and groups. Each node in
863 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
864 * data sources and folder objects.
866 * The address list displays group, person and email objects. These items are linked
867 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
870 * In the tradition of MVC architecture, the data stores have been separated from the
871 * GUI components. The addrindex.c file provides the interface to all data stores.
873 static void addressbook_create(void)
879 GtkWidget *ctree_swin;
881 GtkWidget *editaddress_vbox;
882 GtkWidget *clist_vbox;
883 GtkWidget *clist_swin;
890 GtkWidget *statusbar;
901 GtkWidget *close_btn;
902 GtkWidget *tree_popup;
903 GtkWidget *list_popup;
905 GtkUIManager *ui_manager;
906 GtkActionGroup *action_group;
907 gchar *index_titles[N_INDEX_COLS];
911 static GdkGeometry geometry;
913 debug_print("Creating addressbook window...\n");
915 index_titles[COL_SOURCES] = _("Sources");
917 /* Address book window */
918 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
919 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
920 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
921 gtk_widget_realize(window);
923 g_signal_connect(G_OBJECT(window), "delete_event",
924 G_CALLBACK(addressbook_close), NULL);
925 g_signal_connect(G_OBJECT(window), "size_allocate",
926 G_CALLBACK(addressbook_size_allocate_cb), NULL);
927 g_signal_connect(G_OBJECT(window), "key_press_event",
928 G_CALLBACK(key_pressed), NULL);
929 MANAGE_WINDOW_SIGNALS_CONNECT(window);
931 vbox = gtk_vbox_new(FALSE, 0);
932 gtk_container_add(GTK_CONTAINER(window), vbox);
935 ui_manager = gtk_ui_manager_new();
936 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
937 G_N_ELEMENTS(addressbook_entries), NULL);
938 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
939 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
940 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
941 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
945 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
955 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
990 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
991 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
992 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
995 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
997 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
999 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1001 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1002 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1003 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1005 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1006 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1007 GTK_POLICY_AUTOMATIC,
1008 GTK_POLICY_AUTOMATIC);
1009 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1012 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1013 gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1015 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1016 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1017 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1018 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1019 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1020 GTK_CMCTREE_EXPANDER_TRIANGLE);
1021 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1022 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1023 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1024 addressbook_treenode_compare_func);
1026 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1027 G_CALLBACK(addressbook_tree_selected), NULL);
1028 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1029 G_CALLBACK(addressbook_tree_button_pressed),
1031 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1032 G_CALLBACK(addressbook_tree_button_released),
1035 g_signal_connect(G_OBJECT(ctree), "select_row",
1036 G_CALLBACK(addressbook_select_row_tree), NULL);
1038 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1039 addressbook_drag_types, 1,
1040 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1041 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1042 G_CALLBACK(addressbook_drag_motion_cb),
1044 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1045 G_CALLBACK(addressbook_drag_leave_cb),
1047 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1048 G_CALLBACK(addressbook_drag_received_cb),
1050 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1051 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1052 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1053 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1055 clist_vbox = gtk_vbox_new(FALSE, 4);
1057 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1058 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1059 GTK_POLICY_AUTOMATIC,
1060 GTK_POLICY_AUTOMATIC);
1061 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1064 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1065 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1066 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1067 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1068 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1069 GTK_CMCTREE_EXPANDER_TRIANGLE);
1070 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1071 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1072 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1074 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1076 gtk_widget_set_size_request(clist, -1, 80);
1078 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1079 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1080 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1081 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1082 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1083 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1084 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1085 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1086 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1087 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1088 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1090 for (i = 0; i < N_LIST_COLS; i++)
1091 gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1094 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1095 G_CALLBACK(addressbook_list_row_selected), NULL);
1096 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1097 G_CALLBACK(addressbook_list_row_unselected), NULL);
1098 g_signal_connect(G_OBJECT(clist), "button_press_event",
1099 G_CALLBACK(addressbook_list_button_pressed),
1101 g_signal_connect(G_OBJECT(clist), "button_release_event",
1102 G_CALLBACK(addressbook_list_button_released),
1104 g_signal_connect(G_OBJECT(clist), "tree_expand",
1105 G_CALLBACK(addressbook_person_expand_node), NULL );
1106 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1107 G_CALLBACK(addressbook_person_collapse_node), NULL );
1108 g_signal_connect(G_OBJECT(clist), "start_drag",
1109 G_CALLBACK(addressbook_start_drag), NULL);
1110 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1111 G_CALLBACK(addressbook_drag_data_get), NULL);
1112 hbox = gtk_hbox_new(FALSE, 4);
1113 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1115 label = gtk_label_new(_("Search"));
1116 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1118 entry = gtk_entry_new();
1119 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1121 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1123 g_signal_connect(G_OBJECT(entry), "key_press_event",
1124 G_CALLBACK(addressbook_entry_key_pressed),
1126 g_signal_connect(G_OBJECT(entry), "activate",
1127 G_CALLBACK(addressbook_entry_activated), NULL);
1129 if (!prefs_common.addressbook_use_editaddress_dialog) {
1130 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1131 vpaned = gtk_vpaned_new();
1132 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1133 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1136 editaddress_vbox = NULL;
1138 hpaned = gtk_hpaned_new();
1139 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1140 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1141 if (prefs_common.addressbook_use_editaddress_dialog)
1142 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1144 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1147 hsbox = gtk_hbox_new(FALSE, 0);
1148 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1149 statusbar = gtk_statusbar_new();
1150 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1153 hbbox = gtk_hbutton_box_new();
1154 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1155 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1156 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1157 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1159 gtkut_stock_button_add_help(hbbox, &help_btn);
1161 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1162 gtk_widget_set_can_default(edit_btn, TRUE);
1163 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1164 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1165 gtk_widget_set_can_default(del_btn, TRUE);
1166 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1167 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1168 gtk_widget_set_can_default(reg_btn, TRUE);
1169 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1172 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1173 gtk_widget_set_can_default(lup_btn, TRUE);
1174 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1176 g_signal_connect(G_OBJECT(help_btn), "clicked",
1177 G_CALLBACK(manual_open_with_anchor_cb),
1178 MANUAL_ANCHOR_ADDRBOOK);
1180 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1181 G_CALLBACK(addressbook_edit_clicked), NULL);
1182 g_signal_connect(G_OBJECT(del_btn), "clicked",
1183 G_CALLBACK(addressbook_del_clicked), NULL);
1184 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1185 G_CALLBACK(addressbook_reg_clicked), NULL);
1186 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1187 G_CALLBACK(addressbook_lup_clicked), NULL);
1189 to_btn = gtk_button_new_with_label
1190 (prefs_common_translated_header_name("To:"));
1191 gtk_widget_set_can_default(to_btn, TRUE);
1192 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1193 cc_btn = gtk_button_new_with_label
1194 (prefs_common_translated_header_name("Cc:"));
1195 gtk_widget_set_can_default(cc_btn, TRUE);
1196 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1197 bcc_btn = gtk_button_new_with_label
1198 (prefs_common_translated_header_name("Bcc:"));
1199 gtk_widget_set_can_default(bcc_btn, TRUE);
1200 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1202 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1203 gtk_widget_set_can_default(close_btn, TRUE);
1204 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1206 g_signal_connect(G_OBJECT(to_btn), "clicked",
1207 G_CALLBACK(addressbook_to_clicked),
1208 GINT_TO_POINTER(COMPOSE_TO));
1209 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1210 G_CALLBACK(addressbook_to_clicked),
1211 GINT_TO_POINTER(COMPOSE_CC));
1212 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1213 G_CALLBACK(addressbook_to_clicked),
1214 GINT_TO_POINTER(COMPOSE_BCC));
1215 g_signal_connect(G_OBJECT(close_btn), "clicked",
1216 G_CALLBACK(addressbook_close_clicked), NULL);
1218 /* Build icons for interface */
1220 /* Build control tables */
1221 addrbookctl_build_map(window);
1222 addrbookctl_build_iflist();
1223 addrbookctl_build_ifselect();
1225 addrbook.clist = NULL;
1227 /* Add each interface into the tree as a root level folder */
1228 nodeIf = _addressInterfaceList_;
1230 AdapterInterface *adapter = nodeIf->data;
1231 AddressInterface *iface = adapter->interface;
1232 nodeIf = g_list_next(nodeIf);
1234 if(iface->useInterface) {
1235 AddressTypeControlItem *atci = adapter->atci;
1236 text = atci->displayName;
1238 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1239 NULL, NULL, &text, FOLDER_SPACING,
1243 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1244 gtk_cmctree_node_set_row_data_full(
1245 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1246 addressbook_free_treenode );
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1265 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1266 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1281 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1285 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
1286 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1287 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1289 addrbook.window = window;
1290 addrbook.hpaned = hpaned;
1291 addrbook.vpaned = vpaned;
1292 addrbook.menubar = menubar;
1293 addrbook.ctree = ctree;
1296 addrbook.editaddress_vbox = editaddress_vbox;
1297 addrbook.clist = clist;
1298 addrbook.label = label;
1299 addrbook.entry = entry;
1300 addrbook.statusbar = statusbar;
1301 addrbook.status_cid = gtk_statusbar_get_context_id(
1302 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1304 addrbook.help_btn = help_btn;
1305 addrbook.edit_btn = edit_btn;
1306 addrbook.del_btn = del_btn;
1307 addrbook.reg_btn = reg_btn;
1308 addrbook.lup_btn = lup_btn;
1309 addrbook.to_btn = to_btn;
1310 addrbook.cc_btn = cc_btn;
1311 addrbook.bcc_btn = bcc_btn;
1313 addrbook.tree_popup = tree_popup;
1314 addrbook.list_popup = list_popup;
1315 addrbook.ui_manager = ui_manager;
1317 addrbook.listSelected = NULL;
1319 if (!geometry.min_height) {
1320 geometry.min_width = ADDRESSBOOK_WIDTH;
1321 geometry.min_height = ADDRESSBOOK_HEIGHT;
1324 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1326 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1327 prefs_common.addressbookwin_height);
1329 gtk_window_move(GTK_WINDOW(window), 48, 48);
1332 if (!prefs_common.addressbook_use_editaddress_dialog) {
1333 if (prefs_common.addressbook_vpaned_pos > 0)
1334 gtk_paned_set_position(GTK_PANED(vpaned),
1335 prefs_common.addressbook_vpaned_pos);
1337 if (prefs_common.addressbook_hpaned_pos > 0)
1338 gtk_paned_set_position(GTK_PANED(hpaned),
1339 prefs_common.addressbook_hpaned_pos);
1342 gtk_widget_show_all(window);
1346 * Close address book window and save to file(s).
1348 static gint addressbook_close( void ) {
1349 address_completion_end(addrbook.window);
1350 if (!prefs_common.addressbook_use_editaddress_dialog)
1351 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1353 addressbook_pane_save_position();
1355 gtk_widget_hide(addrbook.window);
1356 addressbook_export_to_file();
1361 * Display message in status line.
1362 * \param msg Message to display.
1364 static void addressbook_status_show( gchar *msg ) {
1365 if( addrbook.statusbar != NULL ) {
1367 GTK_STATUSBAR(addrbook.statusbar),
1368 addrbook.status_cid );
1371 GTK_STATUSBAR(addrbook.statusbar),
1372 addrbook.status_cid, msg );
1377 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1381 *addressbook_msgbuf = '\0';
1383 name = addrindex_ds_get_name( ds );
1384 retVal = addrindex_ds_get_status_code( ds );
1385 if( retVal == MGU_SUCCESS ) {
1386 g_snprintf( addressbook_msgbuf,
1387 sizeof(addressbook_msgbuf), "%s", name );
1390 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1391 g_snprintf( addressbook_msgbuf,
1392 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1395 addressbook_status_show( addressbook_msgbuf );
1398 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1400 addressbook_edit_address_cb(NULL, NULL);
1403 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1405 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1409 * Delete one or more objects from address list.
1411 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1413 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1414 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1415 AddressObject *pobj;
1416 AdapterDSource *ads = NULL;
1417 GtkCMCTreeNode *nodeList;
1420 AddressBookFile *abf = NULL;
1421 AddressDataSource *ds = NULL;
1422 AddressInterface *iface;
1423 AddrItemObject *aio;
1424 AddrSelectItem *item;
1426 gboolean refreshList = FALSE;
1428 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1429 cm_return_if_fail(pobj != NULL);
1431 /* Test whether anything selected for deletion */
1432 nodeList = addrbook.listSelected;
1434 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1435 if( aio == NULL) return;
1436 ds = addressbook_find_datasource( addrbook.treeSelected );
1437 if( ds == NULL ) return;
1439 /* Test for read only */
1440 iface = ds->interface;
1441 if( iface->readOnly ) {
1442 alertpanel( _("Delete address(es)"),
1443 _("This address data is readonly and cannot be deleted."),
1444 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST);
1448 /* Test whether Ok to proceed */
1450 if( pobj->type == ADDR_DATASOURCE ) {
1451 ads = ADAPTER_DSOURCE(pobj);
1452 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1454 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1457 else if( pobj->type == ADDR_ITEM_GROUP ) {
1460 if( ! procFlag ) return;
1461 abf = ds->rawDataSource;
1462 if( abf == NULL ) return;
1464 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1465 g_signal_handlers_block_by_func
1466 (G_OBJECT(addrbook.clist),
1467 G_CALLBACK(addressbook_list_row_unselected), NULL);
1469 /* Process deletions */
1470 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1471 GList *groups = NULL, *persons = NULL, *emails = NULL;
1472 gboolean group_delete = TRUE;
1473 /* Items inside folders */
1474 list = addrselect_get_list( _addressSelect_ );
1475 /* Confirm deletion */
1479 node = g_list_next( node );
1480 aio = ( AddrItemObject * ) item->addressItem;
1481 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1482 group_delete = FALSE;
1487 aval = alertpanel( _("Delete group"),
1488 _("Really delete the group(s)?\n"
1489 "The addresses it contains will not be lost."),
1490 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1491 if( aval != G_ALERTALTERNATE ) {
1495 aval = alertpanel( _("Delete address(es)"),
1496 _("Really delete the address(es)?"),
1497 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1498 if( aval != G_ALERTALTERNATE ) {
1503 /* first, set lists of groups and persons to remove */
1507 node = g_list_next( node );
1508 aio = ( AddrItemObject * ) item->addressItem;
1511 if( aio->type == ITEMTYPE_GROUP ) {
1512 groups = g_list_prepend(groups, item);
1514 else if( aio->type == ITEMTYPE_PERSON ) {
1515 persons = g_list_prepend(persons, item);
1518 /* then set list of emails to remove *if* they're not children of
1519 * persons to remove */
1523 node = g_list_next( node );
1524 aio = ( AddrItemObject * ) item->addressItem;
1527 if( aio->type == ITEMTYPE_EMAIL ) {
1528 ItemEMail *sitem = ( ItemEMail * ) aio;
1529 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1530 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1531 emails = g_list_prepend(emails, item);
1533 /* else, the email will be removed via the parent person */
1536 /* then delete groups */
1540 node = g_list_next( node );
1541 aio = ( AddrItemObject * ) item->addressItem;
1544 if( aio->type == ITEMTYPE_GROUP ) {
1545 ItemGroup *item = ( ItemGroup * ) aio;
1546 GtkCMCTreeNode *nd = NULL;
1547 nd = addressbook_find_group_node( addrbook.opened, item );
1548 item = addrbook_remove_group( abf, item );
1550 addritem_free_item_group( item );
1552 /* Remove group from parent node */
1553 gtk_cmctree_remove_node( ctree, nd );
1557 /* then delete persons */
1561 node = g_list_next( node );
1562 aio = ( AddrItemObject * ) item->addressItem;
1565 if( aio->type == ITEMTYPE_PERSON ) {
1566 ItemPerson *item = ( ItemPerson * ) aio;
1567 item->status = DELETE_ENTRY;
1568 addressbook_folder_remove_one_person( clist, item );
1569 if (pobj->type == ADDR_ITEM_FOLDER)
1570 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1571 item = addrbook_remove_person( abf, item );
1573 if (ds && ds->type == ADDR_IF_LDAP) {
1574 LdapServer *server = ds->rawDataSource;
1575 ldapsvr_set_modified(server, TRUE);
1576 ldapsvr_update_book(server, item);
1580 addritem_person_remove_picture(item);
1581 addritem_free_item_person( item );
1585 /* then delete emails */
1589 node = g_list_next( node );
1590 aio = ( AddrItemObject * ) item->addressItem;
1594 if( aio->type == ITEMTYPE_EMAIL ) {
1595 ItemEMail *sitem = ( ItemEMail * ) aio;
1596 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1597 sitem = addrbook_person_remove_email( abf, person, sitem );
1599 addrcache_remove_email(abf->addressCache, sitem);
1600 addritem_free_item_email( sitem );
1602 addressbook_folder_refresh_one_person( clist, person );
1605 g_list_free( groups );
1606 g_list_free( persons );
1607 g_list_free( emails );
1608 g_list_free( list );
1609 addressbook_list_select_clear();
1611 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1612 addressbook_set_clist(
1613 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1617 addrbook_set_dirty(abf, TRUE);
1618 addressbook_export_to_file();
1619 addressbook_list_menu_setup();
1622 else if( pobj->type == ADDR_ITEM_GROUP ) {
1623 /* Items inside groups */
1624 list = addrselect_get_list( _addressSelect_ );
1628 node = g_list_next( node );
1629 aio = ( AddrItemObject * ) item->addressItem;
1630 if( aio->type == ITEMTYPE_EMAIL ) {
1631 ItemEMail *item = ( ItemEMail * ) aio;
1632 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1633 item = addrbook_person_remove_email( abf, person, item );
1635 addritem_free_item_email( item );
1639 g_list_free( list );
1640 addressbook_list_select_clear();
1641 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1642 addressbook_set_clist(
1643 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1647 addrbook_set_dirty(abf, TRUE);
1648 addressbook_export_to_file();
1649 addressbook_list_menu_setup();
1653 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1654 gtk_cmctree_remove_node( clist, nodeList );
1656 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1657 g_signal_handlers_unblock_by_func
1658 (G_OBJECT(addrbook.clist),
1659 G_CALLBACK(addressbook_list_row_unselected), NULL);
1662 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1664 addressbook_new_address_cb( NULL, NULL );
1667 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1670 gchar *address = NULL;
1672 if( aio->type == ITEMTYPE_EMAIL ) {
1673 ItemPerson *person = NULL;
1674 ItemEMail *email = ( ItemEMail * ) aio;
1676 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1677 if( email->address ) {
1678 if( ADDRITEM_NAME(email) ) {
1679 name = ADDRITEM_NAME(email);
1680 if( *name == '\0' ) {
1681 name = ADDRITEM_NAME(person);
1684 else if( ADDRITEM_NAME(person) ) {
1685 name = ADDRITEM_NAME(person);
1688 buf = g_strdup( email->address );
1690 address = email->address;
1693 else if( aio->type == ITEMTYPE_PERSON ) {
1694 ItemPerson *person = ( ItemPerson * ) aio;
1695 GList *node = person->listEMail;
1697 name = ADDRITEM_NAME(person);
1699 ItemEMail *email = ( ItemEMail * ) node->data;
1700 address = email->address;
1704 if( name && name[0] != '\0' ) {
1705 if( strchr_with_skip_quote( name, '"', ',' ) )
1706 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1708 buf = g_strdup_printf( "%s <%s>", name, address );
1711 buf = g_strdup( address );
1718 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1722 AddrSelectItem *item;
1723 AddrItemObject *aio;
1726 compose = addrbook.target_compose;
1727 if( ! compose ) return;
1729 /* Nothing selected, but maybe there is something in text entry */
1730 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1732 compose_entry_append(
1733 compose, addr, (ComposeEntryType)data , PREF_NONE);
1736 /* Select from address list */
1737 list = addrselect_get_list( _addressSelect_ );
1742 node = g_list_next( node );
1743 aio = item->addressItem;
1744 if( aio->type == ITEMTYPE_PERSON ||
1745 aio->type == ITEMTYPE_EMAIL ) {
1746 addr = addressbook_format_address( aio );
1747 compose_entry_append(
1748 compose, addr, (ComposeEntryType) data, PREF_NONE );
1751 else if( aio->type == ITEMTYPE_GROUP ) {
1752 ItemGroup *group = ( ItemGroup * ) aio;
1753 GList *nodeMail = group->listEMail;
1755 ItemEMail *email = nodeMail->data;
1757 addr = addressbook_format_address(
1758 ( AddrItemObject * ) email );
1759 compose_entry_append(
1760 compose, addr, (ComposeEntryType) data, PREF_NONE );
1762 nodeMail = g_list_next( nodeMail );
1767 AddressObject *obj = NULL;
1769 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1771 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1772 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1773 GList *nodeMail = itemGroup->listEMail;
1775 ItemEMail *email = nodeMail->data;
1777 addr = addressbook_format_address(
1778 ( AddrItemObject * ) email );
1779 compose_entry_append(
1780 compose, addr, (ComposeEntryType) data, PREF_NONE );
1782 nodeMail = g_list_next( nodeMail );
1786 g_list_free( list );
1789 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1792 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1797 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1799 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1800 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1801 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1802 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Merge", sensitive );
1803 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1804 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1807 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1808 gboolean canEdit = FALSE;
1809 gboolean canDelete = TRUE;
1810 gboolean canAdd = FALSE;
1811 gboolean canEditTr = TRUE;
1812 gboolean editAddress = FALSE;
1813 gboolean canExport = TRUE;
1814 AddressTypeControlItem *atci = NULL;
1815 AddressDataSource *ds = NULL;
1816 AddressInterface *iface = NULL;
1818 if( obj == NULL ) return;
1819 if( obj->type == ADDR_INTERFACE ) {
1820 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1821 iface = adapter->interface;
1823 if( iface->haveLibrary ) {
1824 /* Enable appropriate File / New command */
1825 atci = adapter->atci;
1826 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1829 canEditTr = canExport = FALSE;
1831 else if( obj->type == ADDR_DATASOURCE ) {
1832 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1833 ds = ads->dataSource;
1834 iface = ds->interface;
1835 if( ! iface->readOnly ) {
1836 canAdd = canEdit = editAddress = canDelete = TRUE;
1838 if( ! iface->haveLibrary ) {
1839 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1842 else if( obj->type == ADDR_ITEM_FOLDER ) {
1843 ds = addressbook_find_datasource( addrbook.treeSelected );
1845 iface = ds->interface;
1846 if( iface->readOnly ) {
1851 canAdd = editAddress = TRUE;
1855 else if( obj->type == ADDR_ITEM_GROUP ) {
1856 ds = addressbook_find_datasource( addrbook.treeSelected );
1858 iface = ds->interface;
1859 if( ! iface->readOnly ) {
1865 if( addrbook.listSelected == NULL )
1869 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1870 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1871 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1872 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1875 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1876 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1877 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1878 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1880 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1881 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1884 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1885 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1889 * Address book tree callback function that responds to selection of tree
1892 * \param ctree Tree widget.
1893 * \param node Node that was selected.
1894 * \param column Column number where selected occurred.
1895 * \param data Pointer to user data.
1897 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1898 gint column, gpointer data)
1900 AddressObject *obj = NULL;
1901 AdapterDSource *ads = NULL;
1902 AddressDataSource *ds = NULL;
1903 ItemFolder *rootFolder = NULL;
1904 AddressObjectType aot;
1906 addrbook.treeSelected = node;
1907 addrbook.listSelected = NULL;
1908 addressbook_status_show( "" );
1909 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1911 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1913 addressbook_set_clist(NULL, TRUE);
1916 addrbook.opened = node;
1918 if( obj->type == ADDR_DATASOURCE ) {
1919 /* Read from file */
1920 static gboolean tVal = TRUE;
1922 ads = ADAPTER_DSOURCE(obj);
1924 ds = ads->dataSource;
1925 if( ds == NULL ) return;
1927 if( addrindex_ds_get_modify_flag( ds ) ) {
1928 addrindex_ds_read_data( ds );
1931 if( ! addrindex_ds_get_read_flag( ds ) ) {
1932 addrindex_ds_read_data( ds );
1934 addressbook_ds_show_message( ds );
1936 if( ! addrindex_ds_get_access_flag( ds ) ) {
1937 /* Remove existing folders and groups */
1938 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1939 addressbook_tree_remove_children( ctree, node );
1940 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1942 /* Load folders into the tree */
1943 rootFolder = addrindex_ds_get_root_folder( ds );
1944 if( ds && ds->type == ADDR_IF_JPILOT ) {
1945 aot = ADDR_CATEGORY;
1947 else if( ds && ds->type == ADDR_IF_LDAP ) {
1948 aot = ADDR_LDAP_QUERY;
1951 aot = ADDR_ITEM_FOLDER;
1953 addressbook_node_add_folder( node, ds, rootFolder, aot );
1954 addrindex_ds_set_access_flag( ds, &tVal );
1955 gtk_cmctree_expand( ctree, node );
1958 addressbook_set_clist(NULL, TRUE);
1961 /* Update address list */
1962 g_signal_handlers_block_by_func
1964 G_CALLBACK(addressbook_tree_selected), NULL);
1965 addressbook_set_clist( obj, FALSE );
1966 g_signal_handlers_unblock_by_func
1968 G_CALLBACK(addressbook_tree_selected), NULL);
1969 if (!prefs_common.addressbook_use_editaddress_dialog)
1970 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1972 /* Setup main menu selections */
1973 addressbook_menubar_set_sensitive( FALSE );
1974 addressbook_menuitem_set_sensitive( obj, node );
1975 addressbook_list_select_clear();
1976 addressbook_list_menu_setup();
1981 * Setup address list popup menu items. Items are enabled or disabled as
1984 static void addressbook_list_menu_setup( void ) {
1985 GtkCMCTree *clist = NULL;
1986 AddressObject *pobj = NULL;
1987 AddressObject *obj = NULL;
1988 AdapterDSource *ads = NULL;
1989 AddressInterface *iface = NULL;
1990 AddressDataSource *ds = NULL;
1992 AddrItemObject *aio;
1993 AddrSelectItem *item;
1994 gboolean canEdit = FALSE;
1995 gboolean canDelete = FALSE;
1996 gboolean canCut = FALSE;
1997 gboolean canCopy = FALSE;
1998 gboolean canPaste = FALSE;
1999 gboolean canBrowse = FALSE;
2000 gboolean canMerge = FALSE;
2002 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2003 if( pobj == NULL ) return;
2005 clist = GTK_CMCTREE(addrbook.clist);
2006 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2007 if( obj == NULL ) canEdit = FALSE;
2009 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2010 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2012 if( pobj->type == ADDR_DATASOURCE ) {
2013 /* Parent object is a data source */
2014 ads = ADAPTER_DSOURCE(pobj);
2015 ds = ads->dataSource;
2018 iface = ds->interface;
2021 if( ! iface->readOnly ) {
2022 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2023 if (iface->type != ADDR_IF_LDAP)
2024 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2025 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2028 canDelete = canEdit;
2031 else if( pobj->type != ADDR_INTERFACE ) {
2032 /* Parent object is not an interface */
2033 ds = addressbook_find_datasource( addrbook.treeSelected );
2036 iface = ds->interface;
2039 if( ! iface->readOnly ) {
2040 /* Folder or group */
2041 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2042 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2043 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2044 if( obj ) canEdit = TRUE;
2047 if( pobj->type == ADDR_ITEM_FOLDER ) {
2048 if (iface->type != ADDR_IF_LDAP)
2049 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2050 if( obj ) canEdit = TRUE;
2052 canDelete = canEdit;
2054 if( iface->type == ADDR_IF_LDAP ) {
2055 if( obj ) canBrowse = TRUE;
2062 /* Enable cut and paste */
2063 if( ! addrclip_is_empty( _clipBoard_ ) )
2065 if( ! addrselect_test_empty( _addressSelect_ ) )
2067 /* Enable copy if something is selected */
2068 if( ! addrselect_test_empty( _addressSelect_ ) )
2072 /* Disable edit or browse if more than one row selected */
2073 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2078 /* Allow merging persons or emails are selected */
2079 list = _addressSelect_->listSelect;
2080 if (list && list->next ) {
2082 aio = ( AddrItemObject * ) item->addressItem;
2083 if( aio->type == ITEMTYPE_EMAIL ||
2084 aio->type == ITEMTYPE_PERSON ) {
2089 /* Forbid write changes when read-only */
2090 if( iface && iface->readOnly ) {
2097 /* Now go finalize menu items */
2098 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2099 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2101 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2103 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2105 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2106 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge", canMerge );
2108 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2109 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2110 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2112 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2113 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2114 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2115 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Merge", canMerge );
2117 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2118 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2120 if (addrbook.target_compose) {
2121 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2122 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2123 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2126 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2130 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2131 GtkCMCTreeNode *node,
2138 * Add list of items into tree node below specified tree node.
2139 * \param treeNode Tree node.
2140 * \param ds Data source.
2141 * \param listItems List of items.
2143 static void addressbook_treenode_add_list(
2144 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2150 AddrItemObject *aio;
2154 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2157 group = ( ItemGroup * ) aio;
2158 nn = addressbook_node_add_group( treeNode, ds, group );
2160 g_message("error adding addressbook group\n");
2163 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2166 folder = ( ItemFolder * ) aio;
2167 nn = addressbook_node_add_folder(
2168 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2170 g_message("error adding addressbook folder\n");
2173 node = g_list_next( node );
2177 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2178 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2182 * Cut from address list widget.
2184 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2185 _clipBoard_->cutFlag = TRUE;
2186 addrclip_clear( _clipBoard_ );
2187 addrclip_add( _clipBoard_, _addressSelect_ );
2188 /* addrclip_list_show( _clipBoard_, stdout ); */
2192 * Copy from address list widget.
2194 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2195 _clipBoard_->cutFlag = FALSE;
2196 addrclip_clear( _clipBoard_ );
2197 addrclip_add( _clipBoard_, _addressSelect_ );
2198 /* addrclip_list_show( _clipBoard_, stdout ); */
2202 * Paste clipboard into address list widget.
2204 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2205 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2206 AddressObject *pobj = NULL;
2207 AddressDataSource *ds = NULL;
2208 AddressBookFile *abf = NULL;
2209 ItemFolder *folder = NULL;
2210 GList *folderGroup = NULL;
2212 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2213 if( ds == NULL ) return;
2214 if( addrindex_ds_get_readonly( ds ) ) {
2215 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2219 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2221 if( pobj->type == ADDR_ITEM_FOLDER ) {
2222 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2224 else if( pobj->type == ADDR_ITEM_GROUP ) {
2225 alertpanel_error( _("Cannot paste into an address group.") );
2230 /* Get an address book */
2231 abf = addressbook_get_book_file();
2232 if( abf == NULL ) return;
2234 if( _clipBoard_->cutFlag ) {
2236 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2238 /* Remove all groups and folders in clipboard from tree node */
2239 addressbook_treenode_remove_item();
2241 /* Remove all "cut" items */
2242 addrclip_delete_item( _clipBoard_ );
2244 /* Clear clipboard - cut items??? */
2245 addrclip_clear( _clipBoard_ );
2249 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2252 /* addrclip_list_show( _clipBoard_, stdout ); */
2254 /* Update tree by inserting node for each folder or group */
2255 addressbook_treenode_add_list(
2256 addrbook.treeSelected, ds, folderGroup );
2257 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2258 g_list_free( folderGroup );
2262 /* Display items pasted */
2263 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2264 addressbook_set_clist(
2265 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2273 * Add current treenode object to clipboard. Note that widget only allows
2274 * one entry from the tree list to be selected.
2276 static void addressbook_treenode_to_clipboard( void ) {
2277 AddressObject *obj = NULL;
2278 AddressDataSource *ds = NULL;
2279 AddrSelectItem *item;
2280 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2281 GtkCMCTreeNode *node;
2283 node = addrbook.treeSelected;
2284 if( node == NULL ) return;
2285 obj = gtk_cmctree_node_get_row_data( ctree, node );
2286 if( obj == NULL ) return;
2288 ds = addressbook_find_datasource( node );
2289 if( ds == NULL ) return;
2292 if( obj->type == ADDR_ITEM_FOLDER ) {
2293 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2294 ItemFolder *folder = adapter->itemFolder;
2296 item = addrselect_create_node( obj );
2297 item->uid = g_strdup( ADDRITEM_ID(folder) );
2299 else if( obj->type == ADDR_ITEM_GROUP ) {
2300 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2301 ItemGroup *group = adapter->itemGroup;
2303 item = addrselect_create_node( obj );
2304 item->uid = g_strdup( ADDRITEM_ID(group) );
2306 else if( obj->type == ADDR_DATASOURCE ) {
2308 item = addrselect_create_node( obj );
2313 /* Clear existing list and add item into list */
2316 addressbook_list_select_clear();
2317 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2318 addrselect_list_add( _addressSelect_, item, cacheID );
2324 * Cut from tree widget.
2326 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2327 _clipBoard_->cutFlag = TRUE;
2328 addressbook_treenode_to_clipboard();
2329 addrclip_clear( _clipBoard_ );
2330 addrclip_add( _clipBoard_, _addressSelect_ );
2331 /* addrclip_list_show( _clipBoard_, stdout ); */
2335 * Copy from tree widget.
2337 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2338 _clipBoard_->cutFlag = FALSE;
2339 addressbook_treenode_to_clipboard();
2340 addrclip_clear( _clipBoard_ );
2341 addrclip_add( _clipBoard_, _addressSelect_ );
2342 /* addrclip_list_show( _clipBoard_, stdout ); */
2346 * Paste clipboard into address tree widget.
2348 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2349 addressbook_clip_paste_cb(NULL,NULL);
2353 * Clear selected entries in clipboard.
2355 static void addressbook_list_select_clear( void ) {
2356 addrselect_list_clear( _addressSelect_ );
2360 * Add specified address item to selected address list.
2361 * \param aio Address item object.
2362 * \param ds Datasource.
2364 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2367 if( ds == NULL ) return;
2368 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2369 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2374 * Remove specified address item from selected address list.
2375 * \param aio Address item object.
2377 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2378 addrselect_list_remove( _addressSelect_, aio );
2382 * Invoke EMail compose window with addresses in selected address list.
2384 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2387 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2388 listAddress = addrselect_build_list( _addressSelect_ );
2389 compose_new_with_list( NULL, listAddress );
2390 mgu_free_dlist( listAddress );
2395 static void addressbook_merge_list( AddrSelectList *list ) {
2396 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2397 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2398 AddressObject *pobj;
2399 AddressDataSource *ds = NULL;
2401 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
2402 cm_return_if_fail(pobj != NULL);
2404 ds = addressbook_find_datasource( addrbook.treeSelected );
2405 if( ds == NULL ) return;
2407 addrmerge_merge(clist, pobj, ds, list);
2411 * Merge selected entries in the address list
2413 static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
2414 if( addrselect_test_empty( _addressSelect_ ) )
2417 addressbook_merge_list( _addressSelect_ );
2420 static void addressbook_list_row_selected( GtkCMCTree *clist,
2421 GtkCMCTreeNode *node,
2425 AddrItemObject *aio = NULL;
2426 AddressObject *pobj = NULL;
2427 AdapterDSource *ads = NULL;
2428 AddressDataSource *ds = NULL;
2430 addrbook.listSelected = node;
2432 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2433 if( pobj == NULL ) return;
2435 if( pobj->type == ADDR_DATASOURCE ) {
2436 ads = ADAPTER_DSOURCE(pobj);
2437 ds = ads->dataSource;
2439 else if( pobj->type != ADDR_INTERFACE ) {
2440 ds = addressbook_find_datasource( addrbook.treeSelected );
2443 aio = gtk_cmctree_node_get_row_data( clist, node );
2445 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2446 addressbook_list_select_add( aio, ds );
2449 addressbook_list_menu_setup();
2451 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2452 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2454 if (obj && obj->type != ADDR_ITEM_GROUP)
2455 addressbook_edit_address(NULL, 0, NULL, FALSE);
2459 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2460 GtkCMCTreeNode *node,
2464 AddrItemObject *aio;
2466 aio = gtk_cmctree_node_get_row_data( ctree, node );
2468 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2469 addressbook_list_select_remove( aio );
2472 if (!prefs_common.addressbook_use_editaddress_dialog)
2473 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2476 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2478 addressbook_lup_clicked(NULL, NULL);
2481 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2482 GdkEventButton *event,
2485 if( ! event ) return FALSE;
2487 addressbook_list_menu_setup();
2489 if( event->button == 3 ) {
2490 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2491 event->button, event->time );
2492 } else if (event->button == 1) {
2493 if (event->type == GDK_2BUTTON_PRESS) {
2494 if (prefs_common.add_address_by_click &&
2495 addrbook.target_compose)
2496 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2498 if (prefs_common.addressbook_use_editaddress_dialog)
2499 addressbook_edit_address_cb(NULL, NULL);
2501 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2502 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2503 if( obj && obj->type == ADDR_ITEM_GROUP )
2504 addressbook_edit_address_cb(NULL, NULL);
2512 static gboolean addressbook_list_button_released(GtkWidget *widget,
2513 GdkEventButton *event,
2519 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2520 GdkEventButton *event,
2523 GtkCMCList *clist = GTK_CMCLIST(ctree);
2525 AddressObject *obj = NULL;
2526 AdapterDSource *ads = NULL;
2527 AddressInterface *iface = NULL;
2528 AddressDataSource *ds = NULL;
2529 gboolean canEdit = FALSE;
2530 gboolean canDelete = FALSE;
2531 gboolean canCut = FALSE;
2532 gboolean canCopy = FALSE;
2533 gboolean canPaste = FALSE;
2534 gboolean canTreeCut = FALSE;
2535 gboolean canTreeCopy = FALSE;
2536 gboolean canTreePaste = FALSE;
2537 gboolean canLookup = FALSE;
2538 GtkCMCTreeNode *node = NULL;
2540 if( ! event ) return FALSE;
2541 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2543 if (event->button == 1) {
2544 if (event->type == GDK_2BUTTON_PRESS) {
2545 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2546 gtkut_clist_set_focus_row(clist, row);
2547 obj = gtk_cmclist_get_row_data( clist, row );
2552 if (obj->type == ADDR_ITEM_GROUP ||
2553 obj->type == ADDR_DATASOURCE) {
2555 addressbook_treenode_edit_cb(NULL, NULL);
2557 /* expand pr collapse */
2558 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2559 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2565 addressbook_menubar_set_sensitive( FALSE );
2567 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2568 gtkut_clist_set_focus_row(clist, row);
2569 obj = gtk_cmclist_get_row_data( clist, row );
2572 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2576 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2578 if( ! addrclip_is_empty( _clipBoard_ ) )
2579 canTreePaste = TRUE;
2581 if (obj->type == ADDR_INTERFACE) {
2582 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2583 iface = adapter->interface;
2586 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2587 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2589 if( iface->externalQuery )
2592 if (obj->type == ADDR_DATASOURCE) {
2594 ads = ADAPTER_DSOURCE(obj);
2595 ds = ads->dataSource;
2598 iface = ds->interface;
2601 if( !iface->readOnly ) {
2602 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2603 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2604 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2610 else if (obj->type == ADDR_ITEM_FOLDER) {
2612 ds = addressbook_find_datasource( node );
2615 iface = ds->interface;
2618 if( !iface->readOnly ) {
2622 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2623 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2624 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2628 if( iface->externalQuery ) {
2629 /* Enable deletion of LDAP folder */
2633 else if (obj->type == ADDR_ITEM_GROUP) {
2635 ds = addressbook_find_datasource( node );
2638 iface = ds->interface;
2641 if( ! iface->readOnly ) {
2644 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2645 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2649 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2651 if( ! addrselect_test_empty( _addressSelect_ ) )
2653 if( ! addrclip_is_empty( _clipBoard_ ) )
2656 /* Forbid write changes when read-only */
2657 if( iface && iface->readOnly ) {
2659 canTreePaste = FALSE;
2666 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2667 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2668 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2669 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2670 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2672 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2673 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2674 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2675 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2676 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2678 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2679 addrbook.target_compose != NULL);
2681 if( event->button == 3 )
2682 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2683 event->button, event->time);
2688 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2689 GdkEventButton *event,
2692 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2696 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2698 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2699 AddressObject *obj = NULL;
2700 AddressDataSource *ds = NULL;
2701 AddressBookFile *abf = NULL;
2702 ItemFolder *parentFolder = NULL;
2703 ItemFolder *folder = NULL;
2705 if( ! addrbook.treeSelected ) return;
2706 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2707 if( obj == NULL ) return;
2708 ds = addressbook_find_datasource( addrbook.treeSelected );
2709 if( ds == NULL ) return;
2711 if( obj->type == ADDR_DATASOURCE ) {
2712 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2714 else if( obj->type == ADDR_ITEM_FOLDER ) {
2715 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2721 abf = ds->rawDataSource;
2722 if( abf == NULL ) return;
2723 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2726 nn = addressbook_node_add_folder(
2727 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2729 g_message("error adding addressbook folder\n");
2731 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2732 if( addrbook.treeSelected == addrbook.opened )
2733 addressbook_set_clist(obj, TRUE);
2737 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2739 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2740 AddressObject *obj = NULL;
2741 AddressDataSource *ds = NULL;
2742 AddressBookFile *abf = NULL;
2743 ItemFolder *parentFolder = NULL;
2744 ItemGroup *group = NULL;
2746 if( ! addrbook.treeSelected ) return;
2747 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2748 if( obj == NULL ) return;
2749 ds = addressbook_find_datasource( addrbook.treeSelected );
2750 if( ds == NULL ) return;
2752 if( obj->type == ADDR_DATASOURCE ) {
2753 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2755 else if( obj->type == ADDR_ITEM_FOLDER ) {
2756 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2762 abf = ds->rawDataSource;
2763 if( abf == NULL ) return;
2764 group = addressbook_edit_group( abf, parentFolder, NULL );
2767 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2769 g_message("error adding addressbook group\n");
2771 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2772 if( addrbook.treeSelected == addrbook.opened )
2773 addressbook_set_clist(obj, TRUE);
2777 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2779 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2782 GdkPixbuf *pix_cl, *pix_op;
2783 gboolean is_leaf, expanded;
2785 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2787 &is_leaf, &expanded);
2788 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2795 * \param obj Address object to edit.
2796 * \param node Node in tree.
2797 * \return New name of data source.
2799 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2800 gchar *newName = NULL;
2801 AddressDataSource *ds = NULL;
2802 AddressInterface *iface = NULL;
2803 AdapterDSource *ads = NULL;
2805 ds = addressbook_find_datasource( node );
2806 if( ds == NULL ) return NULL;
2807 iface = ds->interface;
2808 if( ! iface->haveLibrary ) return NULL;
2810 /* Read data from data source */
2811 if( addrindex_ds_get_modify_flag( ds ) ) {
2812 addrindex_ds_read_data( ds );
2815 if( ! addrindex_ds_get_read_flag( ds ) ) {
2816 addrindex_ds_read_data( ds );
2820 ads = ADAPTER_DSOURCE(obj);
2821 if( ads->subType == ADDR_BOOK ) {
2822 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2824 else if( ads->subType == ADDR_VCARD ) {
2825 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2828 else if( ads->subType == ADDR_JPILOT ) {
2829 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2833 else if( ads->subType == ADDR_LDAP ) {
2834 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2840 newName = obj->name;
2845 * Edit an object that is in the address tree area.
2847 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2849 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2851 AddressDataSource *ds = NULL;
2852 AddressBookFile *abf = NULL;
2853 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2856 if( ! addrbook.treeSelected ) return;
2857 node = addrbook.treeSelected;
2858 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2859 obj = gtk_cmctree_node_get_row_data( ctree, node );
2860 if( obj == NULL ) return;
2861 parentNode = GTK_CMCTREE_ROW(node)->parent;
2863 ds = addressbook_find_datasource( node );
2864 if( ds == NULL ) return;
2866 if( obj->type == ADDR_DATASOURCE ) {
2867 name = addressbook_edit_datasource( obj, node );
2868 if( name == NULL ) return;
2871 abf = ds->rawDataSource;
2872 if( abf == NULL ) return;
2873 if( obj->type == ADDR_ITEM_FOLDER ) {
2874 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2875 ItemFolder *item = adapter->itemFolder;
2876 ItemFolder *parentFolder = NULL;
2877 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2878 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2879 name = ADDRITEM_NAME(item);
2881 else if( obj->type == ADDR_ITEM_GROUP ) {
2882 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2883 ItemGroup *item = adapter->itemGroup;
2884 ItemFolder *parentFolder = NULL;
2885 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2886 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2887 name = ADDRITEM_NAME(item);
2890 if( name && parentNode ) {
2891 /* Update node in tree view */
2892 addressbook_change_node_name( node, name );
2893 gtk_sctree_sort_node(ctree, parentNode);
2894 gtk_cmctree_expand( ctree, node );
2895 gtk_sctree_select( GTK_SCTREE( ctree), node );
2902 ADDRTREE_DEL_FOLDER_ONLY,
2903 ADDRTREE_DEL_FOLDER_ADDR
2907 * Delete an item from the tree widget.
2908 * \param data Data passed in.
2909 * \param action Action.
2910 * \param widget Widget issuing callback.
2912 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2914 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2915 GtkCMCTreeNode *node = NULL;
2919 AddrBookBase *adbase;
2920 AddressCache *cache;
2921 AdapterDSource *ads = NULL;
2922 AddressInterface *iface = NULL;
2923 AddressDataSource *ds = NULL;
2924 gboolean remFlag = FALSE;
2925 TreeItemDelType delType;
2927 if( ! addrbook.treeSelected ) return;
2928 node = addrbook.treeSelected;
2929 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2931 obj = gtk_cmctree_node_get_row_data( ctree, node );
2932 cm_return_if_fail(obj != NULL);
2934 if( obj->type == ADDR_DATASOURCE ) {
2935 ads = ADAPTER_DSOURCE(obj);
2937 ds = ads->dataSource;
2938 if( ds == NULL ) return;
2941 /* Must be folder or something else */
2942 ds = addressbook_find_datasource( node );
2943 if( ds == NULL ) return;
2945 /* Only allow deletion from non-readOnly */
2946 iface = ds->interface;
2947 if( iface->readOnly ) {
2948 /* Allow deletion of query results */
2949 if( ! iface->externalQuery ) return;
2953 /* Confirm deletion */
2954 delType = ADDRTREE_DEL_NONE;
2955 if( obj->type == ADDR_ITEM_FOLDER ) {
2956 if( iface && iface->externalQuery ) {
2957 message = g_strdup_printf( _(
2958 "Do you want to delete the query " \
2959 "results and addresses in '%s'?" ),
2961 aval = alertpanel( _("Delete"), message,
2962 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
2964 if( aval == G_ALERTALTERNATE ) {
2965 delType = ADDRTREE_DEL_FOLDER_ADDR;
2969 message = g_strdup_printf
2970 ( _( "Do you want to delete '%s'? "
2971 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2973 aval = alertpanel( _("Delete folder"), message,
2974 GTK_STOCK_CANCEL, _("Delete _folder only"), _("Delete folder and _addresses"), ALERTFOCUS_SECOND);
2976 if( aval == G_ALERTALTERNATE ) {
2977 delType = ADDRTREE_DEL_FOLDER_ONLY;
2979 else if( aval == G_ALERTOTHER ) {
2980 delType = ADDRTREE_DEL_FOLDER_ADDR;
2984 else if( obj->type == ADDR_ITEM_GROUP ) {
2985 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2986 "The addresses it contains will not 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_FOLDER_ONLY;
2992 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2993 "The addresses it contains will be lost."), obj->name);
2994 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2995 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2997 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2999 if( delType == ADDRTREE_DEL_NONE ) return;
3001 /* Proceed with deletion */
3002 if( obj->type == ADDR_DATASOURCE ) {
3003 /* Remove node from tree */
3004 gtk_cmctree_remove_node( ctree, node );
3006 if (delType == ADDRTREE_DEL_DATA &&
3007 ds->interface && ds->interface->type == ADDR_IF_BOOK)
3008 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
3010 /* Remove data source. */
3011 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3012 addrindex_free_datasource( ds );
3017 /* Get reference to cache */
3018 adbase = ( AddrBookBase * ) ds->rawDataSource;
3019 if( adbase == NULL ) return;
3020 cache = adbase->addressCache;
3022 /* Remove query results folder */
3023 if( iface && iface->externalQuery ) {
3024 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3025 ItemFolder *folder = adapter->itemFolder;
3027 adapter->itemFolder = NULL;
3029 g_print( "remove folder for ::%s::\n", obj->name );
3030 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3031 g_print( "-------------- remove results\n" );
3033 addrindex_remove_results( ds, folder );
3034 /* g_print( "-------------- remove node\n" ); */
3035 gtk_cmctree_remove_node( ctree, node );
3039 /* Code below is valid for regular address book deletion */
3040 if( obj->type == ADDR_ITEM_FOLDER ) {
3041 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3042 ItemFolder *item = adapter->itemFolder;
3044 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3045 /* Remove folder only */
3046 item = addrcache_remove_folder( cache, item );
3048 addritem_free_item_folder( item );
3049 addressbook_move_nodes_up( ctree, node );
3053 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3054 /* Remove folder and addresses */
3055 item = addrcache_remove_folder_delete( cache, item );
3057 addritem_free_item_folder( item );
3062 else if( obj->type == ADDR_ITEM_GROUP ) {
3063 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3064 ItemGroup *item = adapter->itemGroup;
3066 item = addrcache_remove_group( cache, item );
3068 addritem_free_item_group( item );
3075 gtk_cmctree_remove_node(ctree, node );
3079 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3081 if( person && addrbook.treeSelected == addrbook.opened ) {
3082 person->status = ADD_ENTRY;
3083 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3084 addressbook_folder_refresh_one_person(
3085 GTK_CMCTREE(addrbook.clist), person );
3087 addressbook_address_list_set_focus();
3090 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3092 if( person && addrbook.treeSelected == addrbook.opened) {
3093 person->status = ADD_ENTRY;
3094 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3095 addressbook_set_clist(
3096 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3100 addressbook_address_list_set_focus();
3104 * Label (a format string) that is used to name each folder.
3106 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3109 * Search ctree widget callback function.
3110 * \param pA Pointer to node.
3111 * \param pB Pointer to data item being sought.
3112 * \return Zero (0) if folder found.
3114 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3117 aoA = ( AddressObject * ) pA;
3118 if( aoA->type == ADDR_ITEM_FOLDER ) {
3119 ItemFolder *folder, *fld;
3121 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3122 folder = ( ItemFolder * ) pB;
3123 if( fld == folder ) return 0; /* Found folder */
3128 static ItemFolder * addressbook_setup_subf(
3129 AddressDataSource *ds, gchar *title,
3130 GtkCMCTreeNode *pNode )
3132 AddrBookBase *adbase;
3133 AddressCache *cache;
3136 GtkCMCTreeNode *nNode;
3138 AddressObjectType aoType = ADDR_NONE;
3141 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3143 if( ds && ds->type == ADDR_IF_LDAP ) {
3145 aoType = ADDR_LDAP_QUERY;
3152 ctree = GTK_CMCTREE(addrbook.ctree);
3153 /* Get reference to address cache */
3154 adbase = ( AddrBookBase * ) ds->rawDataSource;
3155 cache = adbase->addressCache;
3157 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3158 GList *cur = children;
3159 for (; cur; cur = cur->next) {
3160 ItemFolder *child = (ItemFolder *) cur->data;
3161 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3162 nNode = gtk_cmctree_find_by_row_data_custom(
3164 addressbook_treenode_find_folder_cb );
3166 addrindex_remove_results( ds, child );
3167 while( child->listPerson ) {
3168 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3169 item = addrcache_remove_person( cache, item );
3171 addritem_free_item_person( item );
3175 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3176 addrbook.treeSelected = nNode;
3183 /* Create a folder */
3184 folder = addrcache_add_new_folder( cache, NULL );
3185 name = g_strdup_printf( "%s", title );
3186 addritem_folder_set_name( folder, name );
3187 addritem_folder_set_remarks( folder, "" );
3190 /* Now let's see the folder */
3191 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3192 gtk_cmctree_expand( ctree, pNode );
3194 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3195 addrbook.treeSelected = nNode;
3201 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3202 AddressObject *pobj = NULL;
3203 AddressDataSource *ds = NULL;
3204 AddressBookFile *abf = NULL;
3205 debug_print("adding address\n");
3206 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3207 if( pobj == NULL ) {
3208 debug_print("no row data\n");
3211 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3213 debug_print("no datasource\n");
3217 abf = ds->rawDataSource;
3219 g_print("no addressbook file\n");
3223 if( pobj->type == ADDR_DATASOURCE ) {
3224 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3225 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3227 ItemFolder *folder = NULL;
3229 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3230 GtkCMCTreeNode *parentNode;
3231 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3232 if( ds == NULL ) return;
3234 /* We must have a datasource that is an external interface */
3235 if( ! ds->interface->haveLibrary ) return;
3236 if( ! ds->interface->externalQuery ) return;
3238 if( pobj->type == ADDR_ITEM_FOLDER ) {
3239 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3242 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3244 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3246 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3248 abf = ds->rawDataSource;
3251 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3252 addrbook.editaddress_vbox,
3253 addressbook_new_address_from_book_post_cb,
3256 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3257 LdapServer *server = ds->rawDataSource;
3258 ldapsvr_set_modified(server, TRUE);
3259 ldapsvr_update_book(server, NULL);
3260 if (server->retVal != LDAPRC_SUCCESS) {
3261 alertpanel( _("Add address(es)"),
3262 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3263 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3264 server->retVal = LDAPRC_SUCCESS;
3269 if (prefs_common.addressbook_use_editaddress_dialog)
3270 addressbook_new_address_from_book_post_cb( person );
3273 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3275 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3278 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3279 GtkCMCTreeNode *parentNode;
3280 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3281 if( ds == NULL ) return;
3283 /* We must have a datasource that is an external interface */
3284 if( ! ds->interface->haveLibrary ) return;
3285 if( ! ds->interface->externalQuery ) return;
3287 if( pobj->type == ADDR_ITEM_FOLDER ) {
3288 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3291 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3293 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3297 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3299 abf = ds->rawDataSource;
3302 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3303 addrbook.editaddress_vbox,
3304 addressbook_new_address_from_folder_post_cb,
3307 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3308 LdapServer *server = ds->rawDataSource;
3309 ldapsvr_set_modified(server, TRUE);
3310 ldapsvr_update_book(server, NULL);
3311 if (server->retVal != LDAPRC_SUCCESS) {
3312 alertpanel( _("Add address(es)"),
3313 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3314 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3319 if (prefs_common.addressbook_use_editaddress_dialog)
3320 addressbook_new_address_from_folder_post_cb( person );
3322 else if( pobj->type == ADDR_ITEM_GROUP ) {
3323 /* New address in group */
3324 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3325 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3326 if (addrbook.treeSelected == addrbook.opened) {
3327 /* Change node name in tree. */
3328 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3329 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3330 addressbook_set_clist(
3331 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3339 * Search for specified child group node in address index tree.
3340 * \param parent Parent node.
3341 * \param group Group to find.
3343 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3344 GtkCMCTreeNode *node = NULL;
3345 GtkCMCTreeRow *currRow;
3347 currRow = GTK_CMCTREE_ROW( parent );
3349 node = currRow->children;
3353 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3354 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3355 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3356 if( g == group ) return node;
3358 currRow = GTK_CMCTREE_ROW(node);
3359 node = currRow->sibling;
3365 static AddressBookFile *addressbook_get_book_file() {
3366 AddressBookFile *abf = NULL;
3367 AddressDataSource *ds = NULL;
3369 ds = addressbook_find_datasource( addrbook.treeSelected );
3370 if( ds == NULL ) return NULL;
3371 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3375 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3376 GtkCMCTreeNode *node;
3379 /* Remove existing folders and groups */
3380 row = GTK_CMCTREE_ROW( parent );
3382 while( (node = row->children) ) {
3383 gtk_cmctree_remove_node( ctree, node );
3388 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3389 GtkCMCTreeNode *parent, *child;
3390 GtkCMCTreeRow *currRow;
3391 currRow = GTK_CMCTREE_ROW( node );
3393 parent = currRow->parent;
3394 while( (child = currRow->children) ) {
3395 gtk_cmctree_move( ctree, child, parent, node );
3397 gtk_sctree_sort_node( ctree, parent );
3401 static void addressbook_edit_address_post_cb( ItemPerson *person )
3405 AddressBookFile *abf = addressbook_get_book_file();
3407 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3408 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3409 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3412 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3413 invalidate_address_completion();
3415 addressbook_address_list_set_focus();
3418 void addressbook_address_list_set_focus( void )
3420 if (!prefs_common.addressbook_use_editaddress_dialog) {
3421 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3422 addressbook_list_menu_setup();
3426 void addressbook_address_list_disable_some_actions(void)
3428 /* disable address copy/pasting when editing contact's detail (embedded form) */
3429 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3430 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3431 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3434 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3435 addressbook_edit_address(data, 0, NULL, TRUE);
3438 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3439 gboolean force_focus ) {
3440 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3442 AddressObject *obj = NULL, *pobj = NULL;
3443 AddressDataSource *ds = NULL;
3444 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3446 AddressBookFile *abf = NULL;
3448 if( addrbook.listSelected == NULL ) return;
3449 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3450 cm_return_if_fail(obj != NULL);
3452 ctree = GTK_CMCTREE( addrbook.ctree );
3453 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3455 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3456 if( ds == NULL ) return;
3458 abf = addressbook_get_book_file();
3460 if( obj->type == ADDR_ITEM_EMAIL ) {
3461 ItemEMail *email = ( ItemEMail * ) obj;
3463 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3464 /* Edit parent group */
3465 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3466 ItemGroup *itemGrp = adapter->itemGroup;
3467 if( abf == NULL ) return;
3468 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3469 name = ADDRITEM_NAME(itemGrp);
3470 node = addrbook.treeSelected;
3471 parentNode = GTK_CMCTREE_ROW(node)->parent;
3474 /* Edit person - email page */
3476 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3477 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3478 addressbook_edit_address_post_cb,
3479 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3482 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3483 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3484 person->status = UPDATE_ENTRY;
3487 if (prefs_common.addressbook_use_editaddress_dialog)
3488 addressbook_edit_address_post_cb( person );
3493 else if( obj->type == ADDR_ITEM_PERSON ) {
3494 /* Edit person - basic page */
3495 ItemPerson *person = ( ItemPerson * ) obj;
3496 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3497 addressbook_edit_address_post_cb,
3498 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3501 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3502 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3503 person->status = UPDATE_ENTRY;
3506 if (prefs_common.addressbook_use_editaddress_dialog)
3507 addressbook_edit_address_post_cb( person );
3511 else if( obj->type == ADDR_ITEM_GROUP ) {
3512 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3513 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3514 parentNode = addrbook.treeSelected;
3515 node = addressbook_find_group_node( parentNode, itemGrp );
3516 name = ADDRITEM_NAME(itemGrp);
3517 invalidate_address_completion();
3523 /* Update tree node with node name */
3524 if( node == NULL ) return;
3525 addressbook_change_node_name( node, name );
3526 gtk_sctree_sort_node( ctree, parentNode );
3527 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3528 addressbook_set_clist(
3529 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3534 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3536 addressbook_del_clicked(NULL, NULL);
3539 static void close_cb(GtkAction *action, gpointer data)
3541 addressbook_close();
3544 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3545 addressbook_export_to_file();
3548 static void addressbook_person_expand_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, TRUE );
3555 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3557 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3558 if( person ) addritem_person_set_opened( person, FALSE );
3562 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3564 gchar *eMailAlias = ADDRITEM_NAME(email);
3565 if( eMailAlias && *eMailAlias != '\0' ) {
3567 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3570 str = g_strdup( eMailAlias );
3576 static gboolean addressbook_match_item(const gchar *name,
3577 const gchar *email_alias,
3579 const gchar *remarks,
3584 if (!str || str[0] == '\0')
3586 if (strcasestr(name, str))
3588 else if (email_alias && strcasestr(email_alias, str))
3590 else if (addr && strcasestr(addr, str))
3592 else if (remarks && strcasestr(remarks, str))
3598 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3599 GList *items = itemGroup->listEMail;
3600 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3601 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3602 for( ; items != NULL; items = g_list_next( items ) ) {
3603 GtkCMCTreeNode *nodeEMail = NULL;
3604 gchar *text[N_LIST_COLS];
3605 ItemEMail *email = items->data;
3609 if( ! email ) continue;
3611 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3613 if( !addressbook_match_item(ADDRITEM_NAME(person),
3614 ADDRITEM_NAME(email),
3615 email->address, email->remarks,
3619 str = addressbook_format_item_clist( person, email );
3621 text[COL_NAME] = addressbook_set_col_name_guard(str);
3624 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3626 text[COL_ADDRESS] = email->address;
3627 text[COL_REMARKS] = email->remarks;
3628 nodeEMail = gtk_sctree_insert_node(
3630 text, FOLDER_SPACING,
3634 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3640 gchar *addressbook_set_col_name_guard(gchar *value)
3642 gchar *ret = "<not set>";
3643 gchar *tmp = g_strdup(value);
3645 if (tmp !=NULL && *tmp != '\0')
3651 static void addressbook_folder_load_one_person(
3652 GtkCMCTree *clist, ItemPerson *person,
3653 AddressTypeControlItem *atci,
3654 AddressTypeControlItem *atciMail )
3656 GtkCMCTreeNode *nodePerson = NULL;
3657 GtkCMCTreeNode *nodeEMail = NULL;
3658 gchar *text[N_LIST_COLS];
3659 gboolean flgFirst = TRUE, haveAddr = FALSE;
3662 AddressBookFile *abf = addressbook_get_book_file();
3665 if( person == NULL ) return;
3667 text[COL_NAME] = "";
3668 node = person->listEMail;
3670 ItemEMail *email = node->data;
3671 gchar *eMailAddr = NULL;
3672 node = g_list_next( node );
3674 text[COL_ADDRESS] = email->address;
3675 text[COL_REMARKS] = email->remarks;
3676 eMailAddr = ADDRITEM_NAME(email);
3677 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3679 /* First email belongs with person */
3680 gchar *str = addressbook_format_item_clist( person, email );
3682 text[COL_NAME] = addressbook_set_col_name_guard(str);
3685 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3686 person && person->nickName ) {
3687 if (person->nickName) {
3688 if (strcmp(person->nickName, "") != 0) {
3689 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3692 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3698 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3700 nodePerson = gtk_sctree_insert_node(
3702 text, FOLDER_SPACING,
3705 FALSE, person->isOpened );
3708 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3711 /* Subsequent email is a child node of person */
3712 text[COL_NAME] = ADDRITEM_NAME(email);
3713 nodeEMail = gtk_sctree_insert_node(
3714 clist, nodePerson, NULL,
3715 text, FOLDER_SPACING,
3717 atciMail->iconXpmOpen,
3719 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3725 /* Have name without EMail */
3726 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3727 text[COL_ADDRESS] = "";
3728 text[COL_REMARKS] = "";
3729 nodePerson = gtk_sctree_insert_node(
3731 text, FOLDER_SPACING,
3734 FALSE, person->isOpened );
3735 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3740 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3742 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3743 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3744 const gchar *search_str;
3746 if( atci == NULL ) return;
3747 if( atciMail == NULL ) return;
3749 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3751 /* Load email addresses */
3752 items = addritem_folder_get_person_list( itemFolder );
3753 for(cur = items ; cur != NULL; cur = g_list_next( cur ) ) {
3758 person = (ItemPerson *)cur->data;
3761 node = person->listEMail;
3762 if (node && node->data) {
3764 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3767 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3771 addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
3773 /* Free up the list */
3774 mgu_clear_list( items );
3775 g_list_free( items );
3778 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3779 addrbook.listSelected = NULL;
3780 gtk_cmctree_remove_node( clist, node );
3781 addressbook_menubar_set_sensitive( FALSE );
3782 addressbook_menuitem_set_sensitive(
3783 gtk_cmctree_node_get_row_data(
3784 GTK_CMCTREE(clist), addrbook.treeSelected ),
3785 addrbook.treeSelected );
3788 void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3789 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3790 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3791 GtkCMCTreeNode *node;
3792 if( atci == NULL ) return;
3793 if( atciMail == NULL ) return;
3794 if( person == NULL ) return;
3795 /* unload the person */
3797 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3799 addressbook_folder_remove_node( clist, node );
3800 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3801 gtk_sctree_sort_node( clist, NULL );
3802 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3804 gtk_sctree_select( GTK_SCTREE(clist), node );
3805 if (!gtk_cmctree_node_is_visible( clist, node ) )
3806 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3810 void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3811 GtkCMCTreeNode *node;
3813 if( person == NULL ) return;
3814 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3816 addressbook_folder_remove_node( clist, node );
3820 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3822 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3823 const gchar *search_str;
3825 /* Load any groups */
3826 if( ! atci ) return;
3828 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3830 items = addritem_folder_get_group_list( itemFolder );
3831 for( ; items != NULL; items = g_list_next( items ) ) {
3832 GtkCMCTreeNode *nodeGroup = NULL;
3833 gchar *text[N_LIST_COLS];
3834 ItemGroup *group = items->data;
3835 if( group == NULL ) continue;
3836 if( !addressbook_match_item(ADDRITEM_NAME(group),
3837 NULL, NULL, NULL, search_str) )
3840 text[COL_NAME] = ADDRITEM_NAME(group);
3841 text[COL_ADDRESS] = "";
3842 text[COL_REMARKS] = "";
3843 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3844 text, FOLDER_SPACING,
3848 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3849 gtk_sctree_sort_node(clist, NULL);
3851 /* Free up the list */
3852 mgu_clear_list( items );
3853 g_list_free( items );
3857 * Search ctree widget callback function.
3858 * \param pA Pointer to node.
3859 * \param pB Pointer to data item being sought.
3860 * \return Zero (0) if group found.
3862 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3865 aoA = ( AddressObject * ) pA;
3866 if( aoA->type == ADDR_ITEM_GROUP ) {
3867 ItemGroup *group, *grp;
3869 grp = ADAPTER_GROUP(aoA)->itemGroup;
3870 group = ( ItemGroup * ) pB;
3871 if( grp == group ) return 0; /* Found group */
3877 * Remove folder and group nodes from tree widget for items contained ("cut")
3880 static void addressbook_treenode_remove_item( void ) {
3882 AddrSelectItem *cutItem;
3883 AddressCache *cache;
3884 AddrItemObject *aio;
3885 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3888 node = _clipBoard_->objectList;
3890 cutItem = node->data;
3891 node = g_list_next( node );
3892 cache = addrindex_get_cache(
3893 _clipBoard_->addressIndex, cutItem->cacheID );
3894 if( cache == NULL ) continue;
3895 aio = addrcache_get_object( cache, cutItem->uid );
3898 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3901 folder = ( ItemFolder * ) aio;
3902 tn = gtk_cmctree_find_by_row_data_custom(
3903 ctree, NULL, folder,
3904 addressbook_treenode_find_folder_cb );
3906 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3909 group = ( ItemGroup * ) aio;
3910 tn = gtk_cmctree_find_by_row_data_custom(
3912 addressbook_treenode_find_group_cb );
3916 /* Free up adapter and remove node. */
3917 gtk_cmctree_remove_node( ctree, tn );
3924 * Find parent datasource for specified tree node.
3925 * \param node Node to test.
3926 * \return Data source, or NULL if not found.
3928 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3929 AddressDataSource *ds = NULL;
3932 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3935 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3936 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3938 /* g_print( "ao->type = %d\n", ao->type ); */
3939 if( ao->type == ADDR_DATASOURCE ) {
3940 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3941 /* g_print( "found it\n" ); */
3942 ds = ads->dataSource;
3946 node = GTK_CMCTREE_ROW(node)->parent;
3952 * Load address list widget with children of specified object.
3953 * \param obj Parent object to be loaded.
3955 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3956 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3957 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3958 AddressDataSource *ds = NULL;
3959 AdapterDSource *ads = NULL;
3960 static AddressObject *last_obj = NULL;
3962 if (addrbook.clist == NULL) {
3965 if (obj == last_obj && !refresh)
3970 gtk_cmclist_clear(clist);
3974 if( obj->type == ADDR_INTERFACE ) {
3975 /* g_print( "set_clist: loading datasource...\n" ); */
3976 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3980 gtk_cmclist_freeze(clist);
3981 gtk_cmclist_clear(clist);
3983 if( obj->type == ADDR_DATASOURCE ) {
3984 ads = ADAPTER_DSOURCE(obj);
3985 ds = ads->dataSource;
3987 /* Load root folder */
3988 ItemFolder *rootFolder = NULL;
3989 rootFolder = addrindex_ds_get_root_folder( ds );
3990 addressbook_folder_load_person(
3991 ctreelist, rootFolder );
3992 addressbook_folder_load_group(
3993 ctreelist, rootFolder );
3997 if( obj->type == ADDR_ITEM_GROUP ) {
3999 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
4000 addressbook_load_group( ctreelist, itemGroup );
4002 else if( obj->type == ADDR_ITEM_FOLDER ) {
4004 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
4005 addressbook_folder_load_person( ctreelist, itemFolder );
4006 addressbook_folder_load_group( ctreelist, itemFolder );
4009 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
4010 clist->focus_row = -1;
4011 gtk_cmclist_thaw(clist);
4015 * Call back function to free adaptor. Call back is setup by function
4016 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4017 * called when the address book tree widget node is removed by calling
4018 * function gtk_cmctree_remove_node().
4020 * \param data Tree node's row data.
4022 static void addressbook_free_treenode( gpointer data ) {
4025 ao = ( AddressObject * ) data;
4026 if( ao == NULL ) return;
4027 if( ao->type == ADDR_INTERFACE ) {
4028 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
4029 addrbookctl_free_interface( ai );
4031 else if( ao->type == ADDR_DATASOURCE ) {
4032 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
4033 addrbookctl_free_datasource( ads );
4035 else if( ao->type == ADDR_ITEM_FOLDER ) {
4036 AdapterFolder *af = ADAPTER_FOLDER(ao);
4037 addrbookctl_free_folder( af );
4039 else if( ao->type == ADDR_ITEM_GROUP ) {
4040 AdapterGroup *ag = ADAPTER_GROUP(ao);
4041 addrbookctl_free_group( ag );
4046 * Create new adaptor for specified data source.
4048 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4049 AddressObjectType otype, gchar *name )
4051 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4052 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4053 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4054 adapter->dataSource = ds;
4055 adapter->subType = otype;
4059 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4060 ADDRESS_OBJECT_NAME(adapter) =
4061 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4065 * Load tree from address index with the initial data.
4067 static void addressbook_load_tree( void ) {
4068 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4069 GList *nodeIf, *nodeDS;
4070 AdapterInterface *adapter;
4071 AddressInterface *iface;
4072 AddressTypeControlItem *atci;
4073 AddressDataSource *ds;
4074 AdapterDSource *ads;
4075 GtkCMCTreeNode *node, *newNode;
4078 nodeIf = _addressInterfaceList_;
4080 adapter = nodeIf->data;
4081 node = adapter->treeNode;
4082 iface = adapter->interface;
4083 atci = adapter->atci;
4085 if( iface->useInterface ) {
4086 /* Load data sources below interface node */
4087 nodeDS = iface->listSource;
4090 name = addrindex_ds_get_name( ds );
4091 ads = addressbook_create_ds_adapter(
4092 ds, atci->objectType, name );
4093 newNode = addressbook_add_object(
4094 node, ADDRESS_OBJECT(ads) );
4095 if (newNode == NULL) {
4096 g_message("error adding addressbook object\n");
4098 nodeDS = g_list_next( nodeDS );
4100 gtk_cmctree_expand( ctree, node );
4103 nodeIf = g_list_next( nodeIf );
4108 * Convert the old address book to new format.
4110 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4111 gboolean retVal = FALSE;
4112 gboolean errFlag = TRUE;
4115 /* Read old address book, performing conversion */
4116 debug_print( "Reading and converting old address book...\n" );
4117 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4118 addrindex_read_data( addrIndex );
4119 if( addrIndex->retVal == MGU_NO_FILE ) {
4120 /* We do not have a file - new user */
4121 debug_print( "New user... create new books...\n" );
4122 addrindex_create_new_books( addrIndex );
4123 if( addrIndex->retVal == MGU_SUCCESS ) {
4124 /* Save index file */
4125 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4126 addrindex_save_data( addrIndex );
4127 if( addrIndex->retVal == MGU_SUCCESS ) {
4132 msg = _( "New user, could not save index file." );
4136 msg = _( "New user, could not save address book files." );
4140 /* We have an old file */
4141 if( addrIndex->wasConverted ) {
4142 /* Converted successfully - save address index */
4143 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4144 addrindex_save_data( addrIndex );
4145 if( addrIndex->retVal == MGU_SUCCESS ) {
4146 msg = _( "Old address book converted successfully." );
4151 msg = _("Old address book converted,\n"
4152 "could not save new address index file." );
4156 /* File conversion failed - just create new books */
4157 debug_print( "File conversion failed... just create new books...\n" );
4158 addrindex_create_new_books( addrIndex );
4159 if( addrIndex->retVal == MGU_SUCCESS ) {
4161 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4162 addrindex_save_data( addrIndex );
4163 if( addrIndex->retVal == MGU_SUCCESS ) {
4164 msg = _("Could not convert address book,\n"
4165 "but created empty new address book files." );
4170 msg = _("Could not convert address book,\n"
4171 "could not save new address index file." );
4175 msg = _("Could not convert address book\n"
4176 "and could not create new address book files." );
4181 debug_print( "Error\n%s\n", msg );
4182 alertpanel_full(_("Addressbook conversion error"), msg,
4183 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4187 debug_print( "Warning\n%s\n", msg );
4188 alertpanel_full(_("Addressbook conversion error"), msg,
4189 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4190 NULL, ALERT_WARNING);
4196 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4200 gboolean failed = FALSE;
4201 GError *error = NULL;
4203 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4204 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4205 error->code, error->message);
4206 g_error_free(error);
4210 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4211 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4214 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4216 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4218 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4231 /* all copies succeeded, we can remove source files */
4232 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4233 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4234 error->code, error->message);
4235 g_error_free(error);
4238 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4239 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4242 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4244 claws_unlink(orig_file);
4254 void addressbook_read_file( void ) {
4255 AddressIndex *addrIndex = NULL;
4256 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4258 debug_print( "Reading address index...\n" );
4259 if( _addressIndex_ ) {
4260 debug_print( "address book already read!!!\n" );
4265 addrIndex = addrindex_create_index();
4266 addrindex_initialize();
4268 /* Use new address book index. */
4270 if ( !is_dir_exist(indexdir) ) {
4271 if ( make_dir(indexdir) < 0 ) {
4272 addrindex_set_file_path( addrIndex, get_rc_dir() );
4273 g_warning( "couldn't create dir '%s'", indexdir);
4275 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4276 remove_dir_recursive(indexdir);
4277 addrindex_set_file_path( addrIndex, get_rc_dir() );
4278 g_error("couldn't migrate dir %s", indexdir);
4280 addrindex_set_file_path( addrIndex, indexdir);
4284 addrindex_set_file_path( addrIndex, indexdir);
4287 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4288 addrindex_read_data( addrIndex );
4289 if( addrIndex->retVal == MGU_NO_FILE ) {
4290 /* Conversion required */
4291 debug_print( "Converting...\n" );
4292 if( addressbook_convert( addrIndex ) ) {
4293 _addressIndex_ = addrIndex;
4296 else if( addrIndex->retVal == MGU_SUCCESS ) {
4297 _addressIndex_ = addrIndex;
4300 /* Error reading address book */
4301 debug_print( "Could not read address index.\n" );
4302 addrindex_print_index( addrIndex, stdout );
4303 alertpanel_full(_("Addressbook Error"),
4304 _("Could not read address index"),
4305 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4308 debug_print( "done.\n" );
4312 * Add object into the address index tree widget.
4313 * Enter: node Parent node.
4314 * obj Object to add.
4315 * Return: Node that was added, or NULL if object not added.
4317 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4320 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4321 GtkCMCTreeNode *added;
4322 AddressObject *pobj;
4323 AddressObjectType otype;
4324 AddressTypeControlItem *atci = NULL;
4326 cm_return_val_if_fail(node != NULL, NULL);
4327 cm_return_val_if_fail(obj != NULL, NULL);
4329 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4330 cm_return_val_if_fail(pobj != NULL, NULL);
4332 /* Determine object type to be displayed */
4333 if( obj->type == ADDR_DATASOURCE ) {
4334 otype = ADAPTER_DSOURCE(obj)->subType;
4340 /* Handle any special conditions. */
4342 atci = addrbookctl_lookup( otype );
4344 if( atci->showInTree ) {
4345 /* Add object to tree */
4348 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4349 atci->iconXpm, atci->iconXpmOpen,
4350 atci->treeLeaf, atci->treeExpand );
4351 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4352 addressbook_free_treenode );
4356 gtk_sctree_sort_node(ctree, node);
4362 * Add group into the address index tree.
4363 * \param node Parent node.
4364 * \param ds Data source.
4365 * \param itemGroup Group to add.
4366 * \return Inserted node.
4368 static GtkCMCTreeNode *addressbook_node_add_group(
4369 GtkCMCTreeNode *node, AddressDataSource *ds,
4370 ItemGroup *itemGroup )
4372 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4373 GtkCMCTreeNode *newNode;
4374 AdapterGroup *adapter;
4375 AddressTypeControlItem *atci = NULL;
4378 if( ds == NULL ) return NULL;
4379 if( node == NULL || itemGroup == NULL ) return NULL;
4381 name = &itemGroup->obj.name;
4383 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4385 adapter = g_new0( AdapterGroup, 1 );
4386 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4387 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4388 adapter->itemGroup = itemGroup;
4390 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4391 atci->iconXpm, atci->iconXpm,
4392 atci->treeLeaf, atci->treeExpand );
4393 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4394 addressbook_free_treenode );
4395 gtk_sctree_sort_node( ctree, node );
4400 * Add folder into the address index tree. Only visible folders are loaded into
4401 * the address index tree. Note that the root folder is not inserted into the
4404 * \param node Parent node.
4405 * \param ds Data source.
4406 * \param itemFolder Folder to add.
4407 * \param otype Object type to display.
4408 * \return Inserted node for the folder.
4410 static GtkCMCTreeNode *addressbook_node_add_folder(
4411 GtkCMCTreeNode *node, AddressDataSource *ds,
4412 ItemFolder *itemFolder, AddressObjectType otype )
4414 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4415 GtkCMCTreeNode *newNode = NULL;
4416 AdapterFolder *adapter;
4417 AddressTypeControlItem *atci = NULL;
4418 GList *listItems = NULL;
4420 ItemFolder *rootFolder;
4422 /* Only visible folders */
4423 if( itemFolder == NULL || itemFolder->isHidden )
4428 if( node == NULL || itemFolder == NULL )
4431 /* Determine object type */
4432 atci = addrbookctl_lookup( otype );
4436 rootFolder = addrindex_ds_get_root_folder( ds );
4437 if( itemFolder == rootFolder ) {
4441 adapter = g_new0( AdapterFolder, 1 );
4442 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4443 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4444 adapter->itemFolder = itemFolder;
4446 name = ADDRITEM_NAME(itemFolder);
4447 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4448 atci->iconXpm, atci->iconXpm,
4449 atci->treeLeaf, atci->treeExpand );
4451 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4452 addressbook_free_treenode );
4456 listItems = itemFolder->listFolder;
4457 while( listItems ) {
4458 ItemFolder *item = listItems->data;
4459 addressbook_node_add_folder( newNode, ds, item, otype );
4460 listItems = g_list_next( listItems );
4462 listItems = itemFolder->listGroup;
4463 while( listItems ) {
4464 ItemGroup *item = listItems->data;
4465 addressbook_node_add_group( newNode, ds, item );
4466 listItems = g_list_next( listItems );
4468 gtk_sctree_sort_node( ctree, node );
4472 void addressbook_export_to_file( void ) {
4473 if( _addressIndex_ ) {
4474 /* Save all new address book data */
4475 debug_print( "Saving address books...\n" );
4476 addrindex_save_all_books( _addressIndex_ );
4478 debug_print( "Exporting addressbook to file...\n" );
4479 addrindex_save_data( _addressIndex_ );
4480 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4481 addrindex_print_index( _addressIndex_, stdout );
4484 /* Notify address completion of new data */
4485 invalidate_address_completion();
4489 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4491 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4492 addressbook_lup_clicked(NULL, NULL);
4497 * Comparison using cell contents (text in first column). Used for sort
4498 * address index widget.
4500 static gint addressbook_treenode_compare_func(
4501 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4503 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4504 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4505 gchar *name1 = NULL, *name2 = NULL;
4506 if( cell1 ) name1 = cell1->u.text;
4507 if( cell2 ) name2 = cell2->u.text;
4508 if( ! name1 ) return ( name2 != NULL );
4509 if( ! name2 ) return -1;
4510 return g_utf8_collate( name1, name2 );
4513 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4514 AdapterDSource *ads;
4515 AdapterInterface *adapter;
4516 GtkCMCTreeNode *newNode;
4518 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4519 if( adapter == NULL ) return;
4520 ads = addressbook_edit_book( _addressIndex_, NULL );
4522 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4524 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4525 addrbook.treeSelected = newNode;
4530 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4531 AdapterDSource *ads;
4532 AdapterInterface *adapter;
4533 GtkCMCTreeNode *newNode;
4535 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4536 if( adapter == NULL ) return;
4537 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4539 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4541 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4542 addrbook.treeSelected = newNode;
4548 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4549 AdapterDSource *ads;
4550 AdapterInterface *adapter;
4551 AddressInterface *iface;
4552 GtkCMCTreeNode *newNode;
4554 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4555 if( adapter == NULL ) return;
4556 iface = adapter->interface;
4557 if( ! iface->haveLibrary ) return;
4558 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4560 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4562 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4563 addrbook.treeSelected = newNode;
4570 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4571 AdapterDSource *ads;
4572 AdapterInterface *adapter;
4573 AddressInterface *iface;
4574 GtkCMCTreeNode *newNode;
4576 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4577 if( adapter == NULL ) return;
4578 iface = adapter->interface;
4579 if( ! iface->haveLibrary ) return;
4580 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4582 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4584 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4585 addrbook.treeSelected = newNode;
4592 * Display address search status message.
4593 * \param queryType Query type.
4594 * \param status Status/Error code.
4596 static void addressbook_search_message( gint queryType, gint sts ) {
4598 *addressbook_msgbuf = '\0';
4600 if( sts != MGU_SUCCESS ) {
4601 if( queryType == ADDRQUERY_LDAP ) {
4603 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4608 g_snprintf( addressbook_msgbuf,
4609 sizeof(addressbook_msgbuf), "%s", desc );
4610 addressbook_status_show( addressbook_msgbuf );
4613 addressbook_status_show( "" );
4618 * Refresh addressbook by forcing refresh of current selected object in
4621 static void addressbook_refresh_current( void ) {
4625 ctree = GTK_CMCTREE(addrbook.ctree);
4626 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4627 if( obj == NULL ) return;
4628 addressbook_set_clist( obj, TRUE );
4632 * Message that is displayed whilst a query is executing in a background
4635 static gchar *_tempMessage_ = N_( "Busy searching..." );
4638 * Address search idle function. This function is called during UI idle time
4639 * while a search is in progress.
4641 * \param data Idler data.
4643 static void addressbook_search_idle( gpointer data ) {
4647 queryID = GPOINTER_TO_INT( data );
4648 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4653 * Search completion callback function. This removes the query from the idle
4656 * \param sender Sender of query.
4657 * \param queryID Query ID of search request.
4658 * \param status Search status.
4659 * \param data Query data.
4661 static void addressbook_search_callback_end(
4662 gpointer sender, gint queryID, gint status, gpointer data )
4666 AddrQueryObject *aqo;
4668 /* Remove idler function */
4669 ptrQID = GINT_TO_POINTER( queryID );
4671 g_idle_remove_by_data( ptrQID );
4674 /* Refresh addressbook contents */
4675 addressbook_refresh_current();
4676 req = qrymgr_find_request( queryID );
4678 aqo = ( AddrQueryObject * ) req->queryList->data;
4679 addressbook_search_message( aqo->queryType, status );
4682 /* Stop the search */
4683 addrindex_stop_search( queryID );
4689 * \param ds Data source to search.
4690 * \param searchTerm String to lookup.
4691 * \param pNode Parent data source node.
4693 static void addressbook_perform_search(
4694 AddressDataSource *ds, gchar *searchTerm,
4695 GtkCMCTreeNode *pNode )
4703 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4705 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4707 /* Create a folder for the search results */
4708 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4709 folder = addressbook_setup_subf(ds, name, pNode);
4712 /* Setup the search */
4713 queryID = addrindex_setup_explicit_search(
4714 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4715 if( queryID == 0 ) return;
4717 /* Set up idler function */
4718 idleID = g_idle_add(
4719 (GSourceFunc) addressbook_search_idle,
4720 GINT_TO_POINTER( queryID ) );
4722 g_message("error adding addressbook_search_idle\n");
4725 /* Start search, sit back and wait for something to happen */
4726 addrindex_start_search( queryID );
4728 addressbook_status_show( _tempMessage_ );
4732 * Lookup button handler. Address search is only performed against
4733 * address interfaces for external queries.
4735 * \param button Lookup button widget.
4736 * \param data Data object.
4738 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4741 AddressDataSource *ds;
4742 AddressInterface *iface;
4744 GtkCMCTreeNode *node, *parentNode;
4746 LdapServer *ldap_server;
4747 LdapControl *ldap_ctl;
4750 node = addrbook.treeSelected;
4751 if( ! node ) return;
4752 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4754 ctree = GTK_CMCTREE(addrbook.ctree);
4755 obj = gtk_cmctree_node_get_row_data( ctree, node );
4756 if( obj == NULL ) return;
4758 if (obj->type != ADDR_DATASOURCE ||
4759 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4760 addressbook_set_clist(
4761 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4762 addrbook.treeSelected),
4766 ds = addressbook_find_datasource( node );
4767 if( ds == NULL ) return;
4769 /* We must have a datasource that is an external interface */
4770 iface = ds->interface;
4771 if( ! iface->haveLibrary ) return;
4772 if( ! iface->externalQuery ) return;
4775 if (iface->type == ADDR_IF_LDAP) {
4776 ldap_server = ds->rawDataSource;
4777 ldap_ctl = ldap_server->control;
4778 if (ldap_ctl != NULL &&
4779 ldap_ctl->bindDN != NULL && strlen(ldap_ctl->bindDN) > 0) {
4780 #ifndef PASSWORD_CRYPTO_OLD
4781 /* LDAP server is password-protected. */
4782 if (master_passphrase() == NULL) {
4783 /* User did not enter master passphrase, do not start a search. */
4786 #endif /* PASSWORD_CRYPTO_OLD */
4789 #endif /* USE_LDAP */
4792 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4793 g_strchomp( searchTerm );
4795 if( obj->type == ADDR_ITEM_FOLDER ) {
4796 parentNode = GTK_CMCTREE_ROW(node)->parent;
4801 addressbook_perform_search( ds, searchTerm, parentNode );
4803 gtk_widget_grab_focus( addrbook.entry );
4805 g_free( searchTerm );
4808 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4809 addressbook_close();
4814 * Browse address entry for highlighted entry.
4816 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4818 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4820 AddressDataSource *ds;
4821 AddressInterface *iface;
4825 if(addrbook.listSelected == NULL)
4828 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4832 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4836 iface = ds->interface;
4837 if(!iface || !iface->haveLibrary )
4841 if (obj->type == ADDR_ITEM_EMAIL) {
4842 email = ( ItemEMail * ) obj;
4844 person = (ItemPerson *) ADDRITEM_PARENT(email);
4846 else if (obj->type == ADDR_ITEM_PERSON) {
4847 person = (ItemPerson *) obj;
4854 if( iface && iface->type == ADDR_IF_LDAP ) {
4855 browseldap_entry(ds, person->externalID);
4860 /* **********************************************************************
4861 * Build lookup tables.
4862 * ***********************************************************************
4866 * Remap object types.
4867 * Enter: abType AddressObjectType (used in tree node).
4868 * Return: ItemObjectType (used in address cache data).
4870 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4871 ItemObjectType ioType;
4874 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4875 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4876 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4877 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4878 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4879 default: ioType = ITEMTYPE_NONE; break;
4884 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4885 atci = addrbookctl_lookup(id); \
4887 atci->iconXpm = icon; \
4888 atci->iconXpmOpen = iconopen; \
4890 g_warning("can't get atci %d", id); \
4895 * Build table that controls the rendering of object types.
4897 static void addrbookctl_build_icons( GtkWidget *window ) {
4898 AddressTypeControlItem *atci;
4902 g_object_unref(interfacexpm);
4904 g_object_unref(folderxpm);
4906 g_object_unref(folderopenxpm);
4908 g_object_unref(groupxpm);
4910 g_object_unref(vcardxpm);
4912 g_object_unref(bookxpm);
4914 g_object_unref(addressxpm);
4916 g_object_unref(jpilotxpm);
4918 g_object_unref(categoryxpm);
4920 g_object_unref(ldapxpm);
4922 g_object_unref(addrsearchxpm);
4923 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4924 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4925 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4926 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4927 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4928 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4929 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4930 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4931 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4932 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4933 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4935 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4936 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4937 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4938 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4939 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4940 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4941 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4942 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4943 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4944 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4945 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4950 * Build table that controls the rendering of object types.
4952 static void addrbookctl_build_map( GtkWidget *window ) {
4953 AddressTypeControlItem *atci;
4955 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4956 _addressBookTypeList_ = NULL;
4959 atci = g_new0( AddressTypeControlItem, 1 );
4960 atci->objectType = ADDR_INTERFACE;
4961 atci->interfaceType = ADDR_IF_NONE;
4962 atci->showInTree = TRUE;
4963 atci->treeExpand = TRUE;
4964 atci->treeLeaf = FALSE;
4965 atci->displayName = _( "Interface" );
4966 atci->menuCommand = NULL;
4967 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4968 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4971 atci = g_new0( AddressTypeControlItem, 1 );
4972 atci->objectType = ADDR_BOOK;
4973 atci->interfaceType = ADDR_IF_BOOK;
4974 atci->showInTree = TRUE;
4975 atci->treeExpand = TRUE;
4976 atci->treeLeaf = FALSE;
4977 atci->displayName = _("Address Books");
4978 atci->menuCommand = "Menu/Book/NewBook";
4979 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4980 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4983 atci = g_new0( AddressTypeControlItem, 1 );
4984 atci->objectType = ADDR_ITEM_PERSON;
4985 atci->interfaceType = ADDR_IF_NONE;
4986 atci->showInTree = FALSE;
4987 atci->treeExpand = FALSE;
4988 atci->treeLeaf = FALSE;
4989 atci->displayName = _( "Person" );
4990 atci->menuCommand = NULL;
4991 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4992 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4995 atci = g_new0( AddressTypeControlItem, 1 );
4996 atci->objectType = ADDR_ITEM_EMAIL;
4997 atci->interfaceType = ADDR_IF_NONE;
4998 atci->showInTree = FALSE;
4999 atci->treeExpand = FALSE;
5000 atci->treeLeaf = TRUE;
5001 atci->displayName = _( "Email Address" );
5002 atci->menuCommand = NULL;
5003 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5004 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5007 atci = g_new0( AddressTypeControlItem, 1 );
5008 atci->objectType = ADDR_ITEM_GROUP;
5009 atci->interfaceType = ADDR_IF_BOOK;
5010 atci->showInTree = TRUE;
5011 atci->treeExpand = FALSE;
5012 atci->treeLeaf = FALSE;
5013 atci->displayName = _( "Group" );
5014 atci->menuCommand = NULL;
5015 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5016 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5019 atci = g_new0( AddressTypeControlItem, 1 );
5020 atci->objectType = ADDR_ITEM_FOLDER;
5021 atci->interfaceType = ADDR_IF_BOOK;
5022 atci->showInTree = TRUE;
5023 atci->treeExpand = FALSE;
5024 atci->treeLeaf = FALSE;
5025 atci->displayName = _( "Folder" );
5026 atci->menuCommand = NULL;
5027 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5028 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5031 atci = g_new0( AddressTypeControlItem, 1 );
5032 atci->objectType = ADDR_VCARD;
5033 atci->interfaceType = ADDR_IF_VCARD;
5034 atci->showInTree = TRUE;
5035 atci->treeExpand = TRUE;
5036 atci->treeLeaf = TRUE;
5037 atci->displayName = _( "vCard" );
5038 atci->menuCommand = "Menu/Book/NewVCard";
5039 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5040 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5043 atci = g_new0( AddressTypeControlItem, 1 );
5044 atci->objectType = ADDR_JPILOT;
5045 atci->interfaceType = ADDR_IF_JPILOT;
5046 atci->showInTree = TRUE;
5047 atci->treeExpand = TRUE;
5048 atci->treeLeaf = FALSE;
5049 atci->displayName = _( "JPilot" );
5050 atci->menuCommand = "Menu/Book/NewJPilot";
5051 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5052 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5055 atci = g_new0( AddressTypeControlItem, 1 );
5056 atci->objectType = ADDR_CATEGORY;
5057 atci->interfaceType = ADDR_IF_JPILOT;
5058 atci->showInTree = TRUE;
5059 atci->treeExpand = TRUE;
5060 atci->treeLeaf = TRUE;
5061 atci->displayName = _( "JPilot" );
5062 atci->menuCommand = NULL;
5063 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5064 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5067 atci = g_new0( AddressTypeControlItem, 1 );
5068 atci->objectType = ADDR_LDAP;
5069 atci->interfaceType = ADDR_IF_LDAP;
5070 atci->showInTree = TRUE;
5071 atci->treeExpand = TRUE;
5072 atci->treeLeaf = FALSE;
5073 atci->displayName = _( "LDAP servers" );
5074 atci->menuCommand = "Menu/Book/NewLDAPServer";
5075 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5076 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5079 atci = g_new0( AddressTypeControlItem, 1 );
5080 atci->objectType = ADDR_LDAP_QUERY;
5081 atci->interfaceType = ADDR_IF_LDAP;
5082 atci->showInTree = TRUE;
5083 atci->treeExpand = FALSE;
5084 atci->treeLeaf = TRUE;
5085 atci->displayName = _( "LDAP Query" );
5086 atci->menuCommand = NULL;
5087 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5088 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5090 addrbookctl_build_icons(window);
5093 void addressbook_reflect_prefs_pixmap_theme(void)
5095 if (addrbook.window)
5096 addrbookctl_build_icons(addrbook.window);
5100 * Search for specified object type.
5102 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5104 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5108 * Search for specified interface type.
5110 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5111 GList *node = _addressBookTypeList_;
5113 AddressTypeControlItem *atci = node->data;
5114 if( atci->interfaceType == ifType ) return atci;
5115 node = g_list_next( node );
5120 static void addrbookctl_free_address( AddressObject *obj ) {
5121 g_free( obj->name );
5122 obj->type = ADDR_NONE;
5126 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5127 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5128 adapter->interface = NULL;
5129 adapter->interfaceType = ADDR_IF_NONE;
5130 adapter->atci = NULL;
5131 adapter->enabled = FALSE;
5132 adapter->haveLibrary = FALSE;
5133 adapter->treeNode = NULL;
5137 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5138 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5139 adapter->dataSource = NULL;
5140 adapter->subType = ADDR_NONE;
5144 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5145 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5146 adapter->itemFolder = NULL;
5150 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5151 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5152 adapter->itemGroup = NULL;
5157 * Build GUI interface list.
5159 static void addrbookctl_build_iflist( void ) {
5160 AddressTypeControlItem *atci;
5161 AdapterInterface *adapter;
5164 if( _addressIndex_ == NULL ) {
5165 _addressIndex_ = addrindex_create_index();
5166 if( _clipBoard_ == NULL ) {
5167 _clipBoard_ = addrclip_create();
5169 addrclip_set_index( _clipBoard_, _addressIndex_ );
5171 _addressInterfaceList_ = NULL;
5172 list = addrindex_get_interface_list( _addressIndex_ );
5174 AddressInterface *interface = list->data;
5175 atci = addrbookctl_lookup_iface( interface->type );
5177 adapter = g_new0( AdapterInterface, 1 );
5178 adapter->interfaceType = interface->type;
5179 adapter->atci = atci;
5180 adapter->interface = interface;
5181 adapter->treeNode = NULL;
5182 adapter->enabled = TRUE;
5183 adapter->haveLibrary = interface->haveLibrary;
5184 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5185 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5186 _addressInterfaceList_ =
5187 g_list_append( _addressInterfaceList_, adapter );
5189 list = g_list_next( list );
5194 * Find GUI interface type specified interface type.
5195 * \param ifType Interface type.
5196 * \return Interface item, or NULL if not found.
5198 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5199 GList *node = _addressInterfaceList_;
5201 AdapterInterface *adapter = node->data;
5202 if( adapter->interfaceType == ifType ) return adapter;
5203 node = g_list_next( node );
5209 * Build interface list selection.
5211 static void addrbookctl_build_ifselect( void ) {
5212 GList *newList = NULL;
5217 gchar *endptr = NULL;
5218 /* gboolean enabled; */
5219 AdapterInterface *adapter;
5221 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5224 splitStr = g_strsplit( selectStr, ",", -1 );
5225 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5227 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5228 ifType = strtol( splitStr[i], &endptr, 10 );
5231 if( strcmp( endptr, "/n" ) == 0 ) {
5236 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5237 adapter = addrbookctl_find_interface( ifType );
5239 newList = g_list_append( newList, adapter );
5246 /* g_print( "i=%d\n", i ); */
5247 g_strfreev( splitStr );
5248 g_free( selectStr );
5250 /* Replace existing list */
5251 mgu_clear_list( _addressIFaceSelection_ );
5252 g_list_free( _addressIFaceSelection_ );
5253 _addressIFaceSelection_ = newList;
5257 /* ***********************************************************************
5258 * Add sender to address book.
5259 * ***********************************************************************
5263 * This function is used by the Add sender to address book function.
5265 gboolean addressbook_add_contact(
5266 const gchar *name, const gchar *address, const gchar *remarks,
5267 GdkPixbuf *picture )
5269 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5270 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5271 debug_print( "addressbook_add_contact - added\n" );
5272 addressbook_refresh();
5277 /* ***********************************************************************
5278 * Book/folder selection.
5279 * ***********************************************************************
5283 * This function is used by the matcher dialog to select a book/folder.
5285 gchar *addressbook_folder_selection( const gchar *folderpath)
5287 AddressBookFile *book = NULL;
5288 ItemFolder *folder = NULL;
5291 cm_return_val_if_fail( folderpath != NULL, NULL);
5293 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5295 if ( folder != NULL) {
5297 gchar *oldtmp = NULL;
5298 AddrItemObject *obj = NULL;
5300 /* walk thru folder->parent to build the full folder path */
5301 /* TODO: wwp: optimize this */
5303 tmp = g_strdup(obj->uid);
5304 while ( obj->parent ) {
5306 if ( obj->name != NULL ) {
5307 oldtmp = g_strdup(tmp);
5309 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5313 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5316 path = g_strdup_printf("%s", book->fileName);
5318 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5324 /* ***********************************************************************
5325 * Book/folder checking.
5326 * ***********************************************************************
5329 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5331 FolderInfo *fi = g_new0( FolderInfo, 1 );
5333 fi->folder = folder;
5337 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5338 FolderInfo *fiParent, FolderPathMatch *match )
5344 FolderPathMatch *nextmatch = NULL;
5349 list = parentFolder->listFolder;
5351 folder = list->data;
5352 fName = g_strdup( ADDRITEM_NAME(folder) );
5354 /* match folder name, match pointer will be set to NULL if next recursive call
5355 doesn't need to match subfolder name */
5356 if ( match != NULL &&
5357 match->matched == FALSE ) {
5358 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5359 /* folder name matches, prepare next subfolder match */
5360 debug_print("matched folder name '%s'\n", fName);
5362 if ( match->folder_path[match->index] == NULL ) {
5363 /* we've matched all elements */
5364 match->matched = TRUE;
5365 match->folder = folder;
5366 debug_print("book/folder path matched!\n");
5368 /* keep on matching */
5376 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5377 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5379 list = g_list_next( list );
5384 * This function is used by to check if a matcher book/folder path corresponds to an
5385 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5386 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5387 if book AND folder are NULL this means that folderpath was empty or Any.
5388 If folderpath is a simple book name (without folder), book will not be NULL and folder
5389 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5392 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5393 AddressDataSource **book,
5394 ItemFolder **folder )
5396 AddressDataSource *ds;
5397 GList *list, *nodeDS;
5398 ItemFolder *rootFolder;
5399 AddressBookFile *abf;
5401 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5408 if ( folderpath == NULL )
5411 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5414 /* split the folder path we've received, we'll try to match this path, subpath by
5415 subpath against the book/folder structure in order */
5416 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5417 if (!folder_path_match.folder_path)
5420 list = addrindex_get_interface_list( _addressIndex_ );
5421 while ( list && !folder_path_match.matched ) {
5422 AddressInterface *interface = list->data;
5423 if ( interface && interface->type == ADDR_IF_BOOK ) {
5424 nodeDS = interface->listSource;
5425 while ( nodeDS && !folder_path_match.matched ) {
5428 /* Read address book */
5429 if( ! addrindex_ds_get_read_flag( ds ) ) {
5430 addrindex_ds_read_data( ds );
5433 /* Add node for address book */
5434 abf = ds->rawDataSource;
5436 /* match book name */
5437 if ( abf && abf->fileName &&
5438 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5440 debug_print("matched book name '%s'\n", abf->fileName);
5441 folder_path_match.book = ds;
5443 if ( folder_path_match.folder_path[1] == NULL ) {
5444 /* no folder part to match */
5446 folder_path_match.matched = TRUE;
5447 folder_path_match.folder = NULL;
5448 debug_print("book path matched!\n");
5451 /* match folder part */
5453 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5454 rootFolder = addrindex_ds_get_root_folder( ds );
5456 /* prepare for recursive call */
5457 folder_path_match.index = 1;
5458 /* this call will set folder_path_match.matched and folder_path_match.folder */
5459 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5464 nodeDS = g_list_next( nodeDS );
5467 list = g_list_next( list );
5470 g_strfreev( folder_path_match.folder_path );
5473 *book = folder_path_match.book;
5475 *folder = folder_path_match.folder;
5476 return folder_path_match.matched;
5480 /* **********************************************************************
5482 * ***********************************************************************
5488 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5489 AddressDataSource *ds = NULL;
5490 AdapterDSource *ads = NULL;
5491 AddressBookFile *abf = NULL;
5492 AdapterInterface *adapter;
5493 GtkCMCTreeNode *newNode;
5495 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5497 if( adapter->treeNode ) {
5498 abf = addressbook_imp_ldif( _addressIndex_ );
5500 ds = addrindex_index_add_datasource(
5501 _addressIndex_, ADDR_IF_BOOK, abf );
5502 ads = addressbook_create_ds_adapter(
5503 ds, ADDR_BOOK, NULL );
5504 addressbook_ads_set_name(
5505 ads, addrbook_get_name( abf ) );
5506 newNode = addressbook_add_object(
5508 ADDRESS_OBJECT(ads) );
5510 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5512 addrbook.treeSelected = newNode;
5515 /* Notify address completion */
5516 invalidate_address_completion();
5525 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5526 AddressDataSource *ds = NULL;
5527 AdapterDSource *ads = NULL;
5528 AddressBookFile *abf = NULL;
5529 AdapterInterface *adapter;
5530 GtkCMCTreeNode *newNode;
5532 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5534 if( adapter->treeNode ) {
5535 abf = addressbook_imp_mutt( _addressIndex_ );
5537 ds = addrindex_index_add_datasource(
5538 _addressIndex_, ADDR_IF_BOOK, abf );
5539 ads = addressbook_create_ds_adapter(
5540 ds, ADDR_BOOK, NULL );
5541 addressbook_ads_set_name(
5542 ads, addrbook_get_name( abf ) );
5543 newNode = addressbook_add_object(
5545 ADDRESS_OBJECT(ads) );
5547 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5549 addrbook.treeSelected = newNode;
5552 /* Notify address completion */
5553 invalidate_address_completion();
5562 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5563 AddressDataSource *ds = NULL;
5564 AdapterDSource *ads = NULL;
5565 AddressBookFile *abf = NULL;
5566 AdapterInterface *adapter;
5567 GtkCMCTreeNode *newNode;
5569 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5571 if( adapter->treeNode ) {
5572 abf = addressbook_imp_pine( _addressIndex_ );
5574 ds = addrindex_index_add_datasource(
5575 _addressIndex_, ADDR_IF_BOOK, abf );
5576 ads = addressbook_create_ds_adapter(
5577 ds, ADDR_BOOK, NULL );
5578 addressbook_ads_set_name(
5579 ads, addrbook_get_name( abf ) );
5580 newNode = addressbook_add_object(
5582 ADDRESS_OBJECT(ads) );
5584 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5586 addrbook.treeSelected = newNode;
5589 /* Notify address completion */
5590 invalidate_address_completion();
5597 * Harvest addresses.
5598 * \param folderItem Folder to import.
5599 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5600 * \param msgList List of message numbers, or NULL to process folder.
5602 void addressbook_harvest(
5603 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5605 AddressDataSource *ds = NULL;
5606 AdapterDSource *ads = NULL;
5607 AddressBookFile *abf = NULL;
5608 AdapterInterface *adapter;
5609 GtkCMCTreeNode *newNode;
5611 abf = addrgather_dlg_execute(
5612 folderItem, _addressIndex_, sourceInd, msgList );
5614 ds = addrindex_index_add_datasource(
5615 _addressIndex_, ADDR_IF_BOOK, abf );
5617 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5619 if( adapter->treeNode ) {
5620 ads = addressbook_create_ds_adapter(
5621 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5622 newNode = addressbook_add_object(
5624 ADDRESS_OBJECT(ads) );
5625 if (newNode == NULL) {
5626 g_message("error adding addressbook object\n");
5631 /* Notify address completion */
5632 invalidate_address_completion();
5639 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5640 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5642 AddressDataSource *ds = NULL;
5643 AddrBookBase *adbase;
5644 AddressCache *cache;
5645 GtkCMCTreeNode *node = NULL;
5647 if( ! addrbook.treeSelected ) return;
5648 node = addrbook.treeSelected;
5649 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5650 obj = gtk_cmctree_node_get_row_data( ctree, node );
5651 if( obj == NULL ) return;
5653 ds = addressbook_find_datasource( node );
5654 if( ds == NULL ) return;
5655 adbase = ( AddrBookBase * ) ds->rawDataSource;
5656 cache = adbase->addressCache;
5657 addressbook_exp_html( cache );
5663 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5664 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5666 AddressDataSource *ds = NULL;
5667 AddrBookBase *adbase;
5668 AddressCache *cache;
5669 GtkCMCTreeNode *node = NULL;
5671 if( ! addrbook.treeSelected ) return;
5672 node = addrbook.treeSelected;
5673 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5674 obj = gtk_cmctree_node_get_row_data( ctree, node );
5675 if( obj == NULL ) return;
5677 ds = addressbook_find_datasource( node );
5678 if( ds == NULL ) return;
5679 adbase = ( AddrBookBase * ) ds->rawDataSource;
5680 cache = adbase->addressCache;
5681 addressbook_exp_ldif( cache );
5684 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5686 addrduplicates_find(GTK_WINDOW(addrbook.window));
5689 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5691 addressbook_custom_attr_edit();
5694 static void addressbook_start_drag(GtkWidget *widget, gint button,
5698 GdkDragContext *context;
5699 if (addressbook_target_list == NULL)
5700 addressbook_target_list = gtk_target_list_new(
5701 addressbook_drag_types, 1);
5702 context = gtk_drag_begin(widget, addressbook_target_list,
5703 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5704 gtk_drag_set_icon_default(context);
5707 static void addressbook_drag_data_get(GtkWidget *widget,
5708 GdkDragContext *drag_context,
5709 GtkSelectionData *selection_data,
5714 AddrItemObject *aio = NULL;
5715 AddressObject *pobj = NULL;
5716 AdapterDSource *ads = NULL;
5717 AddressDataSource *ds = NULL;
5720 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5722 if( pobj == NULL ) return;
5724 if( pobj->type == ADDR_DATASOURCE ) {
5725 ads = ADAPTER_DSOURCE(pobj);
5726 ds = ads->dataSource;
5727 } else if (pobj->type == ADDR_ITEM_GROUP) {
5732 else if( pobj->type != ADDR_INTERFACE ) {
5733 ds = addressbook_find_datasource( addrbook.treeSelected );
5739 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5740 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5741 GTK_CMCTREE_NODE(cur->data));
5742 while (aio && aio->type != ITEMTYPE_PERSON) {
5747 if (aio && aio->type == ITEMTYPE_PERSON) {
5748 if( ds && ds->interface && ds->interface->readOnly)
5749 gtk_selection_data_set(selection_data,
5750 gtk_selection_data_get_target(selection_data), 8,
5751 (const guchar *)"Dummy_addr_copy", 15);
5753 gtk_selection_data_set(selection_data,
5754 gtk_selection_data_get_target(selection_data), 8,
5755 (const guchar *)"Dummy_addr_move", 15);
5759 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5760 GdkDragContext *context,
5766 GtkAllocation allocation;
5767 GtkRequisition requisition;
5769 GtkCMCTreeNode *node = NULL;
5770 gboolean acceptable = FALSE;
5771 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5772 gint height = allocation.height;
5773 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5774 gint total_height = requisition.height;
5775 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5776 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5777 gfloat vpos = gtk_adjustment_get_value(pos);
5779 if (gtk_cmclist_get_selection_info
5780 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5782 if (y > height - 24 && height + vpos < total_height) {
5783 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5784 gtk_adjustment_changed(pos);
5786 if (y < 24 && y > 0) {
5787 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5788 gtk_adjustment_changed(pos);
5790 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5793 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5794 if( obj->type == ADDR_ITEM_FOLDER
5795 || obj->type == ADDR_ITEM_GROUP)
5798 AdapterDSource *ads = NULL;
5799 AddressDataSource *ds = NULL;
5800 ads = ADAPTER_DSOURCE(obj);
5801 if (ads == NULL ){ return FALSE;}
5802 ds = ads->dataSource;
5803 if (ds == NULL ) { return FALSE;}
5811 g_signal_handlers_block_by_func
5813 G_CALLBACK(addressbook_tree_selected), NULL);
5814 gtk_sctree_select( GTK_SCTREE(widget), node);
5815 g_signal_handlers_unblock_by_func
5817 G_CALLBACK(addressbook_tree_selected), NULL);
5818 gdk_drag_status(context,
5819 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5820 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5822 gdk_drag_status(context, 0, time);
5827 static void addressbook_drag_leave_cb(GtkWidget *widget,
5828 GdkDragContext *context,
5832 if (addrbook.treeSelected) {
5833 g_signal_handlers_block_by_func
5835 G_CALLBACK(addressbook_tree_selected), NULL);
5836 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5837 g_signal_handlers_unblock_by_func
5839 G_CALLBACK(addressbook_tree_selected), NULL);
5844 static void addressbook_drag_received_cb(GtkWidget *widget,
5845 GdkDragContext *drag_context,
5848 GtkSelectionData *data,
5854 GtkCMCTreeNode *node;
5855 GtkCMCTreeNode *lastopened = addrbook.opened;
5857 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5858 if (gtk_cmclist_get_selection_info
5859 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5863 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5864 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5867 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5868 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5869 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5870 addressbook_clip_copy_cb(NULL, NULL);
5872 addressbook_clip_cut_cb(NULL, NULL);
5873 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5874 addressbook_clip_paste_cb(NULL,NULL);
5875 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5876 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5877 gtk_drag_finish(drag_context, TRUE, TRUE, time);