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"
47 #include "file-utils.h"
52 #include "addr_compl.h"
56 #include "addressitem.h"
58 #include "addrcache.h"
60 #include "addrindex.h"
61 #include "addrmerge.h"
62 #include "addressadd.h"
63 #include "addrduplicates.h"
64 #include "addressbook_foldersel.h"
66 #include "editvcard.h"
67 #include "editgroup.h"
68 #include "editaddress.h"
70 #include "importldif.h"
71 #include "importmutt.h"
72 #include "importpine.h"
77 #include "editjpilot.h"
82 #include "ldapserver.h"
84 #include "ldapupdate.h"
86 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
89 #include "addrquery.h"
90 #include "addrselect.h"
92 #include "addrgather.h"
93 #include "adbookbase.h"
94 #include "exphtmldlg.h"
95 #include "expldifdlg.h"
96 #include "browseldap.h"
97 #include "addrcustomattr.h"
105 } AddressIndexColumns;
113 } AddressListColumns;
116 AddressBookFile *book;
124 AddressDataSource *book;
128 static gchar *list_titles[] = { N_("Name"),
132 #define COL_NAME_WIDTH 164
133 #define COL_ADDRESS_WIDTH 156
135 #define COL_FOLDER_WIDTH 170
136 #define ADDRESSBOOK_WIDTH 640
137 #define ADDRESSBOOK_HEIGHT 360
139 #define ADDRESSBOOK_MSGBUF_SIZE 2048
141 static GdkPixbuf *folderxpm = NULL;
142 static GdkPixbuf *folderopenxpm = NULL;
143 static GdkPixbuf *groupxpm = NULL;
144 static GdkPixbuf *interfacexpm = NULL;
145 static GdkPixbuf *bookxpm = NULL;
146 static GdkPixbuf *addressxpm = NULL;
147 static GdkPixbuf *vcardxpm = NULL;
148 static GdkPixbuf *jpilotxpm = NULL;
149 static GdkPixbuf *categoryxpm = NULL;
150 static GdkPixbuf *ldapxpm = NULL;
151 static GdkPixbuf *addrsearchxpm = NULL;
154 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
156 /* Address list selection */
157 static AddrSelectList *_addressSelect_ = NULL;
158 static AddressClipboard *_clipBoard_ = NULL;
160 /* Address index file and interfaces */
161 static AddressIndex *_addressIndex_ = NULL;
162 static GList *_addressInterfaceList_ = NULL;
163 static GList *_addressIFaceSelection_ = NULL;
164 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
166 static AddressBook_win addrbook;
168 static GHashTable *_addressBookTypeHash_ = NULL;
169 static GList *_addressBookTypeList_ = NULL;
171 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
172 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
173 static void addressbook_edit_address_post_cb( ItemPerson *person );
175 static void addressbook_create (void);
176 static gint addressbook_close (void);
178 static gboolean address_index_has_focus = FALSE;
179 static gboolean address_list_has_focus = FALSE;
181 /* callback functions */
182 static void addressbook_del_clicked (GtkButton *button,
184 static void addressbook_reg_clicked (GtkButton *button,
186 static void addressbook_to_clicked (GtkButton *button,
188 static void addressbook_lup_clicked (GtkButton *button,
190 static void addressbook_close_clicked (GtkButton *button,
193 static void addressbook_tree_selected (GtkCMCTree *ctree,
194 GtkCMCTreeNode *node,
197 static void addressbook_select_row_tree (GtkCMCTree *ctree,
198 GtkCMCTreeNode *node,
201 static void addressbook_list_row_selected (GtkCMCTree *clist,
202 GtkCMCTreeNode *node,
205 static void addressbook_list_row_unselected (GtkCMCTree *clist,
206 GtkCMCTreeNode *node,
209 static void addressbook_person_expand_node (GtkCMCTree *ctree,
212 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
216 static void addressbook_entry_activated (GtkWidget *widget,
219 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
220 GdkEventButton *event,
222 static gboolean addressbook_list_button_released(GtkWidget *widget,
223 GdkEventButton *event,
225 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
226 GdkEventButton *event,
228 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
229 GdkEventButton *event,
232 static void addressbook_new_folder_cb (GtkAction *action,
234 static void addressbook_new_group_cb (GtkAction *action,
236 static void addressbook_treenode_edit_cb (GtkAction *action,
238 static void addressbook_treenode_delete_cb (GtkAction *action,
241 static void addressbook_change_node_name (GtkCMCTreeNode *node,
244 static void addressbook_new_address_cb (GtkAction *action,
246 static void addressbook_edit_address_cb (GtkAction *action,
248 static void addressbook_delete_address_cb (GtkAction *action,
251 static void close_cb (GtkAction *action,
253 static void addressbook_file_save_cb (GtkAction *action,
256 /* Data source edit stuff */
257 static void addressbook_new_book_cb (GtkAction *action,
259 static void addressbook_new_vcard_cb (GtkAction *action,
263 static void addressbook_new_jpilot_cb (GtkAction *action,
268 static void addressbook_new_ldap_cb (GtkAction *action,
272 static void addressbook_set_clist (AddressObject *obj,
275 static void addressbook_load_tree (void);
276 void addressbook_read_file (void);
278 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
280 static void addressbook_treenode_remove_item ( void );
282 static AddressDataSource *addressbook_find_datasource
283 (GtkCMCTreeNode *node );
285 static AddressBookFile *addressbook_get_book_file(void);
287 static GtkCMCTreeNode *addressbook_node_add_folder
288 (GtkCMCTreeNode *node,
289 AddressDataSource *ds,
290 ItemFolder *itemFolder,
291 AddressObjectType otype);
292 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
293 AddressDataSource *ds,
294 ItemGroup *itemGroup);
295 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
296 GtkCMCTreeNode *parent);
297 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
298 GtkCMCTreeNode *node);
299 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
301 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
304 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
307 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
309 AddressTypeControlItem *atci,
310 AddressTypeControlItem *atciMail);
311 static void addressbook_folder_remove_node (GtkCMCTree *clist,
312 GtkCMCTreeNode *node);
314 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
315 gboolean force_focus );
317 /* LUT's and IF stuff */
318 static void addressbook_free_treenode ( gpointer data );
319 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
320 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
322 static void addrbookctl_build_map (GtkWidget *window);
323 static void addrbookctl_build_iflist (void);
324 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
325 static void addrbookctl_build_ifselect (void);
327 static void addrbookctl_free_interface (AdapterInterface *adapter);
328 static void addrbookctl_free_datasource (AdapterDSource *adapter);
329 static void addrbookctl_free_folder (AdapterFolder *adapter);
330 static void addrbookctl_free_group (AdapterGroup *adapter);
332 static void addressbook_list_select_clear ( void );
333 static void addressbook_list_select_add ( AddrItemObject *aio,
334 AddressDataSource *ds );
335 static void addressbook_list_select_remove ( AddrItemObject *aio );
337 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
338 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
339 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
340 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
341 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
342 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
343 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
344 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
345 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
346 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
347 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
348 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
349 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
350 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
352 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
353 static void addressbook_merge_cb ( GtkAction *action, gpointer data );
356 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
358 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
360 static void addressbook_start_drag(GtkWidget *widget, gint button,
363 static void addressbook_drag_data_get(GtkWidget *widget,
364 GdkDragContext *drag_context,
365 GtkSelectionData *selection_data,
369 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
370 GdkDragContext *context,
375 static void addressbook_drag_leave_cb(GtkWidget *widget,
376 GdkDragContext *context,
379 static void addressbook_drag_received_cb(GtkWidget *widget,
380 GdkDragContext *drag_context,
383 GtkSelectionData *data,
387 static void addressbook_list_menu_setup( void );
389 static GtkTargetEntry addressbook_drag_types[] =
391 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
394 static GtkTargetList *addressbook_target_list = NULL;
396 static void about_show_cb(GtkAction *action, gpointer data)
401 static GtkActionEntry addressbook_entries[] =
403 {"Menu", NULL, "Menu", NULL, NULL, NULL },
405 {"Book", NULL, N_("_Book"), NULL, NULL, NULL },
406 {"Address", NULL, N_("_Edit"), NULL, NULL, NULL },
407 {"Tools", NULL, N_("_Tools"), NULL, NULL, NULL },
408 {"Help", NULL, N_("_Help"), NULL, NULL, NULL },
411 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
412 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
413 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
417 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
420 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
422 {"Book/---", NULL, "---", NULL, NULL, NULL },
424 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
425 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
426 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
427 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
428 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
431 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
432 {"Address/---", NULL, "---", NULL, NULL, NULL },
433 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
434 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
435 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
436 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
437 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
438 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
439 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
440 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
441 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
442 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
443 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
444 {"Address/Merge", NULL, N_("_Merge"), "<control>E", NULL, G_CALLBACK(addressbook_merge_cb) },
448 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
449 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
450 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
451 {"Tools/---", NULL, "---", NULL, NULL, NULL },
452 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
453 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
454 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
455 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
456 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
459 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
463 static GtkActionEntry addressbook_tree_popup_entries[] =
465 {"ABTreePopup", NULL, "ABTreePopup", NULL, NULL, NULL },
466 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
467 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
468 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
469 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
470 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
471 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
472 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
473 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
474 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
475 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
478 static GtkActionEntry addressbook_list_popup_entries[] =
480 {"ABListPopup", NULL, "ABListPopup", NULL, NULL, NULL },
481 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
482 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
483 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
484 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
485 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
486 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
487 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
488 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
489 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
490 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
491 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
492 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
493 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
495 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
497 {"ABListPopup/Merge", NULL, N_("_Merge"), NULL, NULL, G_CALLBACK(addressbook_merge_cb) },
501 * Structure of error message table.
503 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
504 struct _ErrMsgTableEntry {
509 static gchar *_errMsgUnknown_ = N_( "Unknown" );
512 * Lookup table of error messages for general errors. Note that a NULL
513 * description signifies the end of the table.
515 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
516 { MGU_SUCCESS, N_("Success") },
517 { MGU_BAD_ARGS, N_("Bad arguments") },
518 { MGU_NO_FILE, N_("File not specified") },
519 { MGU_OPEN_FILE, N_("Error opening file") },
520 { MGU_ERROR_READ, N_("Error reading file") },
521 { MGU_EOF, N_("End of file encountered") },
522 { MGU_OO_MEMORY, N_("Error allocating memory") },
523 { MGU_BAD_FORMAT, N_("Bad file format") },
524 { MGU_ERROR_WRITE, N_("Error writing to file") },
525 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
526 { MGU_NO_PATH, N_("No path specified") },
532 * Lookup table of error messages for LDAP errors.
534 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
535 { LDAPRC_SUCCESS, N_("Success") },
536 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
537 { LDAPRC_INIT, N_("Error initializing LDAP") },
538 { LDAPRC_BIND, N_("Error binding to LDAP server") },
539 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
540 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
541 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
542 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
543 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
544 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
545 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
546 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
547 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
548 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
554 * Lookup message for specified error code.
555 * \param lut Lookup table.
556 * \param code Code to lookup.
557 * \return Description associated to code.
559 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
561 ErrMsgTableEntry entry;
564 for( i = 0; ; i++ ) {
566 if( entry.description == NULL ) break;
567 if( entry.code == code ) {
568 desc = entry.description;
573 desc = _errMsgUnknown_;
578 static gboolean lastCanLookup = FALSE;
580 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
582 if (add_and_delete) {
583 gtk_widget_show(addrbook.edit_btn);
584 gtk_widget_show(addrbook.del_btn);
585 gtk_widget_show(addrbook.reg_btn);
587 gtk_widget_hide(addrbook.edit_btn);
588 gtk_widget_hide(addrbook.del_btn);
589 gtk_widget_hide(addrbook.reg_btn);
593 gtk_widget_show(addrbook.lup_btn);
594 gtk_widget_show(addrbook.entry);
595 gtk_widget_show(addrbook.label);
597 gtk_widget_hide(addrbook.lup_btn);
598 gtk_widget_hide(addrbook.entry);
599 gtk_widget_hide(addrbook.label);
602 lastCanLookup = lookup;
605 gtk_widget_show(addrbook.to_btn);
606 gtk_widget_show(addrbook.cc_btn);
607 gtk_widget_show(addrbook.bcc_btn);
609 gtk_widget_hide(addrbook.to_btn);
610 gtk_widget_hide(addrbook.cc_btn);
611 gtk_widget_hide(addrbook.bcc_btn);
615 void addressbook_open(Compose *target)
617 /* Initialize all static members */
618 if( _clipBoard_ == NULL ) {
619 _clipBoard_ = addrclip_create();
621 if( _addressIndex_ != NULL ) {
622 addrclip_set_index( _clipBoard_, _addressIndex_ );
624 if( _addressSelect_ == NULL ) {
625 _addressSelect_ = addrselect_list_create();
627 if (!addrbook.window) {
628 addressbook_read_file();
629 addressbook_create();
630 addressbook_load_tree();
631 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
632 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
635 gtk_widget_hide(addrbook.window);
638 gtk_widget_show_all(addrbook.window);
640 if (!prefs_common.addressbook_use_editaddress_dialog)
641 addressbook_edit_person_widgetset_hide();
643 address_completion_start(addrbook.window);
645 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
646 addressbook_set_target_compose(target);
650 * Destroy addressbook.
652 void addressbook_destroy( void ) {
653 /* Free up address stuff */
654 if( _addressSelect_ != NULL ) {
655 addrselect_list_free( _addressSelect_ );
657 if( _clipBoard_ != NULL ) {
658 addrclip_free( _clipBoard_ );
661 if( _addressIndex_ != NULL ) {
662 addrindex_free_index( _addressIndex_ );
663 addrindex_teardown();
665 _addressSelect_ = NULL;
667 _addressIndex_ = NULL;
670 void addressbook_set_target_compose(Compose *target)
672 addrbook.target_compose = target;
675 Compose *addressbook_get_target_compose(void)
677 return addrbook.target_compose;
681 * Refresh addressbook and save to file(s).
683 void addressbook_refresh( void )
685 if (addrbook.window) {
686 if (addrbook.treeSelected) {
687 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
688 addrbook.treeSelected);
689 addressbook_set_clist(
690 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
691 addrbook.treeSelected),
696 addressbook_export_to_file();
699 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
701 if (event && event->keyval == GDK_KEY_Escape)
703 else if (event && event->keyval == GDK_KEY_Delete) {
704 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
705 if ( /* address_index_has_focus || */ address_list_has_focus )
706 addressbook_del_clicked(NULL, NULL);
712 *\brief Save Gtk object size to prefs dataset
714 static void addressbook_size_allocate_cb(GtkWidget *widget,
715 GtkAllocation *allocation)
717 cm_return_if_fail(allocation != NULL);
719 prefs_common.addressbookwin_width = allocation->width;
720 prefs_common.addressbookwin_height = allocation->height;
723 static gint sort_column_number = 0;
724 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
726 static gint list_case_sort(
727 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
729 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
730 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
731 gchar *name1 = NULL, *name2 = NULL;
732 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
733 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
735 if( aio1->type == aio2->type ) {
737 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
739 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
740 if( ! name1 ) return ( name2 != NULL );
741 if( ! name2 ) return -1;
742 return g_utf8_collate( name1, name2 );
744 /* Order groups before person */
745 if( aio1->type == ITEMTYPE_GROUP ) {
746 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
747 } else if( aio2->type == ITEMTYPE_GROUP ) {
748 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
754 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
755 const GtkSortType sort_type)
758 GtkWidget *hbox, *label, *arrow;
760 sort_column_number = col;
761 sort_column_type = sort_type;
762 gtk_cmclist_set_compare_func(clist, list_case_sort);
763 gtk_cmclist_set_sort_type(clist, sort_type);
764 gtk_cmclist_set_sort_column(clist, col);
766 gtk_cmclist_freeze(clist);
767 gtk_cmclist_sort(clist);
769 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
770 hbox = gtk_hbox_new(FALSE, 4);
771 label = gtk_label_new(gettext(list_titles[pos]));
772 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
775 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
776 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
777 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
780 gtk_widget_show_all(hbox);
781 gtk_cmclist_set_column_widget(clist, pos, hbox);
784 gtk_cmclist_thaw(clist);
787 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
789 static GtkSortType sort_type = GTK_SORT_ASCENDING;
791 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
793 addressbook_sort_list(clist, COL_NAME, sort_type);
796 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
798 static GtkSortType sort_type = GTK_SORT_ASCENDING;
800 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
802 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
805 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
807 static GtkSortType sort_type = GTK_SORT_ASCENDING;
809 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
811 addressbook_sort_list(clist, COL_REMARKS, sort_type);
814 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
817 address_index_has_focus = TRUE;
821 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
824 address_index_has_focus = FALSE;
825 if (!prefs_common.addressbook_use_editaddress_dialog
826 && !address_list_has_focus)
827 addressbook_address_list_disable_some_actions();
831 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
834 address_list_has_focus = TRUE;
838 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
841 address_list_has_focus = FALSE;
842 if (!prefs_common.addressbook_use_editaddress_dialog
843 && !address_index_has_focus)
844 addressbook_address_list_disable_some_actions();
848 /* save hpane and vpane's handle position when it moves */
849 static void addressbook_pane_save_position(void)
852 prefs_common.addressbook_hpaned_pos =
853 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
855 prefs_common.addressbook_vpaned_pos =
856 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
860 * Create the address book widgets. The address book contains two CTree widgets: the
861 * address index tree on the left and the address list on the right.
863 * The address index tree displays a hierarchy of interfaces and groups. Each node in
864 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
865 * data sources and folder objects.
867 * The address list displays group, person and email objects. These items are linked
868 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
871 * In the tradition of MVC architecture, the data stores have been separated from the
872 * GUI components. The addrindex.c file provides the interface to all data stores.
874 static void addressbook_create(void)
880 GtkWidget *ctree_swin;
882 GtkWidget *editaddress_vbox;
883 GtkWidget *clist_vbox;
884 GtkWidget *clist_swin;
891 GtkWidget *statusbar;
902 GtkWidget *close_btn;
903 GtkWidget *tree_popup;
904 GtkWidget *list_popup;
906 GtkUIManager *ui_manager;
907 GtkActionGroup *action_group;
908 gchar *index_titles[N_INDEX_COLS];
912 static GdkGeometry geometry;
914 debug_print("Creating addressbook window...\n");
916 index_titles[COL_SOURCES] = _("Sources");
918 /* Address book window */
919 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
920 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
921 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
922 gtk_widget_realize(window);
924 g_signal_connect(G_OBJECT(window), "delete_event",
925 G_CALLBACK(addressbook_close), NULL);
926 g_signal_connect(G_OBJECT(window), "size_allocate",
927 G_CALLBACK(addressbook_size_allocate_cb), NULL);
928 g_signal_connect(G_OBJECT(window), "key_press_event",
929 G_CALLBACK(key_pressed), NULL);
930 MANAGE_WINDOW_SIGNALS_CONNECT(window);
932 vbox = gtk_vbox_new(FALSE, 0);
933 gtk_container_add(GTK_CONTAINER(window), vbox);
936 ui_manager = gtk_ui_manager_new();
937 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
938 G_N_ELEMENTS(addressbook_entries), NULL);
939 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
940 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
941 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
942 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
990 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
991 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
992 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
993 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
996 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
998 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
1000 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1002 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1003 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1004 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1006 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1007 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1008 GTK_POLICY_AUTOMATIC,
1009 GTK_POLICY_AUTOMATIC);
1010 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1013 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1014 gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1016 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1017 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1018 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
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_expander_style(GTK_CMCTREE(clist),
1068 GTK_CMCTREE_EXPANDER_TRIANGLE);
1069 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1070 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1071 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1073 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1075 gtk_widget_set_size_request(clist, -1, 80);
1077 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1078 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1079 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1080 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1081 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1082 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1083 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1084 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1085 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1086 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1087 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1089 for (i = 0; i < N_LIST_COLS; i++)
1090 gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1093 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1094 G_CALLBACK(addressbook_list_row_selected), NULL);
1095 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1096 G_CALLBACK(addressbook_list_row_unselected), NULL);
1097 g_signal_connect(G_OBJECT(clist), "button_press_event",
1098 G_CALLBACK(addressbook_list_button_pressed),
1100 g_signal_connect(G_OBJECT(clist), "button_release_event",
1101 G_CALLBACK(addressbook_list_button_released),
1103 g_signal_connect(G_OBJECT(clist), "tree_expand",
1104 G_CALLBACK(addressbook_person_expand_node), NULL );
1105 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1106 G_CALLBACK(addressbook_person_collapse_node), NULL );
1107 g_signal_connect(G_OBJECT(clist), "start_drag",
1108 G_CALLBACK(addressbook_start_drag), NULL);
1109 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1110 G_CALLBACK(addressbook_drag_data_get), NULL);
1111 hbox = gtk_hbox_new(FALSE, 4);
1112 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1114 label = gtk_label_new(_("Search"));
1115 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1117 entry = gtk_entry_new();
1118 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1120 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1122 g_signal_connect(G_OBJECT(entry), "key_press_event",
1123 G_CALLBACK(addressbook_entry_key_pressed),
1125 g_signal_connect(G_OBJECT(entry), "activate",
1126 G_CALLBACK(addressbook_entry_activated), NULL);
1128 if (!prefs_common.addressbook_use_editaddress_dialog) {
1129 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1130 vpaned = gtk_vpaned_new();
1131 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1132 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1135 editaddress_vbox = NULL;
1137 hpaned = gtk_hpaned_new();
1138 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1139 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1140 if (prefs_common.addressbook_use_editaddress_dialog)
1141 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1143 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1146 hsbox = gtk_hbox_new(FALSE, 0);
1147 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1148 statusbar = gtk_statusbar_new();
1149 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1152 hbbox = gtk_hbutton_box_new();
1153 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1154 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1155 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1156 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1158 gtkut_stock_button_add_help(hbbox, &help_btn);
1160 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1161 gtk_widget_set_can_default(edit_btn, TRUE);
1162 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1163 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1164 gtk_widget_set_can_default(del_btn, TRUE);
1165 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1166 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1167 gtk_widget_set_can_default(reg_btn, TRUE);
1168 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1171 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1172 gtk_widget_set_can_default(lup_btn, TRUE);
1173 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1175 g_signal_connect(G_OBJECT(help_btn), "clicked",
1176 G_CALLBACK(manual_open_with_anchor_cb),
1177 MANUAL_ANCHOR_ADDRBOOK);
1179 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1180 G_CALLBACK(addressbook_edit_clicked), NULL);
1181 g_signal_connect(G_OBJECT(del_btn), "clicked",
1182 G_CALLBACK(addressbook_del_clicked), NULL);
1183 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1184 G_CALLBACK(addressbook_reg_clicked), NULL);
1185 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1186 G_CALLBACK(addressbook_lup_clicked), NULL);
1188 to_btn = gtk_button_new_with_label
1189 (prefs_common_translated_header_name("To:"));
1190 gtk_widget_set_can_default(to_btn, TRUE);
1191 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1192 cc_btn = gtk_button_new_with_label
1193 (prefs_common_translated_header_name("Cc:"));
1194 gtk_widget_set_can_default(cc_btn, TRUE);
1195 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1196 bcc_btn = gtk_button_new_with_label
1197 (prefs_common_translated_header_name("Bcc:"));
1198 gtk_widget_set_can_default(bcc_btn, TRUE);
1199 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1201 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1202 gtk_widget_set_can_default(close_btn, TRUE);
1203 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1205 g_signal_connect(G_OBJECT(to_btn), "clicked",
1206 G_CALLBACK(addressbook_to_clicked),
1207 GINT_TO_POINTER(COMPOSE_TO));
1208 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1209 G_CALLBACK(addressbook_to_clicked),
1210 GINT_TO_POINTER(COMPOSE_CC));
1211 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1212 G_CALLBACK(addressbook_to_clicked),
1213 GINT_TO_POINTER(COMPOSE_BCC));
1214 g_signal_connect(G_OBJECT(close_btn), "clicked",
1215 G_CALLBACK(addressbook_close_clicked), NULL);
1217 /* Build icons for interface */
1219 /* Build control tables */
1220 addrbookctl_build_map(window);
1221 addrbookctl_build_iflist();
1222 addrbookctl_build_ifselect();
1224 addrbook.clist = NULL;
1226 /* Add each interface into the tree as a root level folder */
1227 nodeIf = _addressInterfaceList_;
1229 AdapterInterface *adapter = nodeIf->data;
1230 AddressInterface *iface = adapter->interface;
1231 nodeIf = g_list_next(nodeIf);
1233 if(iface->useInterface) {
1234 AddressTypeControlItem *atci = adapter->atci;
1235 text = atci->displayName;
1237 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1238 NULL, NULL, &text, FOLDER_SPACING,
1242 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1243 gtk_cmctree_node_set_row_data_full(
1244 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1245 addressbook_free_treenode );
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1264 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1265 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1284 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
1285 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1286 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1288 addrbook.window = window;
1289 addrbook.hpaned = hpaned;
1290 addrbook.vpaned = vpaned;
1291 addrbook.menubar = menubar;
1292 addrbook.ctree = ctree;
1295 addrbook.editaddress_vbox = editaddress_vbox;
1296 addrbook.clist = clist;
1297 addrbook.label = label;
1298 addrbook.entry = entry;
1299 addrbook.statusbar = statusbar;
1300 addrbook.status_cid = gtk_statusbar_get_context_id(
1301 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1303 addrbook.help_btn = help_btn;
1304 addrbook.edit_btn = edit_btn;
1305 addrbook.del_btn = del_btn;
1306 addrbook.reg_btn = reg_btn;
1307 addrbook.lup_btn = lup_btn;
1308 addrbook.to_btn = to_btn;
1309 addrbook.cc_btn = cc_btn;
1310 addrbook.bcc_btn = bcc_btn;
1312 addrbook.tree_popup = tree_popup;
1313 addrbook.list_popup = list_popup;
1314 addrbook.ui_manager = ui_manager;
1316 addrbook.listSelected = NULL;
1318 if (!geometry.min_height) {
1319 geometry.min_width = ADDRESSBOOK_WIDTH;
1320 geometry.min_height = ADDRESSBOOK_HEIGHT;
1323 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1325 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1326 prefs_common.addressbookwin_height);
1328 gtk_window_move(GTK_WINDOW(window), 48, 48);
1331 if (!prefs_common.addressbook_use_editaddress_dialog) {
1332 if (prefs_common.addressbook_vpaned_pos > 0)
1333 gtk_paned_set_position(GTK_PANED(vpaned),
1334 prefs_common.addressbook_vpaned_pos);
1336 if (prefs_common.addressbook_hpaned_pos > 0)
1337 gtk_paned_set_position(GTK_PANED(hpaned),
1338 prefs_common.addressbook_hpaned_pos);
1341 gtk_widget_show_all(window);
1345 * Close address book window and save to file(s).
1347 static gint addressbook_close( void ) {
1348 address_completion_end(addrbook.window);
1349 if (!prefs_common.addressbook_use_editaddress_dialog)
1350 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1352 addressbook_pane_save_position();
1354 gtk_widget_hide(addrbook.window);
1355 addressbook_export_to_file();
1360 * Display message in status line.
1361 * \param msg Message to display.
1363 static void addressbook_status_show( gchar *msg ) {
1364 if( addrbook.statusbar != NULL ) {
1366 GTK_STATUSBAR(addrbook.statusbar),
1367 addrbook.status_cid );
1370 GTK_STATUSBAR(addrbook.statusbar),
1371 addrbook.status_cid, msg );
1376 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1380 *addressbook_msgbuf = '\0';
1382 name = addrindex_ds_get_name( ds );
1383 retVal = addrindex_ds_get_status_code( ds );
1384 if( retVal == MGU_SUCCESS ) {
1385 g_snprintf( addressbook_msgbuf,
1386 sizeof(addressbook_msgbuf), "%s", name );
1389 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1390 g_snprintf( addressbook_msgbuf,
1391 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1394 addressbook_status_show( addressbook_msgbuf );
1397 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1399 addressbook_edit_address_cb(NULL, NULL);
1402 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1404 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1408 * Delete one or more objects from address list.
1410 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1412 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1413 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1414 AddressObject *pobj;
1415 AdapterDSource *ads = NULL;
1416 GtkCMCTreeNode *nodeList;
1419 AddressBookFile *abf = NULL;
1420 AddressDataSource *ds = NULL;
1421 AddressInterface *iface;
1422 AddrItemObject *aio;
1423 AddrSelectItem *item;
1425 gboolean refreshList = FALSE;
1427 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1428 cm_return_if_fail(pobj != NULL);
1430 /* Test whether anything selected for deletion */
1431 nodeList = addrbook.listSelected;
1433 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1434 if( aio == NULL) return;
1435 ds = addressbook_find_datasource( addrbook.treeSelected );
1436 if( ds == NULL ) return;
1438 /* Test for read only */
1439 iface = ds->interface;
1440 if( iface->readOnly ) {
1441 alertpanel( _("Delete address(es)"),
1442 _("This address data is readonly and cannot be deleted."),
1443 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST);
1447 /* Test whether Ok to proceed */
1449 if( pobj->type == ADDR_DATASOURCE ) {
1450 ads = ADAPTER_DSOURCE(pobj);
1451 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1453 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1456 else if( pobj->type == ADDR_ITEM_GROUP ) {
1459 if( ! procFlag ) return;
1460 abf = ds->rawDataSource;
1461 if( abf == NULL ) return;
1463 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1464 g_signal_handlers_block_by_func
1465 (G_OBJECT(addrbook.clist),
1466 G_CALLBACK(addressbook_list_row_unselected), NULL);
1468 /* Process deletions */
1469 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1470 GList *groups = NULL, *persons = NULL, *emails = NULL;
1471 gboolean group_delete = TRUE;
1472 /* Items inside folders */
1473 list = addrselect_get_list( _addressSelect_ );
1474 /* Confirm deletion */
1478 node = g_list_next( node );
1479 aio = ( AddrItemObject * ) item->addressItem;
1480 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1481 group_delete = FALSE;
1486 aval = alertpanel( _("Delete group"),
1487 _("Really delete the group(s)?\n"
1488 "The addresses it contains will not be lost."),
1489 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1490 if( aval != G_ALERTALTERNATE ) {
1494 aval = alertpanel( _("Delete address(es)"),
1495 _("Really delete the address(es)?"),
1496 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1497 if( aval != G_ALERTALTERNATE ) {
1502 /* first, set lists of groups and persons to remove */
1506 node = g_list_next( node );
1507 aio = ( AddrItemObject * ) item->addressItem;
1510 if( aio->type == ITEMTYPE_GROUP ) {
1511 groups = g_list_prepend(groups, item);
1513 else if( aio->type == ITEMTYPE_PERSON ) {
1514 persons = g_list_prepend(persons, item);
1517 /* then set list of emails to remove *if* they're not children of
1518 * persons to remove */
1522 node = g_list_next( node );
1523 aio = ( AddrItemObject * ) item->addressItem;
1526 if( aio->type == ITEMTYPE_EMAIL ) {
1527 ItemEMail *sitem = ( ItemEMail * ) aio;
1528 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1529 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1530 emails = g_list_prepend(emails, item);
1532 /* else, the email will be removed via the parent person */
1535 /* then delete groups */
1539 node = g_list_next( node );
1540 aio = ( AddrItemObject * ) item->addressItem;
1543 if( aio->type == ITEMTYPE_GROUP ) {
1544 ItemGroup *item = ( ItemGroup * ) aio;
1545 GtkCMCTreeNode *nd = NULL;
1546 nd = addressbook_find_group_node( addrbook.opened, item );
1547 item = addrbook_remove_group( abf, item );
1549 addritem_free_item_group( item );
1551 /* Remove group from parent node */
1552 gtk_cmctree_remove_node( ctree, nd );
1556 /* then delete persons */
1560 node = g_list_next( node );
1561 aio = ( AddrItemObject * ) item->addressItem;
1564 if( aio->type == ITEMTYPE_PERSON ) {
1565 ItemPerson *item = ( ItemPerson * ) aio;
1566 item->status = DELETE_ENTRY;
1567 addressbook_folder_remove_one_person( clist, item );
1568 if (pobj->type == ADDR_ITEM_FOLDER)
1569 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1570 item = addrbook_remove_person( abf, item );
1572 if (ds && ds->type == ADDR_IF_LDAP) {
1573 LdapServer *server = ds->rawDataSource;
1574 ldapsvr_set_modified(server, TRUE);
1575 ldapsvr_update_book(server, item);
1579 addritem_person_remove_picture(item);
1580 addritem_free_item_person( item );
1584 /* then delete emails */
1588 node = g_list_next( node );
1589 aio = ( AddrItemObject * ) item->addressItem;
1593 if( aio->type == ITEMTYPE_EMAIL ) {
1594 ItemEMail *sitem = ( ItemEMail * ) aio;
1595 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1596 sitem = addrbook_person_remove_email( abf, person, sitem );
1598 addrcache_remove_email(abf->addressCache, sitem);
1599 addritem_free_item_email( sitem );
1601 addressbook_folder_refresh_one_person( clist, person );
1604 g_list_free( groups );
1605 g_list_free( persons );
1606 g_list_free( emails );
1607 g_list_free( list );
1608 addressbook_list_select_clear();
1610 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1611 addressbook_set_clist(
1612 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1616 addrbook_set_dirty(abf, TRUE);
1617 addressbook_export_to_file();
1618 addressbook_list_menu_setup();
1621 else if( pobj->type == ADDR_ITEM_GROUP ) {
1622 /* Items inside groups */
1623 list = addrselect_get_list( _addressSelect_ );
1627 node = g_list_next( node );
1628 aio = ( AddrItemObject * ) item->addressItem;
1629 if( aio->type == ITEMTYPE_EMAIL ) {
1630 ItemEMail *item = ( ItemEMail * ) aio;
1631 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1632 item = addrbook_person_remove_email( abf, person, item );
1634 addritem_free_item_email( item );
1638 g_list_free( list );
1639 addressbook_list_select_clear();
1640 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1641 addressbook_set_clist(
1642 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1646 addrbook_set_dirty(abf, TRUE);
1647 addressbook_export_to_file();
1648 addressbook_list_menu_setup();
1652 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1653 gtk_cmctree_remove_node( clist, nodeList );
1655 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1656 g_signal_handlers_unblock_by_func
1657 (G_OBJECT(addrbook.clist),
1658 G_CALLBACK(addressbook_list_row_unselected), NULL);
1661 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1663 addressbook_new_address_cb( NULL, NULL );
1666 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1669 gchar *address = NULL;
1671 if( aio->type == ITEMTYPE_EMAIL ) {
1672 ItemPerson *person = NULL;
1673 ItemEMail *email = ( ItemEMail * ) aio;
1675 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1676 if( email->address ) {
1677 if( ADDRITEM_NAME(email) ) {
1678 name = ADDRITEM_NAME(email);
1679 if( *name == '\0' ) {
1680 name = ADDRITEM_NAME(person);
1683 else if( ADDRITEM_NAME(person) ) {
1684 name = ADDRITEM_NAME(person);
1687 buf = g_strdup( email->address );
1689 address = email->address;
1692 else if( aio->type == ITEMTYPE_PERSON ) {
1693 ItemPerson *person = ( ItemPerson * ) aio;
1694 GList *node = person->listEMail;
1696 name = ADDRITEM_NAME(person);
1698 ItemEMail *email = ( ItemEMail * ) node->data;
1699 address = email->address;
1703 if( name && name[0] != '\0' ) {
1704 if( strchr_with_skip_quote( name, '"', ',' ) )
1705 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1707 buf = g_strdup_printf( "%s <%s>", name, address );
1710 buf = g_strdup( address );
1717 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1721 AddrSelectItem *item;
1722 AddrItemObject *aio;
1725 compose = addrbook.target_compose;
1726 if( ! compose ) return;
1728 /* Nothing selected, but maybe there is something in text entry */
1729 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1731 compose_entry_append(
1732 compose, addr, (ComposeEntryType)data , PREF_NONE);
1735 /* Select from address list */
1736 list = addrselect_get_list( _addressSelect_ );
1741 node = g_list_next( node );
1742 aio = item->addressItem;
1743 if( aio->type == ITEMTYPE_PERSON ||
1744 aio->type == ITEMTYPE_EMAIL ) {
1745 addr = addressbook_format_address( aio );
1746 compose_entry_append(
1747 compose, addr, (ComposeEntryType) data, PREF_NONE );
1750 else if( aio->type == ITEMTYPE_GROUP ) {
1751 ItemGroup *group = ( ItemGroup * ) aio;
1752 GList *nodeMail = group->listEMail;
1754 ItemEMail *email = nodeMail->data;
1756 addr = addressbook_format_address(
1757 ( AddrItemObject * ) email );
1758 compose_entry_append(
1759 compose, addr, (ComposeEntryType) data, PREF_NONE );
1761 nodeMail = g_list_next( nodeMail );
1766 AddressObject *obj = NULL;
1768 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1770 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1771 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1772 GList *nodeMail = itemGroup->listEMail;
1774 ItemEMail *email = nodeMail->data;
1776 addr = addressbook_format_address(
1777 ( AddrItemObject * ) email );
1778 compose_entry_append(
1779 compose, addr, (ComposeEntryType) data, PREF_NONE );
1781 nodeMail = g_list_next( nodeMail );
1785 g_list_free( list );
1788 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1798 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1799 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1800 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1801 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Merge", sensitive );
1802 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1803 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1806 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1807 gboolean canEdit = FALSE;
1808 gboolean canDelete = TRUE;
1809 gboolean canAdd = FALSE;
1810 gboolean canEditTr = TRUE;
1811 gboolean editAddress = FALSE;
1812 gboolean canExport = TRUE;
1813 AddressTypeControlItem *atci = NULL;
1814 AddressDataSource *ds = NULL;
1815 AddressInterface *iface = NULL;
1817 if( obj == NULL ) return;
1818 if( obj->type == ADDR_INTERFACE ) {
1819 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1820 iface = adapter->interface;
1822 if( iface->haveLibrary ) {
1823 /* Enable appropriate File / New command */
1824 atci = adapter->atci;
1825 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1828 canEditTr = canExport = FALSE;
1830 else if( obj->type == ADDR_DATASOURCE ) {
1831 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1832 ds = ads->dataSource;
1833 iface = ds->interface;
1834 if( ! iface->readOnly ) {
1835 canAdd = canEdit = editAddress = canDelete = TRUE;
1837 if( ! iface->haveLibrary ) {
1838 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1841 else if( obj->type == ADDR_ITEM_FOLDER ) {
1842 ds = addressbook_find_datasource( addrbook.treeSelected );
1844 iface = ds->interface;
1845 if( iface->readOnly ) {
1850 canAdd = editAddress = TRUE;
1854 else if( obj->type == ADDR_ITEM_GROUP ) {
1855 ds = addressbook_find_datasource( addrbook.treeSelected );
1857 iface = ds->interface;
1858 if( ! iface->readOnly ) {
1864 if( addrbook.listSelected == NULL )
1868 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1869 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1870 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1871 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1875 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1876 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1877 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1879 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1880 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1883 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1884 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1888 * Address book tree callback function that responds to selection of tree
1891 * \param ctree Tree widget.
1892 * \param node Node that was selected.
1893 * \param column Column number where selected occurred.
1894 * \param data Pointer to user data.
1896 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1897 gint column, gpointer data)
1899 AddressObject *obj = NULL;
1900 AdapterDSource *ads = NULL;
1901 AddressDataSource *ds = NULL;
1902 ItemFolder *rootFolder = NULL;
1903 AddressObjectType aot;
1905 addrbook.treeSelected = node;
1906 addrbook.listSelected = NULL;
1907 addressbook_status_show( "" );
1908 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1910 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1912 addressbook_set_clist(NULL, TRUE);
1915 addrbook.opened = node;
1917 if( obj->type == ADDR_DATASOURCE ) {
1918 /* Read from file */
1919 static gboolean tVal = TRUE;
1921 ads = ADAPTER_DSOURCE(obj);
1923 ds = ads->dataSource;
1924 if( ds == NULL ) return;
1926 if( addrindex_ds_get_modify_flag( ds ) ) {
1927 addrindex_ds_read_data( ds );
1930 if( ! addrindex_ds_get_read_flag( ds ) ) {
1931 addrindex_ds_read_data( ds );
1933 addressbook_ds_show_message( ds );
1935 if( ! addrindex_ds_get_access_flag( ds ) ) {
1936 /* Remove existing folders and groups */
1937 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1938 addressbook_tree_remove_children( ctree, node );
1939 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1941 /* Load folders into the tree */
1942 rootFolder = addrindex_ds_get_root_folder( ds );
1943 if( ds && ds->type == ADDR_IF_JPILOT ) {
1944 aot = ADDR_CATEGORY;
1946 else if( ds && ds->type == ADDR_IF_LDAP ) {
1947 aot = ADDR_LDAP_QUERY;
1950 aot = ADDR_ITEM_FOLDER;
1952 addressbook_node_add_folder( node, ds, rootFolder, aot );
1953 addrindex_ds_set_access_flag( ds, &tVal );
1954 gtk_cmctree_expand( ctree, node );
1957 addressbook_set_clist(NULL, TRUE);
1960 /* Update address list */
1961 g_signal_handlers_block_by_func
1963 G_CALLBACK(addressbook_tree_selected), NULL);
1964 addressbook_set_clist( obj, FALSE );
1965 g_signal_handlers_unblock_by_func
1967 G_CALLBACK(addressbook_tree_selected), NULL);
1968 if (!prefs_common.addressbook_use_editaddress_dialog)
1969 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1971 /* Setup main menu selections */
1972 addressbook_menubar_set_sensitive( FALSE );
1973 addressbook_menuitem_set_sensitive( obj, node );
1974 addressbook_list_select_clear();
1975 addressbook_list_menu_setup();
1980 * Setup address list popup menu items. Items are enabled or disabled as
1983 static void addressbook_list_menu_setup( void ) {
1984 GtkCMCTree *clist = NULL;
1985 AddressObject *pobj = NULL;
1986 AddressObject *obj = NULL;
1987 AdapterDSource *ads = NULL;
1988 AddressInterface *iface = NULL;
1989 AddressDataSource *ds = NULL;
1991 AddrItemObject *aio;
1992 AddrSelectItem *item;
1993 gboolean canEdit = FALSE;
1994 gboolean canDelete = FALSE;
1995 gboolean canCut = FALSE;
1996 gboolean canCopy = FALSE;
1997 gboolean canPaste = FALSE;
1998 gboolean canBrowse = FALSE;
1999 gboolean canMerge = FALSE;
2001 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2002 if( pobj == NULL ) return;
2004 clist = GTK_CMCTREE(addrbook.clist);
2005 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2006 if( obj == NULL ) canEdit = FALSE;
2008 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2009 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2011 if( pobj->type == ADDR_DATASOURCE ) {
2012 /* Parent object is a data source */
2013 ads = ADAPTER_DSOURCE(pobj);
2014 ds = ads->dataSource;
2017 iface = ds->interface;
2020 if( ! iface->readOnly ) {
2021 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2022 if (iface->type != ADDR_IF_LDAP)
2023 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2024 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2027 canDelete = canEdit;
2030 else if( pobj->type != ADDR_INTERFACE ) {
2031 /* Parent object is not an interface */
2032 ds = addressbook_find_datasource( addrbook.treeSelected );
2035 iface = ds->interface;
2038 if( ! iface->readOnly ) {
2039 /* Folder or group */
2040 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2041 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2042 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2043 if( obj ) canEdit = TRUE;
2046 if( pobj->type == ADDR_ITEM_FOLDER ) {
2047 if (iface->type != ADDR_IF_LDAP)
2048 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2049 if( obj ) canEdit = TRUE;
2051 canDelete = canEdit;
2053 if( iface->type == ADDR_IF_LDAP ) {
2054 if( obj ) canBrowse = TRUE;
2061 /* Enable cut and paste */
2062 if( ! addrclip_is_empty( _clipBoard_ ) )
2064 if( ! addrselect_test_empty( _addressSelect_ ) )
2066 /* Enable copy if something is selected */
2067 if( ! addrselect_test_empty( _addressSelect_ ) )
2071 /* Disable edit or browse if more than one row selected */
2072 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2077 /* Allow merging persons or emails are selected */
2078 list = _addressSelect_->listSelect;
2079 if (list && list->next ) {
2081 aio = ( AddrItemObject * ) item->addressItem;
2082 if( aio->type == ITEMTYPE_EMAIL ||
2083 aio->type == ITEMTYPE_PERSON ) {
2088 /* Forbid write changes when read-only */
2089 if( iface && iface->readOnly ) {
2096 /* Now go finalize menu items */
2097 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2098 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2101 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2104 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2105 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge", canMerge );
2107 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2108 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2109 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2111 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2112 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2113 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2114 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Merge", canMerge );
2116 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2117 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2119 if (addrbook.target_compose) {
2120 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2121 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2122 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2125 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2129 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2130 GtkCMCTreeNode *node,
2137 * Add list of items into tree node below specified tree node.
2138 * \param treeNode Tree node.
2139 * \param ds Data source.
2140 * \param listItems List of items.
2142 static void addressbook_treenode_add_list(
2143 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2149 AddrItemObject *aio;
2153 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2156 group = ( ItemGroup * ) aio;
2157 nn = addressbook_node_add_group( treeNode, ds, group );
2159 g_message("error adding addressbook group\n");
2162 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2165 folder = ( ItemFolder * ) aio;
2166 nn = addressbook_node_add_folder(
2167 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2169 g_message("error adding addressbook folder\n");
2172 node = g_list_next( node );
2176 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2177 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2181 * Cut from address list widget.
2183 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2184 _clipBoard_->cutFlag = TRUE;
2185 addrclip_clear( _clipBoard_ );
2186 addrclip_add( _clipBoard_, _addressSelect_ );
2187 /* addrclip_list_show( _clipBoard_, stdout ); */
2191 * Copy from address list widget.
2193 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2194 _clipBoard_->cutFlag = FALSE;
2195 addrclip_clear( _clipBoard_ );
2196 addrclip_add( _clipBoard_, _addressSelect_ );
2197 /* addrclip_list_show( _clipBoard_, stdout ); */
2201 * Paste clipboard into address list widget.
2203 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2204 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2205 AddressObject *pobj = NULL;
2206 AddressDataSource *ds = NULL;
2207 AddressBookFile *abf = NULL;
2208 ItemFolder *folder = NULL;
2209 GList *folderGroup = NULL;
2211 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2212 if( ds == NULL ) return;
2213 if( addrindex_ds_get_readonly( ds ) ) {
2214 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2218 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2220 if( pobj->type == ADDR_ITEM_FOLDER ) {
2221 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2223 else if( pobj->type == ADDR_ITEM_GROUP ) {
2224 alertpanel_error( _("Cannot paste into an address group.") );
2229 /* Get an address book */
2230 abf = addressbook_get_book_file();
2231 if( abf == NULL ) return;
2233 if( _clipBoard_->cutFlag ) {
2235 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2237 /* Remove all groups and folders in clipboard from tree node */
2238 addressbook_treenode_remove_item();
2240 /* Remove all "cut" items */
2241 addrclip_delete_item( _clipBoard_ );
2243 /* Clear clipboard - cut items??? */
2244 addrclip_clear( _clipBoard_ );
2248 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2251 /* addrclip_list_show( _clipBoard_, stdout ); */
2253 /* Update tree by inserting node for each folder or group */
2254 addressbook_treenode_add_list(
2255 addrbook.treeSelected, ds, folderGroup );
2256 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2257 g_list_free( folderGroup );
2261 /* Display items pasted */
2262 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2263 addressbook_set_clist(
2264 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2272 * Add current treenode object to clipboard. Note that widget only allows
2273 * one entry from the tree list to be selected.
2275 static void addressbook_treenode_to_clipboard( void ) {
2276 AddressObject *obj = NULL;
2277 AddressDataSource *ds = NULL;
2278 AddrSelectItem *item;
2279 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2280 GtkCMCTreeNode *node;
2282 node = addrbook.treeSelected;
2283 if( node == NULL ) return;
2284 obj = gtk_cmctree_node_get_row_data( ctree, node );
2285 if( obj == NULL ) return;
2287 ds = addressbook_find_datasource( node );
2288 if( ds == NULL ) return;
2291 if( obj->type == ADDR_ITEM_FOLDER ) {
2292 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2293 ItemFolder *folder = adapter->itemFolder;
2295 item = addrselect_create_node( obj );
2296 item->uid = g_strdup( ADDRITEM_ID(folder) );
2298 else if( obj->type == ADDR_ITEM_GROUP ) {
2299 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2300 ItemGroup *group = adapter->itemGroup;
2302 item = addrselect_create_node( obj );
2303 item->uid = g_strdup( ADDRITEM_ID(group) );
2305 else if( obj->type == ADDR_DATASOURCE ) {
2307 item = addrselect_create_node( obj );
2312 /* Clear existing list and add item into list */
2315 addressbook_list_select_clear();
2316 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2317 addrselect_list_add( _addressSelect_, item, cacheID );
2323 * Cut from tree widget.
2325 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2326 _clipBoard_->cutFlag = TRUE;
2327 addressbook_treenode_to_clipboard();
2328 addrclip_clear( _clipBoard_ );
2329 addrclip_add( _clipBoard_, _addressSelect_ );
2330 /* addrclip_list_show( _clipBoard_, stdout ); */
2334 * Copy from tree widget.
2336 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2337 _clipBoard_->cutFlag = FALSE;
2338 addressbook_treenode_to_clipboard();
2339 addrclip_clear( _clipBoard_ );
2340 addrclip_add( _clipBoard_, _addressSelect_ );
2341 /* addrclip_list_show( _clipBoard_, stdout ); */
2345 * Paste clipboard into address tree widget.
2347 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2348 addressbook_clip_paste_cb(NULL,NULL);
2352 * Clear selected entries in clipboard.
2354 static void addressbook_list_select_clear( void ) {
2355 addrselect_list_clear( _addressSelect_ );
2359 * Add specified address item to selected address list.
2360 * \param aio Address item object.
2361 * \param ds Datasource.
2363 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2366 if( ds == NULL ) return;
2367 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2368 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2373 * Remove specified address item from selected address list.
2374 * \param aio Address item object.
2376 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2377 addrselect_list_remove( _addressSelect_, aio );
2381 * Invoke EMail compose window with addresses in selected address list.
2383 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2386 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2387 listAddress = addrselect_build_list( _addressSelect_ );
2388 compose_new_with_list( NULL, listAddress );
2389 mgu_free_dlist( listAddress );
2394 static void addressbook_merge_list( AddrSelectList *list ) {
2395 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2396 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2397 AddressObject *pobj;
2398 AddressDataSource *ds = NULL;
2400 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
2401 cm_return_if_fail(pobj != NULL);
2403 ds = addressbook_find_datasource( addrbook.treeSelected );
2404 if( ds == NULL ) return;
2406 addrmerge_merge(clist, pobj, ds, list);
2410 * Merge selected entries in the address list
2412 static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
2413 if( addrselect_test_empty( _addressSelect_ ) )
2416 addressbook_merge_list( _addressSelect_ );
2419 static void addressbook_list_row_selected( GtkCMCTree *clist,
2420 GtkCMCTreeNode *node,
2424 AddrItemObject *aio = NULL;
2425 AddressObject *pobj = NULL;
2426 AdapterDSource *ads = NULL;
2427 AddressDataSource *ds = NULL;
2429 addrbook.listSelected = node;
2431 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2432 if( pobj == NULL ) return;
2434 if( pobj->type == ADDR_DATASOURCE ) {
2435 ads = ADAPTER_DSOURCE(pobj);
2436 ds = ads->dataSource;
2438 else if( pobj->type != ADDR_INTERFACE ) {
2439 ds = addressbook_find_datasource( addrbook.treeSelected );
2442 aio = gtk_cmctree_node_get_row_data( clist, node );
2444 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2445 addressbook_list_select_add( aio, ds );
2448 addressbook_list_menu_setup();
2450 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2451 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2453 if (obj && obj->type != ADDR_ITEM_GROUP)
2454 addressbook_edit_address(NULL, 0, NULL, FALSE);
2458 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2459 GtkCMCTreeNode *node,
2463 AddrItemObject *aio;
2465 aio = gtk_cmctree_node_get_row_data( ctree, node );
2467 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2468 addressbook_list_select_remove( aio );
2471 if (!prefs_common.addressbook_use_editaddress_dialog)
2472 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2475 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2477 addressbook_lup_clicked(NULL, NULL);
2480 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2481 GdkEventButton *event,
2484 if( ! event ) return FALSE;
2485 if( event->window != GTK_CMCLIST(widget)->clist_window ) 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->window != clist->clist_window )
2546 if (event->button == 1) {
2547 if (event->type == GDK_2BUTTON_PRESS) {
2548 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2549 gtkut_clist_set_focus_row(clist, row);
2550 obj = gtk_cmclist_get_row_data( clist, row );
2555 if (obj->type == ADDR_ITEM_GROUP ||
2556 obj->type == ADDR_DATASOURCE) {
2558 addressbook_treenode_edit_cb(NULL, NULL);
2560 /* expand pr collapse */
2561 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2562 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2568 addressbook_menubar_set_sensitive( FALSE );
2570 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2571 gtkut_clist_set_focus_row(clist, row);
2572 obj = gtk_cmclist_get_row_data( clist, row );
2575 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2579 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2581 if( ! addrclip_is_empty( _clipBoard_ ) )
2582 canTreePaste = TRUE;
2584 if (obj->type == ADDR_INTERFACE) {
2585 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2586 iface = adapter->interface;
2589 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2590 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2592 if( iface->externalQuery )
2595 if (obj->type == ADDR_DATASOURCE) {
2597 ads = ADAPTER_DSOURCE(obj);
2598 ds = ads->dataSource;
2601 iface = ds->interface;
2604 if( !iface->readOnly ) {
2605 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2606 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2607 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2613 else if (obj->type == ADDR_ITEM_FOLDER) {
2615 ds = addressbook_find_datasource( node );
2618 iface = ds->interface;
2621 if( !iface->readOnly ) {
2625 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2626 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2627 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2631 if( iface->externalQuery ) {
2632 /* Enable deletion of LDAP folder */
2636 else if (obj->type == ADDR_ITEM_GROUP) {
2638 ds = addressbook_find_datasource( node );
2641 iface = ds->interface;
2644 if( ! iface->readOnly ) {
2647 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2648 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2652 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2654 if( ! addrselect_test_empty( _addressSelect_ ) )
2656 if( ! addrclip_is_empty( _clipBoard_ ) )
2659 /* Forbid write changes when read-only */
2660 if( iface && iface->readOnly ) {
2662 canTreePaste = FALSE;
2669 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2670 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2671 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2672 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2673 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2675 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2676 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2677 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2678 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2679 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2681 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2682 addrbook.target_compose != NULL);
2684 if( event->button == 3 )
2685 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2686 event->button, event->time);
2691 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2692 GdkEventButton *event,
2695 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2699 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2701 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2702 AddressObject *obj = NULL;
2703 AddressDataSource *ds = NULL;
2704 AddressBookFile *abf = NULL;
2705 ItemFolder *parentFolder = NULL;
2706 ItemFolder *folder = NULL;
2708 if( ! addrbook.treeSelected ) return;
2709 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2710 if( obj == NULL ) return;
2711 ds = addressbook_find_datasource( addrbook.treeSelected );
2712 if( ds == NULL ) return;
2714 if( obj->type == ADDR_DATASOURCE ) {
2715 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2717 else if( obj->type == ADDR_ITEM_FOLDER ) {
2718 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2724 abf = ds->rawDataSource;
2725 if( abf == NULL ) return;
2726 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2729 nn = addressbook_node_add_folder(
2730 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2732 g_message("error adding addressbook folder\n");
2734 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2735 if( addrbook.treeSelected == addrbook.opened )
2736 addressbook_set_clist(obj, TRUE);
2740 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2742 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2743 AddressObject *obj = NULL;
2744 AddressDataSource *ds = NULL;
2745 AddressBookFile *abf = NULL;
2746 ItemFolder *parentFolder = NULL;
2747 ItemGroup *group = NULL;
2749 if( ! addrbook.treeSelected ) return;
2750 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2751 if( obj == NULL ) return;
2752 ds = addressbook_find_datasource( addrbook.treeSelected );
2753 if( ds == NULL ) return;
2755 if( obj->type == ADDR_DATASOURCE ) {
2756 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2758 else if( obj->type == ADDR_ITEM_FOLDER ) {
2759 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2765 abf = ds->rawDataSource;
2766 if( abf == NULL ) return;
2767 group = addressbook_edit_group( abf, parentFolder, NULL );
2770 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2772 g_message("error adding addressbook group\n");
2774 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2775 if( addrbook.treeSelected == addrbook.opened )
2776 addressbook_set_clist(obj, TRUE);
2780 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2782 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2785 GdkPixbuf *pix_cl, *pix_op;
2786 gboolean is_leaf, expanded;
2788 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2790 &is_leaf, &expanded);
2791 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2798 * \param obj Address object to edit.
2799 * \param node Node in tree.
2800 * \return New name of data source.
2802 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2803 gchar *newName = NULL;
2804 AddressDataSource *ds = NULL;
2805 AddressInterface *iface = NULL;
2806 AdapterDSource *ads = NULL;
2808 ds = addressbook_find_datasource( node );
2809 if( ds == NULL ) return NULL;
2810 iface = ds->interface;
2811 if( ! iface->haveLibrary ) return NULL;
2813 /* Read data from data source */
2814 if( addrindex_ds_get_modify_flag( ds ) ) {
2815 addrindex_ds_read_data( ds );
2818 if( ! addrindex_ds_get_read_flag( ds ) ) {
2819 addrindex_ds_read_data( ds );
2823 ads = ADAPTER_DSOURCE(obj);
2824 if( ads->subType == ADDR_BOOK ) {
2825 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2827 else if( ads->subType == ADDR_VCARD ) {
2828 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2831 else if( ads->subType == ADDR_JPILOT ) {
2832 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2836 else if( ads->subType == ADDR_LDAP ) {
2837 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2843 newName = obj->name;
2848 * Edit an object that is in the address tree area.
2850 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2852 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2854 AddressDataSource *ds = NULL;
2855 AddressBookFile *abf = NULL;
2856 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2859 if( ! addrbook.treeSelected ) return;
2860 node = addrbook.treeSelected;
2861 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2862 obj = gtk_cmctree_node_get_row_data( ctree, node );
2863 if( obj == NULL ) return;
2864 parentNode = GTK_CMCTREE_ROW(node)->parent;
2866 ds = addressbook_find_datasource( node );
2867 if( ds == NULL ) return;
2869 if( obj->type == ADDR_DATASOURCE ) {
2870 name = addressbook_edit_datasource( obj, node );
2871 if( name == NULL ) return;
2874 abf = ds->rawDataSource;
2875 if( abf == NULL ) return;
2876 if( obj->type == ADDR_ITEM_FOLDER ) {
2877 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2878 ItemFolder *item = adapter->itemFolder;
2879 ItemFolder *parentFolder = NULL;
2880 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2881 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2882 name = ADDRITEM_NAME(item);
2884 else if( obj->type == ADDR_ITEM_GROUP ) {
2885 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2886 ItemGroup *item = adapter->itemGroup;
2887 ItemFolder *parentFolder = NULL;
2888 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2889 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2890 name = ADDRITEM_NAME(item);
2893 if( name && parentNode ) {
2894 /* Update node in tree view */
2895 addressbook_change_node_name( node, name );
2896 gtk_sctree_sort_node(ctree, parentNode);
2897 gtk_cmctree_expand( ctree, node );
2898 gtk_sctree_select( GTK_SCTREE( ctree), node );
2905 ADDRTREE_DEL_FOLDER_ONLY,
2906 ADDRTREE_DEL_FOLDER_ADDR
2910 * Delete an item from the tree widget.
2911 * \param data Data passed in.
2912 * \param action Action.
2913 * \param widget Widget issuing callback.
2915 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2917 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2918 GtkCMCTreeNode *node = NULL;
2922 AddrBookBase *adbase;
2923 AddressCache *cache;
2924 AdapterDSource *ads = NULL;
2925 AddressInterface *iface = NULL;
2926 AddressDataSource *ds = NULL;
2927 gboolean remFlag = FALSE;
2928 TreeItemDelType delType;
2930 if( ! addrbook.treeSelected ) return;
2931 node = addrbook.treeSelected;
2932 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2934 obj = gtk_cmctree_node_get_row_data( ctree, node );
2935 cm_return_if_fail(obj != NULL);
2937 if( obj->type == ADDR_DATASOURCE ) {
2938 ads = ADAPTER_DSOURCE(obj);
2940 ds = ads->dataSource;
2941 if( ds == NULL ) return;
2944 /* Must be folder or something else */
2945 ds = addressbook_find_datasource( node );
2946 if( ds == NULL ) return;
2948 /* Only allow deletion from non-readOnly */
2949 iface = ds->interface;
2950 if( iface->readOnly ) {
2951 /* Allow deletion of query results */
2952 if( ! iface->externalQuery ) return;
2956 /* Confirm deletion */
2957 delType = ADDRTREE_DEL_NONE;
2958 if( obj->type == ADDR_ITEM_FOLDER ) {
2959 if( iface && iface->externalQuery ) {
2960 message = g_strdup_printf( _(
2961 "Do you want to delete the query " \
2962 "results and addresses in '%s'?" ),
2964 aval = alertpanel( _("Delete"), message,
2965 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
2967 if( aval == G_ALERTALTERNATE ) {
2968 delType = ADDRTREE_DEL_FOLDER_ADDR;
2972 message = g_strdup_printf
2973 ( _( "Do you want to delete '%s'? "
2974 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2976 aval = alertpanel( _("Delete folder"), message,
2977 GTK_STOCK_CANCEL, _("Delete _folder only"), _("Delete folder and _addresses"), ALERTFOCUS_SECOND);
2979 if( aval == G_ALERTALTERNATE ) {
2980 delType = ADDRTREE_DEL_FOLDER_ONLY;
2982 else if( aval == G_ALERTOTHER ) {
2983 delType = ADDRTREE_DEL_FOLDER_ADDR;
2987 else if( obj->type == ADDR_ITEM_GROUP ) {
2988 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2989 "The addresses it contains will not be lost."), obj->name);
2990 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2991 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2993 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2995 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2996 "The addresses it contains will be lost."), obj->name);
2997 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2998 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
3000 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
3002 if( delType == ADDRTREE_DEL_NONE ) return;
3004 /* Proceed with deletion */
3005 if( obj->type == ADDR_DATASOURCE ) {
3006 /* Remove node from tree */
3007 gtk_cmctree_remove_node( ctree, node );
3009 if (delType == ADDRTREE_DEL_DATA &&
3010 ds->interface && ds->interface->type == ADDR_IF_BOOK)
3011 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
3013 /* Remove data source. */
3014 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3015 addrindex_free_datasource( ds );
3020 /* Get reference to cache */
3021 adbase = ( AddrBookBase * ) ds->rawDataSource;
3022 if( adbase == NULL ) return;
3023 cache = adbase->addressCache;
3025 /* Remove query results folder */
3026 if( iface && iface->externalQuery ) {
3027 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3028 ItemFolder *folder = adapter->itemFolder;
3030 adapter->itemFolder = NULL;
3032 g_print( "remove folder for ::%s::\n", obj->name );
3033 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3034 g_print( "-------------- remove results\n" );
3036 addrindex_remove_results( ds, folder );
3037 /* g_print( "-------------- remove node\n" ); */
3038 gtk_cmctree_remove_node( ctree, node );
3042 /* Code below is valid for regular address book deletion */
3043 if( obj->type == ADDR_ITEM_FOLDER ) {
3044 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3045 ItemFolder *item = adapter->itemFolder;
3047 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3048 /* Remove folder only */
3049 item = addrcache_remove_folder( cache, item );
3051 addritem_free_item_folder( item );
3052 addressbook_move_nodes_up( ctree, node );
3056 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3057 /* Remove folder and addresses */
3058 item = addrcache_remove_folder_delete( cache, item );
3060 addritem_free_item_folder( item );
3065 else if( obj->type == ADDR_ITEM_GROUP ) {
3066 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3067 ItemGroup *item = adapter->itemGroup;
3069 item = addrcache_remove_group( cache, item );
3071 addritem_free_item_group( item );
3078 gtk_cmctree_remove_node(ctree, node );
3082 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3084 if( person && addrbook.treeSelected == addrbook.opened ) {
3085 person->status = ADD_ENTRY;
3086 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3087 addressbook_folder_refresh_one_person(
3088 GTK_CMCTREE(addrbook.clist), person );
3090 addressbook_address_list_set_focus();
3093 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3095 if( person && addrbook.treeSelected == addrbook.opened) {
3096 person->status = ADD_ENTRY;
3097 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3098 addressbook_set_clist(
3099 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3103 addressbook_address_list_set_focus();
3107 * Label (a format string) that is used to name each folder.
3109 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3112 * Search ctree widget callback function.
3113 * \param pA Pointer to node.
3114 * \param pB Pointer to data item being sought.
3115 * \return Zero (0) if folder found.
3117 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3120 aoA = ( AddressObject * ) pA;
3121 if( aoA->type == ADDR_ITEM_FOLDER ) {
3122 ItemFolder *folder, *fld;
3124 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3125 folder = ( ItemFolder * ) pB;
3126 if( fld == folder ) return 0; /* Found folder */
3131 static ItemFolder * addressbook_setup_subf(
3132 AddressDataSource *ds, gchar *title,
3133 GtkCMCTreeNode *pNode )
3135 AddrBookBase *adbase;
3136 AddressCache *cache;
3139 GtkCMCTreeNode *nNode;
3141 AddressObjectType aoType = ADDR_NONE;
3144 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3146 if( ds && ds->type == ADDR_IF_LDAP ) {
3148 aoType = ADDR_LDAP_QUERY;
3155 ctree = GTK_CMCTREE(addrbook.ctree);
3156 /* Get reference to address cache */
3157 adbase = ( AddrBookBase * ) ds->rawDataSource;
3158 cache = adbase->addressCache;
3160 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3161 GList *cur = children;
3162 for (; cur; cur = cur->next) {
3163 ItemFolder *child = (ItemFolder *) cur->data;
3164 if (!g_strcmp0(ADDRITEM_NAME(child), title)) {
3165 nNode = gtk_cmctree_find_by_row_data_custom(
3167 addressbook_treenode_find_folder_cb );
3169 addrindex_remove_results( ds, child );
3170 while( child->listPerson ) {
3171 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3172 item = addrcache_remove_person( cache, item );
3174 addritem_free_item_person( item );
3178 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3179 addrbook.treeSelected = nNode;
3186 /* Create a folder */
3187 folder = addrcache_add_new_folder( cache, NULL );
3188 name = g_strdup_printf( "%s", title );
3189 addritem_folder_set_name( folder, name );
3190 addritem_folder_set_remarks( folder, "" );
3193 /* Now let's see the folder */
3194 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3195 gtk_cmctree_expand( ctree, pNode );
3197 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3198 addrbook.treeSelected = nNode;
3204 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3205 AddressObject *pobj = NULL;
3206 AddressDataSource *ds = NULL;
3207 AddressBookFile *abf = NULL;
3208 debug_print("adding address\n");
3209 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3210 if( pobj == NULL ) {
3211 debug_print("no row data\n");
3214 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3216 debug_print("no datasource\n");
3220 abf = ds->rawDataSource;
3222 g_print("no addressbook file\n");
3226 if( pobj->type == ADDR_DATASOURCE ) {
3227 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3228 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3230 ItemFolder *folder = NULL;
3232 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3233 GtkCMCTreeNode *parentNode;
3234 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3235 if( ds == NULL ) return;
3237 /* We must have a datasource that is an external interface */
3238 if( ! ds->interface->haveLibrary ) return;
3239 if( ! ds->interface->externalQuery ) return;
3241 if( pobj->type == ADDR_ITEM_FOLDER ) {
3242 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3245 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3247 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3249 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3251 abf = ds->rawDataSource;
3254 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3255 addrbook.editaddress_vbox,
3256 addressbook_new_address_from_book_post_cb,
3259 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3260 LdapServer *server = ds->rawDataSource;
3261 ldapsvr_set_modified(server, TRUE);
3262 ldapsvr_update_book(server, NULL);
3263 if (server->retVal != LDAPRC_SUCCESS) {
3264 alertpanel( _("Add address(es)"),
3265 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3266 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3267 server->retVal = LDAPRC_SUCCESS;
3272 if (prefs_common.addressbook_use_editaddress_dialog)
3273 addressbook_new_address_from_book_post_cb( person );
3276 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3278 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3281 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3282 GtkCMCTreeNode *parentNode;
3283 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3284 if( ds == NULL ) return;
3286 /* We must have a datasource that is an external interface */
3287 if( ! ds->interface->haveLibrary ) return;
3288 if( ! ds->interface->externalQuery ) return;
3290 if( pobj->type == ADDR_ITEM_FOLDER ) {
3291 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3294 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3296 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3300 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3302 abf = ds->rawDataSource;
3305 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3306 addrbook.editaddress_vbox,
3307 addressbook_new_address_from_folder_post_cb,
3310 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3311 LdapServer *server = ds->rawDataSource;
3312 ldapsvr_set_modified(server, TRUE);
3313 ldapsvr_update_book(server, NULL);
3314 if (server->retVal != LDAPRC_SUCCESS) {
3315 alertpanel( _("Add address(es)"),
3316 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3317 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3322 if (prefs_common.addressbook_use_editaddress_dialog)
3323 addressbook_new_address_from_folder_post_cb( person );
3325 else if( pobj->type == ADDR_ITEM_GROUP ) {
3326 /* New address in group */
3327 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3328 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3329 if (addrbook.treeSelected == addrbook.opened) {
3330 /* Change node name in tree. */
3331 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3332 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3333 addressbook_set_clist(
3334 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3342 * Search for specified child group node in address index tree.
3343 * \param parent Parent node.
3344 * \param group Group to find.
3346 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3347 GtkCMCTreeNode *node = NULL;
3348 GtkCMCTreeRow *currRow;
3350 currRow = GTK_CMCTREE_ROW( parent );
3352 node = currRow->children;
3356 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3357 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3358 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3359 if( g == group ) return node;
3361 currRow = GTK_CMCTREE_ROW(node);
3362 node = currRow->sibling;
3368 static AddressBookFile *addressbook_get_book_file() {
3369 AddressBookFile *abf = NULL;
3370 AddressDataSource *ds = NULL;
3372 ds = addressbook_find_datasource( addrbook.treeSelected );
3373 if( ds == NULL ) return NULL;
3374 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3378 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3379 GtkCMCTreeNode *node;
3382 /* Remove existing folders and groups */
3383 row = GTK_CMCTREE_ROW( parent );
3385 while( (node = row->children) ) {
3386 gtk_cmctree_remove_node( ctree, node );
3391 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3392 GtkCMCTreeNode *parent, *child;
3393 GtkCMCTreeRow *currRow;
3394 currRow = GTK_CMCTREE_ROW( node );
3396 parent = currRow->parent;
3397 while( (child = currRow->children) ) {
3398 gtk_cmctree_move( ctree, child, parent, node );
3400 gtk_sctree_sort_node( ctree, parent );
3404 static void addressbook_edit_address_post_cb( ItemPerson *person )
3408 AddressBookFile *abf = addressbook_get_book_file();
3410 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3411 if (g_strcmp0(person->nickName, ADDRITEM_NAME(person)))
3412 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3415 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3416 invalidate_address_completion();
3418 addressbook_address_list_set_focus();
3421 void addressbook_address_list_set_focus( void )
3423 if (!prefs_common.addressbook_use_editaddress_dialog) {
3424 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3425 addressbook_list_menu_setup();
3429 void addressbook_address_list_disable_some_actions(void)
3431 /* disable address copy/pasting when editing contact's detail (embedded form) */
3432 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3433 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3434 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3437 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3438 addressbook_edit_address(data, 0, NULL, TRUE);
3441 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3442 gboolean force_focus ) {
3443 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3445 AddressObject *obj = NULL, *pobj = NULL;
3446 AddressDataSource *ds = NULL;
3447 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3449 AddressBookFile *abf = NULL;
3451 if( addrbook.listSelected == NULL ) return;
3452 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3453 cm_return_if_fail(obj != NULL);
3455 ctree = GTK_CMCTREE( addrbook.ctree );
3456 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3458 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3459 if( ds == NULL ) return;
3461 abf = addressbook_get_book_file();
3463 if( obj->type == ADDR_ITEM_EMAIL ) {
3464 ItemEMail *email = ( ItemEMail * ) obj;
3466 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3467 /* Edit parent group */
3468 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3469 ItemGroup *itemGrp = adapter->itemGroup;
3470 if( abf == NULL ) return;
3471 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3472 name = ADDRITEM_NAME(itemGrp);
3473 node = addrbook.treeSelected;
3474 parentNode = GTK_CMCTREE_ROW(node)->parent;
3477 /* Edit person - email page */
3479 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3480 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3481 addressbook_edit_address_post_cb,
3482 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3485 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3486 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3487 person->status = UPDATE_ENTRY;
3490 if (prefs_common.addressbook_use_editaddress_dialog)
3491 addressbook_edit_address_post_cb( person );
3496 else if( obj->type == ADDR_ITEM_PERSON ) {
3497 /* Edit person - basic page */
3498 ItemPerson *person = ( ItemPerson * ) obj;
3499 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3500 addressbook_edit_address_post_cb,
3501 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3504 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3505 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3506 person->status = UPDATE_ENTRY;
3509 if (prefs_common.addressbook_use_editaddress_dialog)
3510 addressbook_edit_address_post_cb( person );
3514 else if( obj->type == ADDR_ITEM_GROUP ) {
3515 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3516 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3517 parentNode = addrbook.treeSelected;
3518 node = addressbook_find_group_node( parentNode, itemGrp );
3519 name = ADDRITEM_NAME(itemGrp);
3520 invalidate_address_completion();
3526 /* Update tree node with node name */
3527 if( node == NULL ) return;
3528 addressbook_change_node_name( node, name );
3529 gtk_sctree_sort_node( ctree, parentNode );
3530 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3531 addressbook_set_clist(
3532 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3537 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3539 addressbook_del_clicked(NULL, NULL);
3542 static void close_cb(GtkAction *action, gpointer data)
3544 addressbook_close();
3547 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3548 addressbook_export_to_file();
3551 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3553 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3554 if( person ) addritem_person_set_opened( person, TRUE );
3558 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3560 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3561 if( person ) addritem_person_set_opened( person, FALSE );
3565 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3567 gchar *eMailAlias = ADDRITEM_NAME(email);
3568 if( eMailAlias && *eMailAlias != '\0' ) {
3570 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3573 str = g_strdup( eMailAlias );
3579 static gboolean addressbook_match_item(const gchar *name,
3580 const gchar *email_alias,
3582 const gchar *remarks,
3587 if (!str || str[0] == '\0')
3589 if (strcasestr(name, str))
3591 else if (email_alias && strcasestr(email_alias, str))
3593 else if (addr && strcasestr(addr, str))
3595 else if (remarks && strcasestr(remarks, str))
3601 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3602 GList *items = itemGroup->listEMail;
3603 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3604 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3605 for( ; items != NULL; items = g_list_next( items ) ) {
3606 GtkCMCTreeNode *nodeEMail = NULL;
3607 gchar *text[N_LIST_COLS];
3608 ItemEMail *email = items->data;
3612 if( ! email ) continue;
3614 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3616 if( !addressbook_match_item(ADDRITEM_NAME(person),
3617 ADDRITEM_NAME(email),
3618 email->address, email->remarks,
3622 str = addressbook_format_item_clist( person, email );
3624 text[COL_NAME] = addressbook_set_col_name_guard(str);
3627 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3629 text[COL_ADDRESS] = email->address;
3630 text[COL_REMARKS] = email->remarks;
3631 nodeEMail = gtk_sctree_insert_node(
3633 text, FOLDER_SPACING,
3637 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3643 gchar *addressbook_set_col_name_guard(gchar *value)
3645 gchar *ret = "<not set>";
3646 gchar *tmp = g_strdup(value);
3648 if (tmp !=NULL && *tmp != '\0')
3654 static void addressbook_folder_load_one_person(
3655 GtkCMCTree *clist, ItemPerson *person,
3656 AddressTypeControlItem *atci,
3657 AddressTypeControlItem *atciMail )
3659 GtkCMCTreeNode *nodePerson = NULL;
3660 GtkCMCTreeNode *nodeEMail = NULL;
3661 gchar *text[N_LIST_COLS];
3662 gboolean flgFirst = TRUE, haveAddr = FALSE;
3665 AddressBookFile *abf = addressbook_get_book_file();
3668 if( person == NULL ) return;
3670 text[COL_NAME] = "";
3671 node = person->listEMail;
3673 ItemEMail *email = node->data;
3674 gchar *eMailAddr = NULL;
3675 node = g_list_next( node );
3677 text[COL_ADDRESS] = email->address;
3678 text[COL_REMARKS] = email->remarks;
3679 eMailAddr = ADDRITEM_NAME(email);
3680 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3682 /* First email belongs with person */
3683 gchar *str = addressbook_format_item_clist( person, email );
3685 text[COL_NAME] = addressbook_set_col_name_guard(str);
3688 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3689 person && person->nickName ) {
3690 if (person->nickName) {
3691 if (strcmp(person->nickName, "") != 0) {
3692 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3695 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3701 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3703 nodePerson = gtk_sctree_insert_node(
3705 text, FOLDER_SPACING,
3708 FALSE, person->isOpened );
3711 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3714 /* Subsequent email is a child node of person */
3715 text[COL_NAME] = ADDRITEM_NAME(email);
3716 nodeEMail = gtk_sctree_insert_node(
3717 clist, nodePerson, NULL,
3718 text, FOLDER_SPACING,
3720 atciMail->iconXpmOpen,
3722 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3728 /* Have name without EMail */
3729 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3730 text[COL_ADDRESS] = "";
3731 text[COL_REMARKS] = "";
3732 nodePerson = gtk_sctree_insert_node(
3734 text, FOLDER_SPACING,
3737 FALSE, person->isOpened );
3738 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3743 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3745 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3746 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3747 const gchar *search_str;
3749 if( atci == NULL ) return;
3750 if( atciMail == NULL ) return;
3752 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3754 /* Load email addresses */
3755 items = addritem_folder_get_person_list( itemFolder );
3756 for(cur = items ; cur != NULL; cur = g_list_next( cur ) ) {
3761 person = (ItemPerson *)cur->data;
3764 node = person->listEMail;
3765 if (node && node->data) {
3767 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3770 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3774 addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
3776 /* Free up the list */
3777 mgu_clear_list( items );
3778 g_list_free( items );
3781 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3782 addrbook.listSelected = NULL;
3783 gtk_cmctree_remove_node( clist, node );
3784 addressbook_menubar_set_sensitive( FALSE );
3785 addressbook_menuitem_set_sensitive(
3786 gtk_cmctree_node_get_row_data(
3787 GTK_CMCTREE(clist), addrbook.treeSelected ),
3788 addrbook.treeSelected );
3791 void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3792 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3793 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3794 GtkCMCTreeNode *node;
3795 if( atci == NULL ) return;
3796 if( atciMail == NULL ) return;
3797 if( person == NULL ) return;
3798 /* unload the person */
3800 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3802 addressbook_folder_remove_node( clist, node );
3803 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3804 gtk_sctree_sort_node( clist, NULL );
3805 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3807 gtk_sctree_select( GTK_SCTREE(clist), node );
3808 if (!gtk_cmctree_node_is_visible( clist, node ) )
3809 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3813 void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3814 GtkCMCTreeNode *node;
3816 if( person == NULL ) return;
3817 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3819 addressbook_folder_remove_node( clist, node );
3823 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3825 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3826 const gchar *search_str;
3828 /* Load any groups */
3829 if( ! atci ) return;
3831 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3833 items = addritem_folder_get_group_list( itemFolder );
3834 for( ; items != NULL; items = g_list_next( items ) ) {
3835 GtkCMCTreeNode *nodeGroup = NULL;
3836 gchar *text[N_LIST_COLS];
3837 ItemGroup *group = items->data;
3838 if( group == NULL ) continue;
3839 if( !addressbook_match_item(ADDRITEM_NAME(group),
3840 NULL, NULL, NULL, search_str) )
3843 text[COL_NAME] = ADDRITEM_NAME(group);
3844 text[COL_ADDRESS] = "";
3845 text[COL_REMARKS] = "";
3846 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3847 text, FOLDER_SPACING,
3851 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3852 gtk_sctree_sort_node(clist, NULL);
3854 /* Free up the list */
3855 mgu_clear_list( items );
3856 g_list_free( items );
3860 * Search ctree widget callback function.
3861 * \param pA Pointer to node.
3862 * \param pB Pointer to data item being sought.
3863 * \return Zero (0) if group found.
3865 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3868 aoA = ( AddressObject * ) pA;
3869 if( aoA->type == ADDR_ITEM_GROUP ) {
3870 ItemGroup *group, *grp;
3872 grp = ADAPTER_GROUP(aoA)->itemGroup;
3873 group = ( ItemGroup * ) pB;
3874 if( grp == group ) return 0; /* Found group */
3880 * Remove folder and group nodes from tree widget for items contained ("cut")
3883 static void addressbook_treenode_remove_item( void ) {
3885 AddrSelectItem *cutItem;
3886 AddressCache *cache;
3887 AddrItemObject *aio;
3888 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3891 node = _clipBoard_->objectList;
3893 cutItem = node->data;
3894 node = g_list_next( node );
3895 cache = addrindex_get_cache(
3896 _clipBoard_->addressIndex, cutItem->cacheID );
3897 if( cache == NULL ) continue;
3898 aio = addrcache_get_object( cache, cutItem->uid );
3901 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3904 folder = ( ItemFolder * ) aio;
3905 tn = gtk_cmctree_find_by_row_data_custom(
3906 ctree, NULL, folder,
3907 addressbook_treenode_find_folder_cb );
3909 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3912 group = ( ItemGroup * ) aio;
3913 tn = gtk_cmctree_find_by_row_data_custom(
3915 addressbook_treenode_find_group_cb );
3919 /* Free up adapter and remove node. */
3920 gtk_cmctree_remove_node( ctree, tn );
3927 * Find parent datasource for specified tree node.
3928 * \param node Node to test.
3929 * \return Data source, or NULL if not found.
3931 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3932 AddressDataSource *ds = NULL;
3935 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3938 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3939 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3941 /* g_print( "ao->type = %d\n", ao->type ); */
3942 if( ao->type == ADDR_DATASOURCE ) {
3943 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3944 /* g_print( "found it\n" ); */
3945 ds = ads->dataSource;
3949 node = GTK_CMCTREE_ROW(node)->parent;
3955 * Load address list widget with children of specified object.
3956 * \param obj Parent object to be loaded.
3958 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3959 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3960 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3961 AddressDataSource *ds = NULL;
3962 AdapterDSource *ads = NULL;
3963 static AddressObject *last_obj = NULL;
3965 if (addrbook.clist == NULL) {
3968 if (obj == last_obj && !refresh)
3973 gtk_cmclist_clear(clist);
3977 if( obj->type == ADDR_INTERFACE ) {
3978 /* g_print( "set_clist: loading datasource...\n" ); */
3979 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3983 gtk_cmclist_freeze(clist);
3984 gtk_cmclist_clear(clist);
3986 if( obj->type == ADDR_DATASOURCE ) {
3987 ads = ADAPTER_DSOURCE(obj);
3988 ds = ads->dataSource;
3990 /* Load root folder */
3991 ItemFolder *rootFolder = NULL;
3992 rootFolder = addrindex_ds_get_root_folder( ds );
3993 addressbook_folder_load_person(
3994 ctreelist, rootFolder );
3995 addressbook_folder_load_group(
3996 ctreelist, rootFolder );
4000 if( obj->type == ADDR_ITEM_GROUP ) {
4002 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
4003 addressbook_load_group( ctreelist, itemGroup );
4005 else if( obj->type == ADDR_ITEM_FOLDER ) {
4007 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
4008 addressbook_folder_load_person( ctreelist, itemFolder );
4009 addressbook_folder_load_group( ctreelist, itemFolder );
4012 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
4013 clist->focus_row = -1;
4014 gtk_cmclist_thaw(clist);
4018 * Call back function to free adaptor. Call back is setup by function
4019 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4020 * called when the address book tree widget node is removed by calling
4021 * function gtk_cmctree_remove_node().
4023 * \param data Tree node's row data.
4025 static void addressbook_free_treenode( gpointer data ) {
4028 ao = ( AddressObject * ) data;
4029 if( ao == NULL ) return;
4030 if( ao->type == ADDR_INTERFACE ) {
4031 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
4032 addrbookctl_free_interface( ai );
4034 else if( ao->type == ADDR_DATASOURCE ) {
4035 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
4036 addrbookctl_free_datasource( ads );
4038 else if( ao->type == ADDR_ITEM_FOLDER ) {
4039 AdapterFolder *af = ADAPTER_FOLDER(ao);
4040 addrbookctl_free_folder( af );
4042 else if( ao->type == ADDR_ITEM_GROUP ) {
4043 AdapterGroup *ag = ADAPTER_GROUP(ao);
4044 addrbookctl_free_group( ag );
4049 * Create new adaptor for specified data source.
4051 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4052 AddressObjectType otype, gchar *name )
4054 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4055 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4056 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4057 adapter->dataSource = ds;
4058 adapter->subType = otype;
4062 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4063 ADDRESS_OBJECT_NAME(adapter) =
4064 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4068 * Load tree from address index with the initial data.
4070 static void addressbook_load_tree( void ) {
4071 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4072 GList *nodeIf, *nodeDS;
4073 AdapterInterface *adapter;
4074 AddressInterface *iface;
4075 AddressTypeControlItem *atci;
4076 AddressDataSource *ds;
4077 AdapterDSource *ads;
4078 GtkCMCTreeNode *node, *newNode;
4081 nodeIf = _addressInterfaceList_;
4083 adapter = nodeIf->data;
4084 node = adapter->treeNode;
4085 iface = adapter->interface;
4086 atci = adapter->atci;
4088 if( iface->useInterface ) {
4089 /* Load data sources below interface node */
4090 nodeDS = iface->listSource;
4093 name = addrindex_ds_get_name( ds );
4094 ads = addressbook_create_ds_adapter(
4095 ds, atci->objectType, name );
4096 newNode = addressbook_add_object(
4097 node, ADDRESS_OBJECT(ads) );
4098 if (newNode == NULL) {
4099 g_message("error adding addressbook object\n");
4101 nodeDS = g_list_next( nodeDS );
4103 gtk_cmctree_expand( ctree, node );
4106 nodeIf = g_list_next( nodeIf );
4111 * Convert the old address book to new format.
4113 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4114 gboolean retVal = FALSE;
4115 gboolean errFlag = TRUE;
4118 /* Read old address book, performing conversion */
4119 debug_print( "Reading and converting old address book...\n" );
4120 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4121 addrindex_read_data( addrIndex );
4122 if( addrIndex->retVal == MGU_NO_FILE ) {
4123 /* We do not have a file - new user */
4124 debug_print( "New user... create new books...\n" );
4125 addrindex_create_new_books( addrIndex );
4126 if( addrIndex->retVal == MGU_SUCCESS ) {
4127 /* Save index file */
4128 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4129 addrindex_save_data( addrIndex );
4130 if( addrIndex->retVal == MGU_SUCCESS ) {
4135 msg = _( "New user, could not save index file." );
4139 msg = _( "New user, could not save address book files." );
4143 /* We have an old file */
4144 if( addrIndex->wasConverted ) {
4145 /* Converted successfully - save address index */
4146 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4147 addrindex_save_data( addrIndex );
4148 if( addrIndex->retVal == MGU_SUCCESS ) {
4149 msg = _( "Old address book converted successfully." );
4154 msg = _("Old address book converted,\n"
4155 "could not save new address index file." );
4159 /* File conversion failed - just create new books */
4160 debug_print( "File conversion failed... just create new books...\n" );
4161 addrindex_create_new_books( addrIndex );
4162 if( addrIndex->retVal == MGU_SUCCESS ) {
4164 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4165 addrindex_save_data( addrIndex );
4166 if( addrIndex->retVal == MGU_SUCCESS ) {
4167 msg = _("Could not convert address book,\n"
4168 "but created empty new address book files." );
4173 msg = _("Could not convert address book,\n"
4174 "could not save new address index file." );
4178 msg = _("Could not convert address book\n"
4179 "and could not create new address book files." );
4184 debug_print( "Error\n%s\n", msg );
4185 alertpanel_full(_("Addressbook conversion error"), msg,
4186 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4190 debug_print( "Warning\n%s\n", msg );
4191 alertpanel_full(_("Addressbook conversion error"), msg,
4192 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4193 NULL, ALERT_WARNING);
4199 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4203 gboolean failed = FALSE;
4204 GError *error = NULL;
4206 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4207 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4208 error->code, error->message);
4209 g_error_free(error);
4213 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4214 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4217 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4219 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4221 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4234 /* all copies succeeded, we can remove source files */
4235 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4236 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4237 error->code, error->message);
4238 g_error_free(error);
4241 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4242 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4245 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4247 claws_unlink(orig_file);
4257 void addressbook_read_file( void ) {
4258 AddressIndex *addrIndex = NULL;
4259 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4261 debug_print( "Reading address index...\n" );
4262 if( _addressIndex_ ) {
4263 debug_print( "address book already read!!!\n" );
4268 addrIndex = addrindex_create_index();
4269 addrindex_initialize();
4271 /* Use new address book index. */
4273 if ( !is_dir_exist(indexdir) ) {
4274 if ( make_dir(indexdir) < 0 ) {
4275 addrindex_set_file_path( addrIndex, get_rc_dir() );
4276 g_warning( "couldn't create dir '%s'", indexdir);
4278 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4279 remove_dir_recursive(indexdir);
4280 addrindex_set_file_path( addrIndex, get_rc_dir() );
4281 g_error("couldn't migrate dir %s", indexdir);
4283 addrindex_set_file_path( addrIndex, indexdir);
4287 addrindex_set_file_path( addrIndex, indexdir);
4290 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4291 addrindex_read_data( addrIndex );
4292 if( addrIndex->retVal == MGU_NO_FILE ) {
4293 /* Conversion required */
4294 debug_print( "Converting...\n" );
4295 if( addressbook_convert( addrIndex ) ) {
4296 _addressIndex_ = addrIndex;
4299 else if( addrIndex->retVal == MGU_SUCCESS ) {
4300 _addressIndex_ = addrIndex;
4303 /* Error reading address book */
4304 debug_print( "Could not read address index.\n" );
4305 addrindex_print_index( addrIndex, stdout );
4306 alertpanel_full(_("Addressbook Error"),
4307 _("Could not read address index"),
4308 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4311 debug_print( "done.\n" );
4315 * Add object into the address index tree widget.
4316 * Enter: node Parent node.
4317 * obj Object to add.
4318 * Return: Node that was added, or NULL if object not added.
4320 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4323 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4324 GtkCMCTreeNode *added;
4325 AddressObject *pobj;
4326 AddressObjectType otype;
4327 AddressTypeControlItem *atci = NULL;
4329 cm_return_val_if_fail(node != NULL, NULL);
4330 cm_return_val_if_fail(obj != NULL, NULL);
4332 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4333 cm_return_val_if_fail(pobj != NULL, NULL);
4335 /* Determine object type to be displayed */
4336 if( obj->type == ADDR_DATASOURCE ) {
4337 otype = ADAPTER_DSOURCE(obj)->subType;
4343 /* Handle any special conditions. */
4345 atci = addrbookctl_lookup( otype );
4347 if( atci->showInTree ) {
4348 /* Add object to tree */
4351 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4352 atci->iconXpm, atci->iconXpmOpen,
4353 atci->treeLeaf, atci->treeExpand );
4354 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4355 addressbook_free_treenode );
4359 gtk_sctree_sort_node(ctree, node);
4365 * Add group into the address index tree.
4366 * \param node Parent node.
4367 * \param ds Data source.
4368 * \param itemGroup Group to add.
4369 * \return Inserted node.
4371 static GtkCMCTreeNode *addressbook_node_add_group(
4372 GtkCMCTreeNode *node, AddressDataSource *ds,
4373 ItemGroup *itemGroup )
4375 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4376 GtkCMCTreeNode *newNode;
4377 AdapterGroup *adapter;
4378 AddressTypeControlItem *atci = NULL;
4381 if( ds == NULL ) return NULL;
4382 if( node == NULL || itemGroup == NULL ) return NULL;
4384 name = &itemGroup->obj.name;
4386 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4388 adapter = g_new0( AdapterGroup, 1 );
4389 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4390 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4391 adapter->itemGroup = itemGroup;
4393 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4394 atci->iconXpm, atci->iconXpm,
4395 atci->treeLeaf, atci->treeExpand );
4396 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4397 addressbook_free_treenode );
4398 gtk_sctree_sort_node( ctree, node );
4403 * Add folder into the address index tree. Only visible folders are loaded into
4404 * the address index tree. Note that the root folder is not inserted into the
4407 * \param node Parent node.
4408 * \param ds Data source.
4409 * \param itemFolder Folder to add.
4410 * \param otype Object type to display.
4411 * \return Inserted node for the folder.
4413 static GtkCMCTreeNode *addressbook_node_add_folder(
4414 GtkCMCTreeNode *node, AddressDataSource *ds,
4415 ItemFolder *itemFolder, AddressObjectType otype )
4417 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4418 GtkCMCTreeNode *newNode = NULL;
4419 AdapterFolder *adapter;
4420 AddressTypeControlItem *atci = NULL;
4421 GList *listItems = NULL;
4423 ItemFolder *rootFolder;
4425 /* Only visible folders */
4426 if( itemFolder == NULL || itemFolder->isHidden )
4431 if( node == NULL || itemFolder == NULL )
4434 /* Determine object type */
4435 atci = addrbookctl_lookup( otype );
4439 rootFolder = addrindex_ds_get_root_folder( ds );
4440 if( itemFolder == rootFolder ) {
4444 adapter = g_new0( AdapterFolder, 1 );
4445 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4446 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4447 adapter->itemFolder = itemFolder;
4449 name = ADDRITEM_NAME(itemFolder);
4450 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4451 atci->iconXpm, atci->iconXpm,
4452 atci->treeLeaf, atci->treeExpand );
4454 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4455 addressbook_free_treenode );
4459 listItems = itemFolder->listFolder;
4460 while( listItems ) {
4461 ItemFolder *item = listItems->data;
4462 addressbook_node_add_folder( newNode, ds, item, otype );
4463 listItems = g_list_next( listItems );
4465 listItems = itemFolder->listGroup;
4466 while( listItems ) {
4467 ItemGroup *item = listItems->data;
4468 addressbook_node_add_group( newNode, ds, item );
4469 listItems = g_list_next( listItems );
4471 gtk_sctree_sort_node( ctree, node );
4475 void addressbook_export_to_file( void ) {
4476 if( _addressIndex_ ) {
4477 /* Save all new address book data */
4478 debug_print( "Saving address books...\n" );
4479 addrindex_save_all_books( _addressIndex_ );
4481 debug_print( "Exporting addressbook to file...\n" );
4482 addrindex_save_data( _addressIndex_ );
4483 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4484 addrindex_print_index( _addressIndex_, stdout );
4487 /* Notify address completion of new data */
4488 invalidate_address_completion();
4492 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4494 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4495 addressbook_lup_clicked(NULL, NULL);
4500 * Comparison using cell contents (text in first column). Used for sort
4501 * address index widget.
4503 static gint addressbook_treenode_compare_func(
4504 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4506 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4507 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4508 gchar *name1 = NULL, *name2 = NULL;
4509 if( cell1 ) name1 = cell1->u.text;
4510 if( cell2 ) name2 = cell2->u.text;
4511 if( ! name1 ) return ( name2 != NULL );
4512 if( ! name2 ) return -1;
4513 return g_utf8_collate( name1, name2 );
4516 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4517 AdapterDSource *ads;
4518 AdapterInterface *adapter;
4519 GtkCMCTreeNode *newNode;
4521 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4522 if( adapter == NULL ) return;
4523 ads = addressbook_edit_book( _addressIndex_, NULL );
4525 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4527 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4528 addrbook.treeSelected = newNode;
4533 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4534 AdapterDSource *ads;
4535 AdapterInterface *adapter;
4536 GtkCMCTreeNode *newNode;
4538 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4539 if( adapter == NULL ) return;
4540 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4542 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4544 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4545 addrbook.treeSelected = newNode;
4551 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4552 AdapterDSource *ads;
4553 AdapterInterface *adapter;
4554 AddressInterface *iface;
4555 GtkCMCTreeNode *newNode;
4557 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4558 if( adapter == NULL ) return;
4559 iface = adapter->interface;
4560 if( ! iface->haveLibrary ) return;
4561 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4563 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4565 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4566 addrbook.treeSelected = newNode;
4573 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4574 AdapterDSource *ads;
4575 AdapterInterface *adapter;
4576 AddressInterface *iface;
4577 GtkCMCTreeNode *newNode;
4579 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4580 if( adapter == NULL ) return;
4581 iface = adapter->interface;
4582 if( ! iface->haveLibrary ) return;
4583 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4585 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4587 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4588 addrbook.treeSelected = newNode;
4595 * Display address search status message.
4596 * \param queryType Query type.
4597 * \param status Status/Error code.
4599 static void addressbook_search_message( gint queryType, gint sts ) {
4601 *addressbook_msgbuf = '\0';
4603 if( sts != MGU_SUCCESS ) {
4604 if( queryType == ADDRQUERY_LDAP ) {
4606 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4611 g_snprintf( addressbook_msgbuf,
4612 sizeof(addressbook_msgbuf), "%s", desc );
4613 addressbook_status_show( addressbook_msgbuf );
4616 addressbook_status_show( "" );
4621 * Refresh addressbook by forcing refresh of current selected object in
4624 static void addressbook_refresh_current( void ) {
4628 ctree = GTK_CMCTREE(addrbook.ctree);
4629 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4630 if( obj == NULL ) return;
4631 addressbook_set_clist( obj, TRUE );
4635 * Message that is displayed whilst a query is executing in a background
4638 static gchar *_tempMessage_ = N_( "Busy searching..." );
4641 * Address search idle function. This function is called during UI idle time
4642 * while a search is in progress.
4644 * \param data Idler data.
4646 static void addressbook_search_idle( gpointer data ) {
4650 queryID = GPOINTER_TO_INT( data );
4651 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4656 * Search completion callback function. This removes the query from the idle
4659 * \param sender Sender of query.
4660 * \param queryID Query ID of search request.
4661 * \param status Search status.
4662 * \param data Query data.
4664 static void addressbook_search_callback_end(
4665 gpointer sender, gint queryID, gint status, gpointer data )
4669 AddrQueryObject *aqo;
4671 /* Remove idler function */
4672 ptrQID = GINT_TO_POINTER( queryID );
4674 g_idle_remove_by_data( ptrQID );
4677 /* Refresh addressbook contents */
4678 addressbook_refresh_current();
4679 req = qrymgr_find_request( queryID );
4681 aqo = ( AddrQueryObject * ) req->queryList->data;
4682 addressbook_search_message( aqo->queryType, status );
4685 /* Stop the search */
4686 addrindex_stop_search( queryID );
4692 * \param ds Data source to search.
4693 * \param searchTerm String to lookup.
4694 * \param pNode Parent data source node.
4696 static void addressbook_perform_search(
4697 AddressDataSource *ds, gchar *searchTerm,
4698 GtkCMCTreeNode *pNode )
4706 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4708 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4710 /* Create a folder for the search results */
4711 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4712 folder = addressbook_setup_subf(ds, name, pNode);
4715 /* Setup the search */
4716 queryID = addrindex_setup_explicit_search(
4717 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4718 if( queryID == 0 ) return;
4720 /* Set up idler function */
4721 idleID = g_idle_add(
4722 (GSourceFunc) addressbook_search_idle,
4723 GINT_TO_POINTER( queryID ) );
4725 g_message("error adding addressbook_search_idle\n");
4728 /* Start search, sit back and wait for something to happen */
4729 addrindex_start_search( queryID );
4731 addressbook_status_show( _tempMessage_ );
4735 * Lookup button handler. Address search is only performed against
4736 * address interfaces for external queries.
4738 * \param button Lookup button widget.
4739 * \param data Data object.
4741 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4744 AddressDataSource *ds;
4745 AddressInterface *iface;
4747 GtkCMCTreeNode *node, *parentNode;
4749 LdapServer *ldap_server;
4750 LdapControl *ldap_ctl;
4753 node = addrbook.treeSelected;
4754 if( ! node ) return;
4755 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4757 ctree = GTK_CMCTREE(addrbook.ctree);
4758 obj = gtk_cmctree_node_get_row_data( ctree, node );
4759 if( obj == NULL ) return;
4761 if (obj->type != ADDR_DATASOURCE ||
4762 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4763 addressbook_set_clist(
4764 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4765 addrbook.treeSelected),
4769 ds = addressbook_find_datasource( node );
4770 if( ds == NULL ) return;
4772 /* We must have a datasource that is an external interface */
4773 iface = ds->interface;
4774 if( ! iface->haveLibrary ) return;
4775 if( ! iface->externalQuery ) return;
4778 if (iface->type == ADDR_IF_LDAP) {
4779 ldap_server = ds->rawDataSource;
4780 ldap_ctl = ldap_server->control;
4781 if (ldap_ctl != NULL &&
4782 ldap_ctl->bindDN != NULL && strlen(ldap_ctl->bindDN) > 0) {
4783 #ifndef PASSWORD_CRYPTO_OLD
4784 /* LDAP server is password-protected. */
4785 if (master_passphrase() == NULL) {
4786 /* User did not enter master passphrase, do not start a search. */
4789 #endif /* PASSWORD_CRYPTO_OLD */
4792 #endif /* USE_LDAP */
4795 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4796 g_strchomp( searchTerm );
4798 if( obj->type == ADDR_ITEM_FOLDER ) {
4799 parentNode = GTK_CMCTREE_ROW(node)->parent;
4804 addressbook_perform_search( ds, searchTerm, parentNode );
4806 gtk_widget_grab_focus( addrbook.entry );
4808 g_free( searchTerm );
4811 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4812 addressbook_close();
4817 * Browse address entry for highlighted entry.
4819 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4821 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4823 AddressDataSource *ds;
4824 AddressInterface *iface;
4828 if(addrbook.listSelected == NULL)
4831 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4835 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4839 iface = ds->interface;
4840 if(!iface || !iface->haveLibrary )
4844 if (obj->type == ADDR_ITEM_EMAIL) {
4845 email = ( ItemEMail * ) obj;
4847 person = (ItemPerson *) ADDRITEM_PARENT(email);
4849 else if (obj->type == ADDR_ITEM_PERSON) {
4850 person = (ItemPerson *) obj;
4857 if( iface && iface->type == ADDR_IF_LDAP ) {
4858 browseldap_entry(ds, person->externalID);
4863 /* **********************************************************************
4864 * Build lookup tables.
4865 * ***********************************************************************
4869 * Remap object types.
4870 * Enter: abType AddressObjectType (used in tree node).
4871 * Return: ItemObjectType (used in address cache data).
4873 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4874 ItemObjectType ioType;
4877 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4878 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4879 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4880 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4881 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4882 default: ioType = ITEMTYPE_NONE; break;
4887 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4888 atci = addrbookctl_lookup(id); \
4890 atci->iconXpm = icon; \
4891 atci->iconXpmOpen = iconopen; \
4893 g_warning("can't get atci %d", id); \
4898 * Build table that controls the rendering of object types.
4900 static void addrbookctl_build_icons( GtkWidget *window ) {
4901 AddressTypeControlItem *atci;
4905 g_object_unref(interfacexpm);
4907 g_object_unref(folderxpm);
4909 g_object_unref(folderopenxpm);
4911 g_object_unref(groupxpm);
4913 g_object_unref(vcardxpm);
4915 g_object_unref(bookxpm);
4917 g_object_unref(addressxpm);
4919 g_object_unref(jpilotxpm);
4921 g_object_unref(categoryxpm);
4923 g_object_unref(ldapxpm);
4925 g_object_unref(addrsearchxpm);
4926 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4927 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4928 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4929 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4930 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4931 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4932 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4933 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4934 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4935 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4936 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4938 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4939 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4940 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4941 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4942 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4943 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4944 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4945 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4946 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4947 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4948 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4953 * Build table that controls the rendering of object types.
4955 static void addrbookctl_build_map( GtkWidget *window ) {
4956 AddressTypeControlItem *atci;
4958 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4959 _addressBookTypeList_ = NULL;
4962 atci = g_new0( AddressTypeControlItem, 1 );
4963 atci->objectType = ADDR_INTERFACE;
4964 atci->interfaceType = ADDR_IF_NONE;
4965 atci->showInTree = TRUE;
4966 atci->treeExpand = TRUE;
4967 atci->treeLeaf = FALSE;
4968 atci->displayName = _( "Interface" );
4969 atci->menuCommand = NULL;
4970 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4971 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4974 atci = g_new0( AddressTypeControlItem, 1 );
4975 atci->objectType = ADDR_BOOK;
4976 atci->interfaceType = ADDR_IF_BOOK;
4977 atci->showInTree = TRUE;
4978 atci->treeExpand = TRUE;
4979 atci->treeLeaf = FALSE;
4980 atci->displayName = _("Address Books");
4981 atci->menuCommand = "Menu/Book/NewBook";
4982 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4983 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4986 atci = g_new0( AddressTypeControlItem, 1 );
4987 atci->objectType = ADDR_ITEM_PERSON;
4988 atci->interfaceType = ADDR_IF_NONE;
4989 atci->showInTree = FALSE;
4990 atci->treeExpand = FALSE;
4991 atci->treeLeaf = FALSE;
4992 atci->displayName = _( "Person" );
4993 atci->menuCommand = NULL;
4994 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4995 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4998 atci = g_new0( AddressTypeControlItem, 1 );
4999 atci->objectType = ADDR_ITEM_EMAIL;
5000 atci->interfaceType = ADDR_IF_NONE;
5001 atci->showInTree = FALSE;
5002 atci->treeExpand = FALSE;
5003 atci->treeLeaf = TRUE;
5004 atci->displayName = _( "Email Address" );
5005 atci->menuCommand = NULL;
5006 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5007 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5010 atci = g_new0( AddressTypeControlItem, 1 );
5011 atci->objectType = ADDR_ITEM_GROUP;
5012 atci->interfaceType = ADDR_IF_BOOK;
5013 atci->showInTree = TRUE;
5014 atci->treeExpand = FALSE;
5015 atci->treeLeaf = FALSE;
5016 atci->displayName = _( "Group" );
5017 atci->menuCommand = NULL;
5018 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5019 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5022 atci = g_new0( AddressTypeControlItem, 1 );
5023 atci->objectType = ADDR_ITEM_FOLDER;
5024 atci->interfaceType = ADDR_IF_BOOK;
5025 atci->showInTree = TRUE;
5026 atci->treeExpand = FALSE;
5027 atci->treeLeaf = FALSE;
5028 atci->displayName = _( "Folder" );
5029 atci->menuCommand = NULL;
5030 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5031 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5034 atci = g_new0( AddressTypeControlItem, 1 );
5035 atci->objectType = ADDR_VCARD;
5036 atci->interfaceType = ADDR_IF_VCARD;
5037 atci->showInTree = TRUE;
5038 atci->treeExpand = TRUE;
5039 atci->treeLeaf = TRUE;
5040 atci->displayName = _( "vCard" );
5041 atci->menuCommand = "Menu/Book/NewVCard";
5042 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5043 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5046 atci = g_new0( AddressTypeControlItem, 1 );
5047 atci->objectType = ADDR_JPILOT;
5048 atci->interfaceType = ADDR_IF_JPILOT;
5049 atci->showInTree = TRUE;
5050 atci->treeExpand = TRUE;
5051 atci->treeLeaf = FALSE;
5052 atci->displayName = _( "JPilot" );
5053 atci->menuCommand = "Menu/Book/NewJPilot";
5054 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5055 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5058 atci = g_new0( AddressTypeControlItem, 1 );
5059 atci->objectType = ADDR_CATEGORY;
5060 atci->interfaceType = ADDR_IF_JPILOT;
5061 atci->showInTree = TRUE;
5062 atci->treeExpand = TRUE;
5063 atci->treeLeaf = TRUE;
5064 atci->displayName = _( "JPilot" );
5065 atci->menuCommand = NULL;
5066 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5067 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5070 atci = g_new0( AddressTypeControlItem, 1 );
5071 atci->objectType = ADDR_LDAP;
5072 atci->interfaceType = ADDR_IF_LDAP;
5073 atci->showInTree = TRUE;
5074 atci->treeExpand = TRUE;
5075 atci->treeLeaf = FALSE;
5076 atci->displayName = _( "LDAP servers" );
5077 atci->menuCommand = "Menu/Book/NewLDAPServer";
5078 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5079 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5082 atci = g_new0( AddressTypeControlItem, 1 );
5083 atci->objectType = ADDR_LDAP_QUERY;
5084 atci->interfaceType = ADDR_IF_LDAP;
5085 atci->showInTree = TRUE;
5086 atci->treeExpand = FALSE;
5087 atci->treeLeaf = TRUE;
5088 atci->displayName = _( "LDAP Query" );
5089 atci->menuCommand = NULL;
5090 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5091 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5093 addrbookctl_build_icons(window);
5096 void addressbook_reflect_prefs_pixmap_theme(void)
5098 if (addrbook.window)
5099 addrbookctl_build_icons(addrbook.window);
5103 * Search for specified object type.
5105 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5107 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5111 * Search for specified interface type.
5113 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5114 GList *node = _addressBookTypeList_;
5116 AddressTypeControlItem *atci = node->data;
5117 if( atci->interfaceType == ifType ) return atci;
5118 node = g_list_next( node );
5123 static void addrbookctl_free_address( AddressObject *obj ) {
5124 g_free( obj->name );
5125 obj->type = ADDR_NONE;
5129 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5130 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5131 adapter->interface = NULL;
5132 adapter->interfaceType = ADDR_IF_NONE;
5133 adapter->atci = NULL;
5134 adapter->enabled = FALSE;
5135 adapter->haveLibrary = FALSE;
5136 adapter->treeNode = NULL;
5140 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5141 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5142 adapter->dataSource = NULL;
5143 adapter->subType = ADDR_NONE;
5147 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5148 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5149 adapter->itemFolder = NULL;
5153 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5154 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5155 adapter->itemGroup = NULL;
5160 * Build GUI interface list.
5162 static void addrbookctl_build_iflist( void ) {
5163 AddressTypeControlItem *atci;
5164 AdapterInterface *adapter;
5167 if( _addressIndex_ == NULL ) {
5168 _addressIndex_ = addrindex_create_index();
5169 if( _clipBoard_ == NULL ) {
5170 _clipBoard_ = addrclip_create();
5172 addrclip_set_index( _clipBoard_, _addressIndex_ );
5174 _addressInterfaceList_ = NULL;
5175 list = addrindex_get_interface_list( _addressIndex_ );
5177 AddressInterface *interface = list->data;
5178 atci = addrbookctl_lookup_iface( interface->type );
5180 adapter = g_new0( AdapterInterface, 1 );
5181 adapter->interfaceType = interface->type;
5182 adapter->atci = atci;
5183 adapter->interface = interface;
5184 adapter->treeNode = NULL;
5185 adapter->enabled = TRUE;
5186 adapter->haveLibrary = interface->haveLibrary;
5187 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5188 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5189 _addressInterfaceList_ =
5190 g_list_append( _addressInterfaceList_, adapter );
5192 list = g_list_next( list );
5197 * Find GUI interface type specified interface type.
5198 * \param ifType Interface type.
5199 * \return Interface item, or NULL if not found.
5201 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5202 GList *node = _addressInterfaceList_;
5204 AdapterInterface *adapter = node->data;
5205 if( adapter->interfaceType == ifType ) return adapter;
5206 node = g_list_next( node );
5212 * Build interface list selection.
5214 static void addrbookctl_build_ifselect( void ) {
5215 GList *newList = NULL;
5220 gchar *endptr = NULL;
5221 /* gboolean enabled; */
5222 AdapterInterface *adapter;
5224 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5227 splitStr = g_strsplit( selectStr, ",", -1 );
5228 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5230 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5231 ifType = strtol( splitStr[i], &endptr, 10 );
5234 if( strcmp( endptr, "/n" ) == 0 ) {
5239 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5240 adapter = addrbookctl_find_interface( ifType );
5242 newList = g_list_append( newList, adapter );
5249 /* g_print( "i=%d\n", i ); */
5250 g_strfreev( splitStr );
5251 g_free( selectStr );
5253 /* Replace existing list */
5254 mgu_clear_list( _addressIFaceSelection_ );
5255 g_list_free( _addressIFaceSelection_ );
5256 _addressIFaceSelection_ = newList;
5260 /* ***********************************************************************
5261 * Add sender to address book.
5262 * ***********************************************************************
5266 * This function is used by the Add sender to address book function.
5268 gboolean addressbook_add_contact(
5269 const gchar *name, const gchar *address, const gchar *remarks,
5270 GdkPixbuf *picture )
5272 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5273 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5274 debug_print( "addressbook_add_contact - added\n" );
5275 addressbook_refresh();
5280 /* ***********************************************************************
5281 * Book/folder selection.
5282 * ***********************************************************************
5286 * This function is used by the matcher dialog to select a book/folder.
5288 gchar *addressbook_folder_selection( const gchar *folderpath)
5290 AddressBookFile *book = NULL;
5291 ItemFolder *folder = NULL;
5294 cm_return_val_if_fail( folderpath != NULL, NULL);
5296 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5298 if ( folder != NULL) {
5300 gchar *oldtmp = NULL;
5301 AddrItemObject *obj = NULL;
5303 /* walk thru folder->parent to build the full folder path */
5304 /* TODO: wwp: optimize this */
5306 tmp = g_strdup(obj->uid);
5307 while ( obj->parent ) {
5309 if ( obj->name != NULL ) {
5310 oldtmp = g_strdup(tmp);
5312 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5316 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5319 path = g_strdup_printf("%s", book->fileName);
5321 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5327 /* ***********************************************************************
5328 * Book/folder checking.
5329 * ***********************************************************************
5332 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5334 FolderInfo *fi = g_new0( FolderInfo, 1 );
5336 fi->folder = folder;
5340 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5341 FolderInfo *fiParent, FolderPathMatch *match )
5347 FolderPathMatch *nextmatch = NULL;
5352 list = parentFolder->listFolder;
5354 folder = list->data;
5355 fName = g_strdup( ADDRITEM_NAME(folder) );
5357 /* match folder name, match pointer will be set to NULL if next recursive call
5358 doesn't need to match subfolder name */
5359 if ( match != NULL &&
5360 match->matched == FALSE ) {
5361 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5362 /* folder name matches, prepare next subfolder match */
5363 debug_print("matched folder name '%s'\n", fName);
5365 if ( match->folder_path[match->index] == NULL ) {
5366 /* we've matched all elements */
5367 match->matched = TRUE;
5368 match->folder = folder;
5369 debug_print("book/folder path matched!\n");
5371 /* keep on matching */
5379 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5380 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5382 list = g_list_next( list );
5387 * This function is used by to check if a matcher book/folder path corresponds to an
5388 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5389 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5390 if book AND folder are NULL this means that folderpath was empty or Any.
5391 If folderpath is a simple book name (without folder), book will not be NULL and folder
5392 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5395 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5396 AddressDataSource **book,
5397 ItemFolder **folder )
5399 AddressDataSource *ds;
5400 GList *list, *nodeDS;
5401 ItemFolder *rootFolder;
5402 AddressBookFile *abf;
5404 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5411 if ( folderpath == NULL )
5414 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5417 /* split the folder path we've received, we'll try to match this path, subpath by
5418 subpath against the book/folder structure in order */
5419 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5420 if (!folder_path_match.folder_path)
5423 list = addrindex_get_interface_list( _addressIndex_ );
5424 while ( list && !folder_path_match.matched ) {
5425 AddressInterface *interface = list->data;
5426 if ( interface && interface->type == ADDR_IF_BOOK ) {
5427 nodeDS = interface->listSource;
5428 while ( nodeDS && !folder_path_match.matched ) {
5431 /* Read address book */
5432 if( ! addrindex_ds_get_read_flag( ds ) ) {
5433 addrindex_ds_read_data( ds );
5436 /* Add node for address book */
5437 abf = ds->rawDataSource;
5439 /* match book name */
5440 if ( abf && abf->fileName &&
5441 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5443 debug_print("matched book name '%s'\n", abf->fileName);
5444 folder_path_match.book = ds;
5446 if ( folder_path_match.folder_path[1] == NULL ) {
5447 /* no folder part to match */
5449 folder_path_match.matched = TRUE;
5450 folder_path_match.folder = NULL;
5451 debug_print("book path matched!\n");
5454 /* match folder part */
5456 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5457 rootFolder = addrindex_ds_get_root_folder( ds );
5459 /* prepare for recursive call */
5460 folder_path_match.index = 1;
5461 /* this call will set folder_path_match.matched and folder_path_match.folder */
5462 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5467 nodeDS = g_list_next( nodeDS );
5470 list = g_list_next( list );
5473 g_strfreev( folder_path_match.folder_path );
5476 *book = folder_path_match.book;
5478 *folder = folder_path_match.folder;
5479 return folder_path_match.matched;
5483 /* **********************************************************************
5485 * ***********************************************************************
5491 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5492 AddressDataSource *ds = NULL;
5493 AdapterDSource *ads = NULL;
5494 AddressBookFile *abf = NULL;
5495 AdapterInterface *adapter;
5496 GtkCMCTreeNode *newNode;
5498 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5500 if( adapter->treeNode ) {
5501 abf = addressbook_imp_ldif( _addressIndex_ );
5503 ds = addrindex_index_add_datasource(
5504 _addressIndex_, ADDR_IF_BOOK, abf );
5505 ads = addressbook_create_ds_adapter(
5506 ds, ADDR_BOOK, NULL );
5507 addressbook_ads_set_name(
5508 ads, addrbook_get_name( abf ) );
5509 newNode = addressbook_add_object(
5511 ADDRESS_OBJECT(ads) );
5513 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5515 addrbook.treeSelected = newNode;
5518 /* Notify address completion */
5519 invalidate_address_completion();
5528 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5529 AddressDataSource *ds = NULL;
5530 AdapterDSource *ads = NULL;
5531 AddressBookFile *abf = NULL;
5532 AdapterInterface *adapter;
5533 GtkCMCTreeNode *newNode;
5535 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5537 if( adapter->treeNode ) {
5538 abf = addressbook_imp_mutt( _addressIndex_ );
5540 ds = addrindex_index_add_datasource(
5541 _addressIndex_, ADDR_IF_BOOK, abf );
5542 ads = addressbook_create_ds_adapter(
5543 ds, ADDR_BOOK, NULL );
5544 addressbook_ads_set_name(
5545 ads, addrbook_get_name( abf ) );
5546 newNode = addressbook_add_object(
5548 ADDRESS_OBJECT(ads) );
5550 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5552 addrbook.treeSelected = newNode;
5555 /* Notify address completion */
5556 invalidate_address_completion();
5565 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5566 AddressDataSource *ds = NULL;
5567 AdapterDSource *ads = NULL;
5568 AddressBookFile *abf = NULL;
5569 AdapterInterface *adapter;
5570 GtkCMCTreeNode *newNode;
5572 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5574 if( adapter->treeNode ) {
5575 abf = addressbook_imp_pine( _addressIndex_ );
5577 ds = addrindex_index_add_datasource(
5578 _addressIndex_, ADDR_IF_BOOK, abf );
5579 ads = addressbook_create_ds_adapter(
5580 ds, ADDR_BOOK, NULL );
5581 addressbook_ads_set_name(
5582 ads, addrbook_get_name( abf ) );
5583 newNode = addressbook_add_object(
5585 ADDRESS_OBJECT(ads) );
5587 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5589 addrbook.treeSelected = newNode;
5592 /* Notify address completion */
5593 invalidate_address_completion();
5600 * Harvest addresses.
5601 * \param folderItem Folder to import.
5602 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5603 * \param msgList List of message numbers, or NULL to process folder.
5605 void addressbook_harvest(
5606 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5608 AddressDataSource *ds = NULL;
5609 AdapterDSource *ads = NULL;
5610 AddressBookFile *abf = NULL;
5611 AdapterInterface *adapter;
5612 GtkCMCTreeNode *newNode;
5614 abf = addrgather_dlg_execute(
5615 folderItem, _addressIndex_, sourceInd, msgList );
5617 ds = addrindex_index_add_datasource(
5618 _addressIndex_, ADDR_IF_BOOK, abf );
5620 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5622 if( adapter->treeNode ) {
5623 ads = addressbook_create_ds_adapter(
5624 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5625 newNode = addressbook_add_object(
5627 ADDRESS_OBJECT(ads) );
5628 if (newNode == NULL) {
5629 g_message("error adding addressbook object\n");
5634 /* Notify address completion */
5635 invalidate_address_completion();
5642 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5643 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5645 AddressDataSource *ds = NULL;
5646 AddrBookBase *adbase;
5647 AddressCache *cache;
5648 GtkCMCTreeNode *node = NULL;
5650 if( ! addrbook.treeSelected ) return;
5651 node = addrbook.treeSelected;
5652 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5653 obj = gtk_cmctree_node_get_row_data( ctree, node );
5654 if( obj == NULL ) return;
5656 ds = addressbook_find_datasource( node );
5657 if( ds == NULL ) return;
5658 adbase = ( AddrBookBase * ) ds->rawDataSource;
5659 cache = adbase->addressCache;
5660 addressbook_exp_html( cache );
5666 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5667 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5669 AddressDataSource *ds = NULL;
5670 AddrBookBase *adbase;
5671 AddressCache *cache;
5672 GtkCMCTreeNode *node = NULL;
5674 if( ! addrbook.treeSelected ) return;
5675 node = addrbook.treeSelected;
5676 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5677 obj = gtk_cmctree_node_get_row_data( ctree, node );
5678 if( obj == NULL ) return;
5680 ds = addressbook_find_datasource( node );
5681 if( ds == NULL ) return;
5682 adbase = ( AddrBookBase * ) ds->rawDataSource;
5683 cache = adbase->addressCache;
5684 addressbook_exp_ldif( cache );
5687 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5689 addrduplicates_find(GTK_WINDOW(addrbook.window));
5692 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5694 addressbook_custom_attr_edit();
5697 static void addressbook_start_drag(GtkWidget *widget, gint button,
5701 GdkDragContext *context;
5702 if (addressbook_target_list == NULL)
5703 addressbook_target_list = gtk_target_list_new(
5704 addressbook_drag_types, 1);
5705 context = gtk_drag_begin(widget, addressbook_target_list,
5706 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5707 gtk_drag_set_icon_default(context);
5710 static void addressbook_drag_data_get(GtkWidget *widget,
5711 GdkDragContext *drag_context,
5712 GtkSelectionData *selection_data,
5717 AddrItemObject *aio = NULL;
5718 AddressObject *pobj = NULL;
5719 AdapterDSource *ads = NULL;
5720 AddressDataSource *ds = NULL;
5723 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5725 if( pobj == NULL ) return;
5727 if( pobj->type == ADDR_DATASOURCE ) {
5728 ads = ADAPTER_DSOURCE(pobj);
5729 ds = ads->dataSource;
5730 } else if (pobj->type == ADDR_ITEM_GROUP) {
5735 else if( pobj->type != ADDR_INTERFACE ) {
5736 ds = addressbook_find_datasource( addrbook.treeSelected );
5742 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5743 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5744 GTK_CMCTREE_NODE(cur->data));
5745 while (aio && aio->type != ITEMTYPE_PERSON) {
5750 if (aio && aio->type == ITEMTYPE_PERSON) {
5751 if( ds && ds->interface && ds->interface->readOnly)
5752 gtk_selection_data_set(selection_data,
5753 gtk_selection_data_get_target(selection_data), 8,
5754 (const guchar *)"Dummy_addr_copy", 15);
5756 gtk_selection_data_set(selection_data,
5757 gtk_selection_data_get_target(selection_data), 8,
5758 (const guchar *)"Dummy_addr_move", 15);
5762 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5763 GdkDragContext *context,
5769 GtkAllocation allocation;
5770 GtkRequisition requisition;
5772 GtkCMCTreeNode *node = NULL;
5773 gboolean acceptable = FALSE;
5774 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5775 gint height = allocation.height;
5776 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5777 gint total_height = requisition.height;
5778 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5779 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5780 gfloat vpos = gtk_adjustment_get_value(pos);
5782 if (gtk_cmclist_get_selection_info
5783 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5785 if (y > height - 24 && height + vpos < total_height) {
5786 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5787 gtk_adjustment_changed(pos);
5789 if (y < 24 && y > 0) {
5790 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5791 gtk_adjustment_changed(pos);
5793 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5796 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5797 if( obj->type == ADDR_ITEM_FOLDER
5798 || obj->type == ADDR_ITEM_GROUP)
5801 AdapterDSource *ads = NULL;
5802 AddressDataSource *ds = NULL;
5803 ads = ADAPTER_DSOURCE(obj);
5804 if (ads == NULL ){ return FALSE;}
5805 ds = ads->dataSource;
5806 if (ds == NULL ) { return FALSE;}
5814 g_signal_handlers_block_by_func
5816 G_CALLBACK(addressbook_tree_selected), NULL);
5817 gtk_sctree_select( GTK_SCTREE(widget), node);
5818 g_signal_handlers_unblock_by_func
5820 G_CALLBACK(addressbook_tree_selected), NULL);
5821 gdk_drag_status(context,
5822 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5823 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5825 gdk_drag_status(context, 0, time);
5830 static void addressbook_drag_leave_cb(GtkWidget *widget,
5831 GdkDragContext *context,
5835 if (addrbook.treeSelected) {
5836 g_signal_handlers_block_by_func
5838 G_CALLBACK(addressbook_tree_selected), NULL);
5839 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5840 g_signal_handlers_unblock_by_func
5842 G_CALLBACK(addressbook_tree_selected), NULL);
5847 static void addressbook_drag_received_cb(GtkWidget *widget,
5848 GdkDragContext *drag_context,
5851 GtkSelectionData *data,
5857 GtkCMCTreeNode *node;
5858 GtkCMCTreeNode *lastopened = addrbook.opened;
5860 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5861 if (gtk_cmclist_get_selection_info
5862 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5866 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5867 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5870 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5871 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5872 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5873 addressbook_clip_copy_cb(NULL, NULL);
5875 addressbook_clip_cut_cb(NULL, NULL);
5876 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5877 addressbook_clip_paste_cb(NULL,NULL);
5878 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5879 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5880 gtk_drag_finish(drag_context, TRUE, TRUE, time);