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_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
923 gtk_widget_realize(window);
925 g_signal_connect(G_OBJECT(window), "delete_event",
926 G_CALLBACK(addressbook_close), NULL);
927 g_signal_connect(G_OBJECT(window), "size_allocate",
928 G_CALLBACK(addressbook_size_allocate_cb), NULL);
929 g_signal_connect(G_OBJECT(window), "key_press_event",
930 G_CALLBACK(key_pressed), NULL);
931 MANAGE_WINDOW_SIGNALS_CONNECT(window);
933 vbox = gtk_vbox_new(FALSE, 0);
934 gtk_container_add(GTK_CONTAINER(window), vbox);
937 ui_manager = gtk_ui_manager_new();
938 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
939 G_N_ELEMENTS(addressbook_entries), NULL);
940 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
941 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
942 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
943 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
945 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
950 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
955 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
957 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
990 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
991 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
992 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
993 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
994 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
997 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
999 gtk_window_add_accel_group(GTK_WINDOW(window),
1000 gtk_ui_manager_get_accel_group(ui_manager));
1002 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
1004 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1006 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1007 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1008 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1010 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1011 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1012 GTK_POLICY_AUTOMATIC,
1013 GTK_POLICY_AUTOMATIC);
1014 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1017 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1018 gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1020 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1021 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1022 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1023 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1024 GTK_CMCTREE_EXPANDER_TRIANGLE);
1025 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1026 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1027 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1028 addressbook_treenode_compare_func);
1030 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1031 G_CALLBACK(addressbook_tree_selected), NULL);
1032 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1033 G_CALLBACK(addressbook_tree_button_pressed),
1035 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1036 G_CALLBACK(addressbook_tree_button_released),
1039 g_signal_connect(G_OBJECT(ctree), "select_row",
1040 G_CALLBACK(addressbook_select_row_tree), NULL);
1042 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1043 addressbook_drag_types, 1,
1044 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1045 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1046 G_CALLBACK(addressbook_drag_motion_cb),
1048 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1049 G_CALLBACK(addressbook_drag_leave_cb),
1051 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1052 G_CALLBACK(addressbook_drag_received_cb),
1054 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1055 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1056 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1057 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1059 clist_vbox = gtk_vbox_new(FALSE, 4);
1061 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1062 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1063 GTK_POLICY_AUTOMATIC,
1064 GTK_POLICY_AUTOMATIC);
1065 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1068 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1069 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1070 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1071 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1072 GTK_CMCTREE_EXPANDER_TRIANGLE);
1073 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1074 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1075 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1077 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1079 gtk_widget_set_size_request(clist, -1, 80);
1081 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1082 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1083 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1084 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1085 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1086 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1087 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1088 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1089 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1090 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1091 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1093 for (i = 0; i < N_LIST_COLS; i++)
1094 gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1097 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1098 G_CALLBACK(addressbook_list_row_selected), NULL);
1099 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1100 G_CALLBACK(addressbook_list_row_unselected), NULL);
1101 g_signal_connect(G_OBJECT(clist), "button_press_event",
1102 G_CALLBACK(addressbook_list_button_pressed),
1104 g_signal_connect(G_OBJECT(clist), "button_release_event",
1105 G_CALLBACK(addressbook_list_button_released),
1107 g_signal_connect(G_OBJECT(clist), "tree_expand",
1108 G_CALLBACK(addressbook_person_expand_node), NULL );
1109 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1110 G_CALLBACK(addressbook_person_collapse_node), NULL );
1111 g_signal_connect(G_OBJECT(clist), "start_drag",
1112 G_CALLBACK(addressbook_start_drag), NULL);
1113 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1114 G_CALLBACK(addressbook_drag_data_get), NULL);
1115 hbox = gtk_hbox_new(FALSE, 4);
1116 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1118 label = gtk_label_new(_("Search"));
1119 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1121 entry = gtk_entry_new();
1122 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1124 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1126 g_signal_connect(G_OBJECT(entry), "key_press_event",
1127 G_CALLBACK(addressbook_entry_key_pressed),
1129 g_signal_connect(G_OBJECT(entry), "activate",
1130 G_CALLBACK(addressbook_entry_activated), NULL);
1132 if (!prefs_common.addressbook_use_editaddress_dialog) {
1133 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1134 vpaned = gtk_vpaned_new();
1135 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1136 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1139 editaddress_vbox = NULL;
1141 hpaned = gtk_hpaned_new();
1142 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1143 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1144 if (prefs_common.addressbook_use_editaddress_dialog)
1145 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1147 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1150 hsbox = gtk_hbox_new(FALSE, 0);
1151 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1152 statusbar = gtk_statusbar_new();
1153 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1156 hbbox = gtk_hbutton_box_new();
1157 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1158 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1159 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1160 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1162 gtkut_stock_button_add_help(hbbox, &help_btn);
1164 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1165 gtk_widget_set_can_default(edit_btn, TRUE);
1166 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1167 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1168 gtk_widget_set_can_default(del_btn, TRUE);
1169 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1170 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1171 gtk_widget_set_can_default(reg_btn, TRUE);
1172 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1175 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1176 gtk_widget_set_can_default(lup_btn, TRUE);
1177 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1179 g_signal_connect(G_OBJECT(help_btn), "clicked",
1180 G_CALLBACK(manual_open_with_anchor_cb),
1181 MANUAL_ANCHOR_ADDRBOOK);
1183 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1184 G_CALLBACK(addressbook_edit_clicked), NULL);
1185 g_signal_connect(G_OBJECT(del_btn), "clicked",
1186 G_CALLBACK(addressbook_del_clicked), NULL);
1187 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1188 G_CALLBACK(addressbook_reg_clicked), NULL);
1189 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1190 G_CALLBACK(addressbook_lup_clicked), NULL);
1192 to_btn = gtk_button_new_with_label
1193 (prefs_common_translated_header_name("To:"));
1194 gtk_widget_set_can_default(to_btn, TRUE);
1195 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1196 cc_btn = gtk_button_new_with_label
1197 (prefs_common_translated_header_name("Cc:"));
1198 gtk_widget_set_can_default(cc_btn, TRUE);
1199 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1200 bcc_btn = gtk_button_new_with_label
1201 (prefs_common_translated_header_name("Bcc:"));
1202 gtk_widget_set_can_default(bcc_btn, TRUE);
1203 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1205 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1206 gtk_widget_set_can_default(close_btn, TRUE);
1207 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1209 g_signal_connect(G_OBJECT(to_btn), "clicked",
1210 G_CALLBACK(addressbook_to_clicked),
1211 GINT_TO_POINTER(COMPOSE_TO));
1212 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1213 G_CALLBACK(addressbook_to_clicked),
1214 GINT_TO_POINTER(COMPOSE_CC));
1215 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1216 G_CALLBACK(addressbook_to_clicked),
1217 GINT_TO_POINTER(COMPOSE_BCC));
1218 g_signal_connect(G_OBJECT(close_btn), "clicked",
1219 G_CALLBACK(addressbook_close_clicked), NULL);
1221 /* Build icons for interface */
1223 /* Build control tables */
1224 addrbookctl_build_map(window);
1225 addrbookctl_build_iflist();
1226 addrbookctl_build_ifselect();
1228 addrbook.clist = NULL;
1230 /* Add each interface into the tree as a root level folder */
1231 nodeIf = _addressInterfaceList_;
1233 AdapterInterface *adapter = nodeIf->data;
1234 AddressInterface *iface = adapter->interface;
1235 nodeIf = g_list_next(nodeIf);
1237 if(iface->useInterface) {
1238 AddressTypeControlItem *atci = adapter->atci;
1239 text = atci->displayName;
1241 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1242 NULL, NULL, &text, FOLDER_SPACING,
1246 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1247 gtk_cmctree_node_set_row_data_full(
1248 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1249 addressbook_free_treenode );
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1268 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1269 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1281 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1284 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1286 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1288 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
1289 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1290 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1292 addrbook.window = window;
1293 addrbook.hpaned = hpaned;
1294 addrbook.vpaned = vpaned;
1295 addrbook.menubar = menubar;
1296 addrbook.ctree = ctree;
1299 addrbook.editaddress_vbox = editaddress_vbox;
1300 addrbook.clist = clist;
1301 addrbook.label = label;
1302 addrbook.entry = entry;
1303 addrbook.statusbar = statusbar;
1304 addrbook.status_cid = gtk_statusbar_get_context_id(
1305 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1307 addrbook.help_btn = help_btn;
1308 addrbook.edit_btn = edit_btn;
1309 addrbook.del_btn = del_btn;
1310 addrbook.reg_btn = reg_btn;
1311 addrbook.lup_btn = lup_btn;
1312 addrbook.to_btn = to_btn;
1313 addrbook.cc_btn = cc_btn;
1314 addrbook.bcc_btn = bcc_btn;
1316 addrbook.tree_popup = tree_popup;
1317 addrbook.list_popup = list_popup;
1318 addrbook.ui_manager = ui_manager;
1320 addrbook.listSelected = NULL;
1322 if (!geometry.min_height) {
1323 geometry.min_width = ADDRESSBOOK_WIDTH;
1324 geometry.min_height = ADDRESSBOOK_HEIGHT;
1327 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1329 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1330 prefs_common.addressbookwin_height);
1332 gtk_window_move(GTK_WINDOW(window), 48, 48);
1335 if (!prefs_common.addressbook_use_editaddress_dialog) {
1336 if (prefs_common.addressbook_vpaned_pos > 0)
1337 gtk_paned_set_position(GTK_PANED(vpaned),
1338 prefs_common.addressbook_vpaned_pos);
1340 if (prefs_common.addressbook_hpaned_pos > 0)
1341 gtk_paned_set_position(GTK_PANED(hpaned),
1342 prefs_common.addressbook_hpaned_pos);
1345 gtk_widget_show_all(window);
1349 * Close address book window and save to file(s).
1351 static gint addressbook_close( void ) {
1352 address_completion_end(addrbook.window);
1353 if (!prefs_common.addressbook_use_editaddress_dialog)
1354 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1356 addressbook_pane_save_position();
1358 gtk_widget_hide(addrbook.window);
1359 addressbook_export_to_file();
1364 * Display message in status line.
1365 * \param msg Message to display.
1367 static void addressbook_status_show( gchar *msg ) {
1368 if( addrbook.statusbar != NULL ) {
1370 GTK_STATUSBAR(addrbook.statusbar),
1371 addrbook.status_cid );
1374 GTK_STATUSBAR(addrbook.statusbar),
1375 addrbook.status_cid, msg );
1380 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1384 *addressbook_msgbuf = '\0';
1386 name = addrindex_ds_get_name( ds );
1387 retVal = addrindex_ds_get_status_code( ds );
1388 if( retVal == MGU_SUCCESS ) {
1389 g_snprintf( addressbook_msgbuf,
1390 sizeof(addressbook_msgbuf), "%s", name );
1393 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1394 g_snprintf( addressbook_msgbuf,
1395 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1398 addressbook_status_show( addressbook_msgbuf );
1401 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1403 addressbook_edit_address_cb(NULL, NULL);
1406 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1408 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1412 * Delete one or more objects from address list.
1414 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1416 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1417 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1418 AddressObject *pobj;
1419 AdapterDSource *ads = NULL;
1420 GtkCMCTreeNode *nodeList;
1423 AddressBookFile *abf = NULL;
1424 AddressDataSource *ds = NULL;
1425 AddressInterface *iface;
1426 AddrItemObject *aio;
1427 AddrSelectItem *item;
1429 gboolean refreshList = FALSE;
1431 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1432 cm_return_if_fail(pobj != NULL);
1434 /* Test whether anything selected for deletion */
1435 nodeList = addrbook.listSelected;
1437 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1438 if( aio == NULL) return;
1439 ds = addressbook_find_datasource( addrbook.treeSelected );
1440 if( ds == NULL ) return;
1442 /* Test for read only */
1443 iface = ds->interface;
1444 if( iface->readOnly ) {
1445 alertpanel( _("Delete address(es)"),
1446 _("This address data is readonly and cannot be deleted."),
1447 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST);
1451 /* Test whether Ok to proceed */
1453 if( pobj->type == ADDR_DATASOURCE ) {
1454 ads = ADAPTER_DSOURCE(pobj);
1455 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1457 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1460 else if( pobj->type == ADDR_ITEM_GROUP ) {
1463 if( ! procFlag ) return;
1464 abf = ds->rawDataSource;
1465 if( abf == NULL ) return;
1467 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1468 g_signal_handlers_block_by_func
1469 (G_OBJECT(addrbook.clist),
1470 G_CALLBACK(addressbook_list_row_unselected), NULL);
1472 /* Process deletions */
1473 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1474 GList *groups = NULL, *persons = NULL, *emails = NULL;
1475 gboolean group_delete = TRUE;
1476 /* Items inside folders */
1477 list = addrselect_get_list( _addressSelect_ );
1478 /* Confirm deletion */
1482 node = g_list_next( node );
1483 aio = ( AddrItemObject * ) item->addressItem;
1484 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1485 group_delete = FALSE;
1490 aval = alertpanel( _("Delete group"),
1491 _("Really delete the group(s)?\n"
1492 "The addresses it contains will not be lost."),
1493 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1494 if( aval != G_ALERTALTERNATE ) {
1498 aval = alertpanel( _("Delete address(es)"),
1499 _("Really delete the address(es)?"),
1500 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1501 if( aval != G_ALERTALTERNATE ) {
1506 /* first, set lists of groups and persons to remove */
1510 node = g_list_next( node );
1511 aio = ( AddrItemObject * ) item->addressItem;
1514 if( aio->type == ITEMTYPE_GROUP ) {
1515 groups = g_list_prepend(groups, item);
1517 else if( aio->type == ITEMTYPE_PERSON ) {
1518 persons = g_list_prepend(persons, item);
1521 /* then set list of emails to remove *if* they're not children of
1522 * persons to remove */
1526 node = g_list_next( node );
1527 aio = ( AddrItemObject * ) item->addressItem;
1530 if( aio->type == ITEMTYPE_EMAIL ) {
1531 ItemEMail *sitem = ( ItemEMail * ) aio;
1532 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1533 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1534 emails = g_list_prepend(emails, item);
1536 /* else, the email will be removed via the parent person */
1539 /* then delete groups */
1543 node = g_list_next( node );
1544 aio = ( AddrItemObject * ) item->addressItem;
1547 if( aio->type == ITEMTYPE_GROUP ) {
1548 ItemGroup *item = ( ItemGroup * ) aio;
1549 GtkCMCTreeNode *nd = NULL;
1550 nd = addressbook_find_group_node( addrbook.opened, item );
1551 item = addrbook_remove_group( abf, item );
1553 addritem_free_item_group( item );
1555 /* Remove group from parent node */
1556 gtk_cmctree_remove_node( ctree, nd );
1560 /* then delete persons */
1564 node = g_list_next( node );
1565 aio = ( AddrItemObject * ) item->addressItem;
1568 if( aio->type == ITEMTYPE_PERSON ) {
1569 ItemPerson *item = ( ItemPerson * ) aio;
1570 item->status = DELETE_ENTRY;
1571 addressbook_folder_remove_one_person( clist, item );
1572 if (pobj->type == ADDR_ITEM_FOLDER)
1573 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1574 item = addrbook_remove_person( abf, item );
1576 if (ds && ds->type == ADDR_IF_LDAP) {
1577 LdapServer *server = ds->rawDataSource;
1578 ldapsvr_set_modified(server, TRUE);
1579 ldapsvr_update_book(server, item);
1583 addritem_person_remove_picture(item);
1584 addritem_free_item_person( item );
1588 /* then delete emails */
1592 node = g_list_next( node );
1593 aio = ( AddrItemObject * ) item->addressItem;
1597 if( aio->type == ITEMTYPE_EMAIL ) {
1598 ItemEMail *sitem = ( ItemEMail * ) aio;
1599 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1600 sitem = addrbook_person_remove_email( abf, person, sitem );
1602 addrcache_remove_email(abf->addressCache, sitem);
1603 addritem_free_item_email( sitem );
1605 addressbook_folder_refresh_one_person( clist, person );
1608 g_list_free( groups );
1609 g_list_free( persons );
1610 g_list_free( emails );
1611 g_list_free( list );
1612 addressbook_list_select_clear();
1614 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1615 addressbook_set_clist(
1616 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1620 addrbook_set_dirty(abf, TRUE);
1621 addressbook_export_to_file();
1622 addressbook_list_menu_setup();
1625 else if( pobj->type == ADDR_ITEM_GROUP ) {
1626 /* Items inside groups */
1627 list = addrselect_get_list( _addressSelect_ );
1631 node = g_list_next( node );
1632 aio = ( AddrItemObject * ) item->addressItem;
1633 if( aio->type == ITEMTYPE_EMAIL ) {
1634 ItemEMail *item = ( ItemEMail * ) aio;
1635 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1636 item = addrbook_person_remove_email( abf, person, item );
1638 addritem_free_item_email( item );
1642 g_list_free( list );
1643 addressbook_list_select_clear();
1644 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1645 addressbook_set_clist(
1646 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1650 addrbook_set_dirty(abf, TRUE);
1651 addressbook_export_to_file();
1652 addressbook_list_menu_setup();
1656 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1657 gtk_cmctree_remove_node( clist, nodeList );
1659 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1660 g_signal_handlers_unblock_by_func
1661 (G_OBJECT(addrbook.clist),
1662 G_CALLBACK(addressbook_list_row_unselected), NULL);
1665 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1667 addressbook_new_address_cb( NULL, NULL );
1670 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1673 gchar *address = NULL;
1675 if( aio->type == ITEMTYPE_EMAIL ) {
1676 ItemPerson *person = NULL;
1677 ItemEMail *email = ( ItemEMail * ) aio;
1679 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1680 if( email->address ) {
1681 if( ADDRITEM_NAME(email) ) {
1682 name = ADDRITEM_NAME(email);
1683 if( *name == '\0' ) {
1684 name = ADDRITEM_NAME(person);
1687 else if( ADDRITEM_NAME(person) ) {
1688 name = ADDRITEM_NAME(person);
1691 buf = g_strdup( email->address );
1693 address = email->address;
1696 else if( aio->type == ITEMTYPE_PERSON ) {
1697 ItemPerson *person = ( ItemPerson * ) aio;
1698 GList *node = person->listEMail;
1700 name = ADDRITEM_NAME(person);
1702 ItemEMail *email = ( ItemEMail * ) node->data;
1703 address = email->address;
1707 if( name && name[0] != '\0' ) {
1708 if( strchr_with_skip_quote( name, '"', ',' ) )
1709 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1711 buf = g_strdup_printf( "%s <%s>", name, address );
1714 buf = g_strdup( address );
1721 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1725 AddrSelectItem *item;
1726 AddrItemObject *aio;
1729 compose = addrbook.target_compose;
1730 if( ! compose ) return;
1732 /* Nothing selected, but maybe there is something in text entry */
1733 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1735 compose_entry_append(
1736 compose, addr, (ComposeEntryType)data , PREF_NONE);
1739 /* Select from address list */
1740 list = addrselect_get_list( _addressSelect_ );
1745 node = g_list_next( node );
1746 aio = item->addressItem;
1747 if( aio->type == ITEMTYPE_PERSON ||
1748 aio->type == ITEMTYPE_EMAIL ) {
1749 addr = addressbook_format_address( aio );
1750 compose_entry_append(
1751 compose, addr, (ComposeEntryType) data, PREF_NONE );
1754 else if( aio->type == ITEMTYPE_GROUP ) {
1755 ItemGroup *group = ( ItemGroup * ) aio;
1756 GList *nodeMail = group->listEMail;
1758 ItemEMail *email = nodeMail->data;
1760 addr = addressbook_format_address(
1761 ( AddrItemObject * ) email );
1762 compose_entry_append(
1763 compose, addr, (ComposeEntryType) data, PREF_NONE );
1765 nodeMail = g_list_next( nodeMail );
1770 AddressObject *obj = NULL;
1772 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1774 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1775 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1776 GList *nodeMail = itemGroup->listEMail;
1778 ItemEMail *email = nodeMail->data;
1780 addr = addressbook_format_address(
1781 ( AddrItemObject * ) email );
1782 compose_entry_append(
1783 compose, addr, (ComposeEntryType) data, PREF_NONE );
1785 nodeMail = g_list_next( nodeMail );
1789 g_list_free( list );
1792 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1797 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/SelectAll", TRUE );
1798 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", sensitive );
1799 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", sensitive );
1800 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", sensitive );
1802 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", sensitive );
1803 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", sensitive );
1804 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", sensitive );
1805 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", sensitive );
1806 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1807 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1810 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1811 gboolean canEdit = FALSE;
1812 gboolean canDelete = TRUE;
1813 gboolean canAdd = FALSE;
1814 gboolean canEditTr = TRUE;
1815 gboolean editAddress = FALSE;
1816 gboolean canExport = TRUE;
1817 AddressTypeControlItem *atci = NULL;
1818 AddressDataSource *ds = NULL;
1819 AddressInterface *iface = NULL;
1821 if( obj == NULL ) return;
1822 if( obj->type == ADDR_INTERFACE ) {
1823 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1824 iface = adapter->interface;
1826 if( iface->haveLibrary ) {
1827 /* Enable appropriate File / New command */
1828 atci = adapter->atci;
1829 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1832 canEditTr = canExport = FALSE;
1834 else if( obj->type == ADDR_DATASOURCE ) {
1835 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1836 ds = ads->dataSource;
1837 iface = ds->interface;
1838 if( ! iface->readOnly ) {
1839 canAdd = canEdit = editAddress = canDelete = TRUE;
1841 if( ! iface->haveLibrary ) {
1842 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1845 else if( obj->type == ADDR_ITEM_FOLDER ) {
1846 ds = addressbook_find_datasource( addrbook.treeSelected );
1848 iface = ds->interface;
1849 if( iface->readOnly ) {
1854 canAdd = editAddress = TRUE;
1858 else if( obj->type == ADDR_ITEM_GROUP ) {
1859 ds = addressbook_find_datasource( addrbook.treeSelected );
1861 iface = ds->interface;
1862 if( ! iface->readOnly ) {
1868 if( addrbook.listSelected == NULL )
1872 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewAddress", editAddress );
1873 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/NewGroup", canAdd );
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1875 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1878 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
1879 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
1880 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1881 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1883 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1884 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1887 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1888 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1892 * Address book tree callback function that responds to selection of tree
1895 * \param ctree Tree widget.
1896 * \param node Node that was selected.
1897 * \param column Column number where selected occurred.
1898 * \param data Pointer to user data.
1900 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1901 gint column, gpointer data)
1903 AddressObject *obj = NULL;
1904 AdapterDSource *ads = NULL;
1905 AddressDataSource *ds = NULL;
1906 ItemFolder *rootFolder = NULL;
1907 AddressObjectType aot;
1909 addrbook.treeSelected = node;
1910 addrbook.listSelected = NULL;
1911 addressbook_status_show( "" );
1912 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1914 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1916 addressbook_set_clist(NULL, TRUE);
1919 addrbook.opened = node;
1921 if( obj->type == ADDR_DATASOURCE ) {
1922 /* Read from file */
1923 static gboolean tVal = TRUE;
1925 ads = ADAPTER_DSOURCE(obj);
1927 ds = ads->dataSource;
1928 if( ds == NULL ) return;
1930 if( addrindex_ds_get_modify_flag( ds ) ) {
1931 addrindex_ds_read_data( ds );
1934 if( ! addrindex_ds_get_read_flag( ds ) ) {
1935 addrindex_ds_read_data( ds );
1937 addressbook_ds_show_message( ds );
1939 if( ! addrindex_ds_get_access_flag( ds ) ) {
1940 /* Remove existing folders and groups */
1941 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1942 addressbook_tree_remove_children( ctree, node );
1943 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1945 /* Load folders into the tree */
1946 rootFolder = addrindex_ds_get_root_folder( ds );
1947 if( ds && ds->type == ADDR_IF_JPILOT ) {
1948 aot = ADDR_CATEGORY;
1950 else if( ds && ds->type == ADDR_IF_LDAP ) {
1951 aot = ADDR_LDAP_QUERY;
1954 aot = ADDR_ITEM_FOLDER;
1956 addressbook_node_add_folder( node, ds, rootFolder, aot );
1957 addrindex_ds_set_access_flag( ds, &tVal );
1958 gtk_cmctree_expand( ctree, node );
1961 addressbook_set_clist(NULL, TRUE);
1964 /* Update address list */
1965 g_signal_handlers_block_by_func
1967 G_CALLBACK(addressbook_tree_selected), NULL);
1968 addressbook_set_clist( obj, FALSE );
1969 g_signal_handlers_unblock_by_func
1971 G_CALLBACK(addressbook_tree_selected), NULL);
1972 if (!prefs_common.addressbook_use_editaddress_dialog)
1973 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1975 /* Setup main menu selections */
1976 addressbook_menubar_set_sensitive( FALSE );
1977 addressbook_menuitem_set_sensitive( obj, node );
1978 addressbook_list_select_clear();
1979 addressbook_list_menu_setup();
1984 * Setup address list popup menu items. Items are enabled or disabled as
1987 static void addressbook_list_menu_setup( void ) {
1988 GtkCMCTree *clist = NULL;
1989 AddressObject *pobj = NULL;
1990 AddressObject *obj = NULL;
1991 AdapterDSource *ads = NULL;
1992 AddressInterface *iface = NULL;
1993 AddressDataSource *ds = NULL;
1995 AddrItemObject *aio;
1996 AddrSelectItem *item;
1997 gboolean canEdit = FALSE;
1998 gboolean canDelete = FALSE;
1999 gboolean canCut = FALSE;
2000 gboolean canCopy = FALSE;
2001 gboolean canPaste = FALSE;
2002 gboolean canBrowse = FALSE;
2003 gboolean canMerge = FALSE;
2005 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2006 if( pobj == NULL ) return;
2008 clist = GTK_CMCTREE(addrbook.clist);
2009 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2010 if( obj == NULL ) canEdit = FALSE;
2012 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2013 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2015 if( pobj->type == ADDR_DATASOURCE ) {
2016 /* Parent object is a data source */
2017 ads = ADAPTER_DSOURCE(pobj);
2018 ds = ads->dataSource;
2021 iface = ds->interface;
2024 if( ! iface->readOnly ) {
2025 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2026 if (iface->type != ADDR_IF_LDAP)
2027 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2028 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2031 canDelete = canEdit;
2034 else if( pobj->type != ADDR_INTERFACE ) {
2035 /* Parent object is not an interface */
2036 ds = addressbook_find_datasource( addrbook.treeSelected );
2039 iface = ds->interface;
2042 if( ! iface->readOnly ) {
2043 /* Folder or group */
2044 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2045 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2046 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2047 if( obj ) canEdit = TRUE;
2050 if( pobj->type == ADDR_ITEM_FOLDER ) {
2051 if (iface->type != ADDR_IF_LDAP)
2052 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2053 if( obj ) canEdit = TRUE;
2055 canDelete = canEdit;
2057 if( iface->type == ADDR_IF_LDAP ) {
2058 if( obj ) canBrowse = TRUE;
2065 /* Enable cut and paste */
2066 if( ! addrclip_is_empty( _clipBoard_ ) )
2068 if( ! addrselect_test_empty( _addressSelect_ ) )
2070 /* Enable copy if something is selected */
2071 if( ! addrselect_test_empty( _addressSelect_ ) )
2075 /* Disable edit or browse if more than one row selected */
2076 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2081 /* Allow merging persons or emails are selected */
2082 list = _addressSelect_->listSelect;
2083 if (list && list->next ) {
2085 aio = ( AddrItemObject * ) item->addressItem;
2086 if( aio->type == ITEMTYPE_EMAIL ||
2087 aio->type == ITEMTYPE_PERSON ) {
2092 /* Forbid write changes when read-only */
2093 if( iface && iface->readOnly ) {
2100 /* Now go finalize menu items */
2101 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2104 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2105 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2106 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2108 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2109 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge", canMerge );
2111 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2112 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2113 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2115 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Edit", canEdit );
2116 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Delete", canDelete );
2117 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Mailto", canCopy );
2118 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Merge", canMerge );
2120 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2121 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2123 if (addrbook.target_compose) {
2124 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2125 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2126 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2129 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2133 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2134 GtkCMCTreeNode *node,
2141 * Add list of items into tree node below specified tree node.
2142 * \param treeNode Tree node.
2143 * \param ds Data source.
2144 * \param listItems List of items.
2146 static void addressbook_treenode_add_list(
2147 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2153 AddrItemObject *aio;
2157 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2160 group = ( ItemGroup * ) aio;
2161 nn = addressbook_node_add_group( treeNode, ds, group );
2163 g_message("error adding addressbook group\n");
2166 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2169 folder = ( ItemFolder * ) aio;
2170 nn = addressbook_node_add_folder(
2171 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2173 g_message("error adding addressbook folder\n");
2176 node = g_list_next( node );
2180 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2181 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2185 * Cut from address list widget.
2187 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2188 _clipBoard_->cutFlag = TRUE;
2189 addrclip_clear( _clipBoard_ );
2190 addrclip_add( _clipBoard_, _addressSelect_ );
2191 /* addrclip_list_show( _clipBoard_, stdout ); */
2195 * Copy from address list widget.
2197 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2198 _clipBoard_->cutFlag = FALSE;
2199 addrclip_clear( _clipBoard_ );
2200 addrclip_add( _clipBoard_, _addressSelect_ );
2201 /* addrclip_list_show( _clipBoard_, stdout ); */
2205 * Paste clipboard into address list widget.
2207 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2208 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2209 AddressObject *pobj = NULL;
2210 AddressDataSource *ds = NULL;
2211 AddressBookFile *abf = NULL;
2212 ItemFolder *folder = NULL;
2213 GList *folderGroup = NULL;
2215 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2216 if( ds == NULL ) return;
2217 if( addrindex_ds_get_readonly( ds ) ) {
2218 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2222 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2224 if( pobj->type == ADDR_ITEM_FOLDER ) {
2225 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2227 else if( pobj->type == ADDR_ITEM_GROUP ) {
2228 alertpanel_error( _("Cannot paste into an address group.") );
2233 /* Get an address book */
2234 abf = addressbook_get_book_file();
2235 if( abf == NULL ) return;
2237 if( _clipBoard_->cutFlag ) {
2239 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2241 /* Remove all groups and folders in clipboard from tree node */
2242 addressbook_treenode_remove_item();
2244 /* Remove all "cut" items */
2245 addrclip_delete_item( _clipBoard_ );
2247 /* Clear clipboard - cut items??? */
2248 addrclip_clear( _clipBoard_ );
2252 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2255 /* addrclip_list_show( _clipBoard_, stdout ); */
2257 /* Update tree by inserting node for each folder or group */
2258 addressbook_treenode_add_list(
2259 addrbook.treeSelected, ds, folderGroup );
2260 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2261 g_list_free( folderGroup );
2265 /* Display items pasted */
2266 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2267 addressbook_set_clist(
2268 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2276 * Add current treenode object to clipboard. Note that widget only allows
2277 * one entry from the tree list to be selected.
2279 static void addressbook_treenode_to_clipboard( void ) {
2280 AddressObject *obj = NULL;
2281 AddressDataSource *ds = NULL;
2282 AddrSelectItem *item;
2283 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2284 GtkCMCTreeNode *node;
2286 node = addrbook.treeSelected;
2287 if( node == NULL ) return;
2288 obj = gtk_cmctree_node_get_row_data( ctree, node );
2289 if( obj == NULL ) return;
2291 ds = addressbook_find_datasource( node );
2292 if( ds == NULL ) return;
2295 if( obj->type == ADDR_ITEM_FOLDER ) {
2296 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2297 ItemFolder *folder = adapter->itemFolder;
2299 item = addrselect_create_node( obj );
2300 item->uid = g_strdup( ADDRITEM_ID(folder) );
2302 else if( obj->type == ADDR_ITEM_GROUP ) {
2303 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2304 ItemGroup *group = adapter->itemGroup;
2306 item = addrselect_create_node( obj );
2307 item->uid = g_strdup( ADDRITEM_ID(group) );
2309 else if( obj->type == ADDR_DATASOURCE ) {
2311 item = addrselect_create_node( obj );
2316 /* Clear existing list and add item into list */
2319 addressbook_list_select_clear();
2320 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2321 addrselect_list_add( _addressSelect_, item, cacheID );
2327 * Cut from tree widget.
2329 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2330 _clipBoard_->cutFlag = TRUE;
2331 addressbook_treenode_to_clipboard();
2332 addrclip_clear( _clipBoard_ );
2333 addrclip_add( _clipBoard_, _addressSelect_ );
2334 /* addrclip_list_show( _clipBoard_, stdout ); */
2338 * Copy from tree widget.
2340 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2341 _clipBoard_->cutFlag = FALSE;
2342 addressbook_treenode_to_clipboard();
2343 addrclip_clear( _clipBoard_ );
2344 addrclip_add( _clipBoard_, _addressSelect_ );
2345 /* addrclip_list_show( _clipBoard_, stdout ); */
2349 * Paste clipboard into address tree widget.
2351 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2352 addressbook_clip_paste_cb(NULL,NULL);
2356 * Clear selected entries in clipboard.
2358 static void addressbook_list_select_clear( void ) {
2359 addrselect_list_clear( _addressSelect_ );
2363 * Add specified address item to selected address list.
2364 * \param aio Address item object.
2365 * \param ds Datasource.
2367 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2370 if( ds == NULL ) return;
2371 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2372 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2377 * Remove specified address item from selected address list.
2378 * \param aio Address item object.
2380 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2381 addrselect_list_remove( _addressSelect_, aio );
2385 * Invoke EMail compose window with addresses in selected address list.
2387 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2390 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2391 listAddress = addrselect_build_list( _addressSelect_ );
2392 compose_new_with_list( NULL, listAddress );
2393 g_list_free_full( listAddress, g_free );
2398 static void addressbook_merge_list( AddrSelectList *list ) {
2399 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2400 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2401 AddressObject *pobj;
2402 AddressDataSource *ds = NULL;
2404 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
2405 cm_return_if_fail(pobj != NULL);
2407 ds = addressbook_find_datasource( addrbook.treeSelected );
2408 if( ds == NULL ) return;
2410 addrmerge_merge(clist, pobj, ds, list);
2414 * Merge selected entries in the address list
2416 static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
2417 if( addrselect_test_empty( _addressSelect_ ) )
2420 addressbook_merge_list( _addressSelect_ );
2423 static void addressbook_list_row_selected( GtkCMCTree *clist,
2424 GtkCMCTreeNode *node,
2428 AddrItemObject *aio = NULL;
2429 AddressObject *pobj = NULL;
2430 AdapterDSource *ads = NULL;
2431 AddressDataSource *ds = NULL;
2433 addrbook.listSelected = node;
2435 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2436 if( pobj == NULL ) return;
2438 if( pobj->type == ADDR_DATASOURCE ) {
2439 ads = ADAPTER_DSOURCE(pobj);
2440 ds = ads->dataSource;
2442 else if( pobj->type != ADDR_INTERFACE ) {
2443 ds = addressbook_find_datasource( addrbook.treeSelected );
2446 aio = gtk_cmctree_node_get_row_data( clist, node );
2448 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2449 addressbook_list_select_add( aio, ds );
2452 addressbook_list_menu_setup();
2454 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2455 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2457 if (obj && obj->type != ADDR_ITEM_GROUP)
2458 addressbook_edit_address(NULL, 0, NULL, FALSE);
2462 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2463 GtkCMCTreeNode *node,
2467 AddrItemObject *aio;
2469 aio = gtk_cmctree_node_get_row_data( ctree, node );
2471 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2472 addressbook_list_select_remove( aio );
2475 if (!prefs_common.addressbook_use_editaddress_dialog)
2476 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2479 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2481 addressbook_lup_clicked(NULL, NULL);
2484 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2485 GdkEventButton *event,
2488 if( ! event ) return FALSE;
2489 if( event->window != GTK_CMCLIST(widget)->clist_window ) return FALSE;
2491 addressbook_list_menu_setup();
2493 if( event->button == 3 ) {
2494 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2495 event->button, event->time );
2496 } else if (event->button == 1) {
2497 if (event->type == GDK_2BUTTON_PRESS) {
2498 if (prefs_common.add_address_by_click &&
2499 addrbook.target_compose)
2500 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2502 if (prefs_common.addressbook_use_editaddress_dialog)
2503 addressbook_edit_address_cb(NULL, NULL);
2505 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2506 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2507 if( obj && obj->type == ADDR_ITEM_GROUP )
2508 addressbook_edit_address_cb(NULL, NULL);
2516 static gboolean addressbook_list_button_released(GtkWidget *widget,
2517 GdkEventButton *event,
2523 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2524 GdkEventButton *event,
2527 GtkCMCList *clist = GTK_CMCLIST(ctree);
2529 AddressObject *obj = NULL;
2530 AdapterDSource *ads = NULL;
2531 AddressInterface *iface = NULL;
2532 AddressDataSource *ds = NULL;
2533 gboolean canEdit = FALSE;
2534 gboolean canDelete = FALSE;
2535 gboolean canCut = FALSE;
2536 gboolean canCopy = FALSE;
2537 gboolean canPaste = FALSE;
2538 gboolean canTreeCut = FALSE;
2539 gboolean canTreeCopy = FALSE;
2540 gboolean canTreePaste = FALSE;
2541 gboolean canLookup = FALSE;
2542 GtkCMCTreeNode *node = NULL;
2544 if( ! event ) return FALSE;
2545 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2547 if( event->window != clist->clist_window )
2550 if (event->button == 1) {
2551 if (event->type == GDK_2BUTTON_PRESS) {
2552 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2553 gtkut_clist_set_focus_row(clist, row);
2554 obj = gtk_cmclist_get_row_data( clist, row );
2559 if (obj->type == ADDR_ITEM_GROUP ||
2560 obj->type == ADDR_DATASOURCE) {
2562 addressbook_treenode_edit_cb(NULL, NULL);
2564 /* expand pr collapse */
2565 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2566 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2572 addressbook_menubar_set_sensitive( FALSE );
2574 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2575 gtkut_clist_set_focus_row(clist, row);
2576 obj = gtk_cmclist_get_row_data( clist, row );
2579 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2583 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2585 if( ! addrclip_is_empty( _clipBoard_ ) )
2586 canTreePaste = TRUE;
2588 if (obj->type == ADDR_INTERFACE) {
2589 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2590 iface = adapter->interface;
2593 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2594 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2596 if( iface->externalQuery )
2599 if (obj->type == ADDR_DATASOURCE) {
2601 ads = ADAPTER_DSOURCE(obj);
2602 ds = ads->dataSource;
2605 iface = ds->interface;
2608 if( !iface->readOnly ) {
2609 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2610 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2611 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2617 else if (obj->type == ADDR_ITEM_FOLDER) {
2619 ds = addressbook_find_datasource( node );
2622 iface = ds->interface;
2625 if( !iface->readOnly ) {
2629 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2630 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2631 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2635 if( iface->externalQuery ) {
2636 /* Enable deletion of LDAP folder */
2640 else if (obj->type == ADDR_ITEM_GROUP) {
2642 ds = addressbook_find_datasource( node );
2645 iface = ds->interface;
2648 if( ! iface->readOnly ) {
2651 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2652 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2656 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2658 if( ! addrselect_test_empty( _addressSelect_ ) )
2660 if( ! addrclip_is_empty( _clipBoard_ ) )
2663 /* Forbid write changes when read-only */
2664 if( iface && iface->readOnly ) {
2666 canTreePaste = FALSE;
2673 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2674 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2675 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2676 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2677 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2679 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2680 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2681 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", canCut );
2682 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", canCopy );
2683 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", canPaste );
2685 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2686 addrbook.target_compose != NULL);
2688 if( event->button == 3 )
2689 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2690 event->button, event->time);
2695 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2696 GdkEventButton *event,
2699 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2703 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2705 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2706 AddressObject *obj = NULL;
2707 AddressDataSource *ds = NULL;
2708 AddressBookFile *abf = NULL;
2709 ItemFolder *parentFolder = NULL;
2710 ItemFolder *folder = NULL;
2712 if( ! addrbook.treeSelected ) return;
2713 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2714 if( obj == NULL ) return;
2715 ds = addressbook_find_datasource( addrbook.treeSelected );
2716 if( ds == NULL ) return;
2718 if( obj->type == ADDR_DATASOURCE ) {
2719 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2721 else if( obj->type == ADDR_ITEM_FOLDER ) {
2722 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2728 abf = ds->rawDataSource;
2729 if( abf == NULL ) return;
2730 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2733 nn = addressbook_node_add_folder(
2734 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2736 g_message("error adding addressbook folder\n");
2738 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2739 if( addrbook.treeSelected == addrbook.opened )
2740 addressbook_set_clist(obj, TRUE);
2744 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2746 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2747 AddressObject *obj = NULL;
2748 AddressDataSource *ds = NULL;
2749 AddressBookFile *abf = NULL;
2750 ItemFolder *parentFolder = NULL;
2751 ItemGroup *group = NULL;
2753 if( ! addrbook.treeSelected ) return;
2754 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2755 if( obj == NULL ) return;
2756 ds = addressbook_find_datasource( addrbook.treeSelected );
2757 if( ds == NULL ) return;
2759 if( obj->type == ADDR_DATASOURCE ) {
2760 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2762 else if( obj->type == ADDR_ITEM_FOLDER ) {
2763 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2769 abf = ds->rawDataSource;
2770 if( abf == NULL ) return;
2771 group = addressbook_edit_group( abf, parentFolder, NULL );
2774 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2776 g_message("error adding addressbook group\n");
2778 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2779 if( addrbook.treeSelected == addrbook.opened )
2780 addressbook_set_clist(obj, TRUE);
2784 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2786 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2789 GdkPixbuf *pix_cl, *pix_op;
2790 gboolean is_leaf, expanded;
2792 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2794 &is_leaf, &expanded);
2795 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2802 * \param obj Address object to edit.
2803 * \param node Node in tree.
2804 * \return New name of data source.
2806 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2807 gchar *newName = NULL;
2808 AddressDataSource *ds = NULL;
2809 AddressInterface *iface = NULL;
2810 AdapterDSource *ads = NULL;
2812 ds = addressbook_find_datasource( node );
2813 if( ds == NULL ) return NULL;
2814 iface = ds->interface;
2815 if( ! iface->haveLibrary ) return NULL;
2817 /* Read data from data source */
2818 if( addrindex_ds_get_modify_flag( ds ) ) {
2819 addrindex_ds_read_data( ds );
2822 if( ! addrindex_ds_get_read_flag( ds ) ) {
2823 addrindex_ds_read_data( ds );
2827 ads = ADAPTER_DSOURCE(obj);
2828 if( ads->subType == ADDR_BOOK ) {
2829 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2831 else if( ads->subType == ADDR_VCARD ) {
2832 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2835 else if( ads->subType == ADDR_JPILOT ) {
2836 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2840 else if( ads->subType == ADDR_LDAP ) {
2841 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2847 newName = obj->name;
2852 * Edit an object that is in the address tree area.
2854 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2856 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2858 AddressDataSource *ds = NULL;
2859 AddressBookFile *abf = NULL;
2860 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2863 if( ! addrbook.treeSelected ) return;
2864 node = addrbook.treeSelected;
2865 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2866 obj = gtk_cmctree_node_get_row_data( ctree, node );
2867 if( obj == NULL ) return;
2868 parentNode = GTK_CMCTREE_ROW(node)->parent;
2870 ds = addressbook_find_datasource( node );
2871 if( ds == NULL ) return;
2873 if( obj->type == ADDR_DATASOURCE ) {
2874 name = addressbook_edit_datasource( obj, node );
2875 if( name == NULL ) return;
2878 abf = ds->rawDataSource;
2879 if( abf == NULL ) return;
2880 if( obj->type == ADDR_ITEM_FOLDER ) {
2881 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2882 ItemFolder *item = adapter->itemFolder;
2883 ItemFolder *parentFolder = NULL;
2884 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2885 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2886 name = ADDRITEM_NAME(item);
2888 else if( obj->type == ADDR_ITEM_GROUP ) {
2889 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2890 ItemGroup *item = adapter->itemGroup;
2891 ItemFolder *parentFolder = NULL;
2892 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2893 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2894 name = ADDRITEM_NAME(item);
2897 if( name && parentNode ) {
2898 /* Update node in tree view */
2899 addressbook_change_node_name( node, name );
2900 gtk_sctree_sort_node(ctree, parentNode);
2901 gtk_cmctree_expand( ctree, node );
2902 gtk_sctree_select( GTK_SCTREE( ctree), node );
2909 ADDRTREE_DEL_FOLDER_ONLY,
2910 ADDRTREE_DEL_FOLDER_ADDR
2914 * Delete an item from the tree widget.
2915 * \param data Data passed in.
2916 * \param action Action.
2917 * \param widget Widget issuing callback.
2919 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2921 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2922 GtkCMCTreeNode *node = NULL;
2926 AddrBookBase *adbase;
2927 AddressCache *cache;
2928 AdapterDSource *ads = NULL;
2929 AddressInterface *iface = NULL;
2930 AddressDataSource *ds = NULL;
2931 gboolean remFlag = FALSE;
2932 TreeItemDelType delType;
2934 if( ! addrbook.treeSelected ) return;
2935 node = addrbook.treeSelected;
2936 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2938 obj = gtk_cmctree_node_get_row_data( ctree, node );
2939 cm_return_if_fail(obj != NULL);
2941 if( obj->type == ADDR_DATASOURCE ) {
2942 ads = ADAPTER_DSOURCE(obj);
2944 ds = ads->dataSource;
2945 if( ds == NULL ) return;
2948 /* Must be folder or something else */
2949 ds = addressbook_find_datasource( node );
2950 if( ds == NULL ) return;
2952 /* Only allow deletion from non-readOnly */
2953 iface = ds->interface;
2954 if( iface->readOnly ) {
2955 /* Allow deletion of query results */
2956 if( ! iface->externalQuery ) return;
2960 /* Confirm deletion */
2961 delType = ADDRTREE_DEL_NONE;
2962 if( obj->type == ADDR_ITEM_FOLDER ) {
2963 if( iface && iface->externalQuery ) {
2964 message = g_strdup_printf( _(
2965 "Do you want to delete the query " \
2966 "results and addresses in '%s'?" ),
2968 aval = alertpanel( _("Delete"), message,
2969 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
2971 if( aval == G_ALERTALTERNATE ) {
2972 delType = ADDRTREE_DEL_FOLDER_ADDR;
2976 message = g_strdup_printf
2977 ( _( "Do you want to delete '%s'? "
2978 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2980 aval = alertpanel( _("Delete folder"), message,
2981 GTK_STOCK_CANCEL, _("Delete _folder only"), _("Delete folder and _addresses"), ALERTFOCUS_SECOND);
2983 if( aval == G_ALERTALTERNATE ) {
2984 delType = ADDRTREE_DEL_FOLDER_ONLY;
2986 else if( aval == G_ALERTOTHER ) {
2987 delType = ADDRTREE_DEL_FOLDER_ADDR;
2991 else if( obj->type == ADDR_ITEM_GROUP ) {
2992 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2993 "The addresses it contains will not be lost."), obj->name);
2994 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2995 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2997 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2999 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
3000 "The addresses it contains will be lost."), obj->name);
3001 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
3002 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
3004 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
3006 if( delType == ADDRTREE_DEL_NONE ) return;
3008 /* Proceed with deletion */
3009 if( obj->type == ADDR_DATASOURCE ) {
3010 /* Remove node from tree */
3011 gtk_cmctree_remove_node( ctree, node );
3013 if (delType == ADDRTREE_DEL_DATA &&
3014 ds->interface && ds->interface->type == ADDR_IF_BOOK)
3015 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
3017 /* Remove data source. */
3018 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3019 addrindex_free_datasource( ds );
3024 /* Get reference to cache */
3025 adbase = ( AddrBookBase * ) ds->rawDataSource;
3026 if( adbase == NULL ) return;
3027 cache = adbase->addressCache;
3029 /* Remove query results folder */
3030 if( iface && iface->externalQuery ) {
3031 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3032 ItemFolder *folder = adapter->itemFolder;
3034 adapter->itemFolder = NULL;
3036 g_print( "remove folder for ::%s::\n", obj->name );
3037 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3038 g_print( "-------------- remove results\n" );
3040 addrindex_remove_results( ds, folder );
3041 /* g_print( "-------------- remove node\n" ); */
3042 gtk_cmctree_remove_node( ctree, node );
3046 /* Code below is valid for regular address book deletion */
3047 if( obj->type == ADDR_ITEM_FOLDER ) {
3048 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3049 ItemFolder *item = adapter->itemFolder;
3051 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3052 /* Remove folder only */
3053 item = addrcache_remove_folder( cache, item );
3055 addritem_free_item_folder( item );
3056 addressbook_move_nodes_up( ctree, node );
3060 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3061 /* Remove folder and addresses */
3062 item = addrcache_remove_folder_delete( cache, item );
3064 addritem_free_item_folder( item );
3069 else if( obj->type == ADDR_ITEM_GROUP ) {
3070 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3071 ItemGroup *item = adapter->itemGroup;
3073 item = addrcache_remove_group( cache, item );
3075 addritem_free_item_group( item );
3082 gtk_cmctree_remove_node(ctree, node );
3086 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3088 if( person && addrbook.treeSelected == addrbook.opened ) {
3089 person->status = ADD_ENTRY;
3090 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3091 addressbook_folder_refresh_one_person(
3092 GTK_CMCTREE(addrbook.clist), person );
3094 addressbook_address_list_set_focus();
3097 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3099 if( person && addrbook.treeSelected == addrbook.opened) {
3100 person->status = ADD_ENTRY;
3101 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3102 addressbook_set_clist(
3103 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3107 addressbook_address_list_set_focus();
3111 * Label (a format string) that is used to name each folder.
3113 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3116 * Search ctree widget callback function.
3117 * \param pA Pointer to node.
3118 * \param pB Pointer to data item being sought.
3119 * \return Zero (0) if folder found.
3121 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3124 aoA = ( AddressObject * ) pA;
3125 if( aoA->type == ADDR_ITEM_FOLDER ) {
3126 ItemFolder *folder, *fld;
3128 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3129 folder = ( ItemFolder * ) pB;
3130 if( fld == folder ) return 0; /* Found folder */
3135 static ItemFolder * addressbook_setup_subf(
3136 AddressDataSource *ds, gchar *title,
3137 GtkCMCTreeNode *pNode )
3139 AddrBookBase *adbase;
3140 AddressCache *cache;
3143 GtkCMCTreeNode *nNode;
3145 AddressObjectType aoType = ADDR_NONE;
3148 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3150 if( ds && ds->type == ADDR_IF_LDAP ) {
3152 aoType = ADDR_LDAP_QUERY;
3159 ctree = GTK_CMCTREE(addrbook.ctree);
3160 /* Get reference to address cache */
3161 adbase = ( AddrBookBase * ) ds->rawDataSource;
3162 cache = adbase->addressCache;
3164 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3165 GList *cur = children;
3166 for (; cur; cur = cur->next) {
3167 ItemFolder *child = (ItemFolder *) cur->data;
3168 if (!g_strcmp0(ADDRITEM_NAME(child), title)) {
3169 nNode = gtk_cmctree_find_by_row_data_custom(
3171 addressbook_treenode_find_folder_cb );
3173 addrindex_remove_results( ds, child );
3174 while( child->listPerson ) {
3175 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3176 item = addrcache_remove_person( cache, item );
3178 addritem_free_item_person( item );
3182 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3183 addrbook.treeSelected = nNode;
3190 /* Create a folder */
3191 folder = addrcache_add_new_folder( cache, NULL );
3192 name = g_strdup_printf( "%s", title );
3193 addritem_folder_set_name( folder, name );
3194 addritem_folder_set_remarks( folder, "" );
3197 /* Now let's see the folder */
3198 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3199 gtk_cmctree_expand( ctree, pNode );
3201 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3202 addrbook.treeSelected = nNode;
3208 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3209 AddressObject *pobj = NULL;
3210 AddressDataSource *ds = NULL;
3211 AddressBookFile *abf = NULL;
3212 debug_print("adding address\n");
3213 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3214 if( pobj == NULL ) {
3215 debug_print("no row data\n");
3218 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3220 debug_print("no datasource\n");
3224 abf = ds->rawDataSource;
3226 g_print("no addressbook file\n");
3230 if( pobj->type == ADDR_DATASOURCE ) {
3231 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3232 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3234 ItemFolder *folder = NULL;
3236 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3237 GtkCMCTreeNode *parentNode;
3238 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3239 if( ds == NULL ) return;
3241 /* We must have a datasource that is an external interface */
3242 if( ! ds->interface->haveLibrary ) return;
3243 if( ! ds->interface->externalQuery ) return;
3245 if( pobj->type == ADDR_ITEM_FOLDER ) {
3246 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3249 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3251 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3253 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3255 abf = ds->rawDataSource;
3258 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3259 addrbook.editaddress_vbox,
3260 addressbook_new_address_from_book_post_cb,
3263 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3264 LdapServer *server = ds->rawDataSource;
3265 ldapsvr_set_modified(server, TRUE);
3266 ldapsvr_update_book(server, NULL);
3267 if (server->retVal != LDAPRC_SUCCESS) {
3268 alertpanel( _("Add address(es)"),
3269 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3270 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3271 server->retVal = LDAPRC_SUCCESS;
3276 if (prefs_common.addressbook_use_editaddress_dialog)
3277 addressbook_new_address_from_book_post_cb( person );
3280 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3282 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3285 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3286 GtkCMCTreeNode *parentNode;
3287 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3288 if( ds == NULL ) return;
3290 /* We must have a datasource that is an external interface */
3291 if( ! ds->interface->haveLibrary ) return;
3292 if( ! ds->interface->externalQuery ) return;
3294 if( pobj->type == ADDR_ITEM_FOLDER ) {
3295 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3298 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3300 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3304 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3306 abf = ds->rawDataSource;
3309 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3310 addrbook.editaddress_vbox,
3311 addressbook_new_address_from_folder_post_cb,
3314 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3315 LdapServer *server = ds->rawDataSource;
3316 ldapsvr_set_modified(server, TRUE);
3317 ldapsvr_update_book(server, NULL);
3318 if (server->retVal != LDAPRC_SUCCESS) {
3319 alertpanel( _("Add address(es)"),
3320 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3321 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3326 if (prefs_common.addressbook_use_editaddress_dialog)
3327 addressbook_new_address_from_folder_post_cb( person );
3329 else if( pobj->type == ADDR_ITEM_GROUP ) {
3330 /* New address in group */
3331 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3332 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3333 if (addrbook.treeSelected == addrbook.opened) {
3334 /* Change node name in tree. */
3335 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3336 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3337 addressbook_set_clist(
3338 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3346 * Search for specified child group node in address index tree.
3347 * \param parent Parent node.
3348 * \param group Group to find.
3350 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3351 GtkCMCTreeNode *node = NULL;
3352 GtkCMCTreeRow *currRow;
3354 currRow = GTK_CMCTREE_ROW( parent );
3356 node = currRow->children;
3360 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3361 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3362 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3363 if( g == group ) return node;
3365 currRow = GTK_CMCTREE_ROW(node);
3366 node = currRow->sibling;
3372 static AddressBookFile *addressbook_get_book_file() {
3373 AddressBookFile *abf = NULL;
3374 AddressDataSource *ds = NULL;
3376 ds = addressbook_find_datasource( addrbook.treeSelected );
3377 if( ds == NULL ) return NULL;
3378 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3382 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3383 GtkCMCTreeNode *node;
3386 /* Remove existing folders and groups */
3387 row = GTK_CMCTREE_ROW( parent );
3389 while( (node = row->children) ) {
3390 gtk_cmctree_remove_node( ctree, node );
3395 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3396 GtkCMCTreeNode *parent, *child;
3397 GtkCMCTreeRow *currRow;
3398 currRow = GTK_CMCTREE_ROW( node );
3400 parent = currRow->parent;
3401 while( (child = currRow->children) ) {
3402 gtk_cmctree_move( ctree, child, parent, node );
3404 gtk_sctree_sort_node( ctree, parent );
3408 static void addressbook_edit_address_post_cb( ItemPerson *person )
3412 AddressBookFile *abf = addressbook_get_book_file();
3414 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3415 if (g_strcmp0(person->nickName, ADDRITEM_NAME(person)))
3416 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3419 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3420 invalidate_address_completion();
3422 addressbook_address_list_set_focus();
3425 void addressbook_address_list_set_focus( void )
3427 if (!prefs_common.addressbook_use_editaddress_dialog) {
3428 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3429 addressbook_list_menu_setup();
3433 void addressbook_address_list_disable_some_actions(void)
3435 /* disable address copy/pasting when editing contact's detail (embedded form) */
3436 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Cut", FALSE );
3437 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Copy", FALSE );
3438 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Edit/Paste", FALSE );
3441 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3442 addressbook_edit_address(data, 0, NULL, TRUE);
3445 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3446 gboolean force_focus ) {
3447 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3449 AddressObject *obj = NULL, *pobj = NULL;
3450 AddressDataSource *ds = NULL;
3451 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3453 AddressBookFile *abf = NULL;
3455 if( addrbook.listSelected == NULL ) return;
3456 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3457 cm_return_if_fail(obj != NULL);
3459 ctree = GTK_CMCTREE( addrbook.ctree );
3460 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3462 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3463 if( ds == NULL ) return;
3465 abf = addressbook_get_book_file();
3467 if( obj->type == ADDR_ITEM_EMAIL ) {
3468 ItemEMail *email = ( ItemEMail * ) obj;
3470 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3471 /* Edit parent group */
3472 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3473 ItemGroup *itemGrp = adapter->itemGroup;
3474 if( abf == NULL ) return;
3475 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3476 name = ADDRITEM_NAME(itemGrp);
3477 node = addrbook.treeSelected;
3478 parentNode = GTK_CMCTREE_ROW(node)->parent;
3481 /* Edit person - email page */
3483 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3484 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3485 addressbook_edit_address_post_cb,
3486 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3489 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3490 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3491 person->status = UPDATE_ENTRY;
3494 if (prefs_common.addressbook_use_editaddress_dialog)
3495 addressbook_edit_address_post_cb( person );
3500 else if( obj->type == ADDR_ITEM_PERSON ) {
3501 /* Edit person - basic page */
3502 ItemPerson *person = ( ItemPerson * ) obj;
3503 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3504 addressbook_edit_address_post_cb,
3505 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3508 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3509 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3510 person->status = UPDATE_ENTRY;
3513 if (prefs_common.addressbook_use_editaddress_dialog)
3514 addressbook_edit_address_post_cb( person );
3518 else if( obj->type == ADDR_ITEM_GROUP ) {
3519 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3520 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3521 parentNode = addrbook.treeSelected;
3522 node = addressbook_find_group_node( parentNode, itemGrp );
3523 name = ADDRITEM_NAME(itemGrp);
3524 invalidate_address_completion();
3530 /* Update tree node with node name */
3531 if( node == NULL ) return;
3532 addressbook_change_node_name( node, name );
3533 gtk_sctree_sort_node( ctree, parentNode );
3534 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3535 addressbook_set_clist(
3536 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3541 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3543 addressbook_del_clicked(NULL, NULL);
3546 static void close_cb(GtkAction *action, gpointer data)
3548 addressbook_close();
3551 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3552 addressbook_export_to_file();
3555 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3557 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3558 if( person ) addritem_person_set_opened( person, TRUE );
3562 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3564 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3565 if( person ) addritem_person_set_opened( person, FALSE );
3569 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3571 gchar *eMailAlias = ADDRITEM_NAME(email);
3572 if( eMailAlias && *eMailAlias != '\0' ) {
3574 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3577 str = g_strdup( eMailAlias );
3583 static gboolean addressbook_match_item(const gchar *name,
3584 const gchar *email_alias,
3586 const gchar *remarks,
3591 if (!str || str[0] == '\0')
3593 if (strcasestr(name, str))
3595 else if (email_alias && strcasestr(email_alias, str))
3597 else if (addr && strcasestr(addr, str))
3599 else if (remarks && strcasestr(remarks, str))
3605 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3606 GList *items = itemGroup->listEMail;
3607 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3608 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3609 for( ; items != NULL; items = g_list_next( items ) ) {
3610 GtkCMCTreeNode *nodeEMail = NULL;
3611 gchar *text[N_LIST_COLS];
3612 ItemEMail *email = items->data;
3616 if( ! email ) continue;
3618 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3620 if( !addressbook_match_item(ADDRITEM_NAME(person),
3621 ADDRITEM_NAME(email),
3622 email->address, email->remarks,
3626 str = addressbook_format_item_clist( person, email );
3628 text[COL_NAME] = addressbook_set_col_name_guard(str);
3631 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3633 text[COL_ADDRESS] = email->address;
3634 text[COL_REMARKS] = email->remarks;
3635 nodeEMail = gtk_sctree_insert_node(
3637 text, FOLDER_SPACING,
3641 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3647 gchar *addressbook_set_col_name_guard(gchar *value)
3649 gchar *ret = "<not set>";
3650 gchar *tmp = g_strdup(value);
3652 if (tmp !=NULL && *tmp != '\0')
3658 static void addressbook_folder_load_one_person(
3659 GtkCMCTree *clist, ItemPerson *person,
3660 AddressTypeControlItem *atci,
3661 AddressTypeControlItem *atciMail )
3663 GtkCMCTreeNode *nodePerson = NULL;
3664 GtkCMCTreeNode *nodeEMail = NULL;
3665 gchar *text[N_LIST_COLS];
3666 gboolean flgFirst = TRUE, haveAddr = FALSE;
3669 AddressBookFile *abf = addressbook_get_book_file();
3672 if( person == NULL ) return;
3674 text[COL_NAME] = "";
3675 node = person->listEMail;
3677 ItemEMail *email = node->data;
3678 gchar *eMailAddr = NULL;
3679 node = g_list_next( node );
3681 text[COL_ADDRESS] = email->address;
3682 text[COL_REMARKS] = email->remarks;
3683 eMailAddr = ADDRITEM_NAME(email);
3684 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3686 /* First email belongs with person */
3687 gchar *str = addressbook_format_item_clist( person, email );
3689 text[COL_NAME] = addressbook_set_col_name_guard(str);
3692 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3693 person && person->nickName ) {
3694 if (person->nickName) {
3695 if (strcmp(person->nickName, "") != 0) {
3696 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3699 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3705 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3707 nodePerson = gtk_sctree_insert_node(
3709 text, FOLDER_SPACING,
3712 FALSE, person->isOpened );
3715 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3718 /* Subsequent email is a child node of person */
3719 text[COL_NAME] = ADDRITEM_NAME(email);
3720 nodeEMail = gtk_sctree_insert_node(
3721 clist, nodePerson, NULL,
3722 text, FOLDER_SPACING,
3724 atciMail->iconXpmOpen,
3726 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3732 /* Have name without EMail */
3733 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3734 text[COL_ADDRESS] = "";
3735 text[COL_REMARKS] = "";
3736 nodePerson = gtk_sctree_insert_node(
3738 text, FOLDER_SPACING,
3741 FALSE, person->isOpened );
3742 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3747 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3749 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3750 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3751 const gchar *search_str;
3753 if( atci == NULL ) return;
3754 if( atciMail == NULL ) return;
3756 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3758 /* Load email addresses */
3759 items = addritem_folder_get_person_list( itemFolder );
3760 for(cur = items ; cur != NULL; cur = g_list_next( cur ) ) {
3765 person = (ItemPerson *)cur->data;
3768 node = person->listEMail;
3769 if (node && node->data) {
3771 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3774 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3778 addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
3780 /* Free up the list */
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 g_list_free( items );
3862 * Search ctree widget callback function.
3863 * \param pA Pointer to node.
3864 * \param pB Pointer to data item being sought.
3865 * \return Zero (0) if group found.
3867 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3870 aoA = ( AddressObject * ) pA;
3871 if( aoA->type == ADDR_ITEM_GROUP ) {
3872 ItemGroup *group, *grp;
3874 grp = ADAPTER_GROUP(aoA)->itemGroup;
3875 group = ( ItemGroup * ) pB;
3876 if( grp == group ) return 0; /* Found group */
3882 * Remove folder and group nodes from tree widget for items contained ("cut")
3885 static void addressbook_treenode_remove_item( void ) {
3887 AddrSelectItem *cutItem;
3888 AddressCache *cache;
3889 AddrItemObject *aio;
3890 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3893 node = _clipBoard_->objectList;
3895 cutItem = node->data;
3896 node = g_list_next( node );
3897 cache = addrindex_get_cache(
3898 _clipBoard_->addressIndex, cutItem->cacheID );
3899 if( cache == NULL ) continue;
3900 aio = addrcache_get_object( cache, cutItem->uid );
3903 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3906 folder = ( ItemFolder * ) aio;
3907 tn = gtk_cmctree_find_by_row_data_custom(
3908 ctree, NULL, folder,
3909 addressbook_treenode_find_folder_cb );
3911 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3914 group = ( ItemGroup * ) aio;
3915 tn = gtk_cmctree_find_by_row_data_custom(
3917 addressbook_treenode_find_group_cb );
3921 /* Free up adapter and remove node. */
3922 gtk_cmctree_remove_node( ctree, tn );
3929 * Find parent datasource for specified tree node.
3930 * \param node Node to test.
3931 * \return Data source, or NULL if not found.
3933 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3934 AddressDataSource *ds = NULL;
3937 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3940 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3941 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3943 /* g_print( "ao->type = %d\n", ao->type ); */
3944 if( ao->type == ADDR_DATASOURCE ) {
3945 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3946 /* g_print( "found it\n" ); */
3947 ds = ads->dataSource;
3951 node = GTK_CMCTREE_ROW(node)->parent;
3957 * Load address list widget with children of specified object.
3958 * \param obj Parent object to be loaded.
3960 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3961 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3962 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3963 AddressDataSource *ds = NULL;
3964 AdapterDSource *ads = NULL;
3965 static AddressObject *last_obj = NULL;
3967 if (addrbook.clist == NULL) {
3970 if (obj == last_obj && !refresh)
3975 gtk_cmclist_clear(clist);
3979 if( obj->type == ADDR_INTERFACE ) {
3980 /* g_print( "set_clist: loading datasource...\n" ); */
3981 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3985 gtk_cmclist_freeze(clist);
3986 gtk_cmclist_clear(clist);
3988 if( obj->type == ADDR_DATASOURCE ) {
3989 ads = ADAPTER_DSOURCE(obj);
3990 ds = ads->dataSource;
3992 /* Load root folder */
3993 ItemFolder *rootFolder = NULL;
3994 rootFolder = addrindex_ds_get_root_folder( ds );
3995 addressbook_folder_load_person(
3996 ctreelist, rootFolder );
3997 addressbook_folder_load_group(
3998 ctreelist, rootFolder );
4002 if( obj->type == ADDR_ITEM_GROUP ) {
4004 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
4005 addressbook_load_group( ctreelist, itemGroup );
4007 else if( obj->type == ADDR_ITEM_FOLDER ) {
4009 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
4010 addressbook_folder_load_person( ctreelist, itemFolder );
4011 addressbook_folder_load_group( ctreelist, itemFolder );
4014 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
4015 clist->focus_row = -1;
4016 gtk_cmclist_thaw(clist);
4020 * Call back function to free adaptor. Call back is setup by function
4021 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4022 * called when the address book tree widget node is removed by calling
4023 * function gtk_cmctree_remove_node().
4025 * \param data Tree node's row data.
4027 static void addressbook_free_treenode( gpointer data ) {
4030 ao = ( AddressObject * ) data;
4031 if( ao == NULL ) return;
4032 if( ao->type == ADDR_INTERFACE ) {
4033 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
4034 addrbookctl_free_interface( ai );
4036 else if( ao->type == ADDR_DATASOURCE ) {
4037 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
4038 addrbookctl_free_datasource( ads );
4040 else if( ao->type == ADDR_ITEM_FOLDER ) {
4041 AdapterFolder *af = ADAPTER_FOLDER(ao);
4042 addrbookctl_free_folder( af );
4044 else if( ao->type == ADDR_ITEM_GROUP ) {
4045 AdapterGroup *ag = ADAPTER_GROUP(ao);
4046 addrbookctl_free_group( ag );
4051 * Create new adaptor for specified data source.
4053 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4054 AddressObjectType otype, gchar *name )
4056 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4057 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4058 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4059 adapter->dataSource = ds;
4060 adapter->subType = otype;
4064 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4065 ADDRESS_OBJECT_NAME(adapter) =
4066 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4070 * Load tree from address index with the initial data.
4072 static void addressbook_load_tree( void ) {
4073 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4074 GList *nodeIf, *nodeDS;
4075 AdapterInterface *adapter;
4076 AddressInterface *iface;
4077 AddressTypeControlItem *atci;
4078 AddressDataSource *ds;
4079 AdapterDSource *ads;
4080 GtkCMCTreeNode *node, *newNode;
4083 nodeIf = _addressInterfaceList_;
4085 adapter = nodeIf->data;
4086 node = adapter->treeNode;
4087 iface = adapter->interface;
4088 atci = adapter->atci;
4090 if( iface->useInterface ) {
4091 /* Load data sources below interface node */
4092 nodeDS = iface->listSource;
4095 name = addrindex_ds_get_name( ds );
4096 ads = addressbook_create_ds_adapter(
4097 ds, atci->objectType, name );
4098 newNode = addressbook_add_object(
4099 node, ADDRESS_OBJECT(ads) );
4100 if (newNode == NULL) {
4101 g_message("error adding addressbook object\n");
4103 nodeDS = g_list_next( nodeDS );
4105 gtk_cmctree_expand( ctree, node );
4108 nodeIf = g_list_next( nodeIf );
4113 * Convert the old address book to new format.
4115 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4116 gboolean retVal = FALSE;
4117 gboolean errFlag = TRUE;
4120 /* Read old address book, performing conversion */
4121 debug_print( "Reading and converting old address book...\n" );
4122 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4123 addrindex_read_data( addrIndex );
4124 if( addrIndex->retVal == MGU_NO_FILE ) {
4125 /* We do not have a file - new user */
4126 debug_print( "New user... create new books...\n" );
4127 addrindex_create_new_books( addrIndex );
4128 if( addrIndex->retVal == MGU_SUCCESS ) {
4129 /* Save index file */
4130 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4131 addrindex_save_data( addrIndex );
4132 if( addrIndex->retVal == MGU_SUCCESS ) {
4137 msg = _( "New user, could not save index file." );
4141 msg = _( "New user, could not save address book files." );
4145 /* We have an old file */
4146 if( addrIndex->wasConverted ) {
4147 /* Converted successfully - save address index */
4148 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4149 addrindex_save_data( addrIndex );
4150 if( addrIndex->retVal == MGU_SUCCESS ) {
4151 msg = _( "Old address book converted successfully." );
4156 msg = _("Old address book converted,\n"
4157 "could not save new address index file." );
4161 /* File conversion failed - just create new books */
4162 debug_print( "File conversion failed... just create new books...\n" );
4163 addrindex_create_new_books( addrIndex );
4164 if( addrIndex->retVal == MGU_SUCCESS ) {
4166 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4167 addrindex_save_data( addrIndex );
4168 if( addrIndex->retVal == MGU_SUCCESS ) {
4169 msg = _("Could not convert address book,\n"
4170 "but created empty new address book files." );
4175 msg = _("Could not convert address book,\n"
4176 "could not save new address index file." );
4180 msg = _("Could not convert address book\n"
4181 "and could not create new address book files." );
4186 debug_print( "Error\n%s\n", msg );
4187 alertpanel_full(_("Addressbook conversion error"), msg,
4188 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4192 debug_print( "Warning\n%s\n", msg );
4193 alertpanel_full(_("Addressbook conversion error"), msg,
4194 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4195 NULL, ALERT_WARNING);
4201 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4205 gboolean failed = FALSE;
4206 GError *error = NULL;
4208 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4209 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4210 error->code, error->message);
4211 g_error_free(error);
4215 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4216 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4219 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4221 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4223 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4236 /* all copies succeeded, we can remove source files */
4237 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4238 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4239 error->code, error->message);
4240 g_error_free(error);
4243 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4244 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4247 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4249 claws_unlink(orig_file);
4259 void addressbook_read_file( void ) {
4260 AddressIndex *addrIndex = NULL;
4261 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4263 debug_print( "Reading address index...\n" );
4264 if( _addressIndex_ ) {
4265 debug_print( "address book already read!!!\n" );
4270 addrIndex = addrindex_create_index();
4271 addrindex_initialize();
4273 /* Use new address book index. */
4275 if ( !is_dir_exist(indexdir) ) {
4276 if ( make_dir(indexdir) < 0 ) {
4277 addrindex_set_file_path( addrIndex, get_rc_dir() );
4278 g_warning( "couldn't create dir '%s'", indexdir);
4280 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4281 remove_dir_recursive(indexdir);
4282 addrindex_set_file_path( addrIndex, get_rc_dir() );
4283 g_error("couldn't migrate dir %s", indexdir);
4285 addrindex_set_file_path( addrIndex, indexdir);
4289 addrindex_set_file_path( addrIndex, indexdir);
4292 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4293 addrindex_read_data( addrIndex );
4294 if( addrIndex->retVal == MGU_NO_FILE ) {
4295 /* Conversion required */
4296 debug_print( "Converting...\n" );
4297 if( addressbook_convert( addrIndex ) ) {
4298 _addressIndex_ = addrIndex;
4301 else if( addrIndex->retVal == MGU_SUCCESS ) {
4302 _addressIndex_ = addrIndex;
4305 /* Error reading address book */
4306 debug_print( "Could not read address index.\n" );
4307 addrindex_print_index( addrIndex, stdout );
4308 alertpanel_full(_("Addressbook Error"),
4309 _("Could not read address index"),
4310 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4313 debug_print( "done.\n" );
4317 * Add object into the address index tree widget.
4318 * Enter: node Parent node.
4319 * obj Object to add.
4320 * Return: Node that was added, or NULL if object not added.
4322 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4325 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4326 GtkCMCTreeNode *added;
4327 AddressObject *pobj;
4328 AddressObjectType otype;
4329 AddressTypeControlItem *atci = NULL;
4331 cm_return_val_if_fail(node != NULL, NULL);
4332 cm_return_val_if_fail(obj != NULL, NULL);
4334 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4335 cm_return_val_if_fail(pobj != NULL, NULL);
4337 /* Determine object type to be displayed */
4338 if( obj->type == ADDR_DATASOURCE ) {
4339 otype = ADAPTER_DSOURCE(obj)->subType;
4345 /* Handle any special conditions. */
4347 atci = addrbookctl_lookup( otype );
4349 if( atci->showInTree ) {
4350 /* Add object to tree */
4353 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4354 atci->iconXpm, atci->iconXpmOpen,
4355 atci->treeLeaf, atci->treeExpand );
4356 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4357 addressbook_free_treenode );
4361 gtk_sctree_sort_node(ctree, node);
4367 * Add group into the address index tree.
4368 * \param node Parent node.
4369 * \param ds Data source.
4370 * \param itemGroup Group to add.
4371 * \return Inserted node.
4373 static GtkCMCTreeNode *addressbook_node_add_group(
4374 GtkCMCTreeNode *node, AddressDataSource *ds,
4375 ItemGroup *itemGroup )
4377 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4378 GtkCMCTreeNode *newNode;
4379 AdapterGroup *adapter;
4380 AddressTypeControlItem *atci = NULL;
4383 if( ds == NULL ) return NULL;
4384 if( node == NULL || itemGroup == NULL ) return NULL;
4386 name = &itemGroup->obj.name;
4388 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4390 adapter = g_new0( AdapterGroup, 1 );
4391 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4392 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4393 adapter->itemGroup = itemGroup;
4395 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4396 atci->iconXpm, atci->iconXpm,
4397 atci->treeLeaf, atci->treeExpand );
4398 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4399 addressbook_free_treenode );
4400 gtk_sctree_sort_node( ctree, node );
4405 * Add folder into the address index tree. Only visible folders are loaded into
4406 * the address index tree. Note that the root folder is not inserted into the
4409 * \param node Parent node.
4410 * \param ds Data source.
4411 * \param itemFolder Folder to add.
4412 * \param otype Object type to display.
4413 * \return Inserted node for the folder.
4415 static GtkCMCTreeNode *addressbook_node_add_folder(
4416 GtkCMCTreeNode *node, AddressDataSource *ds,
4417 ItemFolder *itemFolder, AddressObjectType otype )
4419 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4420 GtkCMCTreeNode *newNode = NULL;
4421 AdapterFolder *adapter;
4422 AddressTypeControlItem *atci = NULL;
4423 GList *listItems = NULL;
4425 ItemFolder *rootFolder;
4427 /* Only visible folders */
4428 if( itemFolder == NULL || itemFolder->isHidden )
4433 if( node == NULL || itemFolder == NULL )
4436 /* Determine object type */
4437 atci = addrbookctl_lookup( otype );
4441 rootFolder = addrindex_ds_get_root_folder( ds );
4442 if( itemFolder == rootFolder ) {
4446 adapter = g_new0( AdapterFolder, 1 );
4447 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4448 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4449 adapter->itemFolder = itemFolder;
4451 name = ADDRITEM_NAME(itemFolder);
4452 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4453 atci->iconXpm, atci->iconXpm,
4454 atci->treeLeaf, atci->treeExpand );
4456 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4457 addressbook_free_treenode );
4461 listItems = itemFolder->listFolder;
4462 while( listItems ) {
4463 ItemFolder *item = listItems->data;
4464 addressbook_node_add_folder( newNode, ds, item, otype );
4465 listItems = g_list_next( listItems );
4467 listItems = itemFolder->listGroup;
4468 while( listItems ) {
4469 ItemGroup *item = listItems->data;
4470 addressbook_node_add_group( newNode, ds, item );
4471 listItems = g_list_next( listItems );
4473 gtk_sctree_sort_node( ctree, node );
4477 void addressbook_export_to_file( void ) {
4478 if( _addressIndex_ ) {
4479 /* Save all new address book data */
4480 debug_print( "Saving address books...\n" );
4481 addrindex_save_all_books( _addressIndex_ );
4483 debug_print( "Exporting addressbook to file...\n" );
4484 addrindex_save_data( _addressIndex_ );
4485 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4486 addrindex_print_index( _addressIndex_, stdout );
4489 /* Notify address completion of new data */
4490 invalidate_address_completion();
4494 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4496 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4497 addressbook_lup_clicked(NULL, NULL);
4502 * Comparison using cell contents (text in first column). Used for sort
4503 * address index widget.
4505 static gint addressbook_treenode_compare_func(
4506 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4508 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4509 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4510 gchar *name1 = NULL, *name2 = NULL;
4511 if( cell1 ) name1 = cell1->u.text;
4512 if( cell2 ) name2 = cell2->u.text;
4513 if( ! name1 ) return ( name2 != NULL );
4514 if( ! name2 ) return -1;
4515 return g_utf8_collate( name1, name2 );
4518 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4519 AdapterDSource *ads;
4520 AdapterInterface *adapter;
4521 GtkCMCTreeNode *newNode;
4523 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4524 if( adapter == NULL ) return;
4525 ads = addressbook_edit_book( _addressIndex_, NULL );
4527 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4529 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4530 addrbook.treeSelected = newNode;
4535 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4536 AdapterDSource *ads;
4537 AdapterInterface *adapter;
4538 GtkCMCTreeNode *newNode;
4540 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4541 if( adapter == NULL ) return;
4542 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4544 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4546 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4547 addrbook.treeSelected = newNode;
4553 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4554 AdapterDSource *ads;
4555 AdapterInterface *adapter;
4556 AddressInterface *iface;
4557 GtkCMCTreeNode *newNode;
4559 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4560 if( adapter == NULL ) return;
4561 iface = adapter->interface;
4562 if( ! iface->haveLibrary ) return;
4563 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4565 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4567 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4568 addrbook.treeSelected = newNode;
4575 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4576 AdapterDSource *ads;
4577 AdapterInterface *adapter;
4578 AddressInterface *iface;
4579 GtkCMCTreeNode *newNode;
4581 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4582 if( adapter == NULL ) return;
4583 iface = adapter->interface;
4584 if( ! iface->haveLibrary ) return;
4585 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4587 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4589 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4590 addrbook.treeSelected = newNode;
4597 * Display address search status message.
4598 * \param queryType Query type.
4599 * \param status Status/Error code.
4601 static void addressbook_search_message( gint queryType, gint sts ) {
4603 *addressbook_msgbuf = '\0';
4605 if( sts != MGU_SUCCESS ) {
4606 if( queryType == ADDRQUERY_LDAP ) {
4608 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4613 g_snprintf( addressbook_msgbuf,
4614 sizeof(addressbook_msgbuf), "%s", desc );
4615 addressbook_status_show( addressbook_msgbuf );
4618 addressbook_status_show( "" );
4623 * Refresh addressbook by forcing refresh of current selected object in
4626 static void addressbook_refresh_current( void ) {
4630 ctree = GTK_CMCTREE(addrbook.ctree);
4631 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4632 if( obj == NULL ) return;
4633 addressbook_set_clist( obj, TRUE );
4637 * Message that is displayed whilst a query is executing in a background
4640 static gchar *_tempMessage_ = N_( "Busy searching..." );
4643 * Address search idle function. This function is called during UI idle time
4644 * while a search is in progress.
4646 * \param data Idler data.
4648 static void addressbook_search_idle( gpointer data ) {
4652 queryID = GPOINTER_TO_INT( data );
4653 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4658 * Search completion callback function. This removes the query from the idle
4661 * \param sender Sender of query.
4662 * \param queryID Query ID of search request.
4663 * \param status Search status.
4664 * \param data Query data.
4666 static void addressbook_search_callback_end(
4667 gpointer sender, gint queryID, gint status, gpointer data )
4671 AddrQueryObject *aqo;
4673 /* Remove idler function */
4674 ptrQID = GINT_TO_POINTER( queryID );
4676 g_idle_remove_by_data( ptrQID );
4679 /* Refresh addressbook contents */
4680 addressbook_refresh_current();
4681 req = qrymgr_find_request( queryID );
4683 aqo = ( AddrQueryObject * ) req->queryList->data;
4684 addressbook_search_message( aqo->queryType, status );
4687 /* Stop the search */
4688 addrindex_stop_search( queryID );
4694 * \param ds Data source to search.
4695 * \param searchTerm String to lookup.
4696 * \param pNode Parent data source node.
4698 static void addressbook_perform_search(
4699 AddressDataSource *ds, gchar *searchTerm,
4700 GtkCMCTreeNode *pNode )
4708 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4710 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4712 /* Create a folder for the search results */
4713 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4714 folder = addressbook_setup_subf(ds, name, pNode);
4717 /* Setup the search */
4718 queryID = addrindex_setup_explicit_search(
4719 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4720 if( queryID == 0 ) return;
4722 /* Set up idler function */
4723 idleID = g_idle_add(
4724 (GSourceFunc) addressbook_search_idle,
4725 GINT_TO_POINTER( queryID ) );
4727 g_message("error adding addressbook_search_idle\n");
4730 /* Start search, sit back and wait for something to happen */
4731 addrindex_start_search( queryID );
4733 addressbook_status_show( _tempMessage_ );
4737 * Lookup button handler. Address search is only performed against
4738 * address interfaces for external queries.
4740 * \param button Lookup button widget.
4741 * \param data Data object.
4743 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4746 AddressDataSource *ds;
4747 AddressInterface *iface;
4749 GtkCMCTreeNode *node, *parentNode;
4751 LdapServer *ldap_server;
4752 LdapControl *ldap_ctl;
4755 node = addrbook.treeSelected;
4756 if( ! node ) return;
4757 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4759 ctree = GTK_CMCTREE(addrbook.ctree);
4760 obj = gtk_cmctree_node_get_row_data( ctree, node );
4761 if( obj == NULL ) return;
4763 if (obj->type != ADDR_DATASOURCE ||
4764 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4765 addressbook_set_clist(
4766 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4767 addrbook.treeSelected),
4771 ds = addressbook_find_datasource( node );
4772 if( ds == NULL ) return;
4774 /* We must have a datasource that is an external interface */
4775 iface = ds->interface;
4776 if( ! iface->haveLibrary ) return;
4777 if( ! iface->externalQuery ) return;
4780 if (iface->type == ADDR_IF_LDAP) {
4781 ldap_server = ds->rawDataSource;
4782 ldap_ctl = ldap_server->control;
4783 if (ldap_ctl != NULL &&
4784 ldap_ctl->bindDN != NULL && strlen(ldap_ctl->bindDN) > 0) {
4785 #ifndef PASSWORD_CRYPTO_OLD
4786 /* LDAP server is password-protected. */
4787 if (master_passphrase() == NULL) {
4788 /* User did not enter master passphrase, do not start a search. */
4791 #endif /* PASSWORD_CRYPTO_OLD */
4794 #endif /* USE_LDAP */
4797 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4798 g_strchomp( searchTerm );
4800 if( obj->type == ADDR_ITEM_FOLDER ) {
4801 parentNode = GTK_CMCTREE_ROW(node)->parent;
4806 addressbook_perform_search( ds, searchTerm, parentNode );
4808 gtk_widget_grab_focus( addrbook.entry );
4810 g_free( searchTerm );
4813 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4814 addressbook_close();
4819 * Browse address entry for highlighted entry.
4821 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4823 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4825 AddressDataSource *ds;
4826 AddressInterface *iface;
4830 if(addrbook.listSelected == NULL)
4833 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4837 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4841 iface = ds->interface;
4842 if(!iface || !iface->haveLibrary )
4846 if (obj->type == ADDR_ITEM_EMAIL) {
4847 email = ( ItemEMail * ) obj;
4849 person = (ItemPerson *) ADDRITEM_PARENT(email);
4851 else if (obj->type == ADDR_ITEM_PERSON) {
4852 person = (ItemPerson *) obj;
4859 if( iface && iface->type == ADDR_IF_LDAP ) {
4860 browseldap_entry(ds, person->externalID);
4865 /* **********************************************************************
4866 * Build lookup tables.
4867 * ***********************************************************************
4871 * Remap object types.
4872 * Enter: abType AddressObjectType (used in tree node).
4873 * Return: ItemObjectType (used in address cache data).
4875 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4876 ItemObjectType ioType;
4879 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4880 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4881 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4882 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4883 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4884 default: ioType = ITEMTYPE_NONE; break;
4889 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4890 atci = addrbookctl_lookup(id); \
4892 atci->iconXpm = icon; \
4893 atci->iconXpmOpen = iconopen; \
4895 g_warning("can't get atci %d", id); \
4900 * Build table that controls the rendering of object types.
4902 static void addrbookctl_build_icons( GtkWidget *window ) {
4903 AddressTypeControlItem *atci;
4907 g_object_unref(interfacexpm);
4909 g_object_unref(folderxpm);
4911 g_object_unref(folderopenxpm);
4913 g_object_unref(groupxpm);
4915 g_object_unref(vcardxpm);
4917 g_object_unref(bookxpm);
4919 g_object_unref(addressxpm);
4921 g_object_unref(jpilotxpm);
4923 g_object_unref(categoryxpm);
4925 g_object_unref(ldapxpm);
4927 g_object_unref(addrsearchxpm);
4928 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4929 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4930 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4931 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4932 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4933 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4934 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4935 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4936 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4937 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4938 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4940 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4941 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4942 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4943 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4944 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4945 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4946 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4947 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4948 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4949 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4950 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4955 * Build table that controls the rendering of object types.
4957 static void addrbookctl_build_map( GtkWidget *window ) {
4958 AddressTypeControlItem *atci;
4960 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4961 _addressBookTypeList_ = NULL;
4964 atci = g_new0( AddressTypeControlItem, 1 );
4965 atci->objectType = ADDR_INTERFACE;
4966 atci->interfaceType = ADDR_IF_NONE;
4967 atci->showInTree = TRUE;
4968 atci->treeExpand = TRUE;
4969 atci->treeLeaf = FALSE;
4970 atci->displayName = _( "Interface" );
4971 atci->menuCommand = NULL;
4972 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4973 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4976 atci = g_new0( AddressTypeControlItem, 1 );
4977 atci->objectType = ADDR_BOOK;
4978 atci->interfaceType = ADDR_IF_BOOK;
4979 atci->showInTree = TRUE;
4980 atci->treeExpand = TRUE;
4981 atci->treeLeaf = FALSE;
4982 atci->displayName = _("Address Books");
4983 atci->menuCommand = "Menu/Book/NewBook";
4984 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4985 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4988 atci = g_new0( AddressTypeControlItem, 1 );
4989 atci->objectType = ADDR_ITEM_PERSON;
4990 atci->interfaceType = ADDR_IF_NONE;
4991 atci->showInTree = FALSE;
4992 atci->treeExpand = FALSE;
4993 atci->treeLeaf = FALSE;
4994 atci->displayName = _( "Person" );
4995 atci->menuCommand = NULL;
4996 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4997 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5000 atci = g_new0( AddressTypeControlItem, 1 );
5001 atci->objectType = ADDR_ITEM_EMAIL;
5002 atci->interfaceType = ADDR_IF_NONE;
5003 atci->showInTree = FALSE;
5004 atci->treeExpand = FALSE;
5005 atci->treeLeaf = TRUE;
5006 atci->displayName = _( "Email Address" );
5007 atci->menuCommand = NULL;
5008 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5009 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5012 atci = g_new0( AddressTypeControlItem, 1 );
5013 atci->objectType = ADDR_ITEM_GROUP;
5014 atci->interfaceType = ADDR_IF_BOOK;
5015 atci->showInTree = TRUE;
5016 atci->treeExpand = FALSE;
5017 atci->treeLeaf = FALSE;
5018 atci->displayName = _( "Group" );
5019 atci->menuCommand = NULL;
5020 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5021 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5024 atci = g_new0( AddressTypeControlItem, 1 );
5025 atci->objectType = ADDR_ITEM_FOLDER;
5026 atci->interfaceType = ADDR_IF_BOOK;
5027 atci->showInTree = TRUE;
5028 atci->treeExpand = FALSE;
5029 atci->treeLeaf = FALSE;
5030 atci->displayName = _( "Folder" );
5031 atci->menuCommand = NULL;
5032 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5033 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5036 atci = g_new0( AddressTypeControlItem, 1 );
5037 atci->objectType = ADDR_VCARD;
5038 atci->interfaceType = ADDR_IF_VCARD;
5039 atci->showInTree = TRUE;
5040 atci->treeExpand = TRUE;
5041 atci->treeLeaf = TRUE;
5042 atci->displayName = _( "vCard" );
5043 atci->menuCommand = "Menu/Book/NewVCard";
5044 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5045 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5048 atci = g_new0( AddressTypeControlItem, 1 );
5049 atci->objectType = ADDR_JPILOT;
5050 atci->interfaceType = ADDR_IF_JPILOT;
5051 atci->showInTree = TRUE;
5052 atci->treeExpand = TRUE;
5053 atci->treeLeaf = FALSE;
5054 atci->displayName = _( "JPilot" );
5055 atci->menuCommand = "Menu/Book/NewJPilot";
5056 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5057 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5060 atci = g_new0( AddressTypeControlItem, 1 );
5061 atci->objectType = ADDR_CATEGORY;
5062 atci->interfaceType = ADDR_IF_JPILOT;
5063 atci->showInTree = TRUE;
5064 atci->treeExpand = TRUE;
5065 atci->treeLeaf = TRUE;
5066 atci->displayName = _( "JPilot" );
5067 atci->menuCommand = NULL;
5068 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5069 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5072 atci = g_new0( AddressTypeControlItem, 1 );
5073 atci->objectType = ADDR_LDAP;
5074 atci->interfaceType = ADDR_IF_LDAP;
5075 atci->showInTree = TRUE;
5076 atci->treeExpand = TRUE;
5077 atci->treeLeaf = FALSE;
5078 atci->displayName = _( "LDAP servers" );
5079 atci->menuCommand = "Menu/Book/NewLDAPServer";
5080 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5081 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5084 atci = g_new0( AddressTypeControlItem, 1 );
5085 atci->objectType = ADDR_LDAP_QUERY;
5086 atci->interfaceType = ADDR_IF_LDAP;
5087 atci->showInTree = TRUE;
5088 atci->treeExpand = FALSE;
5089 atci->treeLeaf = TRUE;
5090 atci->displayName = _( "LDAP Query" );
5091 atci->menuCommand = NULL;
5092 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5093 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5095 addrbookctl_build_icons(window);
5098 void addressbook_reflect_prefs_pixmap_theme(void)
5100 if (addrbook.window)
5101 addrbookctl_build_icons(addrbook.window);
5105 * Search for specified object type.
5107 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5109 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5113 * Search for specified interface type.
5115 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5116 GList *node = _addressBookTypeList_;
5118 AddressTypeControlItem *atci = node->data;
5119 if( atci->interfaceType == ifType ) return atci;
5120 node = g_list_next( node );
5125 static void addrbookctl_free_address( AddressObject *obj ) {
5126 g_free( obj->name );
5127 obj->type = ADDR_NONE;
5131 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5132 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5133 adapter->interface = NULL;
5134 adapter->interfaceType = ADDR_IF_NONE;
5135 adapter->atci = NULL;
5136 adapter->enabled = FALSE;
5137 adapter->haveLibrary = FALSE;
5138 adapter->treeNode = NULL;
5142 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5143 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5144 adapter->dataSource = NULL;
5145 adapter->subType = ADDR_NONE;
5149 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5150 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5151 adapter->itemFolder = NULL;
5155 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5156 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5157 adapter->itemGroup = NULL;
5162 * Build GUI interface list.
5164 static void addrbookctl_build_iflist( void ) {
5165 AddressTypeControlItem *atci;
5166 AdapterInterface *adapter;
5169 if( _addressIndex_ == NULL ) {
5170 _addressIndex_ = addrindex_create_index();
5171 if( _clipBoard_ == NULL ) {
5172 _clipBoard_ = addrclip_create();
5174 addrclip_set_index( _clipBoard_, _addressIndex_ );
5176 _addressInterfaceList_ = NULL;
5177 list = addrindex_get_interface_list( _addressIndex_ );
5179 AddressInterface *interface = list->data;
5180 atci = addrbookctl_lookup_iface( interface->type );
5182 adapter = g_new0( AdapterInterface, 1 );
5183 adapter->interfaceType = interface->type;
5184 adapter->atci = atci;
5185 adapter->interface = interface;
5186 adapter->treeNode = NULL;
5187 adapter->enabled = TRUE;
5188 adapter->haveLibrary = interface->haveLibrary;
5189 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5190 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5191 _addressInterfaceList_ =
5192 g_list_append( _addressInterfaceList_, adapter );
5194 list = g_list_next( list );
5199 * Find GUI interface type specified interface type.
5200 * \param ifType Interface type.
5201 * \return Interface item, or NULL if not found.
5203 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5204 GList *node = _addressInterfaceList_;
5206 AdapterInterface *adapter = node->data;
5207 if( adapter->interfaceType == ifType ) return adapter;
5208 node = g_list_next( node );
5214 * Build interface list selection.
5216 static void addrbookctl_build_ifselect( void ) {
5217 GList *newList = NULL;
5222 gchar *endptr = NULL;
5223 /* gboolean enabled; */
5224 AdapterInterface *adapter;
5226 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5229 splitStr = g_strsplit( selectStr, ",", -1 );
5230 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5232 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5233 ifType = strtol( splitStr[i], &endptr, 10 );
5236 if( strcmp( endptr, "/n" ) == 0 ) {
5241 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5242 adapter = addrbookctl_find_interface( ifType );
5244 newList = g_list_append( newList, adapter );
5251 /* g_print( "i=%d\n", i ); */
5252 g_strfreev( splitStr );
5253 g_free( selectStr );
5255 /* Replace existing list */
5256 g_list_free( _addressIFaceSelection_ );
5257 _addressIFaceSelection_ = newList;
5261 /* ***********************************************************************
5262 * Add sender to address book.
5263 * ***********************************************************************
5267 * This function is used by the Add sender to address book function.
5269 gboolean addressbook_add_contact(
5270 const gchar *name, const gchar *address, const gchar *remarks,
5271 GdkPixbuf *picture )
5273 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5274 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5275 debug_print( "addressbook_add_contact - added\n" );
5276 addressbook_refresh();
5281 /* ***********************************************************************
5282 * Book/folder selection.
5283 * ***********************************************************************
5287 * This function is used by the matcher dialog to select a book/folder.
5289 gchar *addressbook_folder_selection( const gchar *folderpath)
5291 AddressBookFile *book = NULL;
5292 ItemFolder *folder = NULL;
5295 cm_return_val_if_fail( folderpath != NULL, NULL);
5297 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5299 if ( folder != NULL) {
5301 gchar *oldtmp = NULL;
5302 AddrItemObject *obj = NULL;
5304 /* walk thru folder->parent to build the full folder path */
5305 /* TODO: wwp: optimize this */
5307 tmp = g_strdup(obj->uid);
5308 while ( obj->parent ) {
5310 if ( obj->name != NULL ) {
5311 oldtmp = g_strdup(tmp);
5313 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5317 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5320 path = g_strdup_printf("%s", book->fileName);
5322 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5328 /* ***********************************************************************
5329 * Book/folder checking.
5330 * ***********************************************************************
5333 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5335 FolderInfo *fi = g_new0( FolderInfo, 1 );
5337 fi->folder = folder;
5341 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5342 FolderInfo *fiParent, FolderPathMatch *match )
5348 FolderPathMatch *nextmatch = NULL;
5353 list = parentFolder->listFolder;
5355 folder = list->data;
5356 fName = g_strdup( ADDRITEM_NAME(folder) );
5358 /* match folder name, match pointer will be set to NULL if next recursive call
5359 doesn't need to match subfolder name */
5360 if ( match != NULL &&
5361 match->matched == FALSE ) {
5362 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5363 /* folder name matches, prepare next subfolder match */
5364 debug_print("matched folder name '%s'\n", fName);
5366 if ( match->folder_path[match->index] == NULL ) {
5367 /* we've matched all elements */
5368 match->matched = TRUE;
5369 match->folder = folder;
5370 debug_print("book/folder path matched!\n");
5372 /* keep on matching */
5380 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5381 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5383 list = g_list_next( list );
5388 * This function is used by to check if a matcher book/folder path corresponds to an
5389 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5390 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5391 if book AND folder are NULL this means that folderpath was empty or Any.
5392 If folderpath is a simple book name (without folder), book will not be NULL and folder
5393 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5396 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5397 AddressDataSource **book,
5398 ItemFolder **folder )
5400 AddressDataSource *ds;
5401 GList *list, *nodeDS;
5402 ItemFolder *rootFolder;
5403 AddressBookFile *abf;
5405 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5412 if ( folderpath == NULL )
5415 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5418 /* split the folder path we've received, we'll try to match this path, subpath by
5419 subpath against the book/folder structure in order */
5420 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5421 if (!folder_path_match.folder_path)
5424 list = addrindex_get_interface_list( _addressIndex_ );
5425 while ( list && !folder_path_match.matched ) {
5426 AddressInterface *interface = list->data;
5427 if ( interface && interface->type == ADDR_IF_BOOK ) {
5428 nodeDS = interface->listSource;
5429 while ( nodeDS && !folder_path_match.matched ) {
5432 /* Read address book */
5433 if( ! addrindex_ds_get_read_flag( ds ) ) {
5434 addrindex_ds_read_data( ds );
5437 /* Add node for address book */
5438 abf = ds->rawDataSource;
5440 /* match book name */
5441 if ( abf && abf->fileName &&
5442 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5444 debug_print("matched book name '%s'\n", abf->fileName);
5445 folder_path_match.book = ds;
5447 if ( folder_path_match.folder_path[1] == NULL ) {
5448 /* no folder part to match */
5450 folder_path_match.matched = TRUE;
5451 folder_path_match.folder = NULL;
5452 debug_print("book path matched!\n");
5455 /* match folder part */
5457 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5458 rootFolder = addrindex_ds_get_root_folder( ds );
5460 /* prepare for recursive call */
5461 folder_path_match.index = 1;
5462 /* this call will set folder_path_match.matched and folder_path_match.folder */
5463 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5468 nodeDS = g_list_next( nodeDS );
5471 list = g_list_next( list );
5474 g_strfreev( folder_path_match.folder_path );
5477 *book = folder_path_match.book;
5479 *folder = folder_path_match.folder;
5480 return folder_path_match.matched;
5484 /* **********************************************************************
5486 * ***********************************************************************
5492 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5493 AddressDataSource *ds = NULL;
5494 AdapterDSource *ads = NULL;
5495 AddressBookFile *abf = NULL;
5496 AdapterInterface *adapter;
5497 GtkCMCTreeNode *newNode;
5499 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5501 if( adapter->treeNode ) {
5502 abf = addressbook_imp_ldif( _addressIndex_ );
5504 ds = addrindex_index_add_datasource(
5505 _addressIndex_, ADDR_IF_BOOK, abf );
5506 ads = addressbook_create_ds_adapter(
5507 ds, ADDR_BOOK, NULL );
5508 addressbook_ads_set_name(
5509 ads, addrbook_get_name( abf ) );
5510 newNode = addressbook_add_object(
5512 ADDRESS_OBJECT(ads) );
5514 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5516 addrbook.treeSelected = newNode;
5519 /* Notify address completion */
5520 invalidate_address_completion();
5529 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5530 AddressDataSource *ds = NULL;
5531 AdapterDSource *ads = NULL;
5532 AddressBookFile *abf = NULL;
5533 AdapterInterface *adapter;
5534 GtkCMCTreeNode *newNode;
5536 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5538 if( adapter->treeNode ) {
5539 abf = addressbook_imp_mutt( _addressIndex_ );
5541 ds = addrindex_index_add_datasource(
5542 _addressIndex_, ADDR_IF_BOOK, abf );
5543 ads = addressbook_create_ds_adapter(
5544 ds, ADDR_BOOK, NULL );
5545 addressbook_ads_set_name(
5546 ads, addrbook_get_name( abf ) );
5547 newNode = addressbook_add_object(
5549 ADDRESS_OBJECT(ads) );
5551 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5553 addrbook.treeSelected = newNode;
5556 /* Notify address completion */
5557 invalidate_address_completion();
5566 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5567 AddressDataSource *ds = NULL;
5568 AdapterDSource *ads = NULL;
5569 AddressBookFile *abf = NULL;
5570 AdapterInterface *adapter;
5571 GtkCMCTreeNode *newNode;
5573 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5575 if( adapter->treeNode ) {
5576 abf = addressbook_imp_pine( _addressIndex_ );
5578 ds = addrindex_index_add_datasource(
5579 _addressIndex_, ADDR_IF_BOOK, abf );
5580 ads = addressbook_create_ds_adapter(
5581 ds, ADDR_BOOK, NULL );
5582 addressbook_ads_set_name(
5583 ads, addrbook_get_name( abf ) );
5584 newNode = addressbook_add_object(
5586 ADDRESS_OBJECT(ads) );
5588 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5590 addrbook.treeSelected = newNode;
5593 /* Notify address completion */
5594 invalidate_address_completion();
5601 * Harvest addresses.
5602 * \param folderItem Folder to import.
5603 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5604 * \param msgList List of message numbers, or NULL to process folder.
5606 void addressbook_harvest(
5607 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5609 AddressDataSource *ds = NULL;
5610 AdapterDSource *ads = NULL;
5611 AddressBookFile *abf = NULL;
5612 AdapterInterface *adapter;
5613 GtkCMCTreeNode *newNode;
5615 abf = addrgather_dlg_execute(
5616 folderItem, _addressIndex_, sourceInd, msgList );
5618 ds = addrindex_index_add_datasource(
5619 _addressIndex_, ADDR_IF_BOOK, abf );
5621 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5623 if( adapter->treeNode ) {
5624 ads = addressbook_create_ds_adapter(
5625 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5626 newNode = addressbook_add_object(
5628 ADDRESS_OBJECT(ads) );
5629 if (newNode == NULL) {
5630 g_message("error adding addressbook object\n");
5635 /* Notify address completion */
5636 invalidate_address_completion();
5643 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5644 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5646 AddressDataSource *ds = NULL;
5647 AddrBookBase *adbase;
5648 AddressCache *cache;
5649 GtkCMCTreeNode *node = NULL;
5651 if( ! addrbook.treeSelected ) return;
5652 node = addrbook.treeSelected;
5653 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5654 obj = gtk_cmctree_node_get_row_data( ctree, node );
5655 if( obj == NULL ) return;
5657 ds = addressbook_find_datasource( node );
5658 if( ds == NULL ) return;
5659 adbase = ( AddrBookBase * ) ds->rawDataSource;
5660 cache = adbase->addressCache;
5661 addressbook_exp_html( cache );
5667 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5668 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5670 AddressDataSource *ds = NULL;
5671 AddrBookBase *adbase;
5672 AddressCache *cache;
5673 GtkCMCTreeNode *node = NULL;
5675 if( ! addrbook.treeSelected ) return;
5676 node = addrbook.treeSelected;
5677 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5678 obj = gtk_cmctree_node_get_row_data( ctree, node );
5679 if( obj == NULL ) return;
5681 ds = addressbook_find_datasource( node );
5682 if( ds == NULL ) return;
5683 adbase = ( AddrBookBase * ) ds->rawDataSource;
5684 cache = adbase->addressCache;
5685 addressbook_exp_ldif( cache );
5688 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5690 addrduplicates_find(GTK_WINDOW(addrbook.window));
5693 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5695 addressbook_custom_attr_edit();
5698 static void addressbook_start_drag(GtkWidget *widget, gint button,
5702 GdkDragContext *context;
5703 if (addressbook_target_list == NULL)
5704 addressbook_target_list = gtk_target_list_new(
5705 addressbook_drag_types, 1);
5706 context = gtk_drag_begin(widget, addressbook_target_list,
5707 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5708 gtk_drag_set_icon_default(context);
5711 static void addressbook_drag_data_get(GtkWidget *widget,
5712 GdkDragContext *drag_context,
5713 GtkSelectionData *selection_data,
5718 AddrItemObject *aio = NULL;
5719 AddressObject *pobj = NULL;
5720 AdapterDSource *ads = NULL;
5721 AddressDataSource *ds = NULL;
5724 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5726 if( pobj == NULL ) return;
5728 if( pobj->type == ADDR_DATASOURCE ) {
5729 ads = ADAPTER_DSOURCE(pobj);
5730 ds = ads->dataSource;
5731 } else if (pobj->type == ADDR_ITEM_GROUP) {
5736 else if( pobj->type != ADDR_INTERFACE ) {
5737 ds = addressbook_find_datasource( addrbook.treeSelected );
5743 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5744 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5745 GTK_CMCTREE_NODE(cur->data));
5746 while (aio && aio->type != ITEMTYPE_PERSON) {
5751 if (aio && aio->type == ITEMTYPE_PERSON) {
5752 if( ds && ds->interface && ds->interface->readOnly)
5753 gtk_selection_data_set(selection_data,
5754 gtk_selection_data_get_target(selection_data), 8,
5755 (const guchar *)"Dummy_addr_copy", 15);
5757 gtk_selection_data_set(selection_data,
5758 gtk_selection_data_get_target(selection_data), 8,
5759 (const guchar *)"Dummy_addr_move", 15);
5763 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5764 GdkDragContext *context,
5770 GtkAllocation allocation;
5771 GtkRequisition requisition;
5773 GtkCMCTreeNode *node = NULL;
5774 gboolean acceptable = FALSE;
5775 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5776 gint height = allocation.height;
5777 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5778 gint total_height = requisition.height;
5779 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5780 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5781 gfloat vpos = gtk_adjustment_get_value(pos);
5783 if (gtk_cmclist_get_selection_info
5784 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5786 if (y > height - 24 && height + vpos < total_height) {
5787 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5788 gtk_adjustment_changed(pos);
5790 if (y < 24 && y > 0) {
5791 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5792 gtk_adjustment_changed(pos);
5794 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5797 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5798 if( obj->type == ADDR_ITEM_FOLDER
5799 || obj->type == ADDR_ITEM_GROUP)
5802 AdapterDSource *ads = NULL;
5803 AddressDataSource *ds = NULL;
5804 ads = ADAPTER_DSOURCE(obj);
5805 if (ads == NULL ){ return FALSE;}
5806 ds = ads->dataSource;
5807 if (ds == NULL ) { return FALSE;}
5815 g_signal_handlers_block_by_func
5817 G_CALLBACK(addressbook_tree_selected), NULL);
5818 gtk_sctree_select( GTK_SCTREE(widget), node);
5819 g_signal_handlers_unblock_by_func
5821 G_CALLBACK(addressbook_tree_selected), NULL);
5822 gdk_drag_status(context,
5823 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5824 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5826 gdk_drag_status(context, 0, time);
5831 static void addressbook_drag_leave_cb(GtkWidget *widget,
5832 GdkDragContext *context,
5836 if (addrbook.treeSelected) {
5837 g_signal_handlers_block_by_func
5839 G_CALLBACK(addressbook_tree_selected), NULL);
5840 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5841 g_signal_handlers_unblock_by_func
5843 G_CALLBACK(addressbook_tree_selected), NULL);
5848 static void addressbook_drag_received_cb(GtkWidget *widget,
5849 GdkDragContext *drag_context,
5852 GtkSelectionData *data,
5858 GtkCMCTreeNode *node;
5859 GtkCMCTreeNode *lastopened = addrbook.opened;
5861 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5862 if (gtk_cmclist_get_selection_info
5863 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5867 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5868 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5871 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5872 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5873 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5874 addressbook_clip_copy_cb(NULL, NULL);
5876 addressbook_clip_cut_cb(NULL, NULL);
5877 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5878 addressbook_clip_paste_cb(NULL,NULL);
5879 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5880 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5881 gtk_drag_finish(drag_context, TRUE, TRUE, time);