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 {"Edit", 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", "Edit", "Edit", 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/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "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 gtk_window_add_accel_group(GTK_WINDOW(window),
999 gtk_ui_manager_get_accel_group(ui_manager));
1001 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
1003 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1005 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1006 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1007 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1009 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1010 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1011 GTK_POLICY_AUTOMATIC,
1012 GTK_POLICY_AUTOMATIC);
1013 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1016 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1017 gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1019 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1020 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1021 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1022 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1023 GTK_CMCTREE_EXPANDER_TRIANGLE);
1024 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1025 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1026 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1027 addressbook_treenode_compare_func);
1029 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1030 G_CALLBACK(addressbook_tree_selected), NULL);
1031 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1032 G_CALLBACK(addressbook_tree_button_pressed),
1034 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1035 G_CALLBACK(addressbook_tree_button_released),
1038 g_signal_connect(G_OBJECT(ctree), "select_row",
1039 G_CALLBACK(addressbook_select_row_tree), NULL);
1041 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1042 addressbook_drag_types, 1,
1043 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1044 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1045 G_CALLBACK(addressbook_drag_motion_cb),
1047 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1048 G_CALLBACK(addressbook_drag_leave_cb),
1050 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1051 G_CALLBACK(addressbook_drag_received_cb),
1053 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1054 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1055 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1056 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1058 clist_vbox = gtk_vbox_new(FALSE, 4);
1060 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1061 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1062 GTK_POLICY_AUTOMATIC,
1063 GTK_POLICY_AUTOMATIC);
1064 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1067 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1068 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1069 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1070 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1071 GTK_CMCTREE_EXPANDER_TRIANGLE);
1072 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1073 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1074 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1076 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1078 gtk_widget_set_size_request(clist, -1, 80);
1080 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1081 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1082 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1083 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1084 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1085 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1086 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1087 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1088 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1089 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1090 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1092 for (i = 0; i < N_LIST_COLS; i++)
1093 gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1096 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1097 G_CALLBACK(addressbook_list_row_selected), NULL);
1098 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1099 G_CALLBACK(addressbook_list_row_unselected), NULL);
1100 g_signal_connect(G_OBJECT(clist), "button_press_event",
1101 G_CALLBACK(addressbook_list_button_pressed),
1103 g_signal_connect(G_OBJECT(clist), "button_release_event",
1104 G_CALLBACK(addressbook_list_button_released),
1106 g_signal_connect(G_OBJECT(clist), "tree_expand",
1107 G_CALLBACK(addressbook_person_expand_node), NULL );
1108 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1109 G_CALLBACK(addressbook_person_collapse_node), NULL );
1110 g_signal_connect(G_OBJECT(clist), "start_drag",
1111 G_CALLBACK(addressbook_start_drag), NULL);
1112 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1113 G_CALLBACK(addressbook_drag_data_get), NULL);
1114 hbox = gtk_hbox_new(FALSE, 4);
1115 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1117 label = gtk_label_new(_("Search"));
1118 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1120 entry = gtk_entry_new();
1121 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1123 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1125 g_signal_connect(G_OBJECT(entry), "key_press_event",
1126 G_CALLBACK(addressbook_entry_key_pressed),
1128 g_signal_connect(G_OBJECT(entry), "activate",
1129 G_CALLBACK(addressbook_entry_activated), NULL);
1131 if (!prefs_common.addressbook_use_editaddress_dialog) {
1132 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1133 vpaned = gtk_vpaned_new();
1134 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1135 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1138 editaddress_vbox = NULL;
1140 hpaned = gtk_hpaned_new();
1141 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1142 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1143 if (prefs_common.addressbook_use_editaddress_dialog)
1144 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1146 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1149 hsbox = gtk_hbox_new(FALSE, 0);
1150 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1151 statusbar = gtk_statusbar_new();
1152 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1155 hbbox = gtk_hbutton_box_new();
1156 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1157 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1158 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1159 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1161 gtkut_stock_button_add_help(hbbox, &help_btn);
1163 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1164 gtk_widget_set_can_default(edit_btn, TRUE);
1165 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1166 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1167 gtk_widget_set_can_default(del_btn, TRUE);
1168 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1169 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1170 gtk_widget_set_can_default(reg_btn, TRUE);
1171 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1174 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1175 gtk_widget_set_can_default(lup_btn, TRUE);
1176 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1178 g_signal_connect(G_OBJECT(help_btn), "clicked",
1179 G_CALLBACK(manual_open_with_anchor_cb),
1180 MANUAL_ANCHOR_ADDRBOOK);
1182 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1183 G_CALLBACK(addressbook_edit_clicked), NULL);
1184 g_signal_connect(G_OBJECT(del_btn), "clicked",
1185 G_CALLBACK(addressbook_del_clicked), NULL);
1186 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1187 G_CALLBACK(addressbook_reg_clicked), NULL);
1188 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1189 G_CALLBACK(addressbook_lup_clicked), NULL);
1191 to_btn = gtk_button_new_with_label
1192 (prefs_common_translated_header_name("To:"));
1193 gtk_widget_set_can_default(to_btn, TRUE);
1194 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1195 cc_btn = gtk_button_new_with_label
1196 (prefs_common_translated_header_name("Cc:"));
1197 gtk_widget_set_can_default(cc_btn, TRUE);
1198 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1199 bcc_btn = gtk_button_new_with_label
1200 (prefs_common_translated_header_name("Bcc:"));
1201 gtk_widget_set_can_default(bcc_btn, TRUE);
1202 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1204 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1205 gtk_widget_set_can_default(close_btn, TRUE);
1206 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1208 g_signal_connect(G_OBJECT(to_btn), "clicked",
1209 G_CALLBACK(addressbook_to_clicked),
1210 GINT_TO_POINTER(COMPOSE_TO));
1211 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1212 G_CALLBACK(addressbook_to_clicked),
1213 GINT_TO_POINTER(COMPOSE_CC));
1214 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1215 G_CALLBACK(addressbook_to_clicked),
1216 GINT_TO_POINTER(COMPOSE_BCC));
1217 g_signal_connect(G_OBJECT(close_btn), "clicked",
1218 G_CALLBACK(addressbook_close_clicked), NULL);
1220 /* Build icons for interface */
1222 /* Build control tables */
1223 addrbookctl_build_map(window);
1224 addrbookctl_build_iflist();
1225 addrbookctl_build_ifselect();
1227 addrbook.clist = NULL;
1229 /* Add each interface into the tree as a root level folder */
1230 nodeIf = _addressInterfaceList_;
1232 AdapterInterface *adapter = nodeIf->data;
1233 AddressInterface *iface = adapter->interface;
1234 nodeIf = g_list_next(nodeIf);
1236 if(iface->useInterface) {
1237 AddressTypeControlItem *atci = adapter->atci;
1238 text = atci->displayName;
1240 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1241 NULL, NULL, &text, FOLDER_SPACING,
1245 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1246 gtk_cmctree_node_set_row_data_full(
1247 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1248 addressbook_free_treenode );
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1267 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1268 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1281 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1285 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1287 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
1288 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1289 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1291 addrbook.window = window;
1292 addrbook.hpaned = hpaned;
1293 addrbook.vpaned = vpaned;
1294 addrbook.menubar = menubar;
1295 addrbook.ctree = ctree;
1298 addrbook.editaddress_vbox = editaddress_vbox;
1299 addrbook.clist = clist;
1300 addrbook.label = label;
1301 addrbook.entry = entry;
1302 addrbook.statusbar = statusbar;
1303 addrbook.status_cid = gtk_statusbar_get_context_id(
1304 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1306 addrbook.help_btn = help_btn;
1307 addrbook.edit_btn = edit_btn;
1308 addrbook.del_btn = del_btn;
1309 addrbook.reg_btn = reg_btn;
1310 addrbook.lup_btn = lup_btn;
1311 addrbook.to_btn = to_btn;
1312 addrbook.cc_btn = cc_btn;
1313 addrbook.bcc_btn = bcc_btn;
1315 addrbook.tree_popup = tree_popup;
1316 addrbook.list_popup = list_popup;
1317 addrbook.ui_manager = ui_manager;
1319 addrbook.listSelected = NULL;
1321 if (!geometry.min_height) {
1322 geometry.min_width = ADDRESSBOOK_WIDTH;
1323 geometry.min_height = ADDRESSBOOK_HEIGHT;
1326 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1328 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1329 prefs_common.addressbookwin_height);
1331 gtk_window_move(GTK_WINDOW(window), 48, 48);
1334 if (!prefs_common.addressbook_use_editaddress_dialog) {
1335 if (prefs_common.addressbook_vpaned_pos > 0)
1336 gtk_paned_set_position(GTK_PANED(vpaned),
1337 prefs_common.addressbook_vpaned_pos);
1339 if (prefs_common.addressbook_hpaned_pos > 0)
1340 gtk_paned_set_position(GTK_PANED(hpaned),
1341 prefs_common.addressbook_hpaned_pos);
1344 gtk_widget_show_all(window);
1348 * Close address book window and save to file(s).
1350 static gint addressbook_close( void ) {
1351 address_completion_end(addrbook.window);
1352 if (!prefs_common.addressbook_use_editaddress_dialog)
1353 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1355 addressbook_pane_save_position();
1357 gtk_widget_hide(addrbook.window);
1358 addressbook_export_to_file();
1363 * Display message in status line.
1364 * \param msg Message to display.
1366 static void addressbook_status_show( gchar *msg ) {
1367 if( addrbook.statusbar != NULL ) {
1369 GTK_STATUSBAR(addrbook.statusbar),
1370 addrbook.status_cid );
1373 GTK_STATUSBAR(addrbook.statusbar),
1374 addrbook.status_cid, msg );
1379 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1383 *addressbook_msgbuf = '\0';
1385 name = addrindex_ds_get_name( ds );
1386 retVal = addrindex_ds_get_status_code( ds );
1387 if( retVal == MGU_SUCCESS ) {
1388 g_snprintf( addressbook_msgbuf,
1389 sizeof(addressbook_msgbuf), "%s", name );
1392 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1393 g_snprintf( addressbook_msgbuf,
1394 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1397 addressbook_status_show( addressbook_msgbuf );
1400 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1402 addressbook_edit_address_cb(NULL, NULL);
1405 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1407 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1411 * Delete one or more objects from address list.
1413 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1415 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1416 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1417 AddressObject *pobj;
1418 AdapterDSource *ads = NULL;
1419 GtkCMCTreeNode *nodeList;
1422 AddressBookFile *abf = NULL;
1423 AddressDataSource *ds = NULL;
1424 AddressInterface *iface;
1425 AddrItemObject *aio;
1426 AddrSelectItem *item;
1428 gboolean refreshList = FALSE;
1430 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1431 cm_return_if_fail(pobj != NULL);
1433 /* Test whether anything selected for deletion */
1434 nodeList = addrbook.listSelected;
1436 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1437 if( aio == NULL) return;
1438 ds = addressbook_find_datasource( addrbook.treeSelected );
1439 if( ds == NULL ) return;
1441 /* Test for read only */
1442 iface = ds->interface;
1443 if( iface->readOnly ) {
1444 alertpanel( _("Delete address(es)"),
1445 _("This address data is readonly and cannot be deleted."),
1446 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST);
1450 /* Test whether Ok to proceed */
1452 if( pobj->type == ADDR_DATASOURCE ) {
1453 ads = ADAPTER_DSOURCE(pobj);
1454 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1456 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1459 else if( pobj->type == ADDR_ITEM_GROUP ) {
1462 if( ! procFlag ) return;
1463 abf = ds->rawDataSource;
1464 if( abf == NULL ) return;
1466 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1467 g_signal_handlers_block_by_func
1468 (G_OBJECT(addrbook.clist),
1469 G_CALLBACK(addressbook_list_row_unselected), NULL);
1471 /* Process deletions */
1472 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1473 GList *groups = NULL, *persons = NULL, *emails = NULL;
1474 gboolean group_delete = TRUE;
1475 /* Items inside folders */
1476 list = addrselect_get_list( _addressSelect_ );
1477 /* Confirm deletion */
1481 node = g_list_next( node );
1482 aio = ( AddrItemObject * ) item->addressItem;
1483 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1484 group_delete = FALSE;
1489 aval = alertpanel( _("Delete group"),
1490 _("Really delete the group(s)?\n"
1491 "The addresses it contains will not be lost."),
1492 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1493 if( aval != G_ALERTALTERNATE ) {
1497 aval = alertpanel( _("Delete address(es)"),
1498 _("Really delete the address(es)?"),
1499 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1500 if( aval != G_ALERTALTERNATE ) {
1505 /* first, set lists of groups and persons to remove */
1509 node = g_list_next( node );
1510 aio = ( AddrItemObject * ) item->addressItem;
1513 if( aio->type == ITEMTYPE_GROUP ) {
1514 groups = g_list_prepend(groups, item);
1516 else if( aio->type == ITEMTYPE_PERSON ) {
1517 persons = g_list_prepend(persons, item);
1520 /* then set list of emails to remove *if* they're not children of
1521 * persons to remove */
1525 node = g_list_next( node );
1526 aio = ( AddrItemObject * ) item->addressItem;
1529 if( aio->type == ITEMTYPE_EMAIL ) {
1530 ItemEMail *sitem = ( ItemEMail * ) aio;
1531 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1532 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1533 emails = g_list_prepend(emails, item);
1535 /* else, the email will be removed via the parent person */
1538 /* then delete groups */
1542 node = g_list_next( node );
1543 aio = ( AddrItemObject * ) item->addressItem;
1546 if( aio->type == ITEMTYPE_GROUP ) {
1547 ItemGroup *item = ( ItemGroup * ) aio;
1548 GtkCMCTreeNode *nd = NULL;
1549 nd = addressbook_find_group_node( addrbook.opened, item );
1550 item = addrbook_remove_group( abf, item );
1552 addritem_free_item_group( item );
1554 /* Remove group from parent node */
1555 gtk_cmctree_remove_node( ctree, nd );
1559 /* then delete persons */
1563 node = g_list_next( node );
1564 aio = ( AddrItemObject * ) item->addressItem;
1567 if( aio->type == ITEMTYPE_PERSON ) {
1568 ItemPerson *item = ( ItemPerson * ) aio;
1569 item->status = DELETE_ENTRY;
1570 addressbook_folder_remove_one_person( clist, item );
1571 if (pobj->type == ADDR_ITEM_FOLDER)
1572 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1573 item = addrbook_remove_person( abf, item );
1575 if (ds && ds->type == ADDR_IF_LDAP) {
1576 LdapServer *server = ds->rawDataSource;
1577 ldapsvr_set_modified(server, TRUE);
1578 ldapsvr_update_book(server, item);
1582 addritem_person_remove_picture(item);
1583 addritem_free_item_person( item );
1587 /* then delete emails */
1591 node = g_list_next( node );
1592 aio = ( AddrItemObject * ) item->addressItem;
1596 if( aio->type == ITEMTYPE_EMAIL ) {
1597 ItemEMail *sitem = ( ItemEMail * ) aio;
1598 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1599 sitem = addrbook_person_remove_email( abf, person, sitem );
1601 addrcache_remove_email(abf->addressCache, sitem);
1602 addritem_free_item_email( sitem );
1604 addressbook_folder_refresh_one_person( clist, person );
1607 g_list_free( groups );
1608 g_list_free( persons );
1609 g_list_free( emails );
1610 g_list_free( list );
1611 addressbook_list_select_clear();
1613 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1614 addressbook_set_clist(
1615 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1619 addrbook_set_dirty(abf, TRUE);
1620 addressbook_export_to_file();
1621 addressbook_list_menu_setup();
1624 else if( pobj->type == ADDR_ITEM_GROUP ) {
1625 /* Items inside groups */
1626 list = addrselect_get_list( _addressSelect_ );
1630 node = g_list_next( node );
1631 aio = ( AddrItemObject * ) item->addressItem;
1632 if( aio->type == ITEMTYPE_EMAIL ) {
1633 ItemEMail *item = ( ItemEMail * ) aio;
1634 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1635 item = addrbook_person_remove_email( abf, person, item );
1637 addritem_free_item_email( item );
1641 g_list_free( list );
1642 addressbook_list_select_clear();
1643 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1644 addressbook_set_clist(
1645 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1649 addrbook_set_dirty(abf, TRUE);
1650 addressbook_export_to_file();
1651 addressbook_list_menu_setup();
1655 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1656 gtk_cmctree_remove_node( clist, nodeList );
1658 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1659 g_signal_handlers_unblock_by_func
1660 (G_OBJECT(addrbook.clist),
1661 G_CALLBACK(addressbook_list_row_unselected), NULL);
1664 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1666 addressbook_new_address_cb( NULL, NULL );
1669 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1672 gchar *address = NULL;
1674 if( aio->type == ITEMTYPE_EMAIL ) {
1675 ItemPerson *person = NULL;
1676 ItemEMail *email = ( ItemEMail * ) aio;
1678 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1679 if( email->address ) {
1680 if( ADDRITEM_NAME(email) ) {
1681 name = ADDRITEM_NAME(email);
1682 if( *name == '\0' ) {
1683 name = ADDRITEM_NAME(person);
1686 else if( ADDRITEM_NAME(person) ) {
1687 name = ADDRITEM_NAME(person);
1690 buf = g_strdup( email->address );
1692 address = email->address;
1695 else if( aio->type == ITEMTYPE_PERSON ) {
1696 ItemPerson *person = ( ItemPerson * ) aio;
1697 GList *node = person->listEMail;
1699 name = ADDRITEM_NAME(person);
1701 ItemEMail *email = ( ItemEMail * ) node->data;
1702 address = email->address;
1706 if( name && name[0] != '\0' ) {
1707 if( strchr_with_skip_quote( name, '"', ',' ) )
1708 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1710 buf = g_strdup_printf( "%s <%s>", name, address );
1713 buf = g_strdup( address );
1720 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1724 AddrSelectItem *item;
1725 AddrItemObject *aio;
1728 compose = addrbook.target_compose;
1729 if( ! compose ) return;
1731 /* Nothing selected, but maybe there is something in text entry */
1732 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1734 compose_entry_append(
1735 compose, addr, (ComposeEntryType)data , PREF_NONE);
1738 /* Select from address list */
1739 list = addrselect_get_list( _addressSelect_ );
1744 node = g_list_next( node );
1745 aio = item->addressItem;
1746 if( aio->type == ITEMTYPE_PERSON ||
1747 aio->type == ITEMTYPE_EMAIL ) {
1748 addr = addressbook_format_address( aio );
1749 compose_entry_append(
1750 compose, addr, (ComposeEntryType) data, PREF_NONE );
1753 else if( aio->type == ITEMTYPE_GROUP ) {
1754 ItemGroup *group = ( ItemGroup * ) aio;
1755 GList *nodeMail = group->listEMail;
1757 ItemEMail *email = nodeMail->data;
1759 addr = addressbook_format_address(
1760 ( AddrItemObject * ) email );
1761 compose_entry_append(
1762 compose, addr, (ComposeEntryType) data, PREF_NONE );
1764 nodeMail = g_list_next( nodeMail );
1769 AddressObject *obj = NULL;
1771 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1773 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1774 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1775 GList *nodeMail = itemGroup->listEMail;
1777 ItemEMail *email = nodeMail->data;
1779 addr = addressbook_format_address(
1780 ( AddrItemObject * ) email );
1781 compose_entry_append(
1782 compose, addr, (ComposeEntryType) data, PREF_NONE );
1784 nodeMail = g_list_next( nodeMail );
1788 g_list_free( list );
1791 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1792 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/SelectAll", TRUE );
1797 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", sensitive );
1798 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", sensitive );
1799 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", sensitive );
1801 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", sensitive );
1802 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", sensitive );
1803 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", sensitive );
1804 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", sensitive );
1805 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1806 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1809 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1810 gboolean canEdit = FALSE;
1811 gboolean canDelete = TRUE;
1812 gboolean canAdd = FALSE;
1813 gboolean canEditTr = TRUE;
1814 gboolean editAddress = FALSE;
1815 gboolean canExport = TRUE;
1816 AddressTypeControlItem *atci = NULL;
1817 AddressDataSource *ds = NULL;
1818 AddressInterface *iface = NULL;
1820 if( obj == NULL ) return;
1821 if( obj->type == ADDR_INTERFACE ) {
1822 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1823 iface = adapter->interface;
1825 if( iface->haveLibrary ) {
1826 /* Enable appropriate File / New command */
1827 atci = adapter->atci;
1828 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1831 canEditTr = canExport = FALSE;
1833 else if( obj->type == ADDR_DATASOURCE ) {
1834 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1835 ds = ads->dataSource;
1836 iface = ds->interface;
1837 if( ! iface->readOnly ) {
1838 canAdd = canEdit = editAddress = canDelete = TRUE;
1840 if( ! iface->haveLibrary ) {
1841 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1844 else if( obj->type == ADDR_ITEM_FOLDER ) {
1845 ds = addressbook_find_datasource( addrbook.treeSelected );
1847 iface = ds->interface;
1848 if( iface->readOnly ) {
1853 canAdd = editAddress = TRUE;
1857 else if( obj->type == ADDR_ITEM_GROUP ) {
1858 ds = addressbook_find_datasource( addrbook.treeSelected );
1860 iface = ds->interface;
1861 if( ! iface->readOnly ) {
1867 if( addrbook.listSelected == NULL )
1871 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", editAddress );
1872 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", canAdd );
1873 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1874 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1877 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
1878 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
1879 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1880 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1882 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1883 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1886 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1887 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1891 * Address book tree callback function that responds to selection of tree
1894 * \param ctree Tree widget.
1895 * \param node Node that was selected.
1896 * \param column Column number where selected occurred.
1897 * \param data Pointer to user data.
1899 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1900 gint column, gpointer data)
1902 AddressObject *obj = NULL;
1903 AdapterDSource *ads = NULL;
1904 AddressDataSource *ds = NULL;
1905 ItemFolder *rootFolder = NULL;
1906 AddressObjectType aot;
1908 addrbook.treeSelected = node;
1909 addrbook.listSelected = NULL;
1910 addressbook_status_show( "" );
1911 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1913 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1915 addressbook_set_clist(NULL, TRUE);
1918 addrbook.opened = node;
1920 if( obj->type == ADDR_DATASOURCE ) {
1921 /* Read from file */
1922 static gboolean tVal = TRUE;
1924 ads = ADAPTER_DSOURCE(obj);
1926 ds = ads->dataSource;
1927 if( ds == NULL ) return;
1929 if( addrindex_ds_get_modify_flag( ds ) ) {
1930 addrindex_ds_read_data( ds );
1933 if( ! addrindex_ds_get_read_flag( ds ) ) {
1934 addrindex_ds_read_data( ds );
1936 addressbook_ds_show_message( ds );
1938 if( ! addrindex_ds_get_access_flag( ds ) ) {
1939 /* Remove existing folders and groups */
1940 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1941 addressbook_tree_remove_children( ctree, node );
1942 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1944 /* Load folders into the tree */
1945 rootFolder = addrindex_ds_get_root_folder( ds );
1946 if( ds && ds->type == ADDR_IF_JPILOT ) {
1947 aot = ADDR_CATEGORY;
1949 else if( ds && ds->type == ADDR_IF_LDAP ) {
1950 aot = ADDR_LDAP_QUERY;
1953 aot = ADDR_ITEM_FOLDER;
1955 addressbook_node_add_folder( node, ds, rootFolder, aot );
1956 addrindex_ds_set_access_flag( ds, &tVal );
1957 gtk_cmctree_expand( ctree, node );
1960 addressbook_set_clist(NULL, TRUE);
1963 /* Update address list */
1964 g_signal_handlers_block_by_func
1966 G_CALLBACK(addressbook_tree_selected), NULL);
1967 addressbook_set_clist( obj, FALSE );
1968 g_signal_handlers_unblock_by_func
1970 G_CALLBACK(addressbook_tree_selected), NULL);
1971 if (!prefs_common.addressbook_use_editaddress_dialog)
1972 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1974 /* Setup main menu selections */
1975 addressbook_menubar_set_sensitive( FALSE );
1976 addressbook_menuitem_set_sensitive( obj, node );
1977 addressbook_list_select_clear();
1978 addressbook_list_menu_setup();
1983 * Setup address list popup menu items. Items are enabled or disabled as
1986 static void addressbook_list_menu_setup( void ) {
1987 GtkCMCTree *clist = NULL;
1988 AddressObject *pobj = NULL;
1989 AddressObject *obj = NULL;
1990 AdapterDSource *ads = NULL;
1991 AddressInterface *iface = NULL;
1992 AddressDataSource *ds = NULL;
1994 AddrItemObject *aio;
1995 AddrSelectItem *item;
1996 gboolean canEdit = FALSE;
1997 gboolean canDelete = FALSE;
1998 gboolean canCut = FALSE;
1999 gboolean canCopy = FALSE;
2000 gboolean canPaste = FALSE;
2001 gboolean canBrowse = FALSE;
2002 gboolean canMerge = FALSE;
2004 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2005 if( pobj == NULL ) return;
2007 clist = GTK_CMCTREE(addrbook.clist);
2008 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2009 if( obj == NULL ) canEdit = FALSE;
2011 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2012 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2014 if( pobj->type == ADDR_DATASOURCE ) {
2015 /* Parent object is a data source */
2016 ads = ADAPTER_DSOURCE(pobj);
2017 ds = ads->dataSource;
2020 iface = ds->interface;
2023 if( ! iface->readOnly ) {
2024 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2025 if (iface->type != ADDR_IF_LDAP)
2026 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2027 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2030 canDelete = canEdit;
2033 else if( pobj->type != ADDR_INTERFACE ) {
2034 /* Parent object is not an interface */
2035 ds = addressbook_find_datasource( addrbook.treeSelected );
2038 iface = ds->interface;
2041 if( ! iface->readOnly ) {
2042 /* Folder or group */
2043 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2044 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2045 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2046 if( obj ) canEdit = TRUE;
2049 if( pobj->type == ADDR_ITEM_FOLDER ) {
2050 if (iface->type != ADDR_IF_LDAP)
2051 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2052 if( obj ) canEdit = TRUE;
2054 canDelete = canEdit;
2056 if( iface->type == ADDR_IF_LDAP ) {
2057 if( obj ) canBrowse = TRUE;
2064 /* Enable cut and paste */
2065 if( ! addrclip_is_empty( _clipBoard_ ) )
2067 if( ! addrselect_test_empty( _addressSelect_ ) )
2069 /* Enable copy if something is selected */
2070 if( ! addrselect_test_empty( _addressSelect_ ) )
2074 /* Disable edit or browse if more than one row selected */
2075 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2080 /* Allow merging persons or emails are selected */
2081 list = _addressSelect_->listSelect;
2082 if (list && list->next ) {
2084 aio = ( AddrItemObject * ) item->addressItem;
2085 if( aio->type == ITEMTYPE_EMAIL ||
2086 aio->type == ITEMTYPE_PERSON ) {
2091 /* Forbid write changes when read-only */
2092 if( iface && iface->readOnly ) {
2099 /* Now go finalize menu items */
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2101 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2103 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2104 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2105 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2107 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2108 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge", canMerge );
2110 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2111 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2112 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2114 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
2115 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
2116 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", canCopy );
2117 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", canMerge );
2119 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2120 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2122 if (addrbook.target_compose) {
2123 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2124 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2125 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2128 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2132 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2133 GtkCMCTreeNode *node,
2140 * Add list of items into tree node below specified tree node.
2141 * \param treeNode Tree node.
2142 * \param ds Data source.
2143 * \param listItems List of items.
2145 static void addressbook_treenode_add_list(
2146 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2152 AddrItemObject *aio;
2156 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2159 group = ( ItemGroup * ) aio;
2160 nn = addressbook_node_add_group( treeNode, ds, group );
2162 g_message("error adding addressbook group\n");
2165 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2168 folder = ( ItemFolder * ) aio;
2169 nn = addressbook_node_add_folder(
2170 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2172 g_message("error adding addressbook folder\n");
2175 node = g_list_next( node );
2179 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2180 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2184 * Cut from address list widget.
2186 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2187 _clipBoard_->cutFlag = TRUE;
2188 addrclip_clear( _clipBoard_ );
2189 addrclip_add( _clipBoard_, _addressSelect_ );
2190 /* addrclip_list_show( _clipBoard_, stdout ); */
2194 * Copy from address list widget.
2196 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2197 _clipBoard_->cutFlag = FALSE;
2198 addrclip_clear( _clipBoard_ );
2199 addrclip_add( _clipBoard_, _addressSelect_ );
2200 /* addrclip_list_show( _clipBoard_, stdout ); */
2204 * Paste clipboard into address list widget.
2206 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2207 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2208 AddressObject *pobj = NULL;
2209 AddressDataSource *ds = NULL;
2210 AddressBookFile *abf = NULL;
2211 ItemFolder *folder = NULL;
2212 GList *folderGroup = NULL;
2214 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2215 if( ds == NULL ) return;
2216 if( addrindex_ds_get_readonly( ds ) ) {
2217 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2221 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2223 if( pobj->type == ADDR_ITEM_FOLDER ) {
2224 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2226 else if( pobj->type == ADDR_ITEM_GROUP ) {
2227 alertpanel_error( _("Cannot paste into an address group.") );
2232 /* Get an address book */
2233 abf = addressbook_get_book_file();
2234 if( abf == NULL ) return;
2236 if( _clipBoard_->cutFlag ) {
2238 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2240 /* Remove all groups and folders in clipboard from tree node */
2241 addressbook_treenode_remove_item();
2243 /* Remove all "cut" items */
2244 addrclip_delete_item( _clipBoard_ );
2246 /* Clear clipboard - cut items??? */
2247 addrclip_clear( _clipBoard_ );
2251 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2254 /* addrclip_list_show( _clipBoard_, stdout ); */
2256 /* Update tree by inserting node for each folder or group */
2257 addressbook_treenode_add_list(
2258 addrbook.treeSelected, ds, folderGroup );
2259 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2260 g_list_free( folderGroup );
2264 /* Display items pasted */
2265 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2266 addressbook_set_clist(
2267 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2275 * Add current treenode object to clipboard. Note that widget only allows
2276 * one entry from the tree list to be selected.
2278 static void addressbook_treenode_to_clipboard( void ) {
2279 AddressObject *obj = NULL;
2280 AddressDataSource *ds = NULL;
2281 AddrSelectItem *item;
2282 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2283 GtkCMCTreeNode *node;
2285 node = addrbook.treeSelected;
2286 if( node == NULL ) return;
2287 obj = gtk_cmctree_node_get_row_data( ctree, node );
2288 if( obj == NULL ) return;
2290 ds = addressbook_find_datasource( node );
2291 if( ds == NULL ) return;
2294 if( obj->type == ADDR_ITEM_FOLDER ) {
2295 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2296 ItemFolder *folder = adapter->itemFolder;
2298 item = addrselect_create_node( obj );
2299 item->uid = g_strdup( ADDRITEM_ID(folder) );
2301 else if( obj->type == ADDR_ITEM_GROUP ) {
2302 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2303 ItemGroup *group = adapter->itemGroup;
2305 item = addrselect_create_node( obj );
2306 item->uid = g_strdup( ADDRITEM_ID(group) );
2308 else if( obj->type == ADDR_DATASOURCE ) {
2310 item = addrselect_create_node( obj );
2315 /* Clear existing list and add item into list */
2318 addressbook_list_select_clear();
2319 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2320 addrselect_list_add( _addressSelect_, item, cacheID );
2326 * Cut from tree widget.
2328 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2329 _clipBoard_->cutFlag = TRUE;
2330 addressbook_treenode_to_clipboard();
2331 addrclip_clear( _clipBoard_ );
2332 addrclip_add( _clipBoard_, _addressSelect_ );
2333 /* addrclip_list_show( _clipBoard_, stdout ); */
2337 * Copy from tree widget.
2339 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2340 _clipBoard_->cutFlag = FALSE;
2341 addressbook_treenode_to_clipboard();
2342 addrclip_clear( _clipBoard_ );
2343 addrclip_add( _clipBoard_, _addressSelect_ );
2344 /* addrclip_list_show( _clipBoard_, stdout ); */
2348 * Paste clipboard into address tree widget.
2350 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2351 addressbook_clip_paste_cb(NULL,NULL);
2355 * Clear selected entries in clipboard.
2357 static void addressbook_list_select_clear( void ) {
2358 addrselect_list_clear( _addressSelect_ );
2362 * Add specified address item to selected address list.
2363 * \param aio Address item object.
2364 * \param ds Datasource.
2366 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2369 if( ds == NULL ) return;
2370 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2371 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2376 * Remove specified address item from selected address list.
2377 * \param aio Address item object.
2379 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2380 addrselect_list_remove( _addressSelect_, aio );
2384 * Invoke EMail compose window with addresses in selected address list.
2386 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2389 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2390 listAddress = addrselect_build_list( _addressSelect_ );
2391 compose_new_with_list( NULL, listAddress );
2392 mgu_free_dlist( listAddress );
2397 static void addressbook_merge_list( AddrSelectList *list ) {
2398 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2399 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2400 AddressObject *pobj;
2401 AddressDataSource *ds = NULL;
2403 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
2404 cm_return_if_fail(pobj != NULL);
2406 ds = addressbook_find_datasource( addrbook.treeSelected );
2407 if( ds == NULL ) return;
2409 addrmerge_merge(clist, pobj, ds, list);
2413 * Merge selected entries in the address list
2415 static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
2416 if( addrselect_test_empty( _addressSelect_ ) )
2419 addressbook_merge_list( _addressSelect_ );
2422 static void addressbook_list_row_selected( GtkCMCTree *clist,
2423 GtkCMCTreeNode *node,
2427 AddrItemObject *aio = NULL;
2428 AddressObject *pobj = NULL;
2429 AdapterDSource *ads = NULL;
2430 AddressDataSource *ds = NULL;
2432 addrbook.listSelected = node;
2434 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2435 if( pobj == NULL ) return;
2437 if( pobj->type == ADDR_DATASOURCE ) {
2438 ads = ADAPTER_DSOURCE(pobj);
2439 ds = ads->dataSource;
2441 else if( pobj->type != ADDR_INTERFACE ) {
2442 ds = addressbook_find_datasource( addrbook.treeSelected );
2445 aio = gtk_cmctree_node_get_row_data( clist, node );
2447 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2448 addressbook_list_select_add( aio, ds );
2451 addressbook_list_menu_setup();
2453 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2454 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2456 if (obj && obj->type != ADDR_ITEM_GROUP)
2457 addressbook_edit_address(NULL, 0, NULL, FALSE);
2461 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2462 GtkCMCTreeNode *node,
2466 AddrItemObject *aio;
2468 aio = gtk_cmctree_node_get_row_data( ctree, node );
2470 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2471 addressbook_list_select_remove( aio );
2474 if (!prefs_common.addressbook_use_editaddress_dialog)
2475 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2478 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2480 addressbook_lup_clicked(NULL, NULL);
2483 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2484 GdkEventButton *event,
2487 if( ! event ) return FALSE;
2488 if( event->window != GTK_CMCLIST(widget)->clist_window ) return FALSE;
2490 addressbook_list_menu_setup();
2492 if( event->button == 3 ) {
2493 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2494 event->button, event->time );
2495 } else if (event->button == 1) {
2496 if (event->type == GDK_2BUTTON_PRESS) {
2497 if (prefs_common.add_address_by_click &&
2498 addrbook.target_compose)
2499 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2501 if (prefs_common.addressbook_use_editaddress_dialog)
2502 addressbook_edit_address_cb(NULL, NULL);
2504 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2505 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2506 if( obj && obj->type == ADDR_ITEM_GROUP )
2507 addressbook_edit_address_cb(NULL, NULL);
2515 static gboolean addressbook_list_button_released(GtkWidget *widget,
2516 GdkEventButton *event,
2522 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2523 GdkEventButton *event,
2526 GtkCMCList *clist = GTK_CMCLIST(ctree);
2528 AddressObject *obj = NULL;
2529 AdapterDSource *ads = NULL;
2530 AddressInterface *iface = NULL;
2531 AddressDataSource *ds = NULL;
2532 gboolean canEdit = FALSE;
2533 gboolean canDelete = FALSE;
2534 gboolean canCut = FALSE;
2535 gboolean canCopy = FALSE;
2536 gboolean canPaste = FALSE;
2537 gboolean canTreeCut = FALSE;
2538 gboolean canTreeCopy = FALSE;
2539 gboolean canTreePaste = FALSE;
2540 gboolean canLookup = FALSE;
2541 GtkCMCTreeNode *node = NULL;
2543 if( ! event ) return FALSE;
2544 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2546 if( event->window != clist->clist_window )
2549 if (event->button == 1) {
2550 if (event->type == GDK_2BUTTON_PRESS) {
2551 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2552 gtkut_clist_set_focus_row(clist, row);
2553 obj = gtk_cmclist_get_row_data( clist, row );
2558 if (obj->type == ADDR_ITEM_GROUP ||
2559 obj->type == ADDR_DATASOURCE) {
2561 addressbook_treenode_edit_cb(NULL, NULL);
2563 /* expand pr collapse */
2564 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2565 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2571 addressbook_menubar_set_sensitive( FALSE );
2573 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2574 gtkut_clist_set_focus_row(clist, row);
2575 obj = gtk_cmclist_get_row_data( clist, row );
2578 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2582 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2584 if( ! addrclip_is_empty( _clipBoard_ ) )
2585 canTreePaste = TRUE;
2587 if (obj->type == ADDR_INTERFACE) {
2588 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2589 iface = adapter->interface;
2592 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2593 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2595 if( iface->externalQuery )
2598 if (obj->type == ADDR_DATASOURCE) {
2600 ads = ADAPTER_DSOURCE(obj);
2601 ds = ads->dataSource;
2604 iface = ds->interface;
2607 if( !iface->readOnly ) {
2608 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2609 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2610 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2616 else if (obj->type == ADDR_ITEM_FOLDER) {
2618 ds = addressbook_find_datasource( node );
2621 iface = ds->interface;
2624 if( !iface->readOnly ) {
2628 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2629 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2630 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2634 if( iface->externalQuery ) {
2635 /* Enable deletion of LDAP folder */
2639 else if (obj->type == ADDR_ITEM_GROUP) {
2641 ds = addressbook_find_datasource( node );
2644 iface = ds->interface;
2647 if( ! iface->readOnly ) {
2650 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2651 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2655 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2657 if( ! addrselect_test_empty( _addressSelect_ ) )
2659 if( ! addrclip_is_empty( _clipBoard_ ) )
2662 /* Forbid write changes when read-only */
2663 if( iface && iface->readOnly ) {
2665 canTreePaste = FALSE;
2672 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2673 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2674 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2675 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2676 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2678 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2679 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2680 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2681 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2682 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2684 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2685 addrbook.target_compose != NULL);
2687 if( event->button == 3 )
2688 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2689 event->button, event->time);
2694 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2695 GdkEventButton *event,
2698 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2702 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2704 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2705 AddressObject *obj = NULL;
2706 AddressDataSource *ds = NULL;
2707 AddressBookFile *abf = NULL;
2708 ItemFolder *parentFolder = NULL;
2709 ItemFolder *folder = NULL;
2711 if( ! addrbook.treeSelected ) return;
2712 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2713 if( obj == NULL ) return;
2714 ds = addressbook_find_datasource( addrbook.treeSelected );
2715 if( ds == NULL ) return;
2717 if( obj->type == ADDR_DATASOURCE ) {
2718 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2720 else if( obj->type == ADDR_ITEM_FOLDER ) {
2721 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2727 abf = ds->rawDataSource;
2728 if( abf == NULL ) return;
2729 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2732 nn = addressbook_node_add_folder(
2733 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2735 g_message("error adding addressbook folder\n");
2737 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2738 if( addrbook.treeSelected == addrbook.opened )
2739 addressbook_set_clist(obj, TRUE);
2743 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2745 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2746 AddressObject *obj = NULL;
2747 AddressDataSource *ds = NULL;
2748 AddressBookFile *abf = NULL;
2749 ItemFolder *parentFolder = NULL;
2750 ItemGroup *group = NULL;
2752 if( ! addrbook.treeSelected ) return;
2753 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2754 if( obj == NULL ) return;
2755 ds = addressbook_find_datasource( addrbook.treeSelected );
2756 if( ds == NULL ) return;
2758 if( obj->type == ADDR_DATASOURCE ) {
2759 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2761 else if( obj->type == ADDR_ITEM_FOLDER ) {
2762 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2768 abf = ds->rawDataSource;
2769 if( abf == NULL ) return;
2770 group = addressbook_edit_group( abf, parentFolder, NULL );
2773 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2775 g_message("error adding addressbook group\n");
2777 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2778 if( addrbook.treeSelected == addrbook.opened )
2779 addressbook_set_clist(obj, TRUE);
2783 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2785 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2788 GdkPixbuf *pix_cl, *pix_op;
2789 gboolean is_leaf, expanded;
2791 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2793 &is_leaf, &expanded);
2794 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2801 * \param obj Address object to edit.
2802 * \param node Node in tree.
2803 * \return New name of data source.
2805 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2806 gchar *newName = NULL;
2807 AddressDataSource *ds = NULL;
2808 AddressInterface *iface = NULL;
2809 AdapterDSource *ads = NULL;
2811 ds = addressbook_find_datasource( node );
2812 if( ds == NULL ) return NULL;
2813 iface = ds->interface;
2814 if( ! iface->haveLibrary ) return NULL;
2816 /* Read data from data source */
2817 if( addrindex_ds_get_modify_flag( ds ) ) {
2818 addrindex_ds_read_data( ds );
2821 if( ! addrindex_ds_get_read_flag( ds ) ) {
2822 addrindex_ds_read_data( ds );
2826 ads = ADAPTER_DSOURCE(obj);
2827 if( ads->subType == ADDR_BOOK ) {
2828 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2830 else if( ads->subType == ADDR_VCARD ) {
2831 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2834 else if( ads->subType == ADDR_JPILOT ) {
2835 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2839 else if( ads->subType == ADDR_LDAP ) {
2840 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2846 newName = obj->name;
2851 * Edit an object that is in the address tree area.
2853 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2855 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2857 AddressDataSource *ds = NULL;
2858 AddressBookFile *abf = NULL;
2859 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2862 if( ! addrbook.treeSelected ) return;
2863 node = addrbook.treeSelected;
2864 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2865 obj = gtk_cmctree_node_get_row_data( ctree, node );
2866 if( obj == NULL ) return;
2867 parentNode = GTK_CMCTREE_ROW(node)->parent;
2869 ds = addressbook_find_datasource( node );
2870 if( ds == NULL ) return;
2872 if( obj->type == ADDR_DATASOURCE ) {
2873 name = addressbook_edit_datasource( obj, node );
2874 if( name == NULL ) return;
2877 abf = ds->rawDataSource;
2878 if( abf == NULL ) return;
2879 if( obj->type == ADDR_ITEM_FOLDER ) {
2880 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2881 ItemFolder *item = adapter->itemFolder;
2882 ItemFolder *parentFolder = NULL;
2883 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2884 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2885 name = ADDRITEM_NAME(item);
2887 else if( obj->type == ADDR_ITEM_GROUP ) {
2888 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2889 ItemGroup *item = adapter->itemGroup;
2890 ItemFolder *parentFolder = NULL;
2891 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2892 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2893 name = ADDRITEM_NAME(item);
2896 if( name && parentNode ) {
2897 /* Update node in tree view */
2898 addressbook_change_node_name( node, name );
2899 gtk_sctree_sort_node(ctree, parentNode);
2900 gtk_cmctree_expand( ctree, node );
2901 gtk_sctree_select( GTK_SCTREE( ctree), node );
2908 ADDRTREE_DEL_FOLDER_ONLY,
2909 ADDRTREE_DEL_FOLDER_ADDR
2913 * Delete an item from the tree widget.
2914 * \param data Data passed in.
2915 * \param action Action.
2916 * \param widget Widget issuing callback.
2918 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2920 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2921 GtkCMCTreeNode *node = NULL;
2925 AddrBookBase *adbase;
2926 AddressCache *cache;
2927 AdapterDSource *ads = NULL;
2928 AddressInterface *iface = NULL;
2929 AddressDataSource *ds = NULL;
2930 gboolean remFlag = FALSE;
2931 TreeItemDelType delType;
2933 if( ! addrbook.treeSelected ) return;
2934 node = addrbook.treeSelected;
2935 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2937 obj = gtk_cmctree_node_get_row_data( ctree, node );
2938 cm_return_if_fail(obj != NULL);
2940 if( obj->type == ADDR_DATASOURCE ) {
2941 ads = ADAPTER_DSOURCE(obj);
2943 ds = ads->dataSource;
2944 if( ds == NULL ) return;
2947 /* Must be folder or something else */
2948 ds = addressbook_find_datasource( node );
2949 if( ds == NULL ) return;
2951 /* Only allow deletion from non-readOnly */
2952 iface = ds->interface;
2953 if( iface->readOnly ) {
2954 /* Allow deletion of query results */
2955 if( ! iface->externalQuery ) return;
2959 /* Confirm deletion */
2960 delType = ADDRTREE_DEL_NONE;
2961 if( obj->type == ADDR_ITEM_FOLDER ) {
2962 if( iface && iface->externalQuery ) {
2963 message = g_strdup_printf( _(
2964 "Do you want to delete the query " \
2965 "results and addresses in '%s'?" ),
2967 aval = alertpanel( _("Delete"), message,
2968 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
2970 if( aval == G_ALERTALTERNATE ) {
2971 delType = ADDRTREE_DEL_FOLDER_ADDR;
2975 message = g_strdup_printf
2976 ( _( "Do you want to delete '%s'? "
2977 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2979 aval = alertpanel( _("Delete folder"), message,
2980 GTK_STOCK_CANCEL, _("Delete _folder only"), _("Delete folder and _addresses"), ALERTFOCUS_SECOND);
2982 if( aval == G_ALERTALTERNATE ) {
2983 delType = ADDRTREE_DEL_FOLDER_ONLY;
2985 else if( aval == G_ALERTOTHER ) {
2986 delType = ADDRTREE_DEL_FOLDER_ADDR;
2990 else if( obj->type == ADDR_ITEM_GROUP ) {
2991 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2992 "The addresses it contains will not be lost."), obj->name);
2993 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2994 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2996 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2998 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2999 "The addresses it contains will be lost."), obj->name);
3000 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
3001 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
3003 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
3005 if( delType == ADDRTREE_DEL_NONE ) return;
3007 /* Proceed with deletion */
3008 if( obj->type == ADDR_DATASOURCE ) {
3009 /* Remove node from tree */
3010 gtk_cmctree_remove_node( ctree, node );
3012 if (delType == ADDRTREE_DEL_DATA &&
3013 ds->interface && ds->interface->type == ADDR_IF_BOOK)
3014 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
3016 /* Remove data source. */
3017 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3018 addrindex_free_datasource( ds );
3023 /* Get reference to cache */
3024 adbase = ( AddrBookBase * ) ds->rawDataSource;
3025 if( adbase == NULL ) return;
3026 cache = adbase->addressCache;
3028 /* Remove query results folder */
3029 if( iface && iface->externalQuery ) {
3030 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3031 ItemFolder *folder = adapter->itemFolder;
3033 adapter->itemFolder = NULL;
3035 g_print( "remove folder for ::%s::\n", obj->name );
3036 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3037 g_print( "-------------- remove results\n" );
3039 addrindex_remove_results( ds, folder );
3040 /* g_print( "-------------- remove node\n" ); */
3041 gtk_cmctree_remove_node( ctree, node );
3045 /* Code below is valid for regular address book deletion */
3046 if( obj->type == ADDR_ITEM_FOLDER ) {
3047 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3048 ItemFolder *item = adapter->itemFolder;
3050 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3051 /* Remove folder only */
3052 item = addrcache_remove_folder( cache, item );
3054 addritem_free_item_folder( item );
3055 addressbook_move_nodes_up( ctree, node );
3059 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3060 /* Remove folder and addresses */
3061 item = addrcache_remove_folder_delete( cache, item );
3063 addritem_free_item_folder( item );
3068 else if( obj->type == ADDR_ITEM_GROUP ) {
3069 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3070 ItemGroup *item = adapter->itemGroup;
3072 item = addrcache_remove_group( cache, item );
3074 addritem_free_item_group( item );
3081 gtk_cmctree_remove_node(ctree, node );
3085 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3087 if( person && addrbook.treeSelected == addrbook.opened ) {
3088 person->status = ADD_ENTRY;
3089 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3090 addressbook_folder_refresh_one_person(
3091 GTK_CMCTREE(addrbook.clist), person );
3093 addressbook_address_list_set_focus();
3096 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3098 if( person && addrbook.treeSelected == addrbook.opened) {
3099 person->status = ADD_ENTRY;
3100 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3101 addressbook_set_clist(
3102 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3106 addressbook_address_list_set_focus();
3110 * Label (a format string) that is used to name each folder.
3112 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3115 * Search ctree widget callback function.
3116 * \param pA Pointer to node.
3117 * \param pB Pointer to data item being sought.
3118 * \return Zero (0) if folder found.
3120 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3123 aoA = ( AddressObject * ) pA;
3124 if( aoA->type == ADDR_ITEM_FOLDER ) {
3125 ItemFolder *folder, *fld;
3127 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3128 folder = ( ItemFolder * ) pB;
3129 if( fld == folder ) return 0; /* Found folder */
3134 static ItemFolder * addressbook_setup_subf(
3135 AddressDataSource *ds, gchar *title,
3136 GtkCMCTreeNode *pNode )
3138 AddrBookBase *adbase;
3139 AddressCache *cache;
3142 GtkCMCTreeNode *nNode;
3144 AddressObjectType aoType = ADDR_NONE;
3147 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3149 if( ds && ds->type == ADDR_IF_LDAP ) {
3151 aoType = ADDR_LDAP_QUERY;
3158 ctree = GTK_CMCTREE(addrbook.ctree);
3159 /* Get reference to address cache */
3160 adbase = ( AddrBookBase * ) ds->rawDataSource;
3161 cache = adbase->addressCache;
3163 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3164 GList *cur = children;
3165 for (; cur; cur = cur->next) {
3166 ItemFolder *child = (ItemFolder *) cur->data;
3167 if (!g_strcmp0(ADDRITEM_NAME(child), title)) {
3168 nNode = gtk_cmctree_find_by_row_data_custom(
3170 addressbook_treenode_find_folder_cb );
3172 addrindex_remove_results( ds, child );
3173 while( child->listPerson ) {
3174 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3175 item = addrcache_remove_person( cache, item );
3177 addritem_free_item_person( item );
3181 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3182 addrbook.treeSelected = nNode;
3189 /* Create a folder */
3190 folder = addrcache_add_new_folder( cache, NULL );
3191 name = g_strdup_printf( "%s", title );
3192 addritem_folder_set_name( folder, name );
3193 addritem_folder_set_remarks( folder, "" );
3196 /* Now let's see the folder */
3197 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3198 gtk_cmctree_expand( ctree, pNode );
3200 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3201 addrbook.treeSelected = nNode;
3207 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3208 AddressObject *pobj = NULL;
3209 AddressDataSource *ds = NULL;
3210 AddressBookFile *abf = NULL;
3211 debug_print("adding address\n");
3212 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3213 if( pobj == NULL ) {
3214 debug_print("no row data\n");
3217 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3219 debug_print("no datasource\n");
3223 abf = ds->rawDataSource;
3225 g_print("no addressbook file\n");
3229 if( pobj->type == ADDR_DATASOURCE ) {
3230 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3231 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3233 ItemFolder *folder = NULL;
3235 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3236 GtkCMCTreeNode *parentNode;
3237 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3238 if( ds == NULL ) return;
3240 /* We must have a datasource that is an external interface */
3241 if( ! ds->interface->haveLibrary ) return;
3242 if( ! ds->interface->externalQuery ) return;
3244 if( pobj->type == ADDR_ITEM_FOLDER ) {
3245 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3248 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3250 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3252 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3254 abf = ds->rawDataSource;
3257 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3258 addrbook.editaddress_vbox,
3259 addressbook_new_address_from_book_post_cb,
3262 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3263 LdapServer *server = ds->rawDataSource;
3264 ldapsvr_set_modified(server, TRUE);
3265 ldapsvr_update_book(server, NULL);
3266 if (server->retVal != LDAPRC_SUCCESS) {
3267 alertpanel( _("Add address(es)"),
3268 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3269 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3270 server->retVal = LDAPRC_SUCCESS;
3275 if (prefs_common.addressbook_use_editaddress_dialog)
3276 addressbook_new_address_from_book_post_cb( person );
3279 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3281 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3284 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3285 GtkCMCTreeNode *parentNode;
3286 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3287 if( ds == NULL ) return;
3289 /* We must have a datasource that is an external interface */
3290 if( ! ds->interface->haveLibrary ) return;
3291 if( ! ds->interface->externalQuery ) return;
3293 if( pobj->type == ADDR_ITEM_FOLDER ) {
3294 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3297 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3299 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3303 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3305 abf = ds->rawDataSource;
3308 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3309 addrbook.editaddress_vbox,
3310 addressbook_new_address_from_folder_post_cb,
3313 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3314 LdapServer *server = ds->rawDataSource;
3315 ldapsvr_set_modified(server, TRUE);
3316 ldapsvr_update_book(server, NULL);
3317 if (server->retVal != LDAPRC_SUCCESS) {
3318 alertpanel( _("Add address(es)"),
3319 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3320 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3325 if (prefs_common.addressbook_use_editaddress_dialog)
3326 addressbook_new_address_from_folder_post_cb( person );
3328 else if( pobj->type == ADDR_ITEM_GROUP ) {
3329 /* New address in group */
3330 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3331 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3332 if (addrbook.treeSelected == addrbook.opened) {
3333 /* Change node name in tree. */
3334 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3335 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3336 addressbook_set_clist(
3337 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3345 * Search for specified child group node in address index tree.
3346 * \param parent Parent node.
3347 * \param group Group to find.
3349 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3350 GtkCMCTreeNode *node = NULL;
3351 GtkCMCTreeRow *currRow;
3353 currRow = GTK_CMCTREE_ROW( parent );
3355 node = currRow->children;
3359 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3360 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3361 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3362 if( g == group ) return node;
3364 currRow = GTK_CMCTREE_ROW(node);
3365 node = currRow->sibling;
3371 static AddressBookFile *addressbook_get_book_file() {
3372 AddressBookFile *abf = NULL;
3373 AddressDataSource *ds = NULL;
3375 ds = addressbook_find_datasource( addrbook.treeSelected );
3376 if( ds == NULL ) return NULL;
3377 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3381 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3382 GtkCMCTreeNode *node;
3385 /* Remove existing folders and groups */
3386 row = GTK_CMCTREE_ROW( parent );
3388 while( (node = row->children) ) {
3389 gtk_cmctree_remove_node( ctree, node );
3394 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3395 GtkCMCTreeNode *parent, *child;
3396 GtkCMCTreeRow *currRow;
3397 currRow = GTK_CMCTREE_ROW( node );
3399 parent = currRow->parent;
3400 while( (child = currRow->children) ) {
3401 gtk_cmctree_move( ctree, child, parent, node );
3403 gtk_sctree_sort_node( ctree, parent );
3407 static void addressbook_edit_address_post_cb( ItemPerson *person )
3411 AddressBookFile *abf = addressbook_get_book_file();
3413 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3414 if (g_strcmp0(person->nickName, ADDRITEM_NAME(person)))
3415 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3418 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3419 invalidate_address_completion();
3421 addressbook_address_list_set_focus();
3424 void addressbook_address_list_set_focus( void )
3426 if (!prefs_common.addressbook_use_editaddress_dialog) {
3427 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3428 addressbook_list_menu_setup();
3432 void addressbook_address_list_disable_some_actions(void)
3434 /* disable address copy/pasting when editing contact's detail (embedded form) */
3435 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", FALSE );
3436 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", FALSE );
3437 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", FALSE );
3440 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3441 addressbook_edit_address(data, 0, NULL, TRUE);
3444 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3445 gboolean force_focus ) {
3446 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3448 AddressObject *obj = NULL, *pobj = NULL;
3449 AddressDataSource *ds = NULL;
3450 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3452 AddressBookFile *abf = NULL;
3454 if( addrbook.listSelected == NULL ) return;
3455 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3456 cm_return_if_fail(obj != NULL);
3458 ctree = GTK_CMCTREE( addrbook.ctree );
3459 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3461 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3462 if( ds == NULL ) return;
3464 abf = addressbook_get_book_file();
3466 if( obj->type == ADDR_ITEM_EMAIL ) {
3467 ItemEMail *email = ( ItemEMail * ) obj;
3469 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3470 /* Edit parent group */
3471 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3472 ItemGroup *itemGrp = adapter->itemGroup;
3473 if( abf == NULL ) return;
3474 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3475 name = ADDRITEM_NAME(itemGrp);
3476 node = addrbook.treeSelected;
3477 parentNode = GTK_CMCTREE_ROW(node)->parent;
3480 /* Edit person - email page */
3482 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3483 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3484 addressbook_edit_address_post_cb,
3485 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3488 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3489 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3490 person->status = UPDATE_ENTRY;
3493 if (prefs_common.addressbook_use_editaddress_dialog)
3494 addressbook_edit_address_post_cb( person );
3499 else if( obj->type == ADDR_ITEM_PERSON ) {
3500 /* Edit person - basic page */
3501 ItemPerson *person = ( ItemPerson * ) obj;
3502 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3503 addressbook_edit_address_post_cb,
3504 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3507 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3508 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3509 person->status = UPDATE_ENTRY;
3512 if (prefs_common.addressbook_use_editaddress_dialog)
3513 addressbook_edit_address_post_cb( person );
3517 else if( obj->type == ADDR_ITEM_GROUP ) {
3518 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3519 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3520 parentNode = addrbook.treeSelected;
3521 node = addressbook_find_group_node( parentNode, itemGrp );
3522 name = ADDRITEM_NAME(itemGrp);
3523 invalidate_address_completion();
3529 /* Update tree node with node name */
3530 if( node == NULL ) return;
3531 addressbook_change_node_name( node, name );
3532 gtk_sctree_sort_node( ctree, parentNode );
3533 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3534 addressbook_set_clist(
3535 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3540 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3542 addressbook_del_clicked(NULL, NULL);
3545 static void close_cb(GtkAction *action, gpointer data)
3547 addressbook_close();
3550 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3551 addressbook_export_to_file();
3554 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3556 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3557 if( person ) addritem_person_set_opened( person, TRUE );
3561 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3563 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3564 if( person ) addritem_person_set_opened( person, FALSE );
3568 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3570 gchar *eMailAlias = ADDRITEM_NAME(email);
3571 if( eMailAlias && *eMailAlias != '\0' ) {
3573 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3576 str = g_strdup( eMailAlias );
3582 static gboolean addressbook_match_item(const gchar *name,
3583 const gchar *email_alias,
3585 const gchar *remarks,
3590 if (!str || str[0] == '\0')
3592 if (strcasestr(name, str))
3594 else if (email_alias && strcasestr(email_alias, str))
3596 else if (addr && strcasestr(addr, str))
3598 else if (remarks && strcasestr(remarks, str))
3604 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3605 GList *items = itemGroup->listEMail;
3606 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3607 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3608 for( ; items != NULL; items = g_list_next( items ) ) {
3609 GtkCMCTreeNode *nodeEMail = NULL;
3610 gchar *text[N_LIST_COLS];
3611 ItemEMail *email = items->data;
3615 if( ! email ) continue;
3617 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3619 if( !addressbook_match_item(ADDRITEM_NAME(person),
3620 ADDRITEM_NAME(email),
3621 email->address, email->remarks,
3625 str = addressbook_format_item_clist( person, email );
3627 text[COL_NAME] = addressbook_set_col_name_guard(str);
3630 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3632 text[COL_ADDRESS] = email->address;
3633 text[COL_REMARKS] = email->remarks;
3634 nodeEMail = gtk_sctree_insert_node(
3636 text, FOLDER_SPACING,
3640 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3646 gchar *addressbook_set_col_name_guard(gchar *value)
3648 gchar *ret = "<not set>";
3649 gchar *tmp = g_strdup(value);
3651 if (tmp !=NULL && *tmp != '\0')
3657 static void addressbook_folder_load_one_person(
3658 GtkCMCTree *clist, ItemPerson *person,
3659 AddressTypeControlItem *atci,
3660 AddressTypeControlItem *atciMail )
3662 GtkCMCTreeNode *nodePerson = NULL;
3663 GtkCMCTreeNode *nodeEMail = NULL;
3664 gchar *text[N_LIST_COLS];
3665 gboolean flgFirst = TRUE, haveAddr = FALSE;
3668 AddressBookFile *abf = addressbook_get_book_file();
3671 if( person == NULL ) return;
3673 text[COL_NAME] = "";
3674 node = person->listEMail;
3676 ItemEMail *email = node->data;
3677 gchar *eMailAddr = NULL;
3678 node = g_list_next( node );
3680 text[COL_ADDRESS] = email->address;
3681 text[COL_REMARKS] = email->remarks;
3682 eMailAddr = ADDRITEM_NAME(email);
3683 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3685 /* First email belongs with person */
3686 gchar *str = addressbook_format_item_clist( person, email );
3688 text[COL_NAME] = addressbook_set_col_name_guard(str);
3691 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3692 person && person->nickName ) {
3693 if (person->nickName) {
3694 if (strcmp(person->nickName, "") != 0) {
3695 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3698 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3704 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3706 nodePerson = gtk_sctree_insert_node(
3708 text, FOLDER_SPACING,
3711 FALSE, person->isOpened );
3714 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3717 /* Subsequent email is a child node of person */
3718 text[COL_NAME] = ADDRITEM_NAME(email);
3719 nodeEMail = gtk_sctree_insert_node(
3720 clist, nodePerson, NULL,
3721 text, FOLDER_SPACING,
3723 atciMail->iconXpmOpen,
3725 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3731 /* Have name without EMail */
3732 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3733 text[COL_ADDRESS] = "";
3734 text[COL_REMARKS] = "";
3735 nodePerson = gtk_sctree_insert_node(
3737 text, FOLDER_SPACING,
3740 FALSE, person->isOpened );
3741 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3746 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3748 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3749 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3750 const gchar *search_str;
3752 if( atci == NULL ) return;
3753 if( atciMail == NULL ) return;
3755 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3757 /* Load email addresses */
3758 items = addritem_folder_get_person_list( itemFolder );
3759 for(cur = items ; cur != NULL; cur = g_list_next( cur ) ) {
3764 person = (ItemPerson *)cur->data;
3767 node = person->listEMail;
3768 if (node && node->data) {
3770 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3773 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3777 addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
3779 /* Free up the list */
3780 mgu_clear_list( items );
3781 g_list_free( items );
3784 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3785 addrbook.listSelected = NULL;
3786 gtk_cmctree_remove_node( clist, node );
3787 addressbook_menubar_set_sensitive( FALSE );
3788 addressbook_menuitem_set_sensitive(
3789 gtk_cmctree_node_get_row_data(
3790 GTK_CMCTREE(clist), addrbook.treeSelected ),
3791 addrbook.treeSelected );
3794 void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3795 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3796 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3797 GtkCMCTreeNode *node;
3798 if( atci == NULL ) return;
3799 if( atciMail == NULL ) return;
3800 if( person == NULL ) return;
3801 /* unload the person */
3803 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3805 addressbook_folder_remove_node( clist, node );
3806 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3807 gtk_sctree_sort_node( clist, NULL );
3808 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3810 gtk_sctree_select( GTK_SCTREE(clist), node );
3811 if (!gtk_cmctree_node_is_visible( clist, node ) )
3812 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3816 void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3817 GtkCMCTreeNode *node;
3819 if( person == NULL ) return;
3820 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3822 addressbook_folder_remove_node( clist, node );
3826 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3828 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3829 const gchar *search_str;
3831 /* Load any groups */
3832 if( ! atci ) return;
3834 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3836 items = addritem_folder_get_group_list( itemFolder );
3837 for( ; items != NULL; items = g_list_next( items ) ) {
3838 GtkCMCTreeNode *nodeGroup = NULL;
3839 gchar *text[N_LIST_COLS];
3840 ItemGroup *group = items->data;
3841 if( group == NULL ) continue;
3842 if( !addressbook_match_item(ADDRITEM_NAME(group),
3843 NULL, NULL, NULL, search_str) )
3846 text[COL_NAME] = ADDRITEM_NAME(group);
3847 text[COL_ADDRESS] = "";
3848 text[COL_REMARKS] = "";
3849 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3850 text, FOLDER_SPACING,
3854 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3855 gtk_sctree_sort_node(clist, NULL);
3857 /* Free up the list */
3858 mgu_clear_list( items );
3859 g_list_free( items );
3863 * Search ctree widget callback function.
3864 * \param pA Pointer to node.
3865 * \param pB Pointer to data item being sought.
3866 * \return Zero (0) if group found.
3868 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3871 aoA = ( AddressObject * ) pA;
3872 if( aoA->type == ADDR_ITEM_GROUP ) {
3873 ItemGroup *group, *grp;
3875 grp = ADAPTER_GROUP(aoA)->itemGroup;
3876 group = ( ItemGroup * ) pB;
3877 if( grp == group ) return 0; /* Found group */
3883 * Remove folder and group nodes from tree widget for items contained ("cut")
3886 static void addressbook_treenode_remove_item( void ) {
3888 AddrSelectItem *cutItem;
3889 AddressCache *cache;
3890 AddrItemObject *aio;
3891 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3894 node = _clipBoard_->objectList;
3896 cutItem = node->data;
3897 node = g_list_next( node );
3898 cache = addrindex_get_cache(
3899 _clipBoard_->addressIndex, cutItem->cacheID );
3900 if( cache == NULL ) continue;
3901 aio = addrcache_get_object( cache, cutItem->uid );
3904 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3907 folder = ( ItemFolder * ) aio;
3908 tn = gtk_cmctree_find_by_row_data_custom(
3909 ctree, NULL, folder,
3910 addressbook_treenode_find_folder_cb );
3912 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3915 group = ( ItemGroup * ) aio;
3916 tn = gtk_cmctree_find_by_row_data_custom(
3918 addressbook_treenode_find_group_cb );
3922 /* Free up adapter and remove node. */
3923 gtk_cmctree_remove_node( ctree, tn );
3930 * Find parent datasource for specified tree node.
3931 * \param node Node to test.
3932 * \return Data source, or NULL if not found.
3934 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3935 AddressDataSource *ds = NULL;
3938 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3941 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3942 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3944 /* g_print( "ao->type = %d\n", ao->type ); */
3945 if( ao->type == ADDR_DATASOURCE ) {
3946 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3947 /* g_print( "found it\n" ); */
3948 ds = ads->dataSource;
3952 node = GTK_CMCTREE_ROW(node)->parent;
3958 * Load address list widget with children of specified object.
3959 * \param obj Parent object to be loaded.
3961 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3962 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3963 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3964 AddressDataSource *ds = NULL;
3965 AdapterDSource *ads = NULL;
3966 static AddressObject *last_obj = NULL;
3968 if (addrbook.clist == NULL) {
3971 if (obj == last_obj && !refresh)
3976 gtk_cmclist_clear(clist);
3980 if( obj->type == ADDR_INTERFACE ) {
3981 /* g_print( "set_clist: loading datasource...\n" ); */
3982 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3986 gtk_cmclist_freeze(clist);
3987 gtk_cmclist_clear(clist);
3989 if( obj->type == ADDR_DATASOURCE ) {
3990 ads = ADAPTER_DSOURCE(obj);
3991 ds = ads->dataSource;
3993 /* Load root folder */
3994 ItemFolder *rootFolder = NULL;
3995 rootFolder = addrindex_ds_get_root_folder( ds );
3996 addressbook_folder_load_person(
3997 ctreelist, rootFolder );
3998 addressbook_folder_load_group(
3999 ctreelist, rootFolder );
4003 if( obj->type == ADDR_ITEM_GROUP ) {
4005 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
4006 addressbook_load_group( ctreelist, itemGroup );
4008 else if( obj->type == ADDR_ITEM_FOLDER ) {
4010 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
4011 addressbook_folder_load_person( ctreelist, itemFolder );
4012 addressbook_folder_load_group( ctreelist, itemFolder );
4015 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
4016 clist->focus_row = -1;
4017 gtk_cmclist_thaw(clist);
4021 * Call back function to free adaptor. Call back is setup by function
4022 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4023 * called when the address book tree widget node is removed by calling
4024 * function gtk_cmctree_remove_node().
4026 * \param data Tree node's row data.
4028 static void addressbook_free_treenode( gpointer data ) {
4031 ao = ( AddressObject * ) data;
4032 if( ao == NULL ) return;
4033 if( ao->type == ADDR_INTERFACE ) {
4034 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
4035 addrbookctl_free_interface( ai );
4037 else if( ao->type == ADDR_DATASOURCE ) {
4038 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
4039 addrbookctl_free_datasource( ads );
4041 else if( ao->type == ADDR_ITEM_FOLDER ) {
4042 AdapterFolder *af = ADAPTER_FOLDER(ao);
4043 addrbookctl_free_folder( af );
4045 else if( ao->type == ADDR_ITEM_GROUP ) {
4046 AdapterGroup *ag = ADAPTER_GROUP(ao);
4047 addrbookctl_free_group( ag );
4052 * Create new adaptor for specified data source.
4054 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4055 AddressObjectType otype, gchar *name )
4057 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4058 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4059 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4060 adapter->dataSource = ds;
4061 adapter->subType = otype;
4065 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4066 ADDRESS_OBJECT_NAME(adapter) =
4067 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4071 * Load tree from address index with the initial data.
4073 static void addressbook_load_tree( void ) {
4074 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4075 GList *nodeIf, *nodeDS;
4076 AdapterInterface *adapter;
4077 AddressInterface *iface;
4078 AddressTypeControlItem *atci;
4079 AddressDataSource *ds;
4080 AdapterDSource *ads;
4081 GtkCMCTreeNode *node, *newNode;
4084 nodeIf = _addressInterfaceList_;
4086 adapter = nodeIf->data;
4087 node = adapter->treeNode;
4088 iface = adapter->interface;
4089 atci = adapter->atci;
4091 if( iface->useInterface ) {
4092 /* Load data sources below interface node */
4093 nodeDS = iface->listSource;
4096 name = addrindex_ds_get_name( ds );
4097 ads = addressbook_create_ds_adapter(
4098 ds, atci->objectType, name );
4099 newNode = addressbook_add_object(
4100 node, ADDRESS_OBJECT(ads) );
4101 if (newNode == NULL) {
4102 g_message("error adding addressbook object\n");
4104 nodeDS = g_list_next( nodeDS );
4106 gtk_cmctree_expand( ctree, node );
4109 nodeIf = g_list_next( nodeIf );
4114 * Convert the old address book to new format.
4116 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4117 gboolean retVal = FALSE;
4118 gboolean errFlag = TRUE;
4121 /* Read old address book, performing conversion */
4122 debug_print( "Reading and converting old address book...\n" );
4123 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4124 addrindex_read_data( addrIndex );
4125 if( addrIndex->retVal == MGU_NO_FILE ) {
4126 /* We do not have a file - new user */
4127 debug_print( "New user... create new books...\n" );
4128 addrindex_create_new_books( addrIndex );
4129 if( addrIndex->retVal == MGU_SUCCESS ) {
4130 /* Save index file */
4131 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4132 addrindex_save_data( addrIndex );
4133 if( addrIndex->retVal == MGU_SUCCESS ) {
4138 msg = _( "New user, could not save index file." );
4142 msg = _( "New user, could not save address book files." );
4146 /* We have an old file */
4147 if( addrIndex->wasConverted ) {
4148 /* Converted successfully - save address index */
4149 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4150 addrindex_save_data( addrIndex );
4151 if( addrIndex->retVal == MGU_SUCCESS ) {
4152 msg = _( "Old address book converted successfully." );
4157 msg = _("Old address book converted,\n"
4158 "could not save new address index file." );
4162 /* File conversion failed - just create new books */
4163 debug_print( "File conversion failed... just create new books...\n" );
4164 addrindex_create_new_books( addrIndex );
4165 if( addrIndex->retVal == MGU_SUCCESS ) {
4167 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4168 addrindex_save_data( addrIndex );
4169 if( addrIndex->retVal == MGU_SUCCESS ) {
4170 msg = _("Could not convert address book,\n"
4171 "but created empty new address book files." );
4176 msg = _("Could not convert address book,\n"
4177 "could not save new address index file." );
4181 msg = _("Could not convert address book\n"
4182 "and could not create new address book files." );
4187 debug_print( "Error\n%s\n", msg );
4188 alertpanel_full(_("Addressbook conversion error"), msg,
4189 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4193 debug_print( "Warning\n%s\n", msg );
4194 alertpanel_full(_("Addressbook conversion error"), msg,
4195 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4196 NULL, ALERT_WARNING);
4202 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4206 gboolean failed = FALSE;
4207 GError *error = NULL;
4209 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4210 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4211 error->code, error->message);
4212 g_error_free(error);
4216 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4217 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4220 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4222 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4224 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4237 /* all copies succeeded, we can remove source files */
4238 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4239 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4240 error->code, error->message);
4241 g_error_free(error);
4244 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4245 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4248 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4250 claws_unlink(orig_file);
4260 void addressbook_read_file( void ) {
4261 AddressIndex *addrIndex = NULL;
4262 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4264 debug_print( "Reading address index...\n" );
4265 if( _addressIndex_ ) {
4266 debug_print( "address book already read!!!\n" );
4271 addrIndex = addrindex_create_index();
4272 addrindex_initialize();
4274 /* Use new address book index. */
4276 if ( !is_dir_exist(indexdir) ) {
4277 if ( make_dir(indexdir) < 0 ) {
4278 addrindex_set_file_path( addrIndex, get_rc_dir() );
4279 g_warning( "couldn't create dir '%s'", indexdir);
4281 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4282 remove_dir_recursive(indexdir);
4283 addrindex_set_file_path( addrIndex, get_rc_dir() );
4284 g_error("couldn't migrate dir %s", indexdir);
4286 addrindex_set_file_path( addrIndex, indexdir);
4290 addrindex_set_file_path( addrIndex, indexdir);
4293 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4294 addrindex_read_data( addrIndex );
4295 if( addrIndex->retVal == MGU_NO_FILE ) {
4296 /* Conversion required */
4297 debug_print( "Converting...\n" );
4298 if( addressbook_convert( addrIndex ) ) {
4299 _addressIndex_ = addrIndex;
4302 else if( addrIndex->retVal == MGU_SUCCESS ) {
4303 _addressIndex_ = addrIndex;
4306 /* Error reading address book */
4307 debug_print( "Could not read address index.\n" );
4308 addrindex_print_index( addrIndex, stdout );
4309 alertpanel_full(_("Addressbook Error"),
4310 _("Could not read address index"),
4311 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4314 debug_print( "done.\n" );
4318 * Add object into the address index tree widget.
4319 * Enter: node Parent node.
4320 * obj Object to add.
4321 * Return: Node that was added, or NULL if object not added.
4323 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4326 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4327 GtkCMCTreeNode *added;
4328 AddressObject *pobj;
4329 AddressObjectType otype;
4330 AddressTypeControlItem *atci = NULL;
4332 cm_return_val_if_fail(node != NULL, NULL);
4333 cm_return_val_if_fail(obj != NULL, NULL);
4335 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4336 cm_return_val_if_fail(pobj != NULL, NULL);
4338 /* Determine object type to be displayed */
4339 if( obj->type == ADDR_DATASOURCE ) {
4340 otype = ADAPTER_DSOURCE(obj)->subType;
4346 /* Handle any special conditions. */
4348 atci = addrbookctl_lookup( otype );
4350 if( atci->showInTree ) {
4351 /* Add object to tree */
4354 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4355 atci->iconXpm, atci->iconXpmOpen,
4356 atci->treeLeaf, atci->treeExpand );
4357 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4358 addressbook_free_treenode );
4362 gtk_sctree_sort_node(ctree, node);
4368 * Add group into the address index tree.
4369 * \param node Parent node.
4370 * \param ds Data source.
4371 * \param itemGroup Group to add.
4372 * \return Inserted node.
4374 static GtkCMCTreeNode *addressbook_node_add_group(
4375 GtkCMCTreeNode *node, AddressDataSource *ds,
4376 ItemGroup *itemGroup )
4378 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4379 GtkCMCTreeNode *newNode;
4380 AdapterGroup *adapter;
4381 AddressTypeControlItem *atci = NULL;
4384 if( ds == NULL ) return NULL;
4385 if( node == NULL || itemGroup == NULL ) return NULL;
4387 name = &itemGroup->obj.name;
4389 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4391 adapter = g_new0( AdapterGroup, 1 );
4392 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4393 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4394 adapter->itemGroup = itemGroup;
4396 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4397 atci->iconXpm, atci->iconXpm,
4398 atci->treeLeaf, atci->treeExpand );
4399 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4400 addressbook_free_treenode );
4401 gtk_sctree_sort_node( ctree, node );
4406 * Add folder into the address index tree. Only visible folders are loaded into
4407 * the address index tree. Note that the root folder is not inserted into the
4410 * \param node Parent node.
4411 * \param ds Data source.
4412 * \param itemFolder Folder to add.
4413 * \param otype Object type to display.
4414 * \return Inserted node for the folder.
4416 static GtkCMCTreeNode *addressbook_node_add_folder(
4417 GtkCMCTreeNode *node, AddressDataSource *ds,
4418 ItemFolder *itemFolder, AddressObjectType otype )
4420 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4421 GtkCMCTreeNode *newNode = NULL;
4422 AdapterFolder *adapter;
4423 AddressTypeControlItem *atci = NULL;
4424 GList *listItems = NULL;
4426 ItemFolder *rootFolder;
4428 /* Only visible folders */
4429 if( itemFolder == NULL || itemFolder->isHidden )
4434 if( node == NULL || itemFolder == NULL )
4437 /* Determine object type */
4438 atci = addrbookctl_lookup( otype );
4442 rootFolder = addrindex_ds_get_root_folder( ds );
4443 if( itemFolder == rootFolder ) {
4447 adapter = g_new0( AdapterFolder, 1 );
4448 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4449 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4450 adapter->itemFolder = itemFolder;
4452 name = ADDRITEM_NAME(itemFolder);
4453 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4454 atci->iconXpm, atci->iconXpm,
4455 atci->treeLeaf, atci->treeExpand );
4457 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4458 addressbook_free_treenode );
4462 listItems = itemFolder->listFolder;
4463 while( listItems ) {
4464 ItemFolder *item = listItems->data;
4465 addressbook_node_add_folder( newNode, ds, item, otype );
4466 listItems = g_list_next( listItems );
4468 listItems = itemFolder->listGroup;
4469 while( listItems ) {
4470 ItemGroup *item = listItems->data;
4471 addressbook_node_add_group( newNode, ds, item );
4472 listItems = g_list_next( listItems );
4474 gtk_sctree_sort_node( ctree, node );
4478 void addressbook_export_to_file( void ) {
4479 if( _addressIndex_ ) {
4480 /* Save all new address book data */
4481 debug_print( "Saving address books...\n" );
4482 addrindex_save_all_books( _addressIndex_ );
4484 debug_print( "Exporting addressbook to file...\n" );
4485 addrindex_save_data( _addressIndex_ );
4486 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4487 addrindex_print_index( _addressIndex_, stdout );
4490 /* Notify address completion of new data */
4491 invalidate_address_completion();
4495 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4497 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4498 addressbook_lup_clicked(NULL, NULL);
4503 * Comparison using cell contents (text in first column). Used for sort
4504 * address index widget.
4506 static gint addressbook_treenode_compare_func(
4507 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4509 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4510 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4511 gchar *name1 = NULL, *name2 = NULL;
4512 if( cell1 ) name1 = cell1->u.text;
4513 if( cell2 ) name2 = cell2->u.text;
4514 if( ! name1 ) return ( name2 != NULL );
4515 if( ! name2 ) return -1;
4516 return g_utf8_collate( name1, name2 );
4519 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4520 AdapterDSource *ads;
4521 AdapterInterface *adapter;
4522 GtkCMCTreeNode *newNode;
4524 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4525 if( adapter == NULL ) return;
4526 ads = addressbook_edit_book( _addressIndex_, NULL );
4528 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4530 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4531 addrbook.treeSelected = newNode;
4536 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4537 AdapterDSource *ads;
4538 AdapterInterface *adapter;
4539 GtkCMCTreeNode *newNode;
4541 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4542 if( adapter == NULL ) return;
4543 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4545 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4547 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4548 addrbook.treeSelected = newNode;
4554 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4555 AdapterDSource *ads;
4556 AdapterInterface *adapter;
4557 AddressInterface *iface;
4558 GtkCMCTreeNode *newNode;
4560 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4561 if( adapter == NULL ) return;
4562 iface = adapter->interface;
4563 if( ! iface->haveLibrary ) return;
4564 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4566 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4568 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4569 addrbook.treeSelected = newNode;
4576 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4577 AdapterDSource *ads;
4578 AdapterInterface *adapter;
4579 AddressInterface *iface;
4580 GtkCMCTreeNode *newNode;
4582 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4583 if( adapter == NULL ) return;
4584 iface = adapter->interface;
4585 if( ! iface->haveLibrary ) return;
4586 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4588 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4590 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4591 addrbook.treeSelected = newNode;
4598 * Display address search status message.
4599 * \param queryType Query type.
4600 * \param status Status/Error code.
4602 static void addressbook_search_message( gint queryType, gint sts ) {
4604 *addressbook_msgbuf = '\0';
4606 if( sts != MGU_SUCCESS ) {
4607 if( queryType == ADDRQUERY_LDAP ) {
4609 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4614 g_snprintf( addressbook_msgbuf,
4615 sizeof(addressbook_msgbuf), "%s", desc );
4616 addressbook_status_show( addressbook_msgbuf );
4619 addressbook_status_show( "" );
4624 * Refresh addressbook by forcing refresh of current selected object in
4627 static void addressbook_refresh_current( void ) {
4631 ctree = GTK_CMCTREE(addrbook.ctree);
4632 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4633 if( obj == NULL ) return;
4634 addressbook_set_clist( obj, TRUE );
4638 * Message that is displayed whilst a query is executing in a background
4641 static gchar *_tempMessage_ = N_( "Busy searching..." );
4644 * Address search idle function. This function is called during UI idle time
4645 * while a search is in progress.
4647 * \param data Idler data.
4649 static void addressbook_search_idle( gpointer data ) {
4653 queryID = GPOINTER_TO_INT( data );
4654 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4659 * Search completion callback function. This removes the query from the idle
4662 * \param sender Sender of query.
4663 * \param queryID Query ID of search request.
4664 * \param status Search status.
4665 * \param data Query data.
4667 static void addressbook_search_callback_end(
4668 gpointer sender, gint queryID, gint status, gpointer data )
4672 AddrQueryObject *aqo;
4674 /* Remove idler function */
4675 ptrQID = GINT_TO_POINTER( queryID );
4677 g_idle_remove_by_data( ptrQID );
4680 /* Refresh addressbook contents */
4681 addressbook_refresh_current();
4682 req = qrymgr_find_request( queryID );
4684 aqo = ( AddrQueryObject * ) req->queryList->data;
4685 addressbook_search_message( aqo->queryType, status );
4688 /* Stop the search */
4689 addrindex_stop_search( queryID );
4695 * \param ds Data source to search.
4696 * \param searchTerm String to lookup.
4697 * \param pNode Parent data source node.
4699 static void addressbook_perform_search(
4700 AddressDataSource *ds, gchar *searchTerm,
4701 GtkCMCTreeNode *pNode )
4709 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4711 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4713 /* Create a folder for the search results */
4714 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4715 folder = addressbook_setup_subf(ds, name, pNode);
4718 /* Setup the search */
4719 queryID = addrindex_setup_explicit_search(
4720 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4721 if( queryID == 0 ) return;
4723 /* Set up idler function */
4724 idleID = g_idle_add(
4725 (GSourceFunc) addressbook_search_idle,
4726 GINT_TO_POINTER( queryID ) );
4728 g_message("error adding addressbook_search_idle\n");
4731 /* Start search, sit back and wait for something to happen */
4732 addrindex_start_search( queryID );
4734 addressbook_status_show( _tempMessage_ );
4738 * Lookup button handler. Address search is only performed against
4739 * address interfaces for external queries.
4741 * \param button Lookup button widget.
4742 * \param data Data object.
4744 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4747 AddressDataSource *ds;
4748 AddressInterface *iface;
4750 GtkCMCTreeNode *node, *parentNode;
4752 LdapServer *ldap_server;
4753 LdapControl *ldap_ctl;
4756 node = addrbook.treeSelected;
4757 if( ! node ) return;
4758 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4760 ctree = GTK_CMCTREE(addrbook.ctree);
4761 obj = gtk_cmctree_node_get_row_data( ctree, node );
4762 if( obj == NULL ) return;
4764 if (obj->type != ADDR_DATASOURCE ||
4765 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4766 addressbook_set_clist(
4767 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4768 addrbook.treeSelected),
4772 ds = addressbook_find_datasource( node );
4773 if( ds == NULL ) return;
4775 /* We must have a datasource that is an external interface */
4776 iface = ds->interface;
4777 if( ! iface->haveLibrary ) return;
4778 if( ! iface->externalQuery ) return;
4781 if (iface->type == ADDR_IF_LDAP) {
4782 ldap_server = ds->rawDataSource;
4783 ldap_ctl = ldap_server->control;
4784 if (ldap_ctl != NULL &&
4785 ldap_ctl->bindDN != NULL && strlen(ldap_ctl->bindDN) > 0) {
4786 #ifndef PASSWORD_CRYPTO_OLD
4787 /* LDAP server is password-protected. */
4788 if (master_passphrase() == NULL) {
4789 /* User did not enter master passphrase, do not start a search. */
4792 #endif /* PASSWORD_CRYPTO_OLD */
4795 #endif /* USE_LDAP */
4798 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4799 g_strchomp( searchTerm );
4801 if( obj->type == ADDR_ITEM_FOLDER ) {
4802 parentNode = GTK_CMCTREE_ROW(node)->parent;
4807 addressbook_perform_search( ds, searchTerm, parentNode );
4809 gtk_widget_grab_focus( addrbook.entry );
4811 g_free( searchTerm );
4814 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4815 addressbook_close();
4820 * Browse address entry for highlighted entry.
4822 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4824 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4826 AddressDataSource *ds;
4827 AddressInterface *iface;
4831 if(addrbook.listSelected == NULL)
4834 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4838 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4842 iface = ds->interface;
4843 if(!iface || !iface->haveLibrary )
4847 if (obj->type == ADDR_ITEM_EMAIL) {
4848 email = ( ItemEMail * ) obj;
4850 person = (ItemPerson *) ADDRITEM_PARENT(email);
4852 else if (obj->type == ADDR_ITEM_PERSON) {
4853 person = (ItemPerson *) obj;
4860 if( iface && iface->type == ADDR_IF_LDAP ) {
4861 browseldap_entry(ds, person->externalID);
4866 /* **********************************************************************
4867 * Build lookup tables.
4868 * ***********************************************************************
4872 * Remap object types.
4873 * Enter: abType AddressObjectType (used in tree node).
4874 * Return: ItemObjectType (used in address cache data).
4876 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4877 ItemObjectType ioType;
4880 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4881 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4882 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4883 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4884 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4885 default: ioType = ITEMTYPE_NONE; break;
4890 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4891 atci = addrbookctl_lookup(id); \
4893 atci->iconXpm = icon; \
4894 atci->iconXpmOpen = iconopen; \
4896 g_warning("can't get atci %d", id); \
4901 * Build table that controls the rendering of object types.
4903 static void addrbookctl_build_icons( GtkWidget *window ) {
4904 AddressTypeControlItem *atci;
4908 g_object_unref(interfacexpm);
4910 g_object_unref(folderxpm);
4912 g_object_unref(folderopenxpm);
4914 g_object_unref(groupxpm);
4916 g_object_unref(vcardxpm);
4918 g_object_unref(bookxpm);
4920 g_object_unref(addressxpm);
4922 g_object_unref(jpilotxpm);
4924 g_object_unref(categoryxpm);
4926 g_object_unref(ldapxpm);
4928 g_object_unref(addrsearchxpm);
4929 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4930 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4931 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4932 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4933 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4934 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4935 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4936 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4937 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4938 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4939 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4941 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4942 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4943 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4944 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4945 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4946 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4947 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4948 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4949 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4950 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4951 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4956 * Build table that controls the rendering of object types.
4958 static void addrbookctl_build_map( GtkWidget *window ) {
4959 AddressTypeControlItem *atci;
4961 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4962 _addressBookTypeList_ = NULL;
4965 atci = g_new0( AddressTypeControlItem, 1 );
4966 atci->objectType = ADDR_INTERFACE;
4967 atci->interfaceType = ADDR_IF_NONE;
4968 atci->showInTree = TRUE;
4969 atci->treeExpand = TRUE;
4970 atci->treeLeaf = FALSE;
4971 atci->displayName = _( "Interface" );
4972 atci->menuCommand = NULL;
4973 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4974 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4977 atci = g_new0( AddressTypeControlItem, 1 );
4978 atci->objectType = ADDR_BOOK;
4979 atci->interfaceType = ADDR_IF_BOOK;
4980 atci->showInTree = TRUE;
4981 atci->treeExpand = TRUE;
4982 atci->treeLeaf = FALSE;
4983 atci->displayName = _("Address Books");
4984 atci->menuCommand = "Menu/Book/NewBook";
4985 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4986 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4989 atci = g_new0( AddressTypeControlItem, 1 );
4990 atci->objectType = ADDR_ITEM_PERSON;
4991 atci->interfaceType = ADDR_IF_NONE;
4992 atci->showInTree = FALSE;
4993 atci->treeExpand = FALSE;
4994 atci->treeLeaf = FALSE;
4995 atci->displayName = _( "Person" );
4996 atci->menuCommand = NULL;
4997 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4998 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5001 atci = g_new0( AddressTypeControlItem, 1 );
5002 atci->objectType = ADDR_ITEM_EMAIL;
5003 atci->interfaceType = ADDR_IF_NONE;
5004 atci->showInTree = FALSE;
5005 atci->treeExpand = FALSE;
5006 atci->treeLeaf = TRUE;
5007 atci->displayName = _( "Email Address" );
5008 atci->menuCommand = NULL;
5009 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5010 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5013 atci = g_new0( AddressTypeControlItem, 1 );
5014 atci->objectType = ADDR_ITEM_GROUP;
5015 atci->interfaceType = ADDR_IF_BOOK;
5016 atci->showInTree = TRUE;
5017 atci->treeExpand = FALSE;
5018 atci->treeLeaf = FALSE;
5019 atci->displayName = _( "Group" );
5020 atci->menuCommand = NULL;
5021 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5022 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5025 atci = g_new0( AddressTypeControlItem, 1 );
5026 atci->objectType = ADDR_ITEM_FOLDER;
5027 atci->interfaceType = ADDR_IF_BOOK;
5028 atci->showInTree = TRUE;
5029 atci->treeExpand = FALSE;
5030 atci->treeLeaf = FALSE;
5031 atci->displayName = _( "Folder" );
5032 atci->menuCommand = NULL;
5033 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5034 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5037 atci = g_new0( AddressTypeControlItem, 1 );
5038 atci->objectType = ADDR_VCARD;
5039 atci->interfaceType = ADDR_IF_VCARD;
5040 atci->showInTree = TRUE;
5041 atci->treeExpand = TRUE;
5042 atci->treeLeaf = TRUE;
5043 atci->displayName = _( "vCard" );
5044 atci->menuCommand = "Menu/Book/NewVCard";
5045 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5046 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5049 atci = g_new0( AddressTypeControlItem, 1 );
5050 atci->objectType = ADDR_JPILOT;
5051 atci->interfaceType = ADDR_IF_JPILOT;
5052 atci->showInTree = TRUE;
5053 atci->treeExpand = TRUE;
5054 atci->treeLeaf = FALSE;
5055 atci->displayName = _( "JPilot" );
5056 atci->menuCommand = "Menu/Book/NewJPilot";
5057 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5058 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5061 atci = g_new0( AddressTypeControlItem, 1 );
5062 atci->objectType = ADDR_CATEGORY;
5063 atci->interfaceType = ADDR_IF_JPILOT;
5064 atci->showInTree = TRUE;
5065 atci->treeExpand = TRUE;
5066 atci->treeLeaf = TRUE;
5067 atci->displayName = _( "JPilot" );
5068 atci->menuCommand = NULL;
5069 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5070 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5073 atci = g_new0( AddressTypeControlItem, 1 );
5074 atci->objectType = ADDR_LDAP;
5075 atci->interfaceType = ADDR_IF_LDAP;
5076 atci->showInTree = TRUE;
5077 atci->treeExpand = TRUE;
5078 atci->treeLeaf = FALSE;
5079 atci->displayName = _( "LDAP servers" );
5080 atci->menuCommand = "Menu/Book/NewLDAPServer";
5081 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5082 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5085 atci = g_new0( AddressTypeControlItem, 1 );
5086 atci->objectType = ADDR_LDAP_QUERY;
5087 atci->interfaceType = ADDR_IF_LDAP;
5088 atci->showInTree = TRUE;
5089 atci->treeExpand = FALSE;
5090 atci->treeLeaf = TRUE;
5091 atci->displayName = _( "LDAP Query" );
5092 atci->menuCommand = NULL;
5093 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5094 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5096 addrbookctl_build_icons(window);
5099 void addressbook_reflect_prefs_pixmap_theme(void)
5101 if (addrbook.window)
5102 addrbookctl_build_icons(addrbook.window);
5106 * Search for specified object type.
5108 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5110 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5114 * Search for specified interface type.
5116 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5117 GList *node = _addressBookTypeList_;
5119 AddressTypeControlItem *atci = node->data;
5120 if( atci->interfaceType == ifType ) return atci;
5121 node = g_list_next( node );
5126 static void addrbookctl_free_address( AddressObject *obj ) {
5127 g_free( obj->name );
5128 obj->type = ADDR_NONE;
5132 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5133 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5134 adapter->interface = NULL;
5135 adapter->interfaceType = ADDR_IF_NONE;
5136 adapter->atci = NULL;
5137 adapter->enabled = FALSE;
5138 adapter->haveLibrary = FALSE;
5139 adapter->treeNode = NULL;
5143 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5144 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5145 adapter->dataSource = NULL;
5146 adapter->subType = ADDR_NONE;
5150 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5151 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5152 adapter->itemFolder = NULL;
5156 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5157 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5158 adapter->itemGroup = NULL;
5163 * Build GUI interface list.
5165 static void addrbookctl_build_iflist( void ) {
5166 AddressTypeControlItem *atci;
5167 AdapterInterface *adapter;
5170 if( _addressIndex_ == NULL ) {
5171 _addressIndex_ = addrindex_create_index();
5172 if( _clipBoard_ == NULL ) {
5173 _clipBoard_ = addrclip_create();
5175 addrclip_set_index( _clipBoard_, _addressIndex_ );
5177 _addressInterfaceList_ = NULL;
5178 list = addrindex_get_interface_list( _addressIndex_ );
5180 AddressInterface *interface = list->data;
5181 atci = addrbookctl_lookup_iface( interface->type );
5183 adapter = g_new0( AdapterInterface, 1 );
5184 adapter->interfaceType = interface->type;
5185 adapter->atci = atci;
5186 adapter->interface = interface;
5187 adapter->treeNode = NULL;
5188 adapter->enabled = TRUE;
5189 adapter->haveLibrary = interface->haveLibrary;
5190 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5191 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5192 _addressInterfaceList_ =
5193 g_list_append( _addressInterfaceList_, adapter );
5195 list = g_list_next( list );
5200 * Find GUI interface type specified interface type.
5201 * \param ifType Interface type.
5202 * \return Interface item, or NULL if not found.
5204 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5205 GList *node = _addressInterfaceList_;
5207 AdapterInterface *adapter = node->data;
5208 if( adapter->interfaceType == ifType ) return adapter;
5209 node = g_list_next( node );
5215 * Build interface list selection.
5217 static void addrbookctl_build_ifselect( void ) {
5218 GList *newList = NULL;
5223 gchar *endptr = NULL;
5224 /* gboolean enabled; */
5225 AdapterInterface *adapter;
5227 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5230 splitStr = g_strsplit( selectStr, ",", -1 );
5231 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5233 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5234 ifType = strtol( splitStr[i], &endptr, 10 );
5237 if( strcmp( endptr, "/n" ) == 0 ) {
5242 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5243 adapter = addrbookctl_find_interface( ifType );
5245 newList = g_list_append( newList, adapter );
5252 /* g_print( "i=%d\n", i ); */
5253 g_strfreev( splitStr );
5254 g_free( selectStr );
5256 /* Replace existing list */
5257 mgu_clear_list( _addressIFaceSelection_ );
5258 g_list_free( _addressIFaceSelection_ );
5259 _addressIFaceSelection_ = newList;
5263 /* ***********************************************************************
5264 * Add sender to address book.
5265 * ***********************************************************************
5269 * This function is used by the Add sender to address book function.
5271 gboolean addressbook_add_contact(
5272 const gchar *name, const gchar *address, const gchar *remarks,
5273 GdkPixbuf *picture )
5275 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5276 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5277 debug_print( "addressbook_add_contact - added\n" );
5278 addressbook_refresh();
5283 /* ***********************************************************************
5284 * Book/folder selection.
5285 * ***********************************************************************
5289 * This function is used by the matcher dialog to select a book/folder.
5291 gchar *addressbook_folder_selection( const gchar *folderpath)
5293 AddressBookFile *book = NULL;
5294 ItemFolder *folder = NULL;
5297 cm_return_val_if_fail( folderpath != NULL, NULL);
5299 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5301 if ( folder != NULL) {
5303 gchar *oldtmp = NULL;
5304 AddrItemObject *obj = NULL;
5306 /* walk thru folder->parent to build the full folder path */
5307 /* TODO: wwp: optimize this */
5309 tmp = g_strdup(obj->uid);
5310 while ( obj->parent ) {
5312 if ( obj->name != NULL ) {
5313 oldtmp = g_strdup(tmp);
5315 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5319 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5322 path = g_strdup_printf("%s", book->fileName);
5324 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5330 /* ***********************************************************************
5331 * Book/folder checking.
5332 * ***********************************************************************
5335 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5337 FolderInfo *fi = g_new0( FolderInfo, 1 );
5339 fi->folder = folder;
5343 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5344 FolderInfo *fiParent, FolderPathMatch *match )
5350 FolderPathMatch *nextmatch = NULL;
5355 list = parentFolder->listFolder;
5357 folder = list->data;
5358 fName = g_strdup( ADDRITEM_NAME(folder) );
5360 /* match folder name, match pointer will be set to NULL if next recursive call
5361 doesn't need to match subfolder name */
5362 if ( match != NULL &&
5363 match->matched == FALSE ) {
5364 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5365 /* folder name matches, prepare next subfolder match */
5366 debug_print("matched folder name '%s'\n", fName);
5368 if ( match->folder_path[match->index] == NULL ) {
5369 /* we've matched all elements */
5370 match->matched = TRUE;
5371 match->folder = folder;
5372 debug_print("book/folder path matched!\n");
5374 /* keep on matching */
5382 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5383 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5385 list = g_list_next( list );
5390 * This function is used by to check if a matcher book/folder path corresponds to an
5391 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5392 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5393 if book AND folder are NULL this means that folderpath was empty or Any.
5394 If folderpath is a simple book name (without folder), book will not be NULL and folder
5395 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5398 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5399 AddressDataSource **book,
5400 ItemFolder **folder )
5402 AddressDataSource *ds;
5403 GList *list, *nodeDS;
5404 ItemFolder *rootFolder;
5405 AddressBookFile *abf;
5407 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5414 if ( folderpath == NULL )
5417 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5420 /* split the folder path we've received, we'll try to match this path, subpath by
5421 subpath against the book/folder structure in order */
5422 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5423 if (!folder_path_match.folder_path)
5426 list = addrindex_get_interface_list( _addressIndex_ );
5427 while ( list && !folder_path_match.matched ) {
5428 AddressInterface *interface = list->data;
5429 if ( interface && interface->type == ADDR_IF_BOOK ) {
5430 nodeDS = interface->listSource;
5431 while ( nodeDS && !folder_path_match.matched ) {
5434 /* Read address book */
5435 if( ! addrindex_ds_get_read_flag( ds ) ) {
5436 addrindex_ds_read_data( ds );
5439 /* Add node for address book */
5440 abf = ds->rawDataSource;
5442 /* match book name */
5443 if ( abf && abf->fileName &&
5444 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5446 debug_print("matched book name '%s'\n", abf->fileName);
5447 folder_path_match.book = ds;
5449 if ( folder_path_match.folder_path[1] == NULL ) {
5450 /* no folder part to match */
5452 folder_path_match.matched = TRUE;
5453 folder_path_match.folder = NULL;
5454 debug_print("book path matched!\n");
5457 /* match folder part */
5459 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5460 rootFolder = addrindex_ds_get_root_folder( ds );
5462 /* prepare for recursive call */
5463 folder_path_match.index = 1;
5464 /* this call will set folder_path_match.matched and folder_path_match.folder */
5465 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5470 nodeDS = g_list_next( nodeDS );
5473 list = g_list_next( list );
5476 g_strfreev( folder_path_match.folder_path );
5479 *book = folder_path_match.book;
5481 *folder = folder_path_match.folder;
5482 return folder_path_match.matched;
5486 /* **********************************************************************
5488 * ***********************************************************************
5494 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5495 AddressDataSource *ds = NULL;
5496 AdapterDSource *ads = NULL;
5497 AddressBookFile *abf = NULL;
5498 AdapterInterface *adapter;
5499 GtkCMCTreeNode *newNode;
5501 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5503 if( adapter->treeNode ) {
5504 abf = addressbook_imp_ldif( _addressIndex_ );
5506 ds = addrindex_index_add_datasource(
5507 _addressIndex_, ADDR_IF_BOOK, abf );
5508 ads = addressbook_create_ds_adapter(
5509 ds, ADDR_BOOK, NULL );
5510 addressbook_ads_set_name(
5511 ads, addrbook_get_name( abf ) );
5512 newNode = addressbook_add_object(
5514 ADDRESS_OBJECT(ads) );
5516 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5518 addrbook.treeSelected = newNode;
5521 /* Notify address completion */
5522 invalidate_address_completion();
5531 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5532 AddressDataSource *ds = NULL;
5533 AdapterDSource *ads = NULL;
5534 AddressBookFile *abf = NULL;
5535 AdapterInterface *adapter;
5536 GtkCMCTreeNode *newNode;
5538 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5540 if( adapter->treeNode ) {
5541 abf = addressbook_imp_mutt( _addressIndex_ );
5543 ds = addrindex_index_add_datasource(
5544 _addressIndex_, ADDR_IF_BOOK, abf );
5545 ads = addressbook_create_ds_adapter(
5546 ds, ADDR_BOOK, NULL );
5547 addressbook_ads_set_name(
5548 ads, addrbook_get_name( abf ) );
5549 newNode = addressbook_add_object(
5551 ADDRESS_OBJECT(ads) );
5553 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5555 addrbook.treeSelected = newNode;
5558 /* Notify address completion */
5559 invalidate_address_completion();
5568 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5569 AddressDataSource *ds = NULL;
5570 AdapterDSource *ads = NULL;
5571 AddressBookFile *abf = NULL;
5572 AdapterInterface *adapter;
5573 GtkCMCTreeNode *newNode;
5575 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5577 if( adapter->treeNode ) {
5578 abf = addressbook_imp_pine( _addressIndex_ );
5580 ds = addrindex_index_add_datasource(
5581 _addressIndex_, ADDR_IF_BOOK, abf );
5582 ads = addressbook_create_ds_adapter(
5583 ds, ADDR_BOOK, NULL );
5584 addressbook_ads_set_name(
5585 ads, addrbook_get_name( abf ) );
5586 newNode = addressbook_add_object(
5588 ADDRESS_OBJECT(ads) );
5590 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5592 addrbook.treeSelected = newNode;
5595 /* Notify address completion */
5596 invalidate_address_completion();
5603 * Harvest addresses.
5604 * \param folderItem Folder to import.
5605 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5606 * \param msgList List of message numbers, or NULL to process folder.
5608 void addressbook_harvest(
5609 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5611 AddressDataSource *ds = NULL;
5612 AdapterDSource *ads = NULL;
5613 AddressBookFile *abf = NULL;
5614 AdapterInterface *adapter;
5615 GtkCMCTreeNode *newNode;
5617 abf = addrgather_dlg_execute(
5618 folderItem, _addressIndex_, sourceInd, msgList );
5620 ds = addrindex_index_add_datasource(
5621 _addressIndex_, ADDR_IF_BOOK, abf );
5623 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5625 if( adapter->treeNode ) {
5626 ads = addressbook_create_ds_adapter(
5627 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5628 newNode = addressbook_add_object(
5630 ADDRESS_OBJECT(ads) );
5631 if (newNode == NULL) {
5632 g_message("error adding addressbook object\n");
5637 /* Notify address completion */
5638 invalidate_address_completion();
5645 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5646 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5648 AddressDataSource *ds = NULL;
5649 AddrBookBase *adbase;
5650 AddressCache *cache;
5651 GtkCMCTreeNode *node = NULL;
5653 if( ! addrbook.treeSelected ) return;
5654 node = addrbook.treeSelected;
5655 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5656 obj = gtk_cmctree_node_get_row_data( ctree, node );
5657 if( obj == NULL ) return;
5659 ds = addressbook_find_datasource( node );
5660 if( ds == NULL ) return;
5661 adbase = ( AddrBookBase * ) ds->rawDataSource;
5662 cache = adbase->addressCache;
5663 addressbook_exp_html( cache );
5669 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5670 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5672 AddressDataSource *ds = NULL;
5673 AddrBookBase *adbase;
5674 AddressCache *cache;
5675 GtkCMCTreeNode *node = NULL;
5677 if( ! addrbook.treeSelected ) return;
5678 node = addrbook.treeSelected;
5679 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5680 obj = gtk_cmctree_node_get_row_data( ctree, node );
5681 if( obj == NULL ) return;
5683 ds = addressbook_find_datasource( node );
5684 if( ds == NULL ) return;
5685 adbase = ( AddrBookBase * ) ds->rawDataSource;
5686 cache = adbase->addressCache;
5687 addressbook_exp_ldif( cache );
5690 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5692 addrduplicates_find(GTK_WINDOW(addrbook.window));
5695 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5697 addressbook_custom_attr_edit();
5700 static void addressbook_start_drag(GtkWidget *widget, gint button,
5704 GdkDragContext *context;
5705 if (addressbook_target_list == NULL)
5706 addressbook_target_list = gtk_target_list_new(
5707 addressbook_drag_types, 1);
5708 context = gtk_drag_begin(widget, addressbook_target_list,
5709 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5710 gtk_drag_set_icon_default(context);
5713 static void addressbook_drag_data_get(GtkWidget *widget,
5714 GdkDragContext *drag_context,
5715 GtkSelectionData *selection_data,
5720 AddrItemObject *aio = NULL;
5721 AddressObject *pobj = NULL;
5722 AdapterDSource *ads = NULL;
5723 AddressDataSource *ds = NULL;
5726 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5728 if( pobj == NULL ) return;
5730 if( pobj->type == ADDR_DATASOURCE ) {
5731 ads = ADAPTER_DSOURCE(pobj);
5732 ds = ads->dataSource;
5733 } else if (pobj->type == ADDR_ITEM_GROUP) {
5738 else if( pobj->type != ADDR_INTERFACE ) {
5739 ds = addressbook_find_datasource( addrbook.treeSelected );
5745 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5746 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5747 GTK_CMCTREE_NODE(cur->data));
5748 while (aio && aio->type != ITEMTYPE_PERSON) {
5753 if (aio && aio->type == ITEMTYPE_PERSON) {
5754 if( ds && ds->interface && ds->interface->readOnly)
5755 gtk_selection_data_set(selection_data,
5756 gtk_selection_data_get_target(selection_data), 8,
5757 (const guchar *)"Dummy_addr_copy", 15);
5759 gtk_selection_data_set(selection_data,
5760 gtk_selection_data_get_target(selection_data), 8,
5761 (const guchar *)"Dummy_addr_move", 15);
5765 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5766 GdkDragContext *context,
5772 GtkAllocation allocation;
5773 GtkRequisition requisition;
5775 GtkCMCTreeNode *node = NULL;
5776 gboolean acceptable = FALSE;
5777 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5778 gint height = allocation.height;
5779 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5780 gint total_height = requisition.height;
5781 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5782 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5783 gfloat vpos = gtk_adjustment_get_value(pos);
5785 if (gtk_cmclist_get_selection_info
5786 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5788 if (y > height - 24 && height + vpos < total_height) {
5789 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5790 gtk_adjustment_changed(pos);
5792 if (y < 24 && y > 0) {
5793 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5794 gtk_adjustment_changed(pos);
5796 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5799 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5800 if( obj->type == ADDR_ITEM_FOLDER
5801 || obj->type == ADDR_ITEM_GROUP)
5804 AdapterDSource *ads = NULL;
5805 AddressDataSource *ds = NULL;
5806 ads = ADAPTER_DSOURCE(obj);
5807 if (ads == NULL ){ return FALSE;}
5808 ds = ads->dataSource;
5809 if (ds == NULL ) { return FALSE;}
5817 g_signal_handlers_block_by_func
5819 G_CALLBACK(addressbook_tree_selected), NULL);
5820 gtk_sctree_select( GTK_SCTREE(widget), node);
5821 g_signal_handlers_unblock_by_func
5823 G_CALLBACK(addressbook_tree_selected), NULL);
5824 gdk_drag_status(context,
5825 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5826 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5828 gdk_drag_status(context, 0, time);
5833 static void addressbook_drag_leave_cb(GtkWidget *widget,
5834 GdkDragContext *context,
5838 if (addrbook.treeSelected) {
5839 g_signal_handlers_block_by_func
5841 G_CALLBACK(addressbook_tree_selected), NULL);
5842 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5843 g_signal_handlers_unblock_by_func
5845 G_CALLBACK(addressbook_tree_selected), NULL);
5850 static void addressbook_drag_received_cb(GtkWidget *widget,
5851 GdkDragContext *drag_context,
5854 GtkSelectionData *data,
5860 GtkCMCTreeNode *node;
5861 GtkCMCTreeNode *lastopened = addrbook.opened;
5863 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5864 if (gtk_cmclist_get_selection_info
5865 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5869 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5870 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5873 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5874 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5875 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5876 addressbook_clip_copy_cb(NULL, NULL);
5878 addressbook_clip_cut_cb(NULL, NULL);
5879 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5880 addressbook_clip_paste_cb(NULL,NULL);
5881 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5882 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5883 gtk_drag_finish(drag_context, TRUE, TRUE, time);