2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2013 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "claws-features.h"
28 #include <glib/gi18n.h>
29 #include <gdk/gdkkeysyms.h>
33 #include <sys/types.h>
37 #include "addressbook.h"
38 #include "manage_window.h"
39 #include "prefs_common.h"
40 #include "alertpanel.h"
41 #include "inputdialog.h"
43 #include "stock_pixmap.h"
45 #include "prefs_gtk.h"
47 #include "file-utils.h"
52 #include "addr_compl.h"
56 #include "addressitem.h"
58 #include "addrcache.h"
60 #include "addrindex.h"
61 #include "addrmerge.h"
62 #include "addressadd.h"
63 #include "addrduplicates.h"
64 #include "addressbook_foldersel.h"
66 #include "editvcard.h"
67 #include "editgroup.h"
68 #include "editaddress.h"
70 #include "importldif.h"
71 #include "importmutt.h"
72 #include "importpine.h"
77 #include "editjpilot.h"
82 #include "ldapserver.h"
84 #include "ldapupdate.h"
86 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
89 #include "addrquery.h"
90 #include "addrselect.h"
92 #include "addrgather.h"
93 #include "adbookbase.h"
94 #include "exphtmldlg.h"
95 #include "expldifdlg.h"
96 #include "browseldap.h"
97 #include "addrcustomattr.h"
105 } AddressIndexColumns;
113 } AddressListColumns;
116 AddressBookFile *book;
124 AddressDataSource *book;
128 static gchar *list_titles[] = { N_("Name"),
132 #define COL_NAME_WIDTH 164
133 #define COL_ADDRESS_WIDTH 156
135 #define COL_FOLDER_WIDTH 170
136 #define ADDRESSBOOK_WIDTH 640
137 #define ADDRESSBOOK_HEIGHT 360
139 #define ADDRESSBOOK_MSGBUF_SIZE 2048
141 static GdkPixbuf *folderxpm = NULL;
142 static GdkPixbuf *folderopenxpm = NULL;
143 static GdkPixbuf *groupxpm = NULL;
144 static GdkPixbuf *interfacexpm = NULL;
145 static GdkPixbuf *bookxpm = NULL;
146 static GdkPixbuf *addressxpm = NULL;
147 static GdkPixbuf *vcardxpm = NULL;
148 static GdkPixbuf *jpilotxpm = NULL;
149 static GdkPixbuf *categoryxpm = NULL;
150 static GdkPixbuf *ldapxpm = NULL;
151 static GdkPixbuf *addrsearchxpm = NULL;
154 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
156 /* Address list selection */
157 static AddrSelectList *_addressSelect_ = NULL;
158 static AddressClipboard *_clipBoard_ = NULL;
160 /* Address index file and interfaces */
161 static AddressIndex *_addressIndex_ = NULL;
162 static GList *_addressInterfaceList_ = NULL;
163 static GList *_addressIFaceSelection_ = NULL;
164 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
166 static AddressBook_win addrbook;
168 static GHashTable *_addressBookTypeHash_ = NULL;
169 static GList *_addressBookTypeList_ = NULL;
171 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
172 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
173 static void addressbook_edit_address_post_cb( ItemPerson *person );
175 static void addressbook_create (void);
176 static gint addressbook_close (void);
178 static gboolean address_index_has_focus = FALSE;
179 static gboolean address_list_has_focus = FALSE;
181 /* callback functions */
182 static void addressbook_del_clicked (GtkButton *button,
184 static void addressbook_reg_clicked (GtkButton *button,
186 static void addressbook_to_clicked (GtkButton *button,
188 static void addressbook_lup_clicked (GtkButton *button,
190 static void addressbook_close_clicked (GtkButton *button,
193 static void addressbook_tree_selected (GtkCMCTree *ctree,
194 GtkCMCTreeNode *node,
197 static void addressbook_select_row_tree (GtkCMCTree *ctree,
198 GtkCMCTreeNode *node,
201 static void addressbook_list_row_selected (GtkCMCTree *clist,
202 GtkCMCTreeNode *node,
205 static void addressbook_list_row_unselected (GtkCMCTree *clist,
206 GtkCMCTreeNode *node,
209 static void addressbook_person_expand_node (GtkCMCTree *ctree,
212 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
216 static void addressbook_entry_activated (GtkWidget *widget,
219 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
220 GdkEventButton *event,
222 static gboolean addressbook_list_button_released(GtkWidget *widget,
223 GdkEventButton *event,
225 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
226 GdkEventButton *event,
228 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
229 GdkEventButton *event,
232 static void addressbook_new_folder_cb (GtkAction *action,
234 static void addressbook_new_group_cb (GtkAction *action,
236 static void addressbook_treenode_edit_cb (GtkAction *action,
238 static void addressbook_treenode_delete_cb (GtkAction *action,
241 static void addressbook_change_node_name (GtkCMCTreeNode *node,
244 static void addressbook_new_address_cb (GtkAction *action,
246 static void addressbook_edit_address_cb (GtkAction *action,
248 static void addressbook_delete_address_cb (GtkAction *action,
251 static void close_cb (GtkAction *action,
253 static void addressbook_file_save_cb (GtkAction *action,
256 /* Data source edit stuff */
257 static void addressbook_new_book_cb (GtkAction *action,
259 static void addressbook_new_vcard_cb (GtkAction *action,
263 static void addressbook_new_jpilot_cb (GtkAction *action,
268 static void addressbook_new_ldap_cb (GtkAction *action,
272 static void addressbook_set_clist (AddressObject *obj,
275 static void addressbook_load_tree (void);
276 void addressbook_read_file (void);
278 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
280 static void addressbook_treenode_remove_item ( void );
282 static AddressDataSource *addressbook_find_datasource
283 (GtkCMCTreeNode *node );
285 static AddressBookFile *addressbook_get_book_file(void);
287 static GtkCMCTreeNode *addressbook_node_add_folder
288 (GtkCMCTreeNode *node,
289 AddressDataSource *ds,
290 ItemFolder *itemFolder,
291 AddressObjectType otype);
292 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
293 AddressDataSource *ds,
294 ItemGroup *itemGroup);
295 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
296 GtkCMCTreeNode *parent);
297 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
298 GtkCMCTreeNode *node);
299 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
301 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
304 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
307 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
309 AddressTypeControlItem *atci,
310 AddressTypeControlItem *atciMail);
311 static void addressbook_folder_remove_node (GtkCMCTree *clist,
312 GtkCMCTreeNode *node);
314 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
315 gboolean force_focus );
317 /* LUT's and IF stuff */
318 static void addressbook_free_treenode ( gpointer data );
319 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
320 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
322 static void addrbookctl_build_map (GtkWidget *window);
323 static void addrbookctl_build_iflist (void);
324 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
325 static void addrbookctl_build_ifselect (void);
327 static void addrbookctl_free_interface (AdapterInterface *adapter);
328 static void addrbookctl_free_datasource (AdapterDSource *adapter);
329 static void addrbookctl_free_folder (AdapterFolder *adapter);
330 static void addrbookctl_free_group (AdapterGroup *adapter);
332 static void addressbook_list_select_clear ( void );
333 static void addressbook_list_select_add ( AddrItemObject *aio,
334 AddressDataSource *ds );
335 static void addressbook_list_select_remove ( AddrItemObject *aio );
337 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
338 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
339 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
340 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
341 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
342 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
343 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
344 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
345 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
346 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
347 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
348 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
349 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
350 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
352 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
353 static void addressbook_merge_cb ( GtkAction *action, gpointer data );
356 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
358 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
360 static void addressbook_start_drag(GtkWidget *widget, gint button,
363 static void addressbook_drag_data_get(GtkWidget *widget,
364 GdkDragContext *drag_context,
365 GtkSelectionData *selection_data,
369 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
370 GdkDragContext *context,
375 static void addressbook_drag_leave_cb(GtkWidget *widget,
376 GdkDragContext *context,
379 static void addressbook_drag_received_cb(GtkWidget *widget,
380 GdkDragContext *drag_context,
383 GtkSelectionData *data,
387 static void addressbook_list_menu_setup( void );
389 static GtkTargetEntry addressbook_drag_types[] =
391 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
394 static GtkTargetList *addressbook_target_list = NULL;
396 static void about_show_cb(GtkAction *action, gpointer data)
401 static GtkActionEntry addressbook_entries[] =
403 {"Menu", NULL, "Menu", NULL, NULL, NULL },
405 {"Book", NULL, N_("_Book"), NULL, NULL, NULL },
406 {"Address", NULL, N_("_Edit"), NULL, NULL, NULL },
407 {"Tools", NULL, N_("_Tools"), NULL, NULL, NULL },
408 {"Help", NULL, N_("_Help"), NULL, NULL, NULL },
411 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
412 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
413 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
417 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
420 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
422 {"Book/---", NULL, "---", NULL, NULL, NULL },
424 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
425 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
426 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
427 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
428 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
431 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
432 {"Address/---", NULL, "---", NULL, NULL, NULL },
433 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
434 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
435 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
436 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
437 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
438 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
439 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
440 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
441 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
442 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
443 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
444 {"Address/Merge", NULL, N_("_Merge"), "<control>E", NULL, G_CALLBACK(addressbook_merge_cb) },
448 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
449 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
450 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
451 {"Tools/---", NULL, "---", NULL, NULL, NULL },
452 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
453 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
454 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
455 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
456 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
459 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
463 static GtkActionEntry addressbook_tree_popup_entries[] =
465 {"ABTreePopup", NULL, "ABTreePopup", NULL, NULL, NULL },
466 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
467 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
468 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
469 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
470 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
471 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
472 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
473 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
474 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
475 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
478 static GtkActionEntry addressbook_list_popup_entries[] =
480 {"ABListPopup", NULL, "ABListPopup", NULL, NULL, NULL },
481 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
482 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
483 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
484 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
485 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
486 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
487 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
488 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
489 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
490 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
491 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
492 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
493 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
495 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
497 {"ABListPopup/Merge", NULL, N_("_Merge"), NULL, NULL, G_CALLBACK(addressbook_merge_cb) },
501 * Structure of error message table.
503 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
504 struct _ErrMsgTableEntry {
509 static gchar *_errMsgUnknown_ = N_( "Unknown" );
512 * Lookup table of error messages for general errors. Note that a NULL
513 * description signifies the end of the table.
515 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
516 { MGU_SUCCESS, N_("Success") },
517 { MGU_BAD_ARGS, N_("Bad arguments") },
518 { MGU_NO_FILE, N_("File not specified") },
519 { MGU_OPEN_FILE, N_("Error opening file") },
520 { MGU_ERROR_READ, N_("Error reading file") },
521 { MGU_EOF, N_("End of file encountered") },
522 { MGU_OO_MEMORY, N_("Error allocating memory") },
523 { MGU_BAD_FORMAT, N_("Bad file format") },
524 { MGU_ERROR_WRITE, N_("Error writing to file") },
525 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
526 { MGU_NO_PATH, N_("No path specified") },
532 * Lookup table of error messages for LDAP errors.
534 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
535 { LDAPRC_SUCCESS, N_("Success") },
536 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
537 { LDAPRC_INIT, N_("Error initializing LDAP") },
538 { LDAPRC_BIND, N_("Error binding to LDAP server") },
539 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
540 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
541 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
542 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
543 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
544 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
545 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
546 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
547 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
548 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
554 * Lookup message for specified error code.
555 * \param lut Lookup table.
556 * \param code Code to lookup.
557 * \return Description associated to code.
559 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
561 ErrMsgTableEntry entry;
564 for( i = 0; ; i++ ) {
566 if( entry.description == NULL ) break;
567 if( entry.code == code ) {
568 desc = entry.description;
573 desc = _errMsgUnknown_;
578 static gboolean lastCanLookup = FALSE;
580 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
582 if (add_and_delete) {
583 gtk_widget_show(addrbook.edit_btn);
584 gtk_widget_show(addrbook.del_btn);
585 gtk_widget_show(addrbook.reg_btn);
587 gtk_widget_hide(addrbook.edit_btn);
588 gtk_widget_hide(addrbook.del_btn);
589 gtk_widget_hide(addrbook.reg_btn);
593 gtk_widget_show(addrbook.lup_btn);
594 gtk_widget_show(addrbook.entry);
595 gtk_widget_show(addrbook.label);
597 gtk_widget_hide(addrbook.lup_btn);
598 gtk_widget_hide(addrbook.entry);
599 gtk_widget_hide(addrbook.label);
602 lastCanLookup = lookup;
605 gtk_widget_show(addrbook.to_btn);
606 gtk_widget_show(addrbook.cc_btn);
607 gtk_widget_show(addrbook.bcc_btn);
609 gtk_widget_hide(addrbook.to_btn);
610 gtk_widget_hide(addrbook.cc_btn);
611 gtk_widget_hide(addrbook.bcc_btn);
615 void addressbook_open(Compose *target)
617 /* Initialize all static members */
618 if( _clipBoard_ == NULL ) {
619 _clipBoard_ = addrclip_create();
621 if( _addressIndex_ != NULL ) {
622 addrclip_set_index( _clipBoard_, _addressIndex_ );
624 if( _addressSelect_ == NULL ) {
625 _addressSelect_ = addrselect_list_create();
627 if (!addrbook.window) {
628 addressbook_read_file();
629 addressbook_create();
630 addressbook_load_tree();
631 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
632 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
635 gtk_widget_hide(addrbook.window);
638 gtk_widget_show_all(addrbook.window);
640 if (!prefs_common.addressbook_use_editaddress_dialog)
641 addressbook_edit_person_widgetset_hide();
643 address_completion_start(addrbook.window);
645 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
646 addressbook_set_target_compose(target);
650 * Destroy addressbook.
652 void addressbook_destroy( void ) {
653 /* Free up address stuff */
654 if( _addressSelect_ != NULL ) {
655 addrselect_list_free( _addressSelect_ );
657 if( _clipBoard_ != NULL ) {
658 addrclip_free( _clipBoard_ );
661 if( _addressIndex_ != NULL ) {
662 addrindex_free_index( _addressIndex_ );
663 addrindex_teardown();
665 _addressSelect_ = NULL;
667 _addressIndex_ = NULL;
670 void addressbook_set_target_compose(Compose *target)
672 addrbook.target_compose = target;
675 Compose *addressbook_get_target_compose(void)
677 return addrbook.target_compose;
681 * Refresh addressbook and save to file(s).
683 void addressbook_refresh( void )
685 if (addrbook.window) {
686 if (addrbook.treeSelected) {
687 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
688 addrbook.treeSelected);
689 addressbook_set_clist(
690 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
691 addrbook.treeSelected),
696 addressbook_export_to_file();
699 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
701 if (event && event->keyval == GDK_KEY_Escape)
703 else if (event && event->keyval == GDK_KEY_Delete) {
704 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
705 if ( /* address_index_has_focus || */ address_list_has_focus )
706 addressbook_del_clicked(NULL, NULL);
712 *\brief Save Gtk object size to prefs dataset
714 static void addressbook_size_allocate_cb(GtkWidget *widget,
715 GtkAllocation *allocation)
717 cm_return_if_fail(allocation != NULL);
719 prefs_common.addressbookwin_width = allocation->width;
720 prefs_common.addressbookwin_height = allocation->height;
723 static gint sort_column_number = 0;
724 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
726 static gint list_case_sort(
727 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
729 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
730 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
731 gchar *name1 = NULL, *name2 = NULL;
732 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
733 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
735 if( aio1->type == aio2->type ) {
737 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
739 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
740 if( ! name1 ) return ( name2 != NULL );
741 if( ! name2 ) return -1;
742 return g_utf8_collate( name1, name2 );
744 /* Order groups before person */
745 if( aio1->type == ITEMTYPE_GROUP ) {
746 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
747 } else if( aio2->type == ITEMTYPE_GROUP ) {
748 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
754 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
755 const GtkSortType sort_type)
758 GtkWidget *hbox, *label, *arrow;
760 sort_column_number = col;
761 sort_column_type = sort_type;
762 gtk_cmclist_set_compare_func(clist, list_case_sort);
763 gtk_cmclist_set_sort_type(clist, sort_type);
764 gtk_cmclist_set_sort_column(clist, col);
766 gtk_cmclist_freeze(clist);
767 gtk_cmclist_sort(clist);
769 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
770 hbox = gtk_hbox_new(FALSE, 4);
771 label = gtk_label_new(gettext(list_titles[pos]));
772 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
775 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
776 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
777 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
780 gtk_widget_show_all(hbox);
781 gtk_cmclist_set_column_widget(clist, pos, hbox);
784 gtk_cmclist_thaw(clist);
787 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
789 static GtkSortType sort_type = GTK_SORT_ASCENDING;
791 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
793 addressbook_sort_list(clist, COL_NAME, sort_type);
796 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
798 static GtkSortType sort_type = GTK_SORT_ASCENDING;
800 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
802 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
805 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
807 static GtkSortType sort_type = GTK_SORT_ASCENDING;
809 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
811 addressbook_sort_list(clist, COL_REMARKS, sort_type);
814 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
817 address_index_has_focus = TRUE;
821 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
824 address_index_has_focus = FALSE;
825 if (!prefs_common.addressbook_use_editaddress_dialog
826 && !address_list_has_focus)
827 addressbook_address_list_disable_some_actions();
831 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
834 address_list_has_focus = TRUE;
838 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
841 address_list_has_focus = FALSE;
842 if (!prefs_common.addressbook_use_editaddress_dialog
843 && !address_index_has_focus)
844 addressbook_address_list_disable_some_actions();
848 /* save hpane and vpane's handle position when it moves */
849 static void addressbook_pane_save_position(void)
852 prefs_common.addressbook_hpaned_pos =
853 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
855 prefs_common.addressbook_vpaned_pos =
856 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
860 * Create the address book widgets. The address book contains two CTree widgets: the
861 * address index tree on the left and the address list on the right.
863 * The address index tree displays a hierarchy of interfaces and groups. Each node in
864 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
865 * data sources and folder objects.
867 * The address list displays group, person and email objects. These items are linked
868 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
871 * In the tradition of MVC architecture, the data stores have been separated from the
872 * GUI components. The addrindex.c file provides the interface to all data stores.
874 static void addressbook_create(void)
880 GtkWidget *ctree_swin;
882 GtkWidget *editaddress_vbox;
883 GtkWidget *clist_vbox;
884 GtkWidget *clist_swin;
891 GtkWidget *statusbar;
902 GtkWidget *close_btn;
903 GtkWidget *tree_popup;
904 GtkWidget *list_popup;
906 GtkUIManager *ui_manager;
907 GtkActionGroup *action_group;
908 gchar *index_titles[N_INDEX_COLS];
912 static GdkGeometry geometry;
914 debug_print("Creating addressbook window...\n");
916 index_titles[COL_SOURCES] = _("Sources");
918 /* Address book window */
919 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
920 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
921 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
922 gtk_widget_realize(window);
924 g_signal_connect(G_OBJECT(window), "delete_event",
925 G_CALLBACK(addressbook_close), NULL);
926 g_signal_connect(G_OBJECT(window), "size_allocate",
927 G_CALLBACK(addressbook_size_allocate_cb), NULL);
928 g_signal_connect(G_OBJECT(window), "key_press_event",
929 G_CALLBACK(key_pressed), NULL);
930 MANAGE_WINDOW_SIGNALS_CONNECT(window);
932 vbox = gtk_vbox_new(FALSE, 0);
933 gtk_container_add(GTK_CONTAINER(window), vbox);
936 ui_manager = gtk_ui_manager_new();
937 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
938 G_N_ELEMENTS(addressbook_entries), NULL);
939 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
940 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
941 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
942 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Merge", "Address/Merge", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
990 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
991 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
992 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
993 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
996 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
998 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
1000 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1002 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1003 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1004 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1006 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1007 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1008 GTK_POLICY_AUTOMATIC,
1009 GTK_POLICY_AUTOMATIC);
1010 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1013 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1014 gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1016 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1017 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1018 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1019 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1020 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1021 GTK_CMCTREE_EXPANDER_TRIANGLE);
1022 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1023 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1024 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1025 addressbook_treenode_compare_func);
1027 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1028 G_CALLBACK(addressbook_tree_selected), NULL);
1029 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1030 G_CALLBACK(addressbook_tree_button_pressed),
1032 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1033 G_CALLBACK(addressbook_tree_button_released),
1036 g_signal_connect(G_OBJECT(ctree), "select_row",
1037 G_CALLBACK(addressbook_select_row_tree), NULL);
1039 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1040 addressbook_drag_types, 1,
1041 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1042 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1043 G_CALLBACK(addressbook_drag_motion_cb),
1045 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1046 G_CALLBACK(addressbook_drag_leave_cb),
1048 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1049 G_CALLBACK(addressbook_drag_received_cb),
1051 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1052 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1053 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1054 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1056 clist_vbox = gtk_vbox_new(FALSE, 4);
1058 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1059 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1060 GTK_POLICY_AUTOMATIC,
1061 GTK_POLICY_AUTOMATIC);
1062 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1065 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1066 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1067 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1068 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1069 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1070 GTK_CMCTREE_EXPANDER_TRIANGLE);
1071 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1072 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1073 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1075 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1077 gtk_widget_set_size_request(clist, -1, 80);
1079 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1080 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1081 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1082 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1083 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1084 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1085 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1086 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1087 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1088 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1089 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1091 for (i = 0; i < N_LIST_COLS; i++)
1092 gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1095 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1096 G_CALLBACK(addressbook_list_row_selected), NULL);
1097 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1098 G_CALLBACK(addressbook_list_row_unselected), NULL);
1099 g_signal_connect(G_OBJECT(clist), "button_press_event",
1100 G_CALLBACK(addressbook_list_button_pressed),
1102 g_signal_connect(G_OBJECT(clist), "button_release_event",
1103 G_CALLBACK(addressbook_list_button_released),
1105 g_signal_connect(G_OBJECT(clist), "tree_expand",
1106 G_CALLBACK(addressbook_person_expand_node), NULL );
1107 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1108 G_CALLBACK(addressbook_person_collapse_node), NULL );
1109 g_signal_connect(G_OBJECT(clist), "start_drag",
1110 G_CALLBACK(addressbook_start_drag), NULL);
1111 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1112 G_CALLBACK(addressbook_drag_data_get), NULL);
1113 hbox = gtk_hbox_new(FALSE, 4);
1114 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1116 label = gtk_label_new(_("Search"));
1117 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1119 entry = gtk_entry_new();
1120 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1122 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1124 g_signal_connect(G_OBJECT(entry), "key_press_event",
1125 G_CALLBACK(addressbook_entry_key_pressed),
1127 g_signal_connect(G_OBJECT(entry), "activate",
1128 G_CALLBACK(addressbook_entry_activated), NULL);
1130 if (!prefs_common.addressbook_use_editaddress_dialog) {
1131 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1132 vpaned = gtk_vpaned_new();
1133 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1134 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1137 editaddress_vbox = NULL;
1139 hpaned = gtk_hpaned_new();
1140 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1141 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1142 if (prefs_common.addressbook_use_editaddress_dialog)
1143 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1145 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1148 hsbox = gtk_hbox_new(FALSE, 0);
1149 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1150 statusbar = gtk_statusbar_new();
1151 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1154 hbbox = gtk_hbutton_box_new();
1155 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1156 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1157 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1158 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1160 gtkut_stock_button_add_help(hbbox, &help_btn);
1162 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1163 gtk_widget_set_can_default(edit_btn, TRUE);
1164 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1165 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1166 gtk_widget_set_can_default(del_btn, TRUE);
1167 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1168 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1169 gtk_widget_set_can_default(reg_btn, TRUE);
1170 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1173 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1174 gtk_widget_set_can_default(lup_btn, TRUE);
1175 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1177 g_signal_connect(G_OBJECT(help_btn), "clicked",
1178 G_CALLBACK(manual_open_with_anchor_cb),
1179 MANUAL_ANCHOR_ADDRBOOK);
1181 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1182 G_CALLBACK(addressbook_edit_clicked), NULL);
1183 g_signal_connect(G_OBJECT(del_btn), "clicked",
1184 G_CALLBACK(addressbook_del_clicked), NULL);
1185 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1186 G_CALLBACK(addressbook_reg_clicked), NULL);
1187 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1188 G_CALLBACK(addressbook_lup_clicked), NULL);
1190 to_btn = gtk_button_new_with_label
1191 (prefs_common_translated_header_name("To:"));
1192 gtk_widget_set_can_default(to_btn, TRUE);
1193 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1194 cc_btn = gtk_button_new_with_label
1195 (prefs_common_translated_header_name("Cc:"));
1196 gtk_widget_set_can_default(cc_btn, TRUE);
1197 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1198 bcc_btn = gtk_button_new_with_label
1199 (prefs_common_translated_header_name("Bcc:"));
1200 gtk_widget_set_can_default(bcc_btn, TRUE);
1201 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1203 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1204 gtk_widget_set_can_default(close_btn, TRUE);
1205 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1207 g_signal_connect(G_OBJECT(to_btn), "clicked",
1208 G_CALLBACK(addressbook_to_clicked),
1209 GINT_TO_POINTER(COMPOSE_TO));
1210 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1211 G_CALLBACK(addressbook_to_clicked),
1212 GINT_TO_POINTER(COMPOSE_CC));
1213 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1214 G_CALLBACK(addressbook_to_clicked),
1215 GINT_TO_POINTER(COMPOSE_BCC));
1216 g_signal_connect(G_OBJECT(close_btn), "clicked",
1217 G_CALLBACK(addressbook_close_clicked), NULL);
1219 /* Build icons for interface */
1221 /* Build control tables */
1222 addrbookctl_build_map(window);
1223 addrbookctl_build_iflist();
1224 addrbookctl_build_ifselect();
1226 addrbook.clist = NULL;
1228 /* Add each interface into the tree as a root level folder */
1229 nodeIf = _addressInterfaceList_;
1231 AdapterInterface *adapter = nodeIf->data;
1232 AddressInterface *iface = adapter->interface;
1233 nodeIf = g_list_next(nodeIf);
1235 if(iface->useInterface) {
1236 AddressTypeControlItem *atci = adapter->atci;
1237 text = atci->displayName;
1239 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1240 NULL, NULL, &text, FOLDER_SPACING,
1244 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1245 gtk_cmctree_node_set_row_data_full(
1246 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1247 addressbook_free_treenode );
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1266 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1267 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1281 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1284 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1286 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Merge", "ABListPopup/Merge", GTK_UI_MANAGER_MENUITEM)
1287 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1288 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1290 addrbook.window = window;
1291 addrbook.hpaned = hpaned;
1292 addrbook.vpaned = vpaned;
1293 addrbook.menubar = menubar;
1294 addrbook.ctree = ctree;
1297 addrbook.editaddress_vbox = editaddress_vbox;
1298 addrbook.clist = clist;
1299 addrbook.label = label;
1300 addrbook.entry = entry;
1301 addrbook.statusbar = statusbar;
1302 addrbook.status_cid = gtk_statusbar_get_context_id(
1303 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1305 addrbook.help_btn = help_btn;
1306 addrbook.edit_btn = edit_btn;
1307 addrbook.del_btn = del_btn;
1308 addrbook.reg_btn = reg_btn;
1309 addrbook.lup_btn = lup_btn;
1310 addrbook.to_btn = to_btn;
1311 addrbook.cc_btn = cc_btn;
1312 addrbook.bcc_btn = bcc_btn;
1314 addrbook.tree_popup = tree_popup;
1315 addrbook.list_popup = list_popup;
1316 addrbook.ui_manager = ui_manager;
1318 addrbook.listSelected = NULL;
1320 if (!geometry.min_height) {
1321 geometry.min_width = ADDRESSBOOK_WIDTH;
1322 geometry.min_height = ADDRESSBOOK_HEIGHT;
1325 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1327 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1328 prefs_common.addressbookwin_height);
1330 gtk_window_move(GTK_WINDOW(window), 48, 48);
1333 if (!prefs_common.addressbook_use_editaddress_dialog) {
1334 if (prefs_common.addressbook_vpaned_pos > 0)
1335 gtk_paned_set_position(GTK_PANED(vpaned),
1336 prefs_common.addressbook_vpaned_pos);
1338 if (prefs_common.addressbook_hpaned_pos > 0)
1339 gtk_paned_set_position(GTK_PANED(hpaned),
1340 prefs_common.addressbook_hpaned_pos);
1343 gtk_widget_show_all(window);
1347 * Close address book window and save to file(s).
1349 static gint addressbook_close( void ) {
1350 address_completion_end(addrbook.window);
1351 if (!prefs_common.addressbook_use_editaddress_dialog)
1352 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1354 addressbook_pane_save_position();
1356 gtk_widget_hide(addrbook.window);
1357 addressbook_export_to_file();
1362 * Display message in status line.
1363 * \param msg Message to display.
1365 static void addressbook_status_show( gchar *msg ) {
1366 if( addrbook.statusbar != NULL ) {
1368 GTK_STATUSBAR(addrbook.statusbar),
1369 addrbook.status_cid );
1372 GTK_STATUSBAR(addrbook.statusbar),
1373 addrbook.status_cid, msg );
1378 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1382 *addressbook_msgbuf = '\0';
1384 name = addrindex_ds_get_name( ds );
1385 retVal = addrindex_ds_get_status_code( ds );
1386 if( retVal == MGU_SUCCESS ) {
1387 g_snprintf( addressbook_msgbuf,
1388 sizeof(addressbook_msgbuf), "%s", name );
1391 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1392 g_snprintf( addressbook_msgbuf,
1393 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1396 addressbook_status_show( addressbook_msgbuf );
1399 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1401 addressbook_edit_address_cb(NULL, NULL);
1404 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1406 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1410 * Delete one or more objects from address list.
1412 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1414 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1415 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1416 AddressObject *pobj;
1417 AdapterDSource *ads = NULL;
1418 GtkCMCTreeNode *nodeList;
1421 AddressBookFile *abf = NULL;
1422 AddressDataSource *ds = NULL;
1423 AddressInterface *iface;
1424 AddrItemObject *aio;
1425 AddrSelectItem *item;
1427 gboolean refreshList = FALSE;
1429 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1430 cm_return_if_fail(pobj != NULL);
1432 /* Test whether anything selected for deletion */
1433 nodeList = addrbook.listSelected;
1435 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1436 if( aio == NULL) return;
1437 ds = addressbook_find_datasource( addrbook.treeSelected );
1438 if( ds == NULL ) return;
1440 /* Test for read only */
1441 iface = ds->interface;
1442 if( iface->readOnly ) {
1443 alertpanel( _("Delete address(es)"),
1444 _("This address data is readonly and cannot be deleted."),
1445 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST);
1449 /* Test whether Ok to proceed */
1451 if( pobj->type == ADDR_DATASOURCE ) {
1452 ads = ADAPTER_DSOURCE(pobj);
1453 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1455 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1458 else if( pobj->type == ADDR_ITEM_GROUP ) {
1461 if( ! procFlag ) return;
1462 abf = ds->rawDataSource;
1463 if( abf == NULL ) return;
1465 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1466 g_signal_handlers_block_by_func
1467 (G_OBJECT(addrbook.clist),
1468 G_CALLBACK(addressbook_list_row_unselected), NULL);
1470 /* Process deletions */
1471 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1472 GList *groups = NULL, *persons = NULL, *emails = NULL;
1473 gboolean group_delete = TRUE;
1474 /* Items inside folders */
1475 list = addrselect_get_list( _addressSelect_ );
1476 /* Confirm deletion */
1480 node = g_list_next( node );
1481 aio = ( AddrItemObject * ) item->addressItem;
1482 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1483 group_delete = FALSE;
1488 aval = alertpanel( _("Delete group"),
1489 _("Really delete the group(s)?\n"
1490 "The addresses it contains will not be lost."),
1491 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1492 if( aval != G_ALERTALTERNATE ) {
1496 aval = alertpanel( _("Delete address(es)"),
1497 _("Really delete the address(es)?"),
1498 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
1499 if( aval != G_ALERTALTERNATE ) {
1504 /* first, set lists of groups and persons to remove */
1508 node = g_list_next( node );
1509 aio = ( AddrItemObject * ) item->addressItem;
1512 if( aio->type == ITEMTYPE_GROUP ) {
1513 groups = g_list_prepend(groups, item);
1515 else if( aio->type == ITEMTYPE_PERSON ) {
1516 persons = g_list_prepend(persons, item);
1519 /* then set list of emails to remove *if* they're not children of
1520 * persons to remove */
1524 node = g_list_next( node );
1525 aio = ( AddrItemObject * ) item->addressItem;
1528 if( aio->type == ITEMTYPE_EMAIL ) {
1529 ItemEMail *sitem = ( ItemEMail * ) aio;
1530 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1531 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1532 emails = g_list_prepend(emails, item);
1534 /* else, the email will be removed via the parent person */
1537 /* then delete groups */
1541 node = g_list_next( node );
1542 aio = ( AddrItemObject * ) item->addressItem;
1545 if( aio->type == ITEMTYPE_GROUP ) {
1546 ItemGroup *item = ( ItemGroup * ) aio;
1547 GtkCMCTreeNode *nd = NULL;
1548 nd = addressbook_find_group_node( addrbook.opened, item );
1549 item = addrbook_remove_group( abf, item );
1551 addritem_free_item_group( item );
1553 /* Remove group from parent node */
1554 gtk_cmctree_remove_node( ctree, nd );
1558 /* then delete persons */
1562 node = g_list_next( node );
1563 aio = ( AddrItemObject * ) item->addressItem;
1566 if( aio->type == ITEMTYPE_PERSON ) {
1567 ItemPerson *item = ( ItemPerson * ) aio;
1568 item->status = DELETE_ENTRY;
1569 addressbook_folder_remove_one_person( clist, item );
1570 if (pobj->type == ADDR_ITEM_FOLDER)
1571 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1572 item = addrbook_remove_person( abf, item );
1574 if (ds && ds->type == ADDR_IF_LDAP) {
1575 LdapServer *server = ds->rawDataSource;
1576 ldapsvr_set_modified(server, TRUE);
1577 ldapsvr_update_book(server, item);
1581 addritem_person_remove_picture(item);
1582 addritem_free_item_person( item );
1586 /* then delete emails */
1590 node = g_list_next( node );
1591 aio = ( AddrItemObject * ) item->addressItem;
1595 if( aio->type == ITEMTYPE_EMAIL ) {
1596 ItemEMail *sitem = ( ItemEMail * ) aio;
1597 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1598 sitem = addrbook_person_remove_email( abf, person, sitem );
1600 addrcache_remove_email(abf->addressCache, sitem);
1601 addritem_free_item_email( sitem );
1603 addressbook_folder_refresh_one_person( clist, person );
1606 g_list_free( groups );
1607 g_list_free( persons );
1608 g_list_free( emails );
1609 g_list_free( list );
1610 addressbook_list_select_clear();
1612 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1613 addressbook_set_clist(
1614 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1618 addrbook_set_dirty(abf, TRUE);
1619 addressbook_export_to_file();
1620 addressbook_list_menu_setup();
1623 else if( pobj->type == ADDR_ITEM_GROUP ) {
1624 /* Items inside groups */
1625 list = addrselect_get_list( _addressSelect_ );
1629 node = g_list_next( node );
1630 aio = ( AddrItemObject * ) item->addressItem;
1631 if( aio->type == ITEMTYPE_EMAIL ) {
1632 ItemEMail *item = ( ItemEMail * ) aio;
1633 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1634 item = addrbook_person_remove_email( abf, person, item );
1636 addritem_free_item_email( item );
1640 g_list_free( list );
1641 addressbook_list_select_clear();
1642 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1643 addressbook_set_clist(
1644 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1648 addrbook_set_dirty(abf, TRUE);
1649 addressbook_export_to_file();
1650 addressbook_list_menu_setup();
1654 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1655 gtk_cmctree_remove_node( clist, nodeList );
1657 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1658 g_signal_handlers_unblock_by_func
1659 (G_OBJECT(addrbook.clist),
1660 G_CALLBACK(addressbook_list_row_unselected), NULL);
1663 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1665 addressbook_new_address_cb( NULL, NULL );
1668 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1671 gchar *address = NULL;
1673 if( aio->type == ITEMTYPE_EMAIL ) {
1674 ItemPerson *person = NULL;
1675 ItemEMail *email = ( ItemEMail * ) aio;
1677 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1678 if( email->address ) {
1679 if( ADDRITEM_NAME(email) ) {
1680 name = ADDRITEM_NAME(email);
1681 if( *name == '\0' ) {
1682 name = ADDRITEM_NAME(person);
1685 else if( ADDRITEM_NAME(person) ) {
1686 name = ADDRITEM_NAME(person);
1689 buf = g_strdup( email->address );
1691 address = email->address;
1694 else if( aio->type == ITEMTYPE_PERSON ) {
1695 ItemPerson *person = ( ItemPerson * ) aio;
1696 GList *node = person->listEMail;
1698 name = ADDRITEM_NAME(person);
1700 ItemEMail *email = ( ItemEMail * ) node->data;
1701 address = email->address;
1705 if( name && name[0] != '\0' ) {
1706 if( strchr_with_skip_quote( name, '"', ',' ) )
1707 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1709 buf = g_strdup_printf( "%s <%s>", name, address );
1712 buf = g_strdup( address );
1719 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1723 AddrSelectItem *item;
1724 AddrItemObject *aio;
1727 compose = addrbook.target_compose;
1728 if( ! compose ) return;
1730 /* Nothing selected, but maybe there is something in text entry */
1731 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1733 compose_entry_append(
1734 compose, addr, (ComposeEntryType)data , PREF_NONE);
1737 /* Select from address list */
1738 list = addrselect_get_list( _addressSelect_ );
1743 node = g_list_next( node );
1744 aio = item->addressItem;
1745 if( aio->type == ITEMTYPE_PERSON ||
1746 aio->type == ITEMTYPE_EMAIL ) {
1747 addr = addressbook_format_address( aio );
1748 compose_entry_append(
1749 compose, addr, (ComposeEntryType) data, PREF_NONE );
1752 else if( aio->type == ITEMTYPE_GROUP ) {
1753 ItemGroup *group = ( ItemGroup * ) aio;
1754 GList *nodeMail = group->listEMail;
1756 ItemEMail *email = nodeMail->data;
1758 addr = addressbook_format_address(
1759 ( AddrItemObject * ) email );
1760 compose_entry_append(
1761 compose, addr, (ComposeEntryType) data, PREF_NONE );
1763 nodeMail = g_list_next( nodeMail );
1768 AddressObject *obj = NULL;
1770 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1772 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1773 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1774 GList *nodeMail = itemGroup->listEMail;
1776 ItemEMail *email = nodeMail->data;
1778 addr = addressbook_format_address(
1779 ( AddrItemObject * ) email );
1780 compose_entry_append(
1781 compose, addr, (ComposeEntryType) data, PREF_NONE );
1783 nodeMail = g_list_next( nodeMail );
1787 g_list_free( list );
1790 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1792 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1797 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1798 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1800 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1801 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1802 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1803 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Merge", sensitive );
1804 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1805 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1808 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1809 gboolean canEdit = FALSE;
1810 gboolean canDelete = TRUE;
1811 gboolean canAdd = FALSE;
1812 gboolean canEditTr = TRUE;
1813 gboolean editAddress = FALSE;
1814 gboolean canExport = TRUE;
1815 AddressTypeControlItem *atci = NULL;
1816 AddressDataSource *ds = NULL;
1817 AddressInterface *iface = NULL;
1819 if( obj == NULL ) return;
1820 if( obj->type == ADDR_INTERFACE ) {
1821 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1822 iface = adapter->interface;
1824 if( iface->haveLibrary ) {
1825 /* Enable appropriate File / New command */
1826 atci = adapter->atci;
1827 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1830 canEditTr = canExport = FALSE;
1832 else if( obj->type == ADDR_DATASOURCE ) {
1833 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1834 ds = ads->dataSource;
1835 iface = ds->interface;
1836 if( ! iface->readOnly ) {
1837 canAdd = canEdit = editAddress = canDelete = TRUE;
1839 if( ! iface->haveLibrary ) {
1840 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1843 else if( obj->type == ADDR_ITEM_FOLDER ) {
1844 ds = addressbook_find_datasource( addrbook.treeSelected );
1846 iface = ds->interface;
1847 if( iface->readOnly ) {
1852 canAdd = editAddress = TRUE;
1856 else if( obj->type == ADDR_ITEM_GROUP ) {
1857 ds = addressbook_find_datasource( addrbook.treeSelected );
1859 iface = ds->interface;
1860 if( ! iface->readOnly ) {
1866 if( addrbook.listSelected == NULL )
1870 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1871 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1872 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1873 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1876 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1877 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1878 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1879 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1881 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1882 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1885 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1886 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1890 * Address book tree callback function that responds to selection of tree
1893 * \param ctree Tree widget.
1894 * \param node Node that was selected.
1895 * \param column Column number where selected occurred.
1896 * \param data Pointer to user data.
1898 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1899 gint column, gpointer data)
1901 AddressObject *obj = NULL;
1902 AdapterDSource *ads = NULL;
1903 AddressDataSource *ds = NULL;
1904 ItemFolder *rootFolder = NULL;
1905 AddressObjectType aot;
1907 addrbook.treeSelected = node;
1908 addrbook.listSelected = NULL;
1909 addressbook_status_show( "" );
1910 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1912 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1914 addressbook_set_clist(NULL, TRUE);
1917 addrbook.opened = node;
1919 if( obj->type == ADDR_DATASOURCE ) {
1920 /* Read from file */
1921 static gboolean tVal = TRUE;
1923 ads = ADAPTER_DSOURCE(obj);
1925 ds = ads->dataSource;
1926 if( ds == NULL ) return;
1928 if( addrindex_ds_get_modify_flag( ds ) ) {
1929 addrindex_ds_read_data( ds );
1932 if( ! addrindex_ds_get_read_flag( ds ) ) {
1933 addrindex_ds_read_data( ds );
1935 addressbook_ds_show_message( ds );
1937 if( ! addrindex_ds_get_access_flag( ds ) ) {
1938 /* Remove existing folders and groups */
1939 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1940 addressbook_tree_remove_children( ctree, node );
1941 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1943 /* Load folders into the tree */
1944 rootFolder = addrindex_ds_get_root_folder( ds );
1945 if( ds && ds->type == ADDR_IF_JPILOT ) {
1946 aot = ADDR_CATEGORY;
1948 else if( ds && ds->type == ADDR_IF_LDAP ) {
1949 aot = ADDR_LDAP_QUERY;
1952 aot = ADDR_ITEM_FOLDER;
1954 addressbook_node_add_folder( node, ds, rootFolder, aot );
1955 addrindex_ds_set_access_flag( ds, &tVal );
1956 gtk_cmctree_expand( ctree, node );
1959 addressbook_set_clist(NULL, TRUE);
1962 /* Update address list */
1963 g_signal_handlers_block_by_func
1965 G_CALLBACK(addressbook_tree_selected), NULL);
1966 addressbook_set_clist( obj, FALSE );
1967 g_signal_handlers_unblock_by_func
1969 G_CALLBACK(addressbook_tree_selected), NULL);
1970 if (!prefs_common.addressbook_use_editaddress_dialog)
1971 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1973 /* Setup main menu selections */
1974 addressbook_menubar_set_sensitive( FALSE );
1975 addressbook_menuitem_set_sensitive( obj, node );
1976 addressbook_list_select_clear();
1977 addressbook_list_menu_setup();
1982 * Setup address list popup menu items. Items are enabled or disabled as
1985 static void addressbook_list_menu_setup( void ) {
1986 GtkCMCTree *clist = NULL;
1987 AddressObject *pobj = NULL;
1988 AddressObject *obj = NULL;
1989 AdapterDSource *ads = NULL;
1990 AddressInterface *iface = NULL;
1991 AddressDataSource *ds = NULL;
1993 AddrItemObject *aio;
1994 AddrSelectItem *item;
1995 gboolean canEdit = FALSE;
1996 gboolean canDelete = FALSE;
1997 gboolean canCut = FALSE;
1998 gboolean canCopy = FALSE;
1999 gboolean canPaste = FALSE;
2000 gboolean canBrowse = FALSE;
2001 gboolean canMerge = FALSE;
2003 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2004 if( pobj == NULL ) return;
2006 clist = GTK_CMCTREE(addrbook.clist);
2007 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2008 if( obj == NULL ) canEdit = FALSE;
2010 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2011 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2013 if( pobj->type == ADDR_DATASOURCE ) {
2014 /* Parent object is a data source */
2015 ads = ADAPTER_DSOURCE(pobj);
2016 ds = ads->dataSource;
2019 iface = ds->interface;
2022 if( ! iface->readOnly ) {
2023 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2024 if (iface->type != ADDR_IF_LDAP)
2025 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2026 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2029 canDelete = canEdit;
2032 else if( pobj->type != ADDR_INTERFACE ) {
2033 /* Parent object is not an interface */
2034 ds = addressbook_find_datasource( addrbook.treeSelected );
2037 iface = ds->interface;
2040 if( ! iface->readOnly ) {
2041 /* Folder or group */
2042 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2043 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2044 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2045 if( obj ) canEdit = TRUE;
2048 if( pobj->type == ADDR_ITEM_FOLDER ) {
2049 if (iface->type != ADDR_IF_LDAP)
2050 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2051 if( obj ) canEdit = TRUE;
2053 canDelete = canEdit;
2055 if( iface->type == ADDR_IF_LDAP ) {
2056 if( obj ) canBrowse = TRUE;
2063 /* Enable cut and paste */
2064 if( ! addrclip_is_empty( _clipBoard_ ) )
2066 if( ! addrselect_test_empty( _addressSelect_ ) )
2068 /* Enable copy if something is selected */
2069 if( ! addrselect_test_empty( _addressSelect_ ) )
2073 /* Disable edit or browse if more than one row selected */
2074 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2079 /* Allow merging persons or emails are selected */
2080 list = _addressSelect_->listSelect;
2081 if (list && list->next ) {
2083 aio = ( AddrItemObject * ) item->addressItem;
2084 if( aio->type == ITEMTYPE_EMAIL ||
2085 aio->type == ITEMTYPE_PERSON ) {
2090 /* Forbid write changes when read-only */
2091 if( iface && iface->readOnly ) {
2098 /* Now go finalize menu items */
2099 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2103 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2104 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2106 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2107 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Merge", canMerge );
2109 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2110 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2111 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2113 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2114 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2115 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2116 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Merge", canMerge );
2118 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2119 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2121 if (addrbook.target_compose) {
2122 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2123 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2124 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2127 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2131 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2132 GtkCMCTreeNode *node,
2139 * Add list of items into tree node below specified tree node.
2140 * \param treeNode Tree node.
2141 * \param ds Data source.
2142 * \param listItems List of items.
2144 static void addressbook_treenode_add_list(
2145 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2151 AddrItemObject *aio;
2155 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2158 group = ( ItemGroup * ) aio;
2159 nn = addressbook_node_add_group( treeNode, ds, group );
2161 g_message("error adding addressbook group\n");
2164 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2167 folder = ( ItemFolder * ) aio;
2168 nn = addressbook_node_add_folder(
2169 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2171 g_message("error adding addressbook folder\n");
2174 node = g_list_next( node );
2178 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2179 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2183 * Cut from address list widget.
2185 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2186 _clipBoard_->cutFlag = TRUE;
2187 addrclip_clear( _clipBoard_ );
2188 addrclip_add( _clipBoard_, _addressSelect_ );
2189 /* addrclip_list_show( _clipBoard_, stdout ); */
2193 * Copy from address list widget.
2195 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2196 _clipBoard_->cutFlag = FALSE;
2197 addrclip_clear( _clipBoard_ );
2198 addrclip_add( _clipBoard_, _addressSelect_ );
2199 /* addrclip_list_show( _clipBoard_, stdout ); */
2203 * Paste clipboard into address list widget.
2205 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2206 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2207 AddressObject *pobj = NULL;
2208 AddressDataSource *ds = NULL;
2209 AddressBookFile *abf = NULL;
2210 ItemFolder *folder = NULL;
2211 GList *folderGroup = NULL;
2213 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2214 if( ds == NULL ) return;
2215 if( addrindex_ds_get_readonly( ds ) ) {
2216 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2220 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2222 if( pobj->type == ADDR_ITEM_FOLDER ) {
2223 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2225 else if( pobj->type == ADDR_ITEM_GROUP ) {
2226 alertpanel_error( _("Cannot paste into an address group.") );
2231 /* Get an address book */
2232 abf = addressbook_get_book_file();
2233 if( abf == NULL ) return;
2235 if( _clipBoard_->cutFlag ) {
2237 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2239 /* Remove all groups and folders in clipboard from tree node */
2240 addressbook_treenode_remove_item();
2242 /* Remove all "cut" items */
2243 addrclip_delete_item( _clipBoard_ );
2245 /* Clear clipboard - cut items??? */
2246 addrclip_clear( _clipBoard_ );
2250 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2253 /* addrclip_list_show( _clipBoard_, stdout ); */
2255 /* Update tree by inserting node for each folder or group */
2256 addressbook_treenode_add_list(
2257 addrbook.treeSelected, ds, folderGroup );
2258 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2259 g_list_free( folderGroup );
2263 /* Display items pasted */
2264 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2265 addressbook_set_clist(
2266 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2274 * Add current treenode object to clipboard. Note that widget only allows
2275 * one entry from the tree list to be selected.
2277 static void addressbook_treenode_to_clipboard( void ) {
2278 AddressObject *obj = NULL;
2279 AddressDataSource *ds = NULL;
2280 AddrSelectItem *item;
2281 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2282 GtkCMCTreeNode *node;
2284 node = addrbook.treeSelected;
2285 if( node == NULL ) return;
2286 obj = gtk_cmctree_node_get_row_data( ctree, node );
2287 if( obj == NULL ) return;
2289 ds = addressbook_find_datasource( node );
2290 if( ds == NULL ) return;
2293 if( obj->type == ADDR_ITEM_FOLDER ) {
2294 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2295 ItemFolder *folder = adapter->itemFolder;
2297 item = addrselect_create_node( obj );
2298 item->uid = g_strdup( ADDRITEM_ID(folder) );
2300 else if( obj->type == ADDR_ITEM_GROUP ) {
2301 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2302 ItemGroup *group = adapter->itemGroup;
2304 item = addrselect_create_node( obj );
2305 item->uid = g_strdup( ADDRITEM_ID(group) );
2307 else if( obj->type == ADDR_DATASOURCE ) {
2309 item = addrselect_create_node( obj );
2314 /* Clear existing list and add item into list */
2317 addressbook_list_select_clear();
2318 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2319 addrselect_list_add( _addressSelect_, item, cacheID );
2325 * Cut from tree widget.
2327 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2328 _clipBoard_->cutFlag = TRUE;
2329 addressbook_treenode_to_clipboard();
2330 addrclip_clear( _clipBoard_ );
2331 addrclip_add( _clipBoard_, _addressSelect_ );
2332 /* addrclip_list_show( _clipBoard_, stdout ); */
2336 * Copy from tree widget.
2338 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2339 _clipBoard_->cutFlag = FALSE;
2340 addressbook_treenode_to_clipboard();
2341 addrclip_clear( _clipBoard_ );
2342 addrclip_add( _clipBoard_, _addressSelect_ );
2343 /* addrclip_list_show( _clipBoard_, stdout ); */
2347 * Paste clipboard into address tree widget.
2349 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2350 addressbook_clip_paste_cb(NULL,NULL);
2354 * Clear selected entries in clipboard.
2356 static void addressbook_list_select_clear( void ) {
2357 addrselect_list_clear( _addressSelect_ );
2361 * Add specified address item to selected address list.
2362 * \param aio Address item object.
2363 * \param ds Datasource.
2365 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2368 if( ds == NULL ) return;
2369 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2370 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2375 * Remove specified address item from selected address list.
2376 * \param aio Address item object.
2378 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2379 addrselect_list_remove( _addressSelect_, aio );
2383 * Invoke EMail compose window with addresses in selected address list.
2385 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2388 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2389 listAddress = addrselect_build_list( _addressSelect_ );
2390 compose_new_with_list( NULL, listAddress );
2391 mgu_free_dlist( listAddress );
2396 static void addressbook_merge_list( AddrSelectList *list ) {
2397 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2398 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2399 AddressObject *pobj;
2400 AddressDataSource *ds = NULL;
2402 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
2403 cm_return_if_fail(pobj != NULL);
2405 ds = addressbook_find_datasource( addrbook.treeSelected );
2406 if( ds == NULL ) return;
2408 addrmerge_merge(clist, pobj, ds, list);
2412 * Merge selected entries in the address list
2414 static void addressbook_merge_cb( GtkAction *action, gpointer data ) {
2415 if( addrselect_test_empty( _addressSelect_ ) )
2418 addressbook_merge_list( _addressSelect_ );
2421 static void addressbook_list_row_selected( GtkCMCTree *clist,
2422 GtkCMCTreeNode *node,
2426 AddrItemObject *aio = NULL;
2427 AddressObject *pobj = NULL;
2428 AdapterDSource *ads = NULL;
2429 AddressDataSource *ds = NULL;
2431 addrbook.listSelected = node;
2433 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2434 if( pobj == NULL ) return;
2436 if( pobj->type == ADDR_DATASOURCE ) {
2437 ads = ADAPTER_DSOURCE(pobj);
2438 ds = ads->dataSource;
2440 else if( pobj->type != ADDR_INTERFACE ) {
2441 ds = addressbook_find_datasource( addrbook.treeSelected );
2444 aio = gtk_cmctree_node_get_row_data( clist, node );
2446 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2447 addressbook_list_select_add( aio, ds );
2450 addressbook_list_menu_setup();
2452 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2453 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2455 if (obj && obj->type != ADDR_ITEM_GROUP)
2456 addressbook_edit_address(NULL, 0, NULL, FALSE);
2460 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2461 GtkCMCTreeNode *node,
2465 AddrItemObject *aio;
2467 aio = gtk_cmctree_node_get_row_data( ctree, node );
2469 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2470 addressbook_list_select_remove( aio );
2473 if (!prefs_common.addressbook_use_editaddress_dialog)
2474 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2477 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2479 addressbook_lup_clicked(NULL, NULL);
2482 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2483 GdkEventButton *event,
2486 if( ! event ) return FALSE;
2488 addressbook_list_menu_setup();
2490 if( event->button == 3 ) {
2491 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2492 event->button, event->time );
2493 } else if (event->button == 1) {
2494 if (event->type == GDK_2BUTTON_PRESS) {
2495 if (prefs_common.add_address_by_click &&
2496 addrbook.target_compose)
2497 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2499 if (prefs_common.addressbook_use_editaddress_dialog)
2500 addressbook_edit_address_cb(NULL, NULL);
2502 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2503 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2504 if( obj && obj->type == ADDR_ITEM_GROUP )
2505 addressbook_edit_address_cb(NULL, NULL);
2513 static gboolean addressbook_list_button_released(GtkWidget *widget,
2514 GdkEventButton *event,
2520 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2521 GdkEventButton *event,
2524 GtkCMCList *clist = GTK_CMCLIST(ctree);
2526 AddressObject *obj = NULL;
2527 AdapterDSource *ads = NULL;
2528 AddressInterface *iface = NULL;
2529 AddressDataSource *ds = NULL;
2530 gboolean canEdit = FALSE;
2531 gboolean canDelete = FALSE;
2532 gboolean canCut = FALSE;
2533 gboolean canCopy = FALSE;
2534 gboolean canPaste = FALSE;
2535 gboolean canTreeCut = FALSE;
2536 gboolean canTreeCopy = FALSE;
2537 gboolean canTreePaste = FALSE;
2538 gboolean canLookup = FALSE;
2539 GtkCMCTreeNode *node = NULL;
2541 if( ! event ) return FALSE;
2542 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2544 if (event->button == 1) {
2545 if (event->type == GDK_2BUTTON_PRESS) {
2546 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2547 gtkut_clist_set_focus_row(clist, row);
2548 obj = gtk_cmclist_get_row_data( clist, row );
2553 if (obj->type == ADDR_ITEM_GROUP ||
2554 obj->type == ADDR_DATASOURCE) {
2556 addressbook_treenode_edit_cb(NULL, NULL);
2558 /* expand pr collapse */
2559 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2560 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2566 addressbook_menubar_set_sensitive( FALSE );
2568 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2569 gtkut_clist_set_focus_row(clist, row);
2570 obj = gtk_cmclist_get_row_data( clist, row );
2573 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2577 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2579 if( ! addrclip_is_empty( _clipBoard_ ) )
2580 canTreePaste = TRUE;
2582 if (obj->type == ADDR_INTERFACE) {
2583 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2584 iface = adapter->interface;
2587 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2588 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2590 if( iface->externalQuery )
2593 if (obj->type == ADDR_DATASOURCE) {
2595 ads = ADAPTER_DSOURCE(obj);
2596 ds = ads->dataSource;
2599 iface = ds->interface;
2602 if( !iface->readOnly ) {
2603 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2604 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2605 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2611 else if (obj->type == ADDR_ITEM_FOLDER) {
2613 ds = addressbook_find_datasource( node );
2616 iface = ds->interface;
2619 if( !iface->readOnly ) {
2623 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2624 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2625 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2629 if( iface->externalQuery ) {
2630 /* Enable deletion of LDAP folder */
2634 else if (obj->type == ADDR_ITEM_GROUP) {
2636 ds = addressbook_find_datasource( node );
2639 iface = ds->interface;
2642 if( ! iface->readOnly ) {
2645 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2646 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2650 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2652 if( ! addrselect_test_empty( _addressSelect_ ) )
2654 if( ! addrclip_is_empty( _clipBoard_ ) )
2657 /* Forbid write changes when read-only */
2658 if( iface && iface->readOnly ) {
2660 canTreePaste = FALSE;
2667 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2668 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2669 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2670 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2671 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2673 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2674 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2675 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2676 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2677 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2679 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2680 addrbook.target_compose != NULL);
2682 if( event->button == 3 )
2683 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2684 event->button, event->time);
2689 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2690 GdkEventButton *event,
2693 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2697 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2699 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2700 AddressObject *obj = NULL;
2701 AddressDataSource *ds = NULL;
2702 AddressBookFile *abf = NULL;
2703 ItemFolder *parentFolder = NULL;
2704 ItemFolder *folder = NULL;
2706 if( ! addrbook.treeSelected ) return;
2707 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2708 if( obj == NULL ) return;
2709 ds = addressbook_find_datasource( addrbook.treeSelected );
2710 if( ds == NULL ) return;
2712 if( obj->type == ADDR_DATASOURCE ) {
2713 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2715 else if( obj->type == ADDR_ITEM_FOLDER ) {
2716 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2722 abf = ds->rawDataSource;
2723 if( abf == NULL ) return;
2724 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2727 nn = addressbook_node_add_folder(
2728 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2730 g_message("error adding addressbook folder\n");
2732 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2733 if( addrbook.treeSelected == addrbook.opened )
2734 addressbook_set_clist(obj, TRUE);
2738 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2740 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2741 AddressObject *obj = NULL;
2742 AddressDataSource *ds = NULL;
2743 AddressBookFile *abf = NULL;
2744 ItemFolder *parentFolder = NULL;
2745 ItemGroup *group = NULL;
2747 if( ! addrbook.treeSelected ) return;
2748 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2749 if( obj == NULL ) return;
2750 ds = addressbook_find_datasource( addrbook.treeSelected );
2751 if( ds == NULL ) return;
2753 if( obj->type == ADDR_DATASOURCE ) {
2754 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2756 else if( obj->type == ADDR_ITEM_FOLDER ) {
2757 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2763 abf = ds->rawDataSource;
2764 if( abf == NULL ) return;
2765 group = addressbook_edit_group( abf, parentFolder, NULL );
2768 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2770 g_message("error adding addressbook group\n");
2772 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2773 if( addrbook.treeSelected == addrbook.opened )
2774 addressbook_set_clist(obj, TRUE);
2778 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2780 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2783 GdkPixbuf *pix_cl, *pix_op;
2784 gboolean is_leaf, expanded;
2786 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2788 &is_leaf, &expanded);
2789 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2796 * \param obj Address object to edit.
2797 * \param node Node in tree.
2798 * \return New name of data source.
2800 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2801 gchar *newName = NULL;
2802 AddressDataSource *ds = NULL;
2803 AddressInterface *iface = NULL;
2804 AdapterDSource *ads = NULL;
2806 ds = addressbook_find_datasource( node );
2807 if( ds == NULL ) return NULL;
2808 iface = ds->interface;
2809 if( ! iface->haveLibrary ) return NULL;
2811 /* Read data from data source */
2812 if( addrindex_ds_get_modify_flag( ds ) ) {
2813 addrindex_ds_read_data( ds );
2816 if( ! addrindex_ds_get_read_flag( ds ) ) {
2817 addrindex_ds_read_data( ds );
2821 ads = ADAPTER_DSOURCE(obj);
2822 if( ads->subType == ADDR_BOOK ) {
2823 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2825 else if( ads->subType == ADDR_VCARD ) {
2826 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2829 else if( ads->subType == ADDR_JPILOT ) {
2830 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2834 else if( ads->subType == ADDR_LDAP ) {
2835 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2841 newName = obj->name;
2846 * Edit an object that is in the address tree area.
2848 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2850 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2852 AddressDataSource *ds = NULL;
2853 AddressBookFile *abf = NULL;
2854 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2857 if( ! addrbook.treeSelected ) return;
2858 node = addrbook.treeSelected;
2859 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2860 obj = gtk_cmctree_node_get_row_data( ctree, node );
2861 if( obj == NULL ) return;
2862 parentNode = GTK_CMCTREE_ROW(node)->parent;
2864 ds = addressbook_find_datasource( node );
2865 if( ds == NULL ) return;
2867 if( obj->type == ADDR_DATASOURCE ) {
2868 name = addressbook_edit_datasource( obj, node );
2869 if( name == NULL ) return;
2872 abf = ds->rawDataSource;
2873 if( abf == NULL ) return;
2874 if( obj->type == ADDR_ITEM_FOLDER ) {
2875 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2876 ItemFolder *item = adapter->itemFolder;
2877 ItemFolder *parentFolder = NULL;
2878 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2879 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2880 name = ADDRITEM_NAME(item);
2882 else if( obj->type == ADDR_ITEM_GROUP ) {
2883 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2884 ItemGroup *item = adapter->itemGroup;
2885 ItemFolder *parentFolder = NULL;
2886 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2887 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2888 name = ADDRITEM_NAME(item);
2891 if( name && parentNode ) {
2892 /* Update node in tree view */
2893 addressbook_change_node_name( node, name );
2894 gtk_sctree_sort_node(ctree, parentNode);
2895 gtk_cmctree_expand( ctree, node );
2896 gtk_sctree_select( GTK_SCTREE( ctree), node );
2903 ADDRTREE_DEL_FOLDER_ONLY,
2904 ADDRTREE_DEL_FOLDER_ADDR
2908 * Delete an item from the tree widget.
2909 * \param data Data passed in.
2910 * \param action Action.
2911 * \param widget Widget issuing callback.
2913 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2915 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2916 GtkCMCTreeNode *node = NULL;
2920 AddrBookBase *adbase;
2921 AddressCache *cache;
2922 AdapterDSource *ads = NULL;
2923 AddressInterface *iface = NULL;
2924 AddressDataSource *ds = NULL;
2925 gboolean remFlag = FALSE;
2926 TreeItemDelType delType;
2928 if( ! addrbook.treeSelected ) return;
2929 node = addrbook.treeSelected;
2930 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2932 obj = gtk_cmctree_node_get_row_data( ctree, node );
2933 cm_return_if_fail(obj != NULL);
2935 if( obj->type == ADDR_DATASOURCE ) {
2936 ads = ADAPTER_DSOURCE(obj);
2938 ds = ads->dataSource;
2939 if( ds == NULL ) return;
2942 /* Must be folder or something else */
2943 ds = addressbook_find_datasource( node );
2944 if( ds == NULL ) return;
2946 /* Only allow deletion from non-readOnly */
2947 iface = ds->interface;
2948 if( iface->readOnly ) {
2949 /* Allow deletion of query results */
2950 if( ! iface->externalQuery ) return;
2954 /* Confirm deletion */
2955 delType = ADDRTREE_DEL_NONE;
2956 if( obj->type == ADDR_ITEM_FOLDER ) {
2957 if( iface && iface->externalQuery ) {
2958 message = g_strdup_printf( _(
2959 "Do you want to delete the query " \
2960 "results and addresses in '%s'?" ),
2962 aval = alertpanel( _("Delete"), message,
2963 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND );
2965 if( aval == G_ALERTALTERNATE ) {
2966 delType = ADDRTREE_DEL_FOLDER_ADDR;
2970 message = g_strdup_printf
2971 ( _( "Do you want to delete '%s'? "
2972 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2974 aval = alertpanel( _("Delete folder"), message,
2975 GTK_STOCK_CANCEL, _("Delete _folder only"), _("Delete folder and _addresses"), ALERTFOCUS_SECOND);
2977 if( aval == G_ALERTALTERNATE ) {
2978 delType = ADDRTREE_DEL_FOLDER_ONLY;
2980 else if( aval == G_ALERTOTHER ) {
2981 delType = ADDRTREE_DEL_FOLDER_ADDR;
2985 else if( obj->type == ADDR_ITEM_GROUP ) {
2986 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2987 "The addresses it contains will not be lost."), obj->name);
2988 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2989 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2991 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2993 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2994 "The addresses it contains will be lost."), obj->name);
2995 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2996 GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
2998 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
3000 if( delType == ADDRTREE_DEL_NONE ) return;
3002 /* Proceed with deletion */
3003 if( obj->type == ADDR_DATASOURCE ) {
3004 /* Remove node from tree */
3005 gtk_cmctree_remove_node( ctree, node );
3007 if (delType == ADDRTREE_DEL_DATA &&
3008 ds->interface && ds->interface->type == ADDR_IF_BOOK)
3009 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
3011 /* Remove data source. */
3012 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
3013 addrindex_free_datasource( ds );
3018 /* Get reference to cache */
3019 adbase = ( AddrBookBase * ) ds->rawDataSource;
3020 if( adbase == NULL ) return;
3021 cache = adbase->addressCache;
3023 /* Remove query results folder */
3024 if( iface && iface->externalQuery ) {
3025 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3026 ItemFolder *folder = adapter->itemFolder;
3028 adapter->itemFolder = NULL;
3030 g_print( "remove folder for ::%s::\n", obj->name );
3031 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3032 g_print( "-------------- remove results\n" );
3034 addrindex_remove_results( ds, folder );
3035 /* g_print( "-------------- remove node\n" ); */
3036 gtk_cmctree_remove_node( ctree, node );
3040 /* Code below is valid for regular address book deletion */
3041 if( obj->type == ADDR_ITEM_FOLDER ) {
3042 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3043 ItemFolder *item = adapter->itemFolder;
3045 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3046 /* Remove folder only */
3047 item = addrcache_remove_folder( cache, item );
3049 addritem_free_item_folder( item );
3050 addressbook_move_nodes_up( ctree, node );
3054 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3055 /* Remove folder and addresses */
3056 item = addrcache_remove_folder_delete( cache, item );
3058 addritem_free_item_folder( item );
3063 else if( obj->type == ADDR_ITEM_GROUP ) {
3064 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3065 ItemGroup *item = adapter->itemGroup;
3067 item = addrcache_remove_group( cache, item );
3069 addritem_free_item_group( item );
3076 gtk_cmctree_remove_node(ctree, node );
3080 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3082 if( person && addrbook.treeSelected == addrbook.opened ) {
3083 person->status = ADD_ENTRY;
3084 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3085 addressbook_folder_refresh_one_person(
3086 GTK_CMCTREE(addrbook.clist), person );
3088 addressbook_address_list_set_focus();
3091 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3093 if( person && addrbook.treeSelected == addrbook.opened) {
3094 person->status = ADD_ENTRY;
3095 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3096 addressbook_set_clist(
3097 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3101 addressbook_address_list_set_focus();
3105 * Label (a format string) that is used to name each folder.
3107 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3110 * Search ctree widget callback function.
3111 * \param pA Pointer to node.
3112 * \param pB Pointer to data item being sought.
3113 * \return Zero (0) if folder found.
3115 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3118 aoA = ( AddressObject * ) pA;
3119 if( aoA->type == ADDR_ITEM_FOLDER ) {
3120 ItemFolder *folder, *fld;
3122 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3123 folder = ( ItemFolder * ) pB;
3124 if( fld == folder ) return 0; /* Found folder */
3129 static ItemFolder * addressbook_setup_subf(
3130 AddressDataSource *ds, gchar *title,
3131 GtkCMCTreeNode *pNode )
3133 AddrBookBase *adbase;
3134 AddressCache *cache;
3137 GtkCMCTreeNode *nNode;
3139 AddressObjectType aoType = ADDR_NONE;
3142 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3144 if( ds && ds->type == ADDR_IF_LDAP ) {
3146 aoType = ADDR_LDAP_QUERY;
3153 ctree = GTK_CMCTREE(addrbook.ctree);
3154 /* Get reference to address cache */
3155 adbase = ( AddrBookBase * ) ds->rawDataSource;
3156 cache = adbase->addressCache;
3158 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3159 GList *cur = children;
3160 for (; cur; cur = cur->next) {
3161 ItemFolder *child = (ItemFolder *) cur->data;
3162 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3163 nNode = gtk_cmctree_find_by_row_data_custom(
3165 addressbook_treenode_find_folder_cb );
3167 addrindex_remove_results( ds, child );
3168 while( child->listPerson ) {
3169 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3170 item = addrcache_remove_person( cache, item );
3172 addritem_free_item_person( item );
3176 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3177 addrbook.treeSelected = nNode;
3184 /* Create a folder */
3185 folder = addrcache_add_new_folder( cache, NULL );
3186 name = g_strdup_printf( "%s", title );
3187 addritem_folder_set_name( folder, name );
3188 addritem_folder_set_remarks( folder, "" );
3191 /* Now let's see the folder */
3192 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3193 gtk_cmctree_expand( ctree, pNode );
3195 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3196 addrbook.treeSelected = nNode;
3202 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3203 AddressObject *pobj = NULL;
3204 AddressDataSource *ds = NULL;
3205 AddressBookFile *abf = NULL;
3206 debug_print("adding address\n");
3207 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3208 if( pobj == NULL ) {
3209 debug_print("no row data\n");
3212 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3214 debug_print("no datasource\n");
3218 abf = ds->rawDataSource;
3220 g_print("no addressbook file\n");
3224 if( pobj->type == ADDR_DATASOURCE ) {
3225 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3226 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3228 ItemFolder *folder = NULL;
3230 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3231 GtkCMCTreeNode *parentNode;
3232 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3233 if( ds == NULL ) return;
3235 /* We must have a datasource that is an external interface */
3236 if( ! ds->interface->haveLibrary ) return;
3237 if( ! ds->interface->externalQuery ) return;
3239 if( pobj->type == ADDR_ITEM_FOLDER ) {
3240 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3243 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3245 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3247 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3249 abf = ds->rawDataSource;
3252 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3253 addrbook.editaddress_vbox,
3254 addressbook_new_address_from_book_post_cb,
3257 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3258 LdapServer *server = ds->rawDataSource;
3259 ldapsvr_set_modified(server, TRUE);
3260 ldapsvr_update_book(server, NULL);
3261 if (server->retVal != LDAPRC_SUCCESS) {
3262 alertpanel( _("Add address(es)"),
3263 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3264 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3265 server->retVal = LDAPRC_SUCCESS;
3270 if (prefs_common.addressbook_use_editaddress_dialog)
3271 addressbook_new_address_from_book_post_cb( person );
3274 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3276 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3279 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3280 GtkCMCTreeNode *parentNode;
3281 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3282 if( ds == NULL ) return;
3284 /* We must have a datasource that is an external interface */
3285 if( ! ds->interface->haveLibrary ) return;
3286 if( ! ds->interface->externalQuery ) return;
3288 if( pobj->type == ADDR_ITEM_FOLDER ) {
3289 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3292 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3294 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3298 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3300 abf = ds->rawDataSource;
3303 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3304 addrbook.editaddress_vbox,
3305 addressbook_new_address_from_folder_post_cb,
3308 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3309 LdapServer *server = ds->rawDataSource;
3310 ldapsvr_set_modified(server, TRUE);
3311 ldapsvr_update_book(server, NULL);
3312 if (server->retVal != LDAPRC_SUCCESS) {
3313 alertpanel( _("Add address(es)"),
3314 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3315 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST );
3320 if (prefs_common.addressbook_use_editaddress_dialog)
3321 addressbook_new_address_from_folder_post_cb( person );
3323 else if( pobj->type == ADDR_ITEM_GROUP ) {
3324 /* New address in group */
3325 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3326 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3327 if (addrbook.treeSelected == addrbook.opened) {
3328 /* Change node name in tree. */
3329 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3330 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3331 addressbook_set_clist(
3332 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3340 * Search for specified child group node in address index tree.
3341 * \param parent Parent node.
3342 * \param group Group to find.
3344 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3345 GtkCMCTreeNode *node = NULL;
3346 GtkCMCTreeRow *currRow;
3348 currRow = GTK_CMCTREE_ROW( parent );
3350 node = currRow->children;
3354 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3355 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3356 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3357 if( g == group ) return node;
3359 currRow = GTK_CMCTREE_ROW(node);
3360 node = currRow->sibling;
3366 static AddressBookFile *addressbook_get_book_file() {
3367 AddressBookFile *abf = NULL;
3368 AddressDataSource *ds = NULL;
3370 ds = addressbook_find_datasource( addrbook.treeSelected );
3371 if( ds == NULL ) return NULL;
3372 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3376 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3377 GtkCMCTreeNode *node;
3380 /* Remove existing folders and groups */
3381 row = GTK_CMCTREE_ROW( parent );
3383 while( (node = row->children) ) {
3384 gtk_cmctree_remove_node( ctree, node );
3389 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3390 GtkCMCTreeNode *parent, *child;
3391 GtkCMCTreeRow *currRow;
3392 currRow = GTK_CMCTREE_ROW( node );
3394 parent = currRow->parent;
3395 while( (child = currRow->children) ) {
3396 gtk_cmctree_move( ctree, child, parent, node );
3398 gtk_sctree_sort_node( ctree, parent );
3402 static void addressbook_edit_address_post_cb( ItemPerson *person )
3406 AddressBookFile *abf = addressbook_get_book_file();
3408 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3409 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3410 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3413 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3414 invalidate_address_completion();
3416 addressbook_address_list_set_focus();
3419 void addressbook_address_list_set_focus( void )
3421 if (!prefs_common.addressbook_use_editaddress_dialog) {
3422 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3423 addressbook_list_menu_setup();
3427 void addressbook_address_list_disable_some_actions(void)
3429 /* disable address copy/pasting when editing contact's detail (embedded form) */
3430 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3431 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3432 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3435 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3436 addressbook_edit_address(data, 0, NULL, TRUE);
3439 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3440 gboolean force_focus ) {
3441 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3443 AddressObject *obj = NULL, *pobj = NULL;
3444 AddressDataSource *ds = NULL;
3445 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3447 AddressBookFile *abf = NULL;
3449 if( addrbook.listSelected == NULL ) return;
3450 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3451 cm_return_if_fail(obj != NULL);
3453 ctree = GTK_CMCTREE( addrbook.ctree );
3454 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3456 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3457 if( ds == NULL ) return;
3459 abf = addressbook_get_book_file();
3461 if( obj->type == ADDR_ITEM_EMAIL ) {
3462 ItemEMail *email = ( ItemEMail * ) obj;
3464 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3465 /* Edit parent group */
3466 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3467 ItemGroup *itemGrp = adapter->itemGroup;
3468 if( abf == NULL ) return;
3469 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3470 name = ADDRITEM_NAME(itemGrp);
3471 node = addrbook.treeSelected;
3472 parentNode = GTK_CMCTREE_ROW(node)->parent;
3475 /* Edit person - email page */
3477 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3478 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3479 addressbook_edit_address_post_cb,
3480 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3483 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3484 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3485 person->status = UPDATE_ENTRY;
3488 if (prefs_common.addressbook_use_editaddress_dialog)
3489 addressbook_edit_address_post_cb( person );
3494 else if( obj->type == ADDR_ITEM_PERSON ) {
3495 /* Edit person - basic page */
3496 ItemPerson *person = ( ItemPerson * ) obj;
3497 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3498 addressbook_edit_address_post_cb,
3499 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3502 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3503 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3504 person->status = UPDATE_ENTRY;
3507 if (prefs_common.addressbook_use_editaddress_dialog)
3508 addressbook_edit_address_post_cb( person );
3512 else if( obj->type == ADDR_ITEM_GROUP ) {
3513 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3514 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3515 parentNode = addrbook.treeSelected;
3516 node = addressbook_find_group_node( parentNode, itemGrp );
3517 name = ADDRITEM_NAME(itemGrp);
3518 invalidate_address_completion();
3524 /* Update tree node with node name */
3525 if( node == NULL ) return;
3526 addressbook_change_node_name( node, name );
3527 gtk_sctree_sort_node( ctree, parentNode );
3528 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3529 addressbook_set_clist(
3530 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3535 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3537 addressbook_del_clicked(NULL, NULL);
3540 static void close_cb(GtkAction *action, gpointer data)
3542 addressbook_close();
3545 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3546 addressbook_export_to_file();
3549 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3551 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3552 if( person ) addritem_person_set_opened( person, TRUE );
3556 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3558 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3559 if( person ) addritem_person_set_opened( person, FALSE );
3563 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3565 gchar *eMailAlias = ADDRITEM_NAME(email);
3566 if( eMailAlias && *eMailAlias != '\0' ) {
3568 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3571 str = g_strdup( eMailAlias );
3577 static gboolean addressbook_match_item(const gchar *name,
3578 const gchar *email_alias,
3580 const gchar *remarks,
3585 if (!str || str[0] == '\0')
3587 if (strcasestr(name, str))
3589 else if (email_alias && strcasestr(email_alias, str))
3591 else if (addr && strcasestr(addr, str))
3593 else if (remarks && strcasestr(remarks, str))
3599 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3600 GList *items = itemGroup->listEMail;
3601 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3602 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3603 for( ; items != NULL; items = g_list_next( items ) ) {
3604 GtkCMCTreeNode *nodeEMail = NULL;
3605 gchar *text[N_LIST_COLS];
3606 ItemEMail *email = items->data;
3610 if( ! email ) continue;
3612 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3614 if( !addressbook_match_item(ADDRITEM_NAME(person),
3615 ADDRITEM_NAME(email),
3616 email->address, email->remarks,
3620 str = addressbook_format_item_clist( person, email );
3622 text[COL_NAME] = addressbook_set_col_name_guard(str);
3625 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3627 text[COL_ADDRESS] = email->address;
3628 text[COL_REMARKS] = email->remarks;
3629 nodeEMail = gtk_sctree_insert_node(
3631 text, FOLDER_SPACING,
3635 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3641 gchar *addressbook_set_col_name_guard(gchar *value)
3643 gchar *ret = "<not set>";
3644 gchar *tmp = g_strdup(value);
3646 if (tmp !=NULL && *tmp != '\0')
3652 static void addressbook_folder_load_one_person(
3653 GtkCMCTree *clist, ItemPerson *person,
3654 AddressTypeControlItem *atci,
3655 AddressTypeControlItem *atciMail )
3657 GtkCMCTreeNode *nodePerson = NULL;
3658 GtkCMCTreeNode *nodeEMail = NULL;
3659 gchar *text[N_LIST_COLS];
3660 gboolean flgFirst = TRUE, haveAddr = FALSE;
3663 AddressBookFile *abf = addressbook_get_book_file();
3666 if( person == NULL ) return;
3668 text[COL_NAME] = "";
3669 node = person->listEMail;
3671 ItemEMail *email = node->data;
3672 gchar *eMailAddr = NULL;
3673 node = g_list_next( node );
3675 text[COL_ADDRESS] = email->address;
3676 text[COL_REMARKS] = email->remarks;
3677 eMailAddr = ADDRITEM_NAME(email);
3678 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3680 /* First email belongs with person */
3681 gchar *str = addressbook_format_item_clist( person, email );
3683 text[COL_NAME] = addressbook_set_col_name_guard(str);
3686 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3687 person && person->nickName ) {
3688 if (person->nickName) {
3689 if (strcmp(person->nickName, "") != 0) {
3690 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3693 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3699 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3701 nodePerson = gtk_sctree_insert_node(
3703 text, FOLDER_SPACING,
3706 FALSE, person->isOpened );
3709 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3712 /* Subsequent email is a child node of person */
3713 text[COL_NAME] = ADDRITEM_NAME(email);
3714 nodeEMail = gtk_sctree_insert_node(
3715 clist, nodePerson, NULL,
3716 text, FOLDER_SPACING,
3718 atciMail->iconXpmOpen,
3720 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3726 /* Have name without EMail */
3727 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3728 text[COL_ADDRESS] = "";
3729 text[COL_REMARKS] = "";
3730 nodePerson = gtk_sctree_insert_node(
3732 text, FOLDER_SPACING,
3735 FALSE, person->isOpened );
3736 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3741 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3743 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3744 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3745 const gchar *search_str;
3747 if( atci == NULL ) return;
3748 if( atciMail == NULL ) return;
3750 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3752 /* Load email addresses */
3753 items = addritem_folder_get_person_list( itemFolder );
3754 for(cur = items ; cur != NULL; cur = g_list_next( cur ) ) {
3759 person = (ItemPerson *)cur->data;
3762 node = person->listEMail;
3763 if (node && node->data) {
3765 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3768 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3772 addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
3774 /* Free up the list */
3775 mgu_clear_list( items );
3776 g_list_free( items );
3779 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3780 addrbook.listSelected = NULL;
3781 gtk_cmctree_remove_node( clist, node );
3782 addressbook_menubar_set_sensitive( FALSE );
3783 addressbook_menuitem_set_sensitive(
3784 gtk_cmctree_node_get_row_data(
3785 GTK_CMCTREE(clist), addrbook.treeSelected ),
3786 addrbook.treeSelected );
3789 void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3790 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3791 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3792 GtkCMCTreeNode *node;
3793 if( atci == NULL ) return;
3794 if( atciMail == NULL ) return;
3795 if( person == NULL ) return;
3796 /* unload the person */
3798 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3800 addressbook_folder_remove_node( clist, node );
3801 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3802 gtk_sctree_sort_node( clist, NULL );
3803 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3805 gtk_sctree_select( GTK_SCTREE(clist), node );
3806 if (!gtk_cmctree_node_is_visible( clist, node ) )
3807 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3811 void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3812 GtkCMCTreeNode *node;
3814 if( person == NULL ) return;
3815 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3817 addressbook_folder_remove_node( clist, node );
3821 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3823 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3824 const gchar *search_str;
3826 /* Load any groups */
3827 if( ! atci ) return;
3829 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3831 items = addritem_folder_get_group_list( itemFolder );
3832 for( ; items != NULL; items = g_list_next( items ) ) {
3833 GtkCMCTreeNode *nodeGroup = NULL;
3834 gchar *text[N_LIST_COLS];
3835 ItemGroup *group = items->data;
3836 if( group == NULL ) continue;
3837 if( !addressbook_match_item(ADDRITEM_NAME(group),
3838 NULL, NULL, NULL, search_str) )
3841 text[COL_NAME] = ADDRITEM_NAME(group);
3842 text[COL_ADDRESS] = "";
3843 text[COL_REMARKS] = "";
3844 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3845 text, FOLDER_SPACING,
3849 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3850 gtk_sctree_sort_node(clist, NULL);
3852 /* Free up the list */
3853 mgu_clear_list( items );
3854 g_list_free( items );
3858 * Search ctree widget callback function.
3859 * \param pA Pointer to node.
3860 * \param pB Pointer to data item being sought.
3861 * \return Zero (0) if group found.
3863 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3866 aoA = ( AddressObject * ) pA;
3867 if( aoA->type == ADDR_ITEM_GROUP ) {
3868 ItemGroup *group, *grp;
3870 grp = ADAPTER_GROUP(aoA)->itemGroup;
3871 group = ( ItemGroup * ) pB;
3872 if( grp == group ) return 0; /* Found group */
3878 * Remove folder and group nodes from tree widget for items contained ("cut")
3881 static void addressbook_treenode_remove_item( void ) {
3883 AddrSelectItem *cutItem;
3884 AddressCache *cache;
3885 AddrItemObject *aio;
3886 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3889 node = _clipBoard_->objectList;
3891 cutItem = node->data;
3892 node = g_list_next( node );
3893 cache = addrindex_get_cache(
3894 _clipBoard_->addressIndex, cutItem->cacheID );
3895 if( cache == NULL ) continue;
3896 aio = addrcache_get_object( cache, cutItem->uid );
3899 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3902 folder = ( ItemFolder * ) aio;
3903 tn = gtk_cmctree_find_by_row_data_custom(
3904 ctree, NULL, folder,
3905 addressbook_treenode_find_folder_cb );
3907 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3910 group = ( ItemGroup * ) aio;
3911 tn = gtk_cmctree_find_by_row_data_custom(
3913 addressbook_treenode_find_group_cb );
3917 /* Free up adapter and remove node. */
3918 gtk_cmctree_remove_node( ctree, tn );
3925 * Find parent datasource for specified tree node.
3926 * \param node Node to test.
3927 * \return Data source, or NULL if not found.
3929 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3930 AddressDataSource *ds = NULL;
3933 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3936 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3937 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3939 /* g_print( "ao->type = %d\n", ao->type ); */
3940 if( ao->type == ADDR_DATASOURCE ) {
3941 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3942 /* g_print( "found it\n" ); */
3943 ds = ads->dataSource;
3947 node = GTK_CMCTREE_ROW(node)->parent;
3953 * Load address list widget with children of specified object.
3954 * \param obj Parent object to be loaded.
3956 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3957 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3958 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3959 AddressDataSource *ds = NULL;
3960 AdapterDSource *ads = NULL;
3961 static AddressObject *last_obj = NULL;
3963 if (addrbook.clist == NULL) {
3966 if (obj == last_obj && !refresh)
3971 gtk_cmclist_clear(clist);
3975 if( obj->type == ADDR_INTERFACE ) {
3976 /* g_print( "set_clist: loading datasource...\n" ); */
3977 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3981 gtk_cmclist_freeze(clist);
3982 gtk_cmclist_clear(clist);
3984 if( obj->type == ADDR_DATASOURCE ) {
3985 ads = ADAPTER_DSOURCE(obj);
3986 ds = ads->dataSource;
3988 /* Load root folder */
3989 ItemFolder *rootFolder = NULL;
3990 rootFolder = addrindex_ds_get_root_folder( ds );
3991 addressbook_folder_load_person(
3992 ctreelist, rootFolder );
3993 addressbook_folder_load_group(
3994 ctreelist, rootFolder );
3998 if( obj->type == ADDR_ITEM_GROUP ) {
4000 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
4001 addressbook_load_group( ctreelist, itemGroup );
4003 else if( obj->type == ADDR_ITEM_FOLDER ) {
4005 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
4006 addressbook_folder_load_person( ctreelist, itemFolder );
4007 addressbook_folder_load_group( ctreelist, itemFolder );
4010 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
4011 clist->focus_row = -1;
4012 gtk_cmclist_thaw(clist);
4016 * Call back function to free adaptor. Call back is setup by function
4017 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
4018 * called when the address book tree widget node is removed by calling
4019 * function gtk_cmctree_remove_node().
4021 * \param data Tree node's row data.
4023 static void addressbook_free_treenode( gpointer data ) {
4026 ao = ( AddressObject * ) data;
4027 if( ao == NULL ) return;
4028 if( ao->type == ADDR_INTERFACE ) {
4029 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
4030 addrbookctl_free_interface( ai );
4032 else if( ao->type == ADDR_DATASOURCE ) {
4033 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
4034 addrbookctl_free_datasource( ads );
4036 else if( ao->type == ADDR_ITEM_FOLDER ) {
4037 AdapterFolder *af = ADAPTER_FOLDER(ao);
4038 addrbookctl_free_folder( af );
4040 else if( ao->type == ADDR_ITEM_GROUP ) {
4041 AdapterGroup *ag = ADAPTER_GROUP(ao);
4042 addrbookctl_free_group( ag );
4047 * Create new adaptor for specified data source.
4049 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4050 AddressObjectType otype, gchar *name )
4052 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4053 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4054 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4055 adapter->dataSource = ds;
4056 adapter->subType = otype;
4060 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4061 ADDRESS_OBJECT_NAME(adapter) =
4062 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4066 * Load tree from address index with the initial data.
4068 static void addressbook_load_tree( void ) {
4069 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4070 GList *nodeIf, *nodeDS;
4071 AdapterInterface *adapter;
4072 AddressInterface *iface;
4073 AddressTypeControlItem *atci;
4074 AddressDataSource *ds;
4075 AdapterDSource *ads;
4076 GtkCMCTreeNode *node, *newNode;
4079 nodeIf = _addressInterfaceList_;
4081 adapter = nodeIf->data;
4082 node = adapter->treeNode;
4083 iface = adapter->interface;
4084 atci = adapter->atci;
4086 if( iface->useInterface ) {
4087 /* Load data sources below interface node */
4088 nodeDS = iface->listSource;
4091 name = addrindex_ds_get_name( ds );
4092 ads = addressbook_create_ds_adapter(
4093 ds, atci->objectType, name );
4094 newNode = addressbook_add_object(
4095 node, ADDRESS_OBJECT(ads) );
4096 if (newNode == NULL) {
4097 g_message("error adding addressbook object\n");
4099 nodeDS = g_list_next( nodeDS );
4101 gtk_cmctree_expand( ctree, node );
4104 nodeIf = g_list_next( nodeIf );
4109 * Convert the old address book to new format.
4111 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4112 gboolean retVal = FALSE;
4113 gboolean errFlag = TRUE;
4116 /* Read old address book, performing conversion */
4117 debug_print( "Reading and converting old address book...\n" );
4118 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4119 addrindex_read_data( addrIndex );
4120 if( addrIndex->retVal == MGU_NO_FILE ) {
4121 /* We do not have a file - new user */
4122 debug_print( "New user... create new books...\n" );
4123 addrindex_create_new_books( addrIndex );
4124 if( addrIndex->retVal == MGU_SUCCESS ) {
4125 /* Save index file */
4126 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4127 addrindex_save_data( addrIndex );
4128 if( addrIndex->retVal == MGU_SUCCESS ) {
4133 msg = _( "New user, could not save index file." );
4137 msg = _( "New user, could not save address book files." );
4141 /* We have an old file */
4142 if( addrIndex->wasConverted ) {
4143 /* Converted successfully - save address index */
4144 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4145 addrindex_save_data( addrIndex );
4146 if( addrIndex->retVal == MGU_SUCCESS ) {
4147 msg = _( "Old address book converted successfully." );
4152 msg = _("Old address book converted,\n"
4153 "could not save new address index file." );
4157 /* File conversion failed - just create new books */
4158 debug_print( "File conversion failed... just create new books...\n" );
4159 addrindex_create_new_books( addrIndex );
4160 if( addrIndex->retVal == MGU_SUCCESS ) {
4162 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4163 addrindex_save_data( addrIndex );
4164 if( addrIndex->retVal == MGU_SUCCESS ) {
4165 msg = _("Could not convert address book,\n"
4166 "but created empty new address book files." );
4171 msg = _("Could not convert address book,\n"
4172 "could not save new address index file." );
4176 msg = _("Could not convert address book\n"
4177 "and could not create new address book files." );
4182 debug_print( "Error\n%s\n", msg );
4183 alertpanel_full(_("Addressbook conversion error"), msg,
4184 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4188 debug_print( "Warning\n%s\n", msg );
4189 alertpanel_full(_("Addressbook conversion error"), msg,
4190 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4191 NULL, ALERT_WARNING);
4197 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4201 gboolean failed = FALSE;
4202 GError *error = NULL;
4204 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4205 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4206 error->code, error->message);
4207 g_error_free(error);
4211 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4212 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4215 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4217 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4219 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4232 /* all copies succeeded, we can remove source files */
4233 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4234 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4235 error->code, error->message);
4236 g_error_free(error);
4239 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4240 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4243 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4245 claws_unlink(orig_file);
4255 void addressbook_read_file( void ) {
4256 AddressIndex *addrIndex = NULL;
4257 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4259 debug_print( "Reading address index...\n" );
4260 if( _addressIndex_ ) {
4261 debug_print( "address book already read!!!\n" );
4266 addrIndex = addrindex_create_index();
4267 addrindex_initialize();
4269 /* Use new address book index. */
4271 if ( !is_dir_exist(indexdir) ) {
4272 if ( make_dir(indexdir) < 0 ) {
4273 addrindex_set_file_path( addrIndex, get_rc_dir() );
4274 g_warning( "couldn't create dir '%s'", indexdir);
4276 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4277 remove_dir_recursive(indexdir);
4278 addrindex_set_file_path( addrIndex, get_rc_dir() );
4279 g_error("couldn't migrate dir %s", indexdir);
4281 addrindex_set_file_path( addrIndex, indexdir);
4285 addrindex_set_file_path( addrIndex, indexdir);
4288 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4289 addrindex_read_data( addrIndex );
4290 if( addrIndex->retVal == MGU_NO_FILE ) {
4291 /* Conversion required */
4292 debug_print( "Converting...\n" );
4293 if( addressbook_convert( addrIndex ) ) {
4294 _addressIndex_ = addrIndex;
4297 else if( addrIndex->retVal == MGU_SUCCESS ) {
4298 _addressIndex_ = addrIndex;
4301 /* Error reading address book */
4302 debug_print( "Could not read address index.\n" );
4303 addrindex_print_index( addrIndex, stdout );
4304 alertpanel_full(_("Addressbook Error"),
4305 _("Could not read address index"),
4306 GTK_STOCK_CLOSE, NULL, NULL, ALERTFOCUS_FIRST, FALSE,
4309 debug_print( "done.\n" );
4313 * Add object into the address index tree widget.
4314 * Enter: node Parent node.
4315 * obj Object to add.
4316 * Return: Node that was added, or NULL if object not added.
4318 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4321 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4322 GtkCMCTreeNode *added;
4323 AddressObject *pobj;
4324 AddressObjectType otype;
4325 AddressTypeControlItem *atci = NULL;
4327 cm_return_val_if_fail(node != NULL, NULL);
4328 cm_return_val_if_fail(obj != NULL, NULL);
4330 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4331 cm_return_val_if_fail(pobj != NULL, NULL);
4333 /* Determine object type to be displayed */
4334 if( obj->type == ADDR_DATASOURCE ) {
4335 otype = ADAPTER_DSOURCE(obj)->subType;
4341 /* Handle any special conditions. */
4343 atci = addrbookctl_lookup( otype );
4345 if( atci->showInTree ) {
4346 /* Add object to tree */
4349 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4350 atci->iconXpm, atci->iconXpmOpen,
4351 atci->treeLeaf, atci->treeExpand );
4352 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4353 addressbook_free_treenode );
4357 gtk_sctree_sort_node(ctree, node);
4363 * Add group into the address index tree.
4364 * \param node Parent node.
4365 * \param ds Data source.
4366 * \param itemGroup Group to add.
4367 * \return Inserted node.
4369 static GtkCMCTreeNode *addressbook_node_add_group(
4370 GtkCMCTreeNode *node, AddressDataSource *ds,
4371 ItemGroup *itemGroup )
4373 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4374 GtkCMCTreeNode *newNode;
4375 AdapterGroup *adapter;
4376 AddressTypeControlItem *atci = NULL;
4379 if( ds == NULL ) return NULL;
4380 if( node == NULL || itemGroup == NULL ) return NULL;
4382 name = &itemGroup->obj.name;
4384 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4386 adapter = g_new0( AdapterGroup, 1 );
4387 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4388 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4389 adapter->itemGroup = itemGroup;
4391 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4392 atci->iconXpm, atci->iconXpm,
4393 atci->treeLeaf, atci->treeExpand );
4394 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4395 addressbook_free_treenode );
4396 gtk_sctree_sort_node( ctree, node );
4401 * Add folder into the address index tree. Only visible folders are loaded into
4402 * the address index tree. Note that the root folder is not inserted into the
4405 * \param node Parent node.
4406 * \param ds Data source.
4407 * \param itemFolder Folder to add.
4408 * \param otype Object type to display.
4409 * \return Inserted node for the folder.
4411 static GtkCMCTreeNode *addressbook_node_add_folder(
4412 GtkCMCTreeNode *node, AddressDataSource *ds,
4413 ItemFolder *itemFolder, AddressObjectType otype )
4415 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4416 GtkCMCTreeNode *newNode = NULL;
4417 AdapterFolder *adapter;
4418 AddressTypeControlItem *atci = NULL;
4419 GList *listItems = NULL;
4421 ItemFolder *rootFolder;
4423 /* Only visible folders */
4424 if( itemFolder == NULL || itemFolder->isHidden )
4429 if( node == NULL || itemFolder == NULL )
4432 /* Determine object type */
4433 atci = addrbookctl_lookup( otype );
4437 rootFolder = addrindex_ds_get_root_folder( ds );
4438 if( itemFolder == rootFolder ) {
4442 adapter = g_new0( AdapterFolder, 1 );
4443 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4444 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4445 adapter->itemFolder = itemFolder;
4447 name = ADDRITEM_NAME(itemFolder);
4448 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4449 atci->iconXpm, atci->iconXpm,
4450 atci->treeLeaf, atci->treeExpand );
4452 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4453 addressbook_free_treenode );
4457 listItems = itemFolder->listFolder;
4458 while( listItems ) {
4459 ItemFolder *item = listItems->data;
4460 addressbook_node_add_folder( newNode, ds, item, otype );
4461 listItems = g_list_next( listItems );
4463 listItems = itemFolder->listGroup;
4464 while( listItems ) {
4465 ItemGroup *item = listItems->data;
4466 addressbook_node_add_group( newNode, ds, item );
4467 listItems = g_list_next( listItems );
4469 gtk_sctree_sort_node( ctree, node );
4473 void addressbook_export_to_file( void ) {
4474 if( _addressIndex_ ) {
4475 /* Save all new address book data */
4476 debug_print( "Saving address books...\n" );
4477 addrindex_save_all_books( _addressIndex_ );
4479 debug_print( "Exporting addressbook to file...\n" );
4480 addrindex_save_data( _addressIndex_ );
4481 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4482 addrindex_print_index( _addressIndex_, stdout );
4485 /* Notify address completion of new data */
4486 invalidate_address_completion();
4490 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4492 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4493 addressbook_lup_clicked(NULL, NULL);
4498 * Comparison using cell contents (text in first column). Used for sort
4499 * address index widget.
4501 static gint addressbook_treenode_compare_func(
4502 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4504 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4505 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4506 gchar *name1 = NULL, *name2 = NULL;
4507 if( cell1 ) name1 = cell1->u.text;
4508 if( cell2 ) name2 = cell2->u.text;
4509 if( ! name1 ) return ( name2 != NULL );
4510 if( ! name2 ) return -1;
4511 return g_utf8_collate( name1, name2 );
4514 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4515 AdapterDSource *ads;
4516 AdapterInterface *adapter;
4517 GtkCMCTreeNode *newNode;
4519 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4520 if( adapter == NULL ) return;
4521 ads = addressbook_edit_book( _addressIndex_, NULL );
4523 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4525 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4526 addrbook.treeSelected = newNode;
4531 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4532 AdapterDSource *ads;
4533 AdapterInterface *adapter;
4534 GtkCMCTreeNode *newNode;
4536 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4537 if( adapter == NULL ) return;
4538 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4540 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4542 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4543 addrbook.treeSelected = newNode;
4549 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4550 AdapterDSource *ads;
4551 AdapterInterface *adapter;
4552 AddressInterface *iface;
4553 GtkCMCTreeNode *newNode;
4555 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4556 if( adapter == NULL ) return;
4557 iface = adapter->interface;
4558 if( ! iface->haveLibrary ) return;
4559 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4561 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4563 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4564 addrbook.treeSelected = newNode;
4571 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4572 AdapterDSource *ads;
4573 AdapterInterface *adapter;
4574 AddressInterface *iface;
4575 GtkCMCTreeNode *newNode;
4577 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4578 if( adapter == NULL ) return;
4579 iface = adapter->interface;
4580 if( ! iface->haveLibrary ) return;
4581 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4583 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4585 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4586 addrbook.treeSelected = newNode;
4593 * Display address search status message.
4594 * \param queryType Query type.
4595 * \param status Status/Error code.
4597 static void addressbook_search_message( gint queryType, gint sts ) {
4599 *addressbook_msgbuf = '\0';
4601 if( sts != MGU_SUCCESS ) {
4602 if( queryType == ADDRQUERY_LDAP ) {
4604 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4609 g_snprintf( addressbook_msgbuf,
4610 sizeof(addressbook_msgbuf), "%s", desc );
4611 addressbook_status_show( addressbook_msgbuf );
4614 addressbook_status_show( "" );
4619 * Refresh addressbook by forcing refresh of current selected object in
4622 static void addressbook_refresh_current( void ) {
4626 ctree = GTK_CMCTREE(addrbook.ctree);
4627 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4628 if( obj == NULL ) return;
4629 addressbook_set_clist( obj, TRUE );
4633 * Message that is displayed whilst a query is executing in a background
4636 static gchar *_tempMessage_ = N_( "Busy searching..." );
4639 * Address search idle function. This function is called during UI idle time
4640 * while a search is in progress.
4642 * \param data Idler data.
4644 static void addressbook_search_idle( gpointer data ) {
4648 queryID = GPOINTER_TO_INT( data );
4649 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4654 * Search completion callback function. This removes the query from the idle
4657 * \param sender Sender of query.
4658 * \param queryID Query ID of search request.
4659 * \param status Search status.
4660 * \param data Query data.
4662 static void addressbook_search_callback_end(
4663 gpointer sender, gint queryID, gint status, gpointer data )
4667 AddrQueryObject *aqo;
4669 /* Remove idler function */
4670 ptrQID = GINT_TO_POINTER( queryID );
4672 g_idle_remove_by_data( ptrQID );
4675 /* Refresh addressbook contents */
4676 addressbook_refresh_current();
4677 req = qrymgr_find_request( queryID );
4679 aqo = ( AddrQueryObject * ) req->queryList->data;
4680 addressbook_search_message( aqo->queryType, status );
4683 /* Stop the search */
4684 addrindex_stop_search( queryID );
4690 * \param ds Data source to search.
4691 * \param searchTerm String to lookup.
4692 * \param pNode Parent data source node.
4694 static void addressbook_perform_search(
4695 AddressDataSource *ds, gchar *searchTerm,
4696 GtkCMCTreeNode *pNode )
4704 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4706 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4708 /* Create a folder for the search results */
4709 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4710 folder = addressbook_setup_subf(ds, name, pNode);
4713 /* Setup the search */
4714 queryID = addrindex_setup_explicit_search(
4715 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4716 if( queryID == 0 ) return;
4718 /* Set up idler function */
4719 idleID = g_idle_add(
4720 (GSourceFunc) addressbook_search_idle,
4721 GINT_TO_POINTER( queryID ) );
4723 g_message("error adding addressbook_search_idle\n");
4726 /* Start search, sit back and wait for something to happen */
4727 addrindex_start_search( queryID );
4729 addressbook_status_show( _tempMessage_ );
4733 * Lookup button handler. Address search is only performed against
4734 * address interfaces for external queries.
4736 * \param button Lookup button widget.
4737 * \param data Data object.
4739 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4742 AddressDataSource *ds;
4743 AddressInterface *iface;
4745 GtkCMCTreeNode *node, *parentNode;
4747 LdapServer *ldap_server;
4748 LdapControl *ldap_ctl;
4751 node = addrbook.treeSelected;
4752 if( ! node ) return;
4753 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4755 ctree = GTK_CMCTREE(addrbook.ctree);
4756 obj = gtk_cmctree_node_get_row_data( ctree, node );
4757 if( obj == NULL ) return;
4759 if (obj->type != ADDR_DATASOURCE ||
4760 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4761 addressbook_set_clist(
4762 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4763 addrbook.treeSelected),
4767 ds = addressbook_find_datasource( node );
4768 if( ds == NULL ) return;
4770 /* We must have a datasource that is an external interface */
4771 iface = ds->interface;
4772 if( ! iface->haveLibrary ) return;
4773 if( ! iface->externalQuery ) return;
4776 if (iface->type == ADDR_IF_LDAP) {
4777 ldap_server = ds->rawDataSource;
4778 ldap_ctl = ldap_server->control;
4779 if (ldap_ctl != NULL &&
4780 ldap_ctl->bindDN != NULL && strlen(ldap_ctl->bindDN) > 0) {
4781 #ifndef PASSWORD_CRYPTO_OLD
4782 /* LDAP server is password-protected. */
4783 if (master_passphrase() == NULL) {
4784 /* User did not enter master passphrase, do not start a search. */
4787 #endif /* PASSWORD_CRYPTO_OLD */
4790 #endif /* USE_LDAP */
4793 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4794 g_strchomp( searchTerm );
4796 if( obj->type == ADDR_ITEM_FOLDER ) {
4797 parentNode = GTK_CMCTREE_ROW(node)->parent;
4802 addressbook_perform_search( ds, searchTerm, parentNode );
4804 gtk_widget_grab_focus( addrbook.entry );
4806 g_free( searchTerm );
4809 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4810 addressbook_close();
4815 * Browse address entry for highlighted entry.
4817 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4819 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4821 AddressDataSource *ds;
4822 AddressInterface *iface;
4826 if(addrbook.listSelected == NULL)
4829 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4833 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4837 iface = ds->interface;
4838 if(!iface || !iface->haveLibrary )
4842 if (obj->type == ADDR_ITEM_EMAIL) {
4843 email = ( ItemEMail * ) obj;
4845 person = (ItemPerson *) ADDRITEM_PARENT(email);
4847 else if (obj->type == ADDR_ITEM_PERSON) {
4848 person = (ItemPerson *) obj;
4855 if( iface && iface->type == ADDR_IF_LDAP ) {
4856 browseldap_entry(ds, person->externalID);
4861 /* **********************************************************************
4862 * Build lookup tables.
4863 * ***********************************************************************
4867 * Remap object types.
4868 * Enter: abType AddressObjectType (used in tree node).
4869 * Return: ItemObjectType (used in address cache data).
4871 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4872 ItemObjectType ioType;
4875 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4876 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4877 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4878 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4879 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4880 default: ioType = ITEMTYPE_NONE; break;
4885 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4886 atci = addrbookctl_lookup(id); \
4888 atci->iconXpm = icon; \
4889 atci->iconXpmOpen = iconopen; \
4891 g_warning("can't get atci %d", id); \
4896 * Build table that controls the rendering of object types.
4898 static void addrbookctl_build_icons( GtkWidget *window ) {
4899 AddressTypeControlItem *atci;
4903 g_object_unref(interfacexpm);
4905 g_object_unref(folderxpm);
4907 g_object_unref(folderopenxpm);
4909 g_object_unref(groupxpm);
4911 g_object_unref(vcardxpm);
4913 g_object_unref(bookxpm);
4915 g_object_unref(addressxpm);
4917 g_object_unref(jpilotxpm);
4919 g_object_unref(categoryxpm);
4921 g_object_unref(ldapxpm);
4923 g_object_unref(addrsearchxpm);
4924 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4925 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4926 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4927 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4928 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4929 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4930 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4931 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4932 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4933 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4934 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4936 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4937 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4938 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4939 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4940 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4941 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4942 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4943 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4944 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4945 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4946 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4951 * Build table that controls the rendering of object types.
4953 static void addrbookctl_build_map( GtkWidget *window ) {
4954 AddressTypeControlItem *atci;
4956 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4957 _addressBookTypeList_ = NULL;
4960 atci = g_new0( AddressTypeControlItem, 1 );
4961 atci->objectType = ADDR_INTERFACE;
4962 atci->interfaceType = ADDR_IF_NONE;
4963 atci->showInTree = TRUE;
4964 atci->treeExpand = TRUE;
4965 atci->treeLeaf = FALSE;
4966 atci->displayName = _( "Interface" );
4967 atci->menuCommand = NULL;
4968 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4969 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4972 atci = g_new0( AddressTypeControlItem, 1 );
4973 atci->objectType = ADDR_BOOK;
4974 atci->interfaceType = ADDR_IF_BOOK;
4975 atci->showInTree = TRUE;
4976 atci->treeExpand = TRUE;
4977 atci->treeLeaf = FALSE;
4978 atci->displayName = _("Address Books");
4979 atci->menuCommand = "Menu/Book/NewBook";
4980 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4981 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4984 atci = g_new0( AddressTypeControlItem, 1 );
4985 atci->objectType = ADDR_ITEM_PERSON;
4986 atci->interfaceType = ADDR_IF_NONE;
4987 atci->showInTree = FALSE;
4988 atci->treeExpand = FALSE;
4989 atci->treeLeaf = FALSE;
4990 atci->displayName = _( "Person" );
4991 atci->menuCommand = NULL;
4992 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4993 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4996 atci = g_new0( AddressTypeControlItem, 1 );
4997 atci->objectType = ADDR_ITEM_EMAIL;
4998 atci->interfaceType = ADDR_IF_NONE;
4999 atci->showInTree = FALSE;
5000 atci->treeExpand = FALSE;
5001 atci->treeLeaf = TRUE;
5002 atci->displayName = _( "Email Address" );
5003 atci->menuCommand = NULL;
5004 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5005 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5008 atci = g_new0( AddressTypeControlItem, 1 );
5009 atci->objectType = ADDR_ITEM_GROUP;
5010 atci->interfaceType = ADDR_IF_BOOK;
5011 atci->showInTree = TRUE;
5012 atci->treeExpand = FALSE;
5013 atci->treeLeaf = FALSE;
5014 atci->displayName = _( "Group" );
5015 atci->menuCommand = NULL;
5016 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5017 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5020 atci = g_new0( AddressTypeControlItem, 1 );
5021 atci->objectType = ADDR_ITEM_FOLDER;
5022 atci->interfaceType = ADDR_IF_BOOK;
5023 atci->showInTree = TRUE;
5024 atci->treeExpand = FALSE;
5025 atci->treeLeaf = FALSE;
5026 atci->displayName = _( "Folder" );
5027 atci->menuCommand = NULL;
5028 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5029 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5032 atci = g_new0( AddressTypeControlItem, 1 );
5033 atci->objectType = ADDR_VCARD;
5034 atci->interfaceType = ADDR_IF_VCARD;
5035 atci->showInTree = TRUE;
5036 atci->treeExpand = TRUE;
5037 atci->treeLeaf = TRUE;
5038 atci->displayName = _( "vCard" );
5039 atci->menuCommand = "Menu/Book/NewVCard";
5040 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5041 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5044 atci = g_new0( AddressTypeControlItem, 1 );
5045 atci->objectType = ADDR_JPILOT;
5046 atci->interfaceType = ADDR_IF_JPILOT;
5047 atci->showInTree = TRUE;
5048 atci->treeExpand = TRUE;
5049 atci->treeLeaf = FALSE;
5050 atci->displayName = _( "JPilot" );
5051 atci->menuCommand = "Menu/Book/NewJPilot";
5052 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5053 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5056 atci = g_new0( AddressTypeControlItem, 1 );
5057 atci->objectType = ADDR_CATEGORY;
5058 atci->interfaceType = ADDR_IF_JPILOT;
5059 atci->showInTree = TRUE;
5060 atci->treeExpand = TRUE;
5061 atci->treeLeaf = TRUE;
5062 atci->displayName = _( "JPilot" );
5063 atci->menuCommand = NULL;
5064 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5065 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5068 atci = g_new0( AddressTypeControlItem, 1 );
5069 atci->objectType = ADDR_LDAP;
5070 atci->interfaceType = ADDR_IF_LDAP;
5071 atci->showInTree = TRUE;
5072 atci->treeExpand = TRUE;
5073 atci->treeLeaf = FALSE;
5074 atci->displayName = _( "LDAP servers" );
5075 atci->menuCommand = "Menu/Book/NewLDAPServer";
5076 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5077 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5080 atci = g_new0( AddressTypeControlItem, 1 );
5081 atci->objectType = ADDR_LDAP_QUERY;
5082 atci->interfaceType = ADDR_IF_LDAP;
5083 atci->showInTree = TRUE;
5084 atci->treeExpand = FALSE;
5085 atci->treeLeaf = TRUE;
5086 atci->displayName = _( "LDAP Query" );
5087 atci->menuCommand = NULL;
5088 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5089 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5091 addrbookctl_build_icons(window);
5094 void addressbook_reflect_prefs_pixmap_theme(void)
5096 if (addrbook.window)
5097 addrbookctl_build_icons(addrbook.window);
5101 * Search for specified object type.
5103 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5105 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5109 * Search for specified interface type.
5111 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5112 GList *node = _addressBookTypeList_;
5114 AddressTypeControlItem *atci = node->data;
5115 if( atci->interfaceType == ifType ) return atci;
5116 node = g_list_next( node );
5121 static void addrbookctl_free_address( AddressObject *obj ) {
5122 g_free( obj->name );
5123 obj->type = ADDR_NONE;
5127 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5128 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5129 adapter->interface = NULL;
5130 adapter->interfaceType = ADDR_IF_NONE;
5131 adapter->atci = NULL;
5132 adapter->enabled = FALSE;
5133 adapter->haveLibrary = FALSE;
5134 adapter->treeNode = NULL;
5138 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5139 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5140 adapter->dataSource = NULL;
5141 adapter->subType = ADDR_NONE;
5145 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5146 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5147 adapter->itemFolder = NULL;
5151 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5152 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5153 adapter->itemGroup = NULL;
5158 * Build GUI interface list.
5160 static void addrbookctl_build_iflist( void ) {
5161 AddressTypeControlItem *atci;
5162 AdapterInterface *adapter;
5165 if( _addressIndex_ == NULL ) {
5166 _addressIndex_ = addrindex_create_index();
5167 if( _clipBoard_ == NULL ) {
5168 _clipBoard_ = addrclip_create();
5170 addrclip_set_index( _clipBoard_, _addressIndex_ );
5172 _addressInterfaceList_ = NULL;
5173 list = addrindex_get_interface_list( _addressIndex_ );
5175 AddressInterface *interface = list->data;
5176 atci = addrbookctl_lookup_iface( interface->type );
5178 adapter = g_new0( AdapterInterface, 1 );
5179 adapter->interfaceType = interface->type;
5180 adapter->atci = atci;
5181 adapter->interface = interface;
5182 adapter->treeNode = NULL;
5183 adapter->enabled = TRUE;
5184 adapter->haveLibrary = interface->haveLibrary;
5185 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5186 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5187 _addressInterfaceList_ =
5188 g_list_append( _addressInterfaceList_, adapter );
5190 list = g_list_next( list );
5195 * Find GUI interface type specified interface type.
5196 * \param ifType Interface type.
5197 * \return Interface item, or NULL if not found.
5199 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5200 GList *node = _addressInterfaceList_;
5202 AdapterInterface *adapter = node->data;
5203 if( adapter->interfaceType == ifType ) return adapter;
5204 node = g_list_next( node );
5210 * Build interface list selection.
5212 static void addrbookctl_build_ifselect( void ) {
5213 GList *newList = NULL;
5218 gchar *endptr = NULL;
5219 /* gboolean enabled; */
5220 AdapterInterface *adapter;
5222 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5225 splitStr = g_strsplit( selectStr, ",", -1 );
5226 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5228 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5229 ifType = strtol( splitStr[i], &endptr, 10 );
5232 if( strcmp( endptr, "/n" ) == 0 ) {
5237 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5238 adapter = addrbookctl_find_interface( ifType );
5240 newList = g_list_append( newList, adapter );
5247 /* g_print( "i=%d\n", i ); */
5248 g_strfreev( splitStr );
5249 g_free( selectStr );
5251 /* Replace existing list */
5252 mgu_clear_list( _addressIFaceSelection_ );
5253 g_list_free( _addressIFaceSelection_ );
5254 _addressIFaceSelection_ = newList;
5258 /* ***********************************************************************
5259 * Add sender to address book.
5260 * ***********************************************************************
5264 * This function is used by the Add sender to address book function.
5266 gboolean addressbook_add_contact(
5267 const gchar *name, const gchar *address, const gchar *remarks,
5268 GdkPixbuf *picture )
5270 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5271 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5272 debug_print( "addressbook_add_contact - added\n" );
5273 addressbook_refresh();
5278 /* ***********************************************************************
5279 * Book/folder selection.
5280 * ***********************************************************************
5284 * This function is used by the matcher dialog to select a book/folder.
5286 gchar *addressbook_folder_selection( const gchar *folderpath)
5288 AddressBookFile *book = NULL;
5289 ItemFolder *folder = NULL;
5292 cm_return_val_if_fail( folderpath != NULL, NULL);
5294 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5296 if ( folder != NULL) {
5298 gchar *oldtmp = NULL;
5299 AddrItemObject *obj = NULL;
5301 /* walk thru folder->parent to build the full folder path */
5302 /* TODO: wwp: optimize this */
5304 tmp = g_strdup(obj->uid);
5305 while ( obj->parent ) {
5307 if ( obj->name != NULL ) {
5308 oldtmp = g_strdup(tmp);
5310 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5314 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5317 path = g_strdup_printf("%s", book->fileName);
5319 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5325 /* ***********************************************************************
5326 * Book/folder checking.
5327 * ***********************************************************************
5330 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5332 FolderInfo *fi = g_new0( FolderInfo, 1 );
5334 fi->folder = folder;
5338 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5339 FolderInfo *fiParent, FolderPathMatch *match )
5345 FolderPathMatch *nextmatch = NULL;
5350 list = parentFolder->listFolder;
5352 folder = list->data;
5353 fName = g_strdup( ADDRITEM_NAME(folder) );
5355 /* match folder name, match pointer will be set to NULL if next recursive call
5356 doesn't need to match subfolder name */
5357 if ( match != NULL &&
5358 match->matched == FALSE ) {
5359 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5360 /* folder name matches, prepare next subfolder match */
5361 debug_print("matched folder name '%s'\n", fName);
5363 if ( match->folder_path[match->index] == NULL ) {
5364 /* we've matched all elements */
5365 match->matched = TRUE;
5366 match->folder = folder;
5367 debug_print("book/folder path matched!\n");
5369 /* keep on matching */
5377 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5378 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5380 list = g_list_next( list );
5385 * This function is used by to check if a matcher book/folder path corresponds to an
5386 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5387 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5388 if book AND folder are NULL this means that folderpath was empty or Any.
5389 If folderpath is a simple book name (without folder), book will not be NULL and folder
5390 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5393 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5394 AddressDataSource **book,
5395 ItemFolder **folder )
5397 AddressDataSource *ds;
5398 GList *list, *nodeDS;
5399 ItemFolder *rootFolder;
5400 AddressBookFile *abf;
5402 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5409 if ( folderpath == NULL )
5412 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5415 /* split the folder path we've received, we'll try to match this path, subpath by
5416 subpath against the book/folder structure in order */
5417 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5418 if (!folder_path_match.folder_path)
5421 list = addrindex_get_interface_list( _addressIndex_ );
5422 while ( list && !folder_path_match.matched ) {
5423 AddressInterface *interface = list->data;
5424 if ( interface && interface->type == ADDR_IF_BOOK ) {
5425 nodeDS = interface->listSource;
5426 while ( nodeDS && !folder_path_match.matched ) {
5429 /* Read address book */
5430 if( ! addrindex_ds_get_read_flag( ds ) ) {
5431 addrindex_ds_read_data( ds );
5434 /* Add node for address book */
5435 abf = ds->rawDataSource;
5437 /* match book name */
5438 if ( abf && abf->fileName &&
5439 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5441 debug_print("matched book name '%s'\n", abf->fileName);
5442 folder_path_match.book = ds;
5444 if ( folder_path_match.folder_path[1] == NULL ) {
5445 /* no folder part to match */
5447 folder_path_match.matched = TRUE;
5448 folder_path_match.folder = NULL;
5449 debug_print("book path matched!\n");
5452 /* match folder part */
5454 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5455 rootFolder = addrindex_ds_get_root_folder( ds );
5457 /* prepare for recursive call */
5458 folder_path_match.index = 1;
5459 /* this call will set folder_path_match.matched and folder_path_match.folder */
5460 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5465 nodeDS = g_list_next( nodeDS );
5468 list = g_list_next( list );
5471 g_strfreev( folder_path_match.folder_path );
5474 *book = folder_path_match.book;
5476 *folder = folder_path_match.folder;
5477 return folder_path_match.matched;
5481 /* **********************************************************************
5483 * ***********************************************************************
5489 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5490 AddressDataSource *ds = NULL;
5491 AdapterDSource *ads = NULL;
5492 AddressBookFile *abf = NULL;
5493 AdapterInterface *adapter;
5494 GtkCMCTreeNode *newNode;
5496 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5498 if( adapter->treeNode ) {
5499 abf = addressbook_imp_ldif( _addressIndex_ );
5501 ds = addrindex_index_add_datasource(
5502 _addressIndex_, ADDR_IF_BOOK, abf );
5503 ads = addressbook_create_ds_adapter(
5504 ds, ADDR_BOOK, NULL );
5505 addressbook_ads_set_name(
5506 ads, addrbook_get_name( abf ) );
5507 newNode = addressbook_add_object(
5509 ADDRESS_OBJECT(ads) );
5511 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5513 addrbook.treeSelected = newNode;
5516 /* Notify address completion */
5517 invalidate_address_completion();
5526 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5527 AddressDataSource *ds = NULL;
5528 AdapterDSource *ads = NULL;
5529 AddressBookFile *abf = NULL;
5530 AdapterInterface *adapter;
5531 GtkCMCTreeNode *newNode;
5533 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5535 if( adapter->treeNode ) {
5536 abf = addressbook_imp_mutt( _addressIndex_ );
5538 ds = addrindex_index_add_datasource(
5539 _addressIndex_, ADDR_IF_BOOK, abf );
5540 ads = addressbook_create_ds_adapter(
5541 ds, ADDR_BOOK, NULL );
5542 addressbook_ads_set_name(
5543 ads, addrbook_get_name( abf ) );
5544 newNode = addressbook_add_object(
5546 ADDRESS_OBJECT(ads) );
5548 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5550 addrbook.treeSelected = newNode;
5553 /* Notify address completion */
5554 invalidate_address_completion();
5563 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5564 AddressDataSource *ds = NULL;
5565 AdapterDSource *ads = NULL;
5566 AddressBookFile *abf = NULL;
5567 AdapterInterface *adapter;
5568 GtkCMCTreeNode *newNode;
5570 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5572 if( adapter->treeNode ) {
5573 abf = addressbook_imp_pine( _addressIndex_ );
5575 ds = addrindex_index_add_datasource(
5576 _addressIndex_, ADDR_IF_BOOK, abf );
5577 ads = addressbook_create_ds_adapter(
5578 ds, ADDR_BOOK, NULL );
5579 addressbook_ads_set_name(
5580 ads, addrbook_get_name( abf ) );
5581 newNode = addressbook_add_object(
5583 ADDRESS_OBJECT(ads) );
5585 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5587 addrbook.treeSelected = newNode;
5590 /* Notify address completion */
5591 invalidate_address_completion();
5598 * Harvest addresses.
5599 * \param folderItem Folder to import.
5600 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5601 * \param msgList List of message numbers, or NULL to process folder.
5603 void addressbook_harvest(
5604 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5606 AddressDataSource *ds = NULL;
5607 AdapterDSource *ads = NULL;
5608 AddressBookFile *abf = NULL;
5609 AdapterInterface *adapter;
5610 GtkCMCTreeNode *newNode;
5612 abf = addrgather_dlg_execute(
5613 folderItem, _addressIndex_, sourceInd, msgList );
5615 ds = addrindex_index_add_datasource(
5616 _addressIndex_, ADDR_IF_BOOK, abf );
5618 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5620 if( adapter->treeNode ) {
5621 ads = addressbook_create_ds_adapter(
5622 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5623 newNode = addressbook_add_object(
5625 ADDRESS_OBJECT(ads) );
5626 if (newNode == NULL) {
5627 g_message("error adding addressbook object\n");
5632 /* Notify address completion */
5633 invalidate_address_completion();
5640 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5641 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5643 AddressDataSource *ds = NULL;
5644 AddrBookBase *adbase;
5645 AddressCache *cache;
5646 GtkCMCTreeNode *node = NULL;
5648 if( ! addrbook.treeSelected ) return;
5649 node = addrbook.treeSelected;
5650 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5651 obj = gtk_cmctree_node_get_row_data( ctree, node );
5652 if( obj == NULL ) return;
5654 ds = addressbook_find_datasource( node );
5655 if( ds == NULL ) return;
5656 adbase = ( AddrBookBase * ) ds->rawDataSource;
5657 cache = adbase->addressCache;
5658 addressbook_exp_html( cache );
5664 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5665 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5667 AddressDataSource *ds = NULL;
5668 AddrBookBase *adbase;
5669 AddressCache *cache;
5670 GtkCMCTreeNode *node = NULL;
5672 if( ! addrbook.treeSelected ) return;
5673 node = addrbook.treeSelected;
5674 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5675 obj = gtk_cmctree_node_get_row_data( ctree, node );
5676 if( obj == NULL ) return;
5678 ds = addressbook_find_datasource( node );
5679 if( ds == NULL ) return;
5680 adbase = ( AddrBookBase * ) ds->rawDataSource;
5681 cache = adbase->addressCache;
5682 addressbook_exp_ldif( cache );
5685 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5687 addrduplicates_find(GTK_WINDOW(addrbook.window));
5690 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5692 addressbook_custom_attr_edit();
5695 static void addressbook_start_drag(GtkWidget *widget, gint button,
5699 GdkDragContext *context;
5700 if (addressbook_target_list == NULL)
5701 addressbook_target_list = gtk_target_list_new(
5702 addressbook_drag_types, 1);
5703 context = gtk_drag_begin(widget, addressbook_target_list,
5704 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5705 gtk_drag_set_icon_default(context);
5708 static void addressbook_drag_data_get(GtkWidget *widget,
5709 GdkDragContext *drag_context,
5710 GtkSelectionData *selection_data,
5715 AddrItemObject *aio = NULL;
5716 AddressObject *pobj = NULL;
5717 AdapterDSource *ads = NULL;
5718 AddressDataSource *ds = NULL;
5721 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5723 if( pobj == NULL ) return;
5725 if( pobj->type == ADDR_DATASOURCE ) {
5726 ads = ADAPTER_DSOURCE(pobj);
5727 ds = ads->dataSource;
5728 } else if (pobj->type == ADDR_ITEM_GROUP) {
5733 else if( pobj->type != ADDR_INTERFACE ) {
5734 ds = addressbook_find_datasource( addrbook.treeSelected );
5740 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5741 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5742 GTK_CMCTREE_NODE(cur->data));
5743 while (aio && aio->type != ITEMTYPE_PERSON) {
5748 if (aio && aio->type == ITEMTYPE_PERSON) {
5749 if( ds && ds->interface && ds->interface->readOnly)
5750 gtk_selection_data_set(selection_data,
5751 gtk_selection_data_get_target(selection_data), 8,
5752 (const guchar *)"Dummy_addr_copy", 15);
5754 gtk_selection_data_set(selection_data,
5755 gtk_selection_data_get_target(selection_data), 8,
5756 (const guchar *)"Dummy_addr_move", 15);
5760 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5761 GdkDragContext *context,
5767 GtkAllocation allocation;
5768 GtkRequisition requisition;
5770 GtkCMCTreeNode *node = NULL;
5771 gboolean acceptable = FALSE;
5772 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5773 gint height = allocation.height;
5774 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5775 gint total_height = requisition.height;
5776 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5777 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5778 gfloat vpos = gtk_adjustment_get_value(pos);
5780 if (gtk_cmclist_get_selection_info
5781 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5783 if (y > height - 24 && height + vpos < total_height) {
5784 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5785 gtk_adjustment_changed(pos);
5787 if (y < 24 && y > 0) {
5788 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5789 gtk_adjustment_changed(pos);
5791 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5794 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5795 if( obj->type == ADDR_ITEM_FOLDER
5796 || obj->type == ADDR_ITEM_GROUP)
5799 AdapterDSource *ads = NULL;
5800 AddressDataSource *ds = NULL;
5801 ads = ADAPTER_DSOURCE(obj);
5802 if (ads == NULL ){ return FALSE;}
5803 ds = ads->dataSource;
5804 if (ds == NULL ) { return FALSE;}
5812 g_signal_handlers_block_by_func
5814 G_CALLBACK(addressbook_tree_selected), NULL);
5815 gtk_sctree_select( GTK_SCTREE(widget), node);
5816 g_signal_handlers_unblock_by_func
5818 G_CALLBACK(addressbook_tree_selected), NULL);
5819 gdk_drag_status(context,
5820 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5821 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5823 gdk_drag_status(context, 0, time);
5828 static void addressbook_drag_leave_cb(GtkWidget *widget,
5829 GdkDragContext *context,
5833 if (addrbook.treeSelected) {
5834 g_signal_handlers_block_by_func
5836 G_CALLBACK(addressbook_tree_selected), NULL);
5837 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5838 g_signal_handlers_unblock_by_func
5840 G_CALLBACK(addressbook_tree_selected), NULL);
5845 static void addressbook_drag_received_cb(GtkWidget *widget,
5846 GdkDragContext *drag_context,
5849 GtkSelectionData *data,
5855 GtkCMCTreeNode *node;
5856 GtkCMCTreeNode *lastopened = addrbook.opened;
5858 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5859 if (gtk_cmclist_get_selection_info
5860 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5864 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5865 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5868 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5869 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5870 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5871 addressbook_clip_copy_cb(NULL, NULL);
5873 addressbook_clip_cut_cb(NULL, NULL);
5874 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5875 addressbook_clip_paste_cb(NULL,NULL);
5876 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5877 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5878 gtk_drag_finish(drag_context, TRUE, TRUE, time);