2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2013 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "claws-features.h"
28 #include <glib/gi18n.h>
29 #include <gdk/gdkkeysyms.h>
33 #include <sys/types.h>
37 #include "addressbook.h"
38 #include "manage_window.h"
39 #include "prefs_common.h"
40 #include "alertpanel.h"
41 #include "inputdialog.h"
43 #include "stock_pixmap.h"
45 #include "prefs_gtk.h"
51 #include "addr_compl.h"
54 #include "addressitem.h"
56 #include "addrcache.h"
58 #include "addrindex.h"
59 #include "addressadd.h"
60 #include "addrduplicates.h"
61 #include "addressbook_foldersel.h"
63 #include "editvcard.h"
64 #include "editgroup.h"
65 #include "editaddress.h"
67 #include "importldif.h"
68 #include "importmutt.h"
69 #include "importpine.h"
74 #include "editjpilot.h"
79 #include "ldapserver.h"
81 #include "ldapupdate.h"
83 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
86 #include "addrquery.h"
87 #include "addrselect.h"
89 #include "addrgather.h"
90 #include "adbookbase.h"
91 #include "exphtmldlg.h"
92 #include "expldifdlg.h"
93 #include "browseldap.h"
94 #include "addrcustomattr.h"
102 } AddressIndexColumns;
110 } AddressListColumns;
113 AddressBookFile *book;
121 AddressDataSource *book;
125 static gchar *list_titles[] = { N_("Name"),
129 #define COL_NAME_WIDTH 164
130 #define COL_ADDRESS_WIDTH 156
132 #define COL_FOLDER_WIDTH 170
133 #define ADDRESSBOOK_WIDTH 640
134 #define ADDRESSBOOK_HEIGHT 360
136 #define ADDRESSBOOK_MSGBUF_SIZE 2048
138 static GdkPixbuf *folderxpm = NULL;
139 static GdkPixbuf *folderopenxpm = NULL;
140 static GdkPixbuf *groupxpm = NULL;
141 static GdkPixbuf *interfacexpm = NULL;
142 static GdkPixbuf *bookxpm = NULL;
143 static GdkPixbuf *addressxpm = NULL;
144 static GdkPixbuf *vcardxpm = NULL;
145 static GdkPixbuf *jpilotxpm = NULL;
146 static GdkPixbuf *categoryxpm = NULL;
147 static GdkPixbuf *ldapxpm = NULL;
148 static GdkPixbuf *addrsearchxpm = NULL;
151 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
153 /* Address list selection */
154 static AddrSelectList *_addressSelect_ = NULL;
155 static AddressClipboard *_clipBoard_ = NULL;
157 /* Address index file and interfaces */
158 static AddressIndex *_addressIndex_ = NULL;
159 static GList *_addressInterfaceList_ = NULL;
160 static GList *_addressIFaceSelection_ = NULL;
161 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
163 static AddressBook_win addrbook;
165 static GHashTable *_addressBookTypeHash_ = NULL;
166 static GList *_addressBookTypeList_ = NULL;
168 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
169 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
170 static void addressbook_edit_address_post_cb( ItemPerson *person );
172 static void addressbook_create (void);
173 static gint addressbook_close (void);
175 static gboolean address_index_has_focus = FALSE;
176 static gboolean address_list_has_focus = FALSE;
178 /* callback functions */
179 static void addressbook_del_clicked (GtkButton *button,
181 static void addressbook_reg_clicked (GtkButton *button,
183 static void addressbook_to_clicked (GtkButton *button,
185 static void addressbook_lup_clicked (GtkButton *button,
187 static void addressbook_close_clicked (GtkButton *button,
190 static void addressbook_tree_selected (GtkCMCTree *ctree,
191 GtkCMCTreeNode *node,
194 static void addressbook_select_row_tree (GtkCMCTree *ctree,
195 GtkCMCTreeNode *node,
198 static void addressbook_list_row_selected (GtkCMCTree *clist,
199 GtkCMCTreeNode *node,
202 static void addressbook_list_row_unselected (GtkCMCTree *clist,
203 GtkCMCTreeNode *node,
206 static void addressbook_person_expand_node (GtkCMCTree *ctree,
209 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
213 static void addressbook_entry_activated (GtkWidget *widget,
216 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
217 GdkEventButton *event,
219 static gboolean addressbook_list_button_released(GtkWidget *widget,
220 GdkEventButton *event,
222 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
223 GdkEventButton *event,
225 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
226 GdkEventButton *event,
229 static void addressbook_new_folder_cb (GtkAction *action,
231 static void addressbook_new_group_cb (GtkAction *action,
233 static void addressbook_treenode_edit_cb (GtkAction *action,
235 static void addressbook_treenode_delete_cb (GtkAction *action,
238 static void addressbook_change_node_name (GtkCMCTreeNode *node,
241 static void addressbook_new_address_cb (GtkAction *action,
243 static void addressbook_edit_address_cb (GtkAction *action,
245 static void addressbook_delete_address_cb (GtkAction *action,
248 static void close_cb (GtkAction *action,
250 static void addressbook_file_save_cb (GtkAction *action,
253 /* Data source edit stuff */
254 static void addressbook_new_book_cb (GtkAction *action,
256 static void addressbook_new_vcard_cb (GtkAction *action,
260 static void addressbook_new_jpilot_cb (GtkAction *action,
265 static void addressbook_new_ldap_cb (GtkAction *action,
269 static void addressbook_set_clist (AddressObject *obj,
272 static void addressbook_load_tree (void);
273 void addressbook_read_file (void);
275 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
277 static void addressbook_treenode_remove_item ( void );
279 static AddressDataSource *addressbook_find_datasource
280 (GtkCMCTreeNode *node );
282 static AddressBookFile *addressbook_get_book_file(void);
284 static GtkCMCTreeNode *addressbook_node_add_folder
285 (GtkCMCTreeNode *node,
286 AddressDataSource *ds,
287 ItemFolder *itemFolder,
288 AddressObjectType otype);
289 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
290 AddressDataSource *ds,
291 ItemGroup *itemGroup);
292 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
293 GtkCMCTreeNode *parent);
294 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
295 GtkCMCTreeNode *node);
296 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
298 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
301 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
304 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
306 AddressTypeControlItem *atci,
307 AddressTypeControlItem *atciMail);
308 static void addressbook_folder_refresh_one_person(GtkCMCTree *clist,
310 static void addressbook_folder_remove_one_person(GtkCMCTree *clist,
312 static void addressbook_folder_remove_node (GtkCMCTree *clist,
313 GtkCMCTreeNode *node);
315 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
316 gboolean force_focus );
318 /* LUT's and IF stuff */
319 static void addressbook_free_treenode ( gpointer data );
320 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
321 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
323 static void addrbookctl_build_map (GtkWidget *window);
324 static void addrbookctl_build_iflist (void);
325 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
326 static void addrbookctl_build_ifselect (void);
328 static void addrbookctl_free_interface (AdapterInterface *adapter);
329 static void addrbookctl_free_datasource (AdapterDSource *adapter);
330 static void addrbookctl_free_folder (AdapterFolder *adapter);
331 static void addrbookctl_free_group (AdapterGroup *adapter);
333 static void addressbook_list_select_clear ( void );
334 static void addressbook_list_select_add ( AddrItemObject *aio,
335 AddressDataSource *ds );
336 static void addressbook_list_select_remove ( AddrItemObject *aio );
338 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
339 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
340 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
341 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
342 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
343 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
344 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
345 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
346 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
347 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
348 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
349 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
350 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
351 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
353 static void addressbook_mail_to_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" },
405 {"Book", NULL, N_("_Book") },
406 {"Address", NULL, N_("_Edit") },
407 {"Tools", NULL, N_("_Tools") },
408 {"Help", NULL, N_("_Help") },
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) },
447 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
448 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
449 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
450 {"Tools/---", NULL, "---", NULL, NULL, NULL },
451 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
452 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
453 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
454 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
455 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
458 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
462 static GtkActionEntry addressbook_tree_popup_entries[] =
464 {"ABTreePopup", NULL, "ABTreePopup" },
465 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
466 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
467 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
468 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
469 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
470 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
471 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
472 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
473 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
474 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
477 static GtkActionEntry addressbook_list_popup_entries[] =
479 {"ABListPopup", NULL, "ABListPopup" },
480 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
481 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
482 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
483 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
484 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
485 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
486 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
487 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
488 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
489 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
490 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
491 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
492 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
494 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
499 * Structure of error message table.
501 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
502 struct _ErrMsgTableEntry {
507 static gchar *_errMsgUnknown_ = N_( "Unknown" );
510 * Lookup table of error messages for general errors. Note that a NULL
511 * description signifies the end of the table.
513 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
514 { MGU_SUCCESS, N_("Success") },
515 { MGU_BAD_ARGS, N_("Bad arguments") },
516 { MGU_NO_FILE, N_("File not specified") },
517 { MGU_OPEN_FILE, N_("Error opening file") },
518 { MGU_ERROR_READ, N_("Error reading file") },
519 { MGU_EOF, N_("End of file encountered") },
520 { MGU_OO_MEMORY, N_("Error allocating memory") },
521 { MGU_BAD_FORMAT, N_("Bad file format") },
522 { MGU_ERROR_WRITE, N_("Error writing to file") },
523 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
524 { MGU_NO_PATH, N_("No path specified") },
530 * Lookup table of error messages for LDAP errors.
532 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
533 { LDAPRC_SUCCESS, N_("Success") },
534 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
535 { LDAPRC_INIT, N_("Error initializing LDAP") },
536 { LDAPRC_BIND, N_("Error binding to LDAP server") },
537 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
538 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
539 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
540 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
541 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
542 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
543 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
544 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
545 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
546 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
552 * Lookup message for specified error code.
553 * \param lut Lookup table.
554 * \param code Code to lookup.
555 * \return Description associated to code.
557 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
559 ErrMsgTableEntry entry;
562 for( i = 0; ; i++ ) {
564 if( entry.description == NULL ) break;
565 if( entry.code == code ) {
566 desc = entry.description;
571 desc = _errMsgUnknown_;
576 static gboolean lastCanLookup = FALSE;
578 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
580 if (add_and_delete) {
581 gtk_widget_show(addrbook.edit_btn);
582 gtk_widget_show(addrbook.del_btn);
583 gtk_widget_show(addrbook.reg_btn);
585 gtk_widget_hide(addrbook.edit_btn);
586 gtk_widget_hide(addrbook.del_btn);
587 gtk_widget_hide(addrbook.reg_btn);
591 gtk_widget_show(addrbook.lup_btn);
592 gtk_widget_show(addrbook.entry);
593 gtk_widget_show(addrbook.label);
595 gtk_widget_hide(addrbook.lup_btn);
596 gtk_widget_hide(addrbook.entry);
597 gtk_widget_hide(addrbook.label);
600 lastCanLookup = lookup;
603 gtk_widget_show(addrbook.to_btn);
604 gtk_widget_show(addrbook.cc_btn);
605 gtk_widget_show(addrbook.bcc_btn);
607 gtk_widget_hide(addrbook.to_btn);
608 gtk_widget_hide(addrbook.cc_btn);
609 gtk_widget_hide(addrbook.bcc_btn);
613 void addressbook_open(Compose *target)
615 /* Initialize all static members */
616 if( _clipBoard_ == NULL ) {
617 _clipBoard_ = addrclip_create();
619 if( _addressIndex_ != NULL ) {
620 addrclip_set_index( _clipBoard_, _addressIndex_ );
622 if( _addressSelect_ == NULL ) {
623 _addressSelect_ = addrselect_list_create();
625 if (!addrbook.window) {
626 addressbook_read_file();
627 addressbook_create();
628 addressbook_load_tree();
629 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
630 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
633 gtk_widget_hide(addrbook.window);
636 gtk_widget_show_all(addrbook.window);
638 if (!prefs_common.addressbook_use_editaddress_dialog)
639 addressbook_edit_person_widgetset_hide();
641 address_completion_start(addrbook.window);
643 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
644 addressbook_set_target_compose(target);
648 * Destroy addressbook.
650 void addressbook_destroy( void ) {
651 /* Free up address stuff */
652 if( _addressSelect_ != NULL ) {
653 addrselect_list_free( _addressSelect_ );
655 if( _clipBoard_ != NULL ) {
656 addrclip_free( _clipBoard_ );
658 if( _addressIndex_ != NULL ) {
659 addrindex_free_index( _addressIndex_ );
660 addrindex_teardown();
662 _addressSelect_ = NULL;
664 _addressIndex_ = NULL;
667 void addressbook_set_target_compose(Compose *target)
669 addrbook.target_compose = target;
672 Compose *addressbook_get_target_compose(void)
674 return addrbook.target_compose;
678 * Refresh addressbook and save to file(s).
680 void addressbook_refresh( void )
682 if (addrbook.window) {
683 if (addrbook.treeSelected) {
684 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
685 addrbook.treeSelected);
686 addressbook_set_clist(
687 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
688 addrbook.treeSelected),
693 addressbook_export_to_file();
696 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
698 if (event && event->keyval == GDK_KEY_Escape)
700 else if (event && event->keyval == GDK_KEY_Delete) {
701 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
702 if ( /* address_index_has_focus || */ address_list_has_focus )
703 addressbook_del_clicked(NULL, NULL);
709 *\brief Save Gtk object size to prefs dataset
711 static void addressbook_size_allocate_cb(GtkWidget *widget,
712 GtkAllocation *allocation)
714 cm_return_if_fail(allocation != NULL);
716 prefs_common.addressbookwin_width = allocation->width;
717 prefs_common.addressbookwin_height = allocation->height;
720 static gint sort_column_number = 0;
721 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
723 static gint list_case_sort(
724 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
726 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
727 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
728 gchar *name1 = NULL, *name2 = NULL;
729 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
730 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
732 if( aio1->type == aio2->type ) {
734 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
736 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
737 if( ! name1 ) return ( name2 != NULL );
738 if( ! name2 ) return -1;
739 return g_utf8_collate( name1, name2 );
741 /* Order groups before person */
742 if( aio1->type == ITEMTYPE_GROUP ) {
743 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
744 } else if( aio2->type == ITEMTYPE_GROUP ) {
745 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
751 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
752 const GtkSortType sort_type)
755 GtkWidget *hbox, *label, *arrow;
757 sort_column_number = col;
758 sort_column_type = sort_type;
759 gtk_cmclist_set_compare_func(clist, list_case_sort);
760 gtk_cmclist_set_sort_type(clist, sort_type);
761 gtk_cmclist_set_sort_column(clist, col);
763 gtk_cmclist_freeze(clist);
764 gtk_cmclist_sort(clist);
766 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
767 hbox = gtk_hbox_new(FALSE, 4);
768 label = gtk_label_new(gettext(list_titles[pos]));
769 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
772 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
773 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
774 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
777 gtk_widget_show_all(hbox);
778 gtk_cmclist_set_column_widget(clist, pos, hbox);
781 gtk_cmclist_thaw(clist);
784 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
786 static GtkSortType sort_type = GTK_SORT_ASCENDING;
788 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
790 addressbook_sort_list(clist, COL_NAME, sort_type);
793 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
795 static GtkSortType sort_type = GTK_SORT_ASCENDING;
797 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
799 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
802 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
804 static GtkSortType sort_type = GTK_SORT_ASCENDING;
806 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
808 addressbook_sort_list(clist, COL_REMARKS, sort_type);
811 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
814 address_index_has_focus = TRUE;
818 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
821 address_index_has_focus = FALSE;
822 if (!prefs_common.addressbook_use_editaddress_dialog
823 && !address_list_has_focus)
824 addressbook_address_list_disable_some_actions();
828 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
831 address_list_has_focus = TRUE;
835 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
838 address_list_has_focus = FALSE;
839 if (!prefs_common.addressbook_use_editaddress_dialog
840 && !address_index_has_focus)
841 addressbook_address_list_disable_some_actions();
845 /* save hpane and vpane's handle position when it moves */
846 static void addressbook_pane_save_position(void)
849 prefs_common.addressbook_hpaned_pos =
850 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
852 prefs_common.addressbook_vpaned_pos =
853 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
857 * Create the address book widgets. The address book contains two CTree widgets: the
858 * address index tree on the left and the address list on the right.
860 * The address index tree displays a hierarchy of interfaces and groups. Each node in
861 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
862 * data sources and folder objects.
864 * The address list displays group, person and email objects. These items are linked
865 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
868 * In the tradition of MVC architecture, the data stores have been separated from the
869 * GUI components. The addrindex.c file provides the interface to all data stores.
871 static void addressbook_create(void)
877 GtkWidget *ctree_swin;
879 GtkWidget *editaddress_vbox;
880 GtkWidget *clist_vbox;
881 GtkWidget *clist_swin;
888 GtkWidget *statusbar;
899 GtkWidget *close_btn;
900 GtkWidget *tree_popup;
901 GtkWidget *list_popup;
903 GtkUIManager *ui_manager;
904 GtkActionGroup *action_group;
905 gchar *index_titles[N_INDEX_COLS];
909 static GdkGeometry geometry;
911 debug_print("Creating addressbook window...\n");
913 index_titles[COL_SOURCES] = _("Sources");
915 /* Address book window */
916 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
917 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
918 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
919 gtk_widget_realize(window);
921 g_signal_connect(G_OBJECT(window), "delete_event",
922 G_CALLBACK(addressbook_close), NULL);
923 g_signal_connect(G_OBJECT(window), "size_allocate",
924 G_CALLBACK(addressbook_size_allocate_cb), NULL);
925 g_signal_connect(G_OBJECT(window), "key_press_event",
926 G_CALLBACK(key_pressed), NULL);
927 MANAGE_WINDOW_SIGNALS_CONNECT(window);
929 vbox = gtk_vbox_new(FALSE, 0);
930 gtk_container_add(GTK_CONTAINER(window), vbox);
933 ui_manager = gtk_ui_manager_new();
934 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
935 G_N_ELEMENTS(addressbook_entries), NULL);
936 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
937 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
938 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
939 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
941 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
945 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
950 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
992 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
994 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
996 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
998 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
999 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1000 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1002 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1003 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1004 GTK_POLICY_AUTOMATIC,
1005 GTK_POLICY_AUTOMATIC);
1006 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1009 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1010 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1012 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1013 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1014 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1015 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1016 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1017 GTK_CMCTREE_EXPANDER_TRIANGLE);
1018 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1019 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1020 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1021 addressbook_treenode_compare_func);
1023 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1024 G_CALLBACK(addressbook_tree_selected), NULL);
1025 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1026 G_CALLBACK(addressbook_tree_button_pressed),
1028 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1029 G_CALLBACK(addressbook_tree_button_released),
1032 g_signal_connect(G_OBJECT(ctree), "select_row",
1033 G_CALLBACK(addressbook_select_row_tree), NULL);
1035 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1036 addressbook_drag_types, 1,
1037 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1038 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1039 G_CALLBACK(addressbook_drag_motion_cb),
1041 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1042 G_CALLBACK(addressbook_drag_leave_cb),
1044 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1045 G_CALLBACK(addressbook_drag_received_cb),
1047 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1048 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1049 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1050 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1052 clist_vbox = gtk_vbox_new(FALSE, 4);
1054 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1055 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1056 GTK_POLICY_AUTOMATIC,
1057 GTK_POLICY_AUTOMATIC);
1058 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1061 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1062 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1063 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1064 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1065 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1066 GTK_CMCTREE_EXPANDER_TRIANGLE);
1067 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1068 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1069 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1071 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1073 gtk_widget_set_size_request(clist, -1, 80);
1075 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1076 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1077 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1078 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1079 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1080 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1081 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1082 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1083 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1084 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1085 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1087 for (i = 0; i < N_LIST_COLS; i++)
1088 gtkut_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1091 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1092 G_CALLBACK(addressbook_list_row_selected), NULL);
1093 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1094 G_CALLBACK(addressbook_list_row_unselected), NULL);
1095 g_signal_connect(G_OBJECT(clist), "button_press_event",
1096 G_CALLBACK(addressbook_list_button_pressed),
1098 g_signal_connect(G_OBJECT(clist), "button_release_event",
1099 G_CALLBACK(addressbook_list_button_released),
1101 g_signal_connect(G_OBJECT(clist), "tree_expand",
1102 G_CALLBACK(addressbook_person_expand_node), NULL );
1103 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1104 G_CALLBACK(addressbook_person_collapse_node), NULL );
1105 g_signal_connect(G_OBJECT(clist), "start_drag",
1106 G_CALLBACK(addressbook_start_drag), NULL);
1107 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1108 G_CALLBACK(addressbook_drag_data_get), NULL);
1109 hbox = gtk_hbox_new(FALSE, 4);
1110 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1112 label = gtk_label_new(_("Search"));
1113 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1115 entry = gtk_entry_new();
1116 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1118 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1120 g_signal_connect(G_OBJECT(entry), "key_press_event",
1121 G_CALLBACK(addressbook_entry_key_pressed),
1123 g_signal_connect(G_OBJECT(entry), "activate",
1124 G_CALLBACK(addressbook_entry_activated), NULL);
1126 if (!prefs_common.addressbook_use_editaddress_dialog) {
1127 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1128 vpaned = gtk_vpaned_new();
1129 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1130 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1133 editaddress_vbox = NULL;
1135 hpaned = gtk_hpaned_new();
1136 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1137 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1138 if (prefs_common.addressbook_use_editaddress_dialog)
1139 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1141 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1144 hsbox = gtk_hbox_new(FALSE, 0);
1145 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1146 statusbar = gtk_statusbar_new();
1147 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1150 hbbox = gtk_hbutton_box_new();
1151 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1152 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1153 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1154 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1156 gtkut_stock_button_add_help(hbbox, &help_btn);
1158 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1159 gtkut_widget_set_can_default(edit_btn, TRUE);
1160 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1161 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1162 gtkut_widget_set_can_default(del_btn, TRUE);
1163 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1164 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1165 gtkut_widget_set_can_default(reg_btn, TRUE);
1166 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1169 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1170 gtkut_widget_set_can_default(lup_btn, TRUE);
1171 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1173 g_signal_connect(G_OBJECT(help_btn), "clicked",
1174 G_CALLBACK(manual_open_with_anchor_cb),
1175 MANUAL_ANCHOR_ADDRBOOK);
1177 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1178 G_CALLBACK(addressbook_edit_clicked), NULL);
1179 g_signal_connect(G_OBJECT(del_btn), "clicked",
1180 G_CALLBACK(addressbook_del_clicked), NULL);
1181 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1182 G_CALLBACK(addressbook_reg_clicked), NULL);
1183 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1184 G_CALLBACK(addressbook_lup_clicked), NULL);
1186 to_btn = gtk_button_new_with_label
1187 (prefs_common_translated_header_name("To:"));
1188 gtkut_widget_set_can_default(to_btn, TRUE);
1189 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1190 cc_btn = gtk_button_new_with_label
1191 (prefs_common_translated_header_name("Cc:"));
1192 gtkut_widget_set_can_default(cc_btn, TRUE);
1193 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1194 bcc_btn = gtk_button_new_with_label
1195 (prefs_common_translated_header_name("Bcc:"));
1196 gtkut_widget_set_can_default(bcc_btn, TRUE);
1197 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1199 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1200 gtkut_widget_set_can_default(close_btn, TRUE);
1201 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1203 g_signal_connect(G_OBJECT(to_btn), "clicked",
1204 G_CALLBACK(addressbook_to_clicked),
1205 GINT_TO_POINTER(COMPOSE_TO));
1206 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1207 G_CALLBACK(addressbook_to_clicked),
1208 GINT_TO_POINTER(COMPOSE_CC));
1209 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1210 G_CALLBACK(addressbook_to_clicked),
1211 GINT_TO_POINTER(COMPOSE_BCC));
1212 g_signal_connect(G_OBJECT(close_btn), "clicked",
1213 G_CALLBACK(addressbook_close_clicked), NULL);
1215 /* Build icons for interface */
1217 /* Build control tables */
1218 addrbookctl_build_map(window);
1219 addrbookctl_build_iflist();
1220 addrbookctl_build_ifselect();
1222 addrbook.clist = NULL;
1224 /* Add each interface into the tree as a root level folder */
1225 nodeIf = _addressInterfaceList_;
1227 AdapterInterface *adapter = nodeIf->data;
1228 AddressInterface *iface = adapter->interface;
1229 nodeIf = g_list_next(nodeIf);
1231 if(iface->useInterface) {
1232 AddressTypeControlItem *atci = adapter->atci;
1233 text = atci->displayName;
1235 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1236 NULL, NULL, &text, FOLDER_SPACING,
1240 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1241 gtk_cmctree_node_set_row_data_full(
1242 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1243 addressbook_free_treenode );
1249 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1250 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1262 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1263 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1282 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1283 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1285 addrbook.window = window;
1286 addrbook.hpaned = hpaned;
1287 addrbook.vpaned = vpaned;
1288 addrbook.menubar = menubar;
1289 addrbook.ctree = ctree;
1292 addrbook.editaddress_vbox = editaddress_vbox;
1293 addrbook.clist = clist;
1294 addrbook.label = label;
1295 addrbook.entry = entry;
1296 addrbook.statusbar = statusbar;
1297 addrbook.status_cid = gtk_statusbar_get_context_id(
1298 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1300 addrbook.help_btn = help_btn;
1301 addrbook.edit_btn = edit_btn;
1302 addrbook.del_btn = del_btn;
1303 addrbook.reg_btn = reg_btn;
1304 addrbook.lup_btn = lup_btn;
1305 addrbook.to_btn = to_btn;
1306 addrbook.cc_btn = cc_btn;
1307 addrbook.bcc_btn = bcc_btn;
1309 addrbook.tree_popup = tree_popup;
1310 addrbook.list_popup = list_popup;
1311 addrbook.ui_manager = ui_manager;
1313 addrbook.listSelected = NULL;
1315 if (!geometry.min_height) {
1316 geometry.min_width = ADDRESSBOOK_WIDTH;
1317 geometry.min_height = ADDRESSBOOK_HEIGHT;
1320 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1322 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1323 prefs_common.addressbookwin_height);
1325 gtk_window_move(GTK_WINDOW(window), 48, 48);
1328 if (!prefs_common.addressbook_use_editaddress_dialog) {
1329 if (prefs_common.addressbook_vpaned_pos > 0)
1330 gtk_paned_set_position(GTK_PANED(vpaned),
1331 prefs_common.addressbook_vpaned_pos);
1333 if (prefs_common.addressbook_hpaned_pos > 0)
1334 gtk_paned_set_position(GTK_PANED(hpaned),
1335 prefs_common.addressbook_hpaned_pos);
1338 gtk_widget_show_all(window);
1342 * Close address book window and save to file(s).
1344 static gint addressbook_close( void ) {
1345 address_completion_end(addrbook.window);
1346 if (!prefs_common.addressbook_use_editaddress_dialog)
1347 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1349 addressbook_pane_save_position();
1351 gtk_widget_hide(addrbook.window);
1352 addressbook_export_to_file();
1357 * Display message in status line.
1358 * \param msg Message to display.
1360 static void addressbook_status_show( gchar *msg ) {
1361 if( addrbook.statusbar != NULL ) {
1363 GTK_STATUSBAR(addrbook.statusbar),
1364 addrbook.status_cid );
1367 GTK_STATUSBAR(addrbook.statusbar),
1368 addrbook.status_cid, msg );
1373 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1377 *addressbook_msgbuf = '\0';
1379 name = addrindex_ds_get_name( ds );
1380 retVal = addrindex_ds_get_status_code( ds );
1381 if( retVal == MGU_SUCCESS ) {
1382 g_snprintf( addressbook_msgbuf,
1383 sizeof(addressbook_msgbuf), "%s", name );
1386 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1387 g_snprintf( addressbook_msgbuf,
1388 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1391 addressbook_status_show( addressbook_msgbuf );
1394 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1396 addressbook_edit_address_cb(NULL, NULL);
1399 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1401 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1405 * Delete one or more objects from address list.
1407 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1409 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1410 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1411 AddressObject *pobj;
1412 AdapterDSource *ads = NULL;
1413 GtkCMCTreeNode *nodeList;
1416 AddressBookFile *abf = NULL;
1417 AddressDataSource *ds = NULL;
1418 AddressInterface *iface;
1419 AddrItemObject *aio;
1420 AddrSelectItem *item;
1422 gboolean refreshList = FALSE;
1424 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1425 cm_return_if_fail(pobj != NULL);
1427 /* Test whether anything selected for deletion */
1428 nodeList = addrbook.listSelected;
1430 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1431 if( aio == NULL) return;
1432 ds = addressbook_find_datasource( addrbook.treeSelected );
1433 if( ds == NULL ) return;
1435 /* Test for read only */
1436 iface = ds->interface;
1437 if( iface->readOnly ) {
1438 alertpanel( _("Delete address(es)"),
1439 _("This address data is readonly and cannot be deleted."),
1440 GTK_STOCK_CLOSE, NULL, NULL );
1444 /* Test whether Ok to proceed */
1446 if( pobj->type == ADDR_DATASOURCE ) {
1447 ads = ADAPTER_DSOURCE(pobj);
1448 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1450 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1453 else if( pobj->type == ADDR_ITEM_GROUP ) {
1456 if( ! procFlag ) return;
1457 abf = ds->rawDataSource;
1458 if( abf == NULL ) return;
1460 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1461 g_signal_handlers_block_by_func
1462 (G_OBJECT(addrbook.clist),
1463 G_CALLBACK(addressbook_list_row_unselected), NULL);
1465 /* Process deletions */
1466 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1467 GList *groups = NULL, *persons = NULL, *emails = NULL;
1468 gboolean group_delete = TRUE;
1469 /* Items inside folders */
1470 list = addrselect_get_list( _addressSelect_ );
1471 /* Confirm deletion */
1475 node = g_list_next( node );
1476 aio = ( AddrItemObject * ) item->addressItem;
1477 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1478 group_delete = FALSE;
1483 aval = alertpanel( _("Delete group"),
1484 _("Really delete the group(s)?\n"
1485 "The addresses it contains will not be lost."),
1486 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1487 if( aval != G_ALERTALTERNATE ) {
1491 aval = alertpanel( _("Delete address(es)"),
1492 _("Really delete the address(es)?"),
1493 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1494 if( aval != G_ALERTALTERNATE ) {
1499 /* first, set lists of groups and persons to remove */
1503 node = g_list_next( node );
1504 aio = ( AddrItemObject * ) item->addressItem;
1507 if( aio->type == ITEMTYPE_GROUP ) {
1508 groups = g_list_prepend(groups, item);
1510 else if( aio->type == ITEMTYPE_PERSON ) {
1511 persons = g_list_prepend(persons, item);
1514 /* then set list of emails to remove *if* they're not children of
1515 * persons to remove */
1519 node = g_list_next( node );
1520 aio = ( AddrItemObject * ) item->addressItem;
1523 if( aio->type == ITEMTYPE_EMAIL ) {
1524 ItemEMail *sitem = ( ItemEMail * ) aio;
1525 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1526 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1527 emails = g_list_prepend(emails, item);
1529 /* else, the email will be removed via the parent person */
1532 /* then delete groups */
1536 node = g_list_next( node );
1537 aio = ( AddrItemObject * ) item->addressItem;
1540 if( aio->type == ITEMTYPE_GROUP ) {
1541 ItemGroup *item = ( ItemGroup * ) aio;
1542 GtkCMCTreeNode *nd = NULL;
1543 nd = addressbook_find_group_node( addrbook.opened, item );
1544 item = addrbook_remove_group( abf, item );
1546 addritem_free_item_group( item );
1548 /* Remove group from parent node */
1549 gtk_cmctree_remove_node( ctree, nd );
1553 /* then delete persons */
1557 node = g_list_next( node );
1558 aio = ( AddrItemObject * ) item->addressItem;
1561 if( aio->type == ITEMTYPE_PERSON ) {
1562 ItemPerson *item = ( ItemPerson * ) aio;
1563 item->status = DELETE_ENTRY;
1564 addressbook_folder_remove_one_person( clist, item );
1565 if (pobj->type == ADDR_ITEM_FOLDER)
1566 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1567 item = addrbook_remove_person( abf, item );
1569 if (ds && ds->type == ADDR_IF_LDAP) {
1570 LdapServer *server = ds->rawDataSource;
1571 ldapsvr_set_modified(server, TRUE);
1572 ldapsvr_update_book(server, item);
1576 addritem_person_remove_picture(item);
1577 addritem_free_item_person( item );
1581 /* then delete emails */
1585 node = g_list_next( node );
1586 aio = ( AddrItemObject * ) item->addressItem;
1590 if( aio->type == ITEMTYPE_EMAIL ) {
1591 ItemEMail *sitem = ( ItemEMail * ) aio;
1592 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1593 sitem = addrbook_person_remove_email( abf, person, sitem );
1595 addrcache_remove_email(abf->addressCache, sitem);
1596 addritem_free_item_email( sitem );
1598 addressbook_folder_refresh_one_person( clist, person );
1601 g_list_free( groups );
1602 g_list_free( persons );
1603 g_list_free( emails );
1604 g_list_free( list );
1605 addressbook_list_select_clear();
1607 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1608 addressbook_set_clist(
1609 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1613 addrbook_set_dirty(abf, TRUE);
1614 addressbook_export_to_file();
1615 addressbook_list_menu_setup();
1618 else if( pobj->type == ADDR_ITEM_GROUP ) {
1619 /* Items inside groups */
1620 list = addrselect_get_list( _addressSelect_ );
1624 node = g_list_next( node );
1625 aio = ( AddrItemObject * ) item->addressItem;
1626 if( aio->type == ITEMTYPE_EMAIL ) {
1627 ItemEMail *item = ( ItemEMail * ) aio;
1628 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1629 item = addrbook_person_remove_email( abf, person, item );
1631 addritem_free_item_email( item );
1635 g_list_free( list );
1636 addressbook_list_select_clear();
1637 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1638 addressbook_set_clist(
1639 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1643 addrbook_set_dirty(abf, TRUE);
1644 addressbook_export_to_file();
1645 addressbook_list_menu_setup();
1649 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1650 gtk_cmctree_remove_node( clist, nodeList );
1652 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1653 g_signal_handlers_unblock_by_func
1654 (G_OBJECT(addrbook.clist),
1655 G_CALLBACK(addressbook_list_row_unselected), NULL);
1658 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1660 addressbook_new_address_cb( NULL, NULL );
1663 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1666 gchar *address = NULL;
1668 if( aio->type == ITEMTYPE_EMAIL ) {
1669 ItemPerson *person = NULL;
1670 ItemEMail *email = ( ItemEMail * ) aio;
1672 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1673 if( email->address ) {
1674 if( ADDRITEM_NAME(email) ) {
1675 name = ADDRITEM_NAME(email);
1676 if( *name == '\0' ) {
1677 name = ADDRITEM_NAME(person);
1680 else if( ADDRITEM_NAME(person) ) {
1681 name = ADDRITEM_NAME(person);
1684 buf = g_strdup( email->address );
1686 address = email->address;
1689 else if( aio->type == ITEMTYPE_PERSON ) {
1690 ItemPerson *person = ( ItemPerson * ) aio;
1691 GList *node = person->listEMail;
1693 name = ADDRITEM_NAME(person);
1695 ItemEMail *email = ( ItemEMail * ) node->data;
1696 address = email->address;
1700 if( name && name[0] != '\0' ) {
1701 if( strchr_with_skip_quote( name, '"', ',' ) )
1702 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1704 buf = g_strdup_printf( "%s <%s>", name, address );
1707 buf = g_strdup( address );
1714 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1718 AddrSelectItem *item;
1719 AddrItemObject *aio;
1722 compose = addrbook.target_compose;
1723 if( ! compose ) return;
1725 /* Nothing selected, but maybe there is something in text entry */
1726 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1728 compose_entry_append(
1729 compose, addr, (ComposeEntryType)data , PREF_NONE);
1732 /* Select from address list */
1733 list = addrselect_get_list( _addressSelect_ );
1738 node = g_list_next( node );
1739 aio = item->addressItem;
1740 if( aio->type == ITEMTYPE_PERSON ||
1741 aio->type == ITEMTYPE_EMAIL ) {
1742 addr = addressbook_format_address( aio );
1743 compose_entry_append(
1744 compose, addr, (ComposeEntryType) data, PREF_NONE );
1747 else if( aio->type == ITEMTYPE_GROUP ) {
1748 ItemGroup *group = ( ItemGroup * ) aio;
1749 GList *nodeMail = group->listEMail;
1751 ItemEMail *email = nodeMail->data;
1753 addr = addressbook_format_address(
1754 ( AddrItemObject * ) email );
1755 compose_entry_append(
1756 compose, addr, (ComposeEntryType) data, PREF_NONE );
1758 nodeMail = g_list_next( nodeMail );
1763 AddressObject *obj = NULL;
1765 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1767 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1768 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1769 GList *nodeMail = itemGroup->listEMail;
1771 ItemEMail *email = nodeMail->data;
1773 addr = addressbook_format_address(
1774 ( AddrItemObject * ) email );
1775 compose_entry_append(
1776 compose, addr, (ComposeEntryType) data, PREF_NONE );
1778 nodeMail = g_list_next( nodeMail );
1782 g_list_free( list );
1785 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1786 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1787 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1788 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1791 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1792 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1797 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1798 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1799 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1802 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1803 gboolean canEdit = FALSE;
1804 gboolean canDelete = TRUE;
1805 gboolean canAdd = FALSE;
1806 gboolean canEditTr = TRUE;
1807 gboolean editAddress = FALSE;
1808 gboolean canExport = TRUE;
1809 AddressTypeControlItem *atci = NULL;
1810 AddressDataSource *ds = NULL;
1811 AddressInterface *iface = NULL;
1813 if( obj == NULL ) return;
1814 if( obj->type == ADDR_INTERFACE ) {
1815 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1816 iface = adapter->interface;
1818 if( iface->haveLibrary ) {
1819 /* Enable appropriate File / New command */
1820 atci = adapter->atci;
1821 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1824 canEditTr = canExport = FALSE;
1826 else if( obj->type == ADDR_DATASOURCE ) {
1827 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1828 ds = ads->dataSource;
1829 iface = ds->interface;
1830 if( ! iface->readOnly ) {
1831 canAdd = canEdit = editAddress = canDelete = TRUE;
1833 if( ! iface->haveLibrary ) {
1834 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1837 else if( obj->type == ADDR_ITEM_FOLDER ) {
1838 ds = addressbook_find_datasource( addrbook.treeSelected );
1840 iface = ds->interface;
1841 if( iface->readOnly ) {
1846 canAdd = editAddress = TRUE;
1850 else if( obj->type == ADDR_ITEM_GROUP ) {
1851 ds = addressbook_find_datasource( addrbook.treeSelected );
1853 iface = ds->interface;
1854 if( ! iface->readOnly ) {
1860 if( addrbook.listSelected == NULL )
1864 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1865 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1866 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1867 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1870 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1871 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1872 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1873 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1875 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1876 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1879 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1880 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1884 * Address book tree callback function that responds to selection of tree
1887 * \param ctree Tree widget.
1888 * \param node Node that was selected.
1889 * \param column Column number where selected occurred.
1890 * \param data Pointer to user data.
1892 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1893 gint column, gpointer data)
1895 AddressObject *obj = NULL;
1896 AdapterDSource *ads = NULL;
1897 AddressDataSource *ds = NULL;
1898 ItemFolder *rootFolder = NULL;
1899 AddressObjectType aot;
1901 addrbook.treeSelected = node;
1902 addrbook.listSelected = NULL;
1903 addressbook_status_show( "" );
1904 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1906 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1908 addressbook_set_clist(NULL, TRUE);
1911 addrbook.opened = node;
1913 if( obj->type == ADDR_DATASOURCE ) {
1914 /* Read from file */
1915 static gboolean tVal = TRUE;
1917 ads = ADAPTER_DSOURCE(obj);
1919 ds = ads->dataSource;
1920 if( ds == NULL ) return;
1922 if( addrindex_ds_get_modify_flag( ds ) ) {
1923 addrindex_ds_read_data( ds );
1926 if( ! addrindex_ds_get_read_flag( ds ) ) {
1927 addrindex_ds_read_data( ds );
1929 addressbook_ds_show_message( ds );
1931 if( ! addrindex_ds_get_access_flag( ds ) ) {
1932 /* Remove existing folders and groups */
1933 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1934 addressbook_tree_remove_children( ctree, node );
1935 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1937 /* Load folders into the tree */
1938 rootFolder = addrindex_ds_get_root_folder( ds );
1939 if( ds && ds->type == ADDR_IF_JPILOT ) {
1940 aot = ADDR_CATEGORY;
1942 else if( ds && ds->type == ADDR_IF_LDAP ) {
1943 aot = ADDR_LDAP_QUERY;
1946 aot = ADDR_ITEM_FOLDER;
1948 addressbook_node_add_folder( node, ds, rootFolder, aot );
1949 addrindex_ds_set_access_flag( ds, &tVal );
1950 gtk_cmctree_expand( ctree, node );
1953 addressbook_set_clist(NULL, TRUE);
1956 /* Update address list */
1957 g_signal_handlers_block_by_func
1959 G_CALLBACK(addressbook_tree_selected), NULL);
1960 addressbook_set_clist( obj, FALSE );
1961 g_signal_handlers_unblock_by_func
1963 G_CALLBACK(addressbook_tree_selected), NULL);
1964 if (!prefs_common.addressbook_use_editaddress_dialog)
1965 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1967 /* Setup main menu selections */
1968 addressbook_menubar_set_sensitive( FALSE );
1969 addressbook_menuitem_set_sensitive( obj, node );
1970 addressbook_list_select_clear();
1971 addressbook_list_menu_setup();
1976 * Setup address list popup menu items. Items are enabled or disabled as
1979 static void addressbook_list_menu_setup( void ) {
1980 GtkCMCTree *clist = NULL;
1981 AddressObject *pobj = NULL;
1982 AddressObject *obj = NULL;
1983 AdapterDSource *ads = NULL;
1984 AddressInterface *iface = NULL;
1985 AddressDataSource *ds = NULL;
1986 gboolean canEdit = FALSE;
1987 gboolean canDelete = FALSE;
1988 gboolean canCut = FALSE;
1989 gboolean canCopy = FALSE;
1990 gboolean canPaste = FALSE;
1991 gboolean canBrowse = FALSE;
1993 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1994 if( pobj == NULL ) return;
1996 clist = GTK_CMCTREE(addrbook.clist);
1997 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
1998 if( obj == NULL ) canEdit = FALSE;
2000 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2001 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2003 if( pobj->type == ADDR_DATASOURCE ) {
2004 /* Parent object is a data source */
2005 ads = ADAPTER_DSOURCE(pobj);
2006 ds = ads->dataSource;
2009 iface = ds->interface;
2012 if( ! iface->readOnly ) {
2013 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2014 if (iface->type != ADDR_IF_LDAP)
2015 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2016 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2019 canDelete = canEdit;
2022 else if( pobj->type != ADDR_INTERFACE ) {
2023 /* Parent object is not an interface */
2024 ds = addressbook_find_datasource( addrbook.treeSelected );
2027 iface = ds->interface;
2030 if( ! iface->readOnly ) {
2031 /* Folder or group */
2032 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2033 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2034 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2035 if( obj ) canEdit = TRUE;
2038 if( pobj->type == ADDR_ITEM_FOLDER ) {
2039 if (iface->type != ADDR_IF_LDAP)
2040 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2041 if( obj ) canEdit = TRUE;
2043 canDelete = canEdit;
2045 if( iface->type == ADDR_IF_LDAP ) {
2046 if( obj ) canBrowse = TRUE;
2053 /* Enable cut and paste */
2054 if( ! addrclip_is_empty( _clipBoard_ ) )
2056 if( ! addrselect_test_empty( _addressSelect_ ) )
2058 /* Enable copy if something is selected */
2059 if( ! addrselect_test_empty( _addressSelect_ ) )
2063 /* Disable edit or browse if more than one row selected */
2064 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2069 /* Forbid write changes when read-only */
2070 if( iface && iface->readOnly ) {
2076 /* Now go finalize menu items */
2077 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2078 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2080 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2081 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2082 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2084 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2086 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2087 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2088 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2090 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2091 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2092 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2094 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2095 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2097 if (addrbook.target_compose) {
2098 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2099 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2100 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2103 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2107 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2108 GtkCMCTreeNode *node,
2115 * Add list of items into tree node below specified tree node.
2116 * \param treeNode Tree node.
2117 * \param ds Data source.
2118 * \param listItems List of items.
2120 static void addressbook_treenode_add_list(
2121 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2127 AddrItemObject *aio;
2131 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2134 group = ( ItemGroup * ) aio;
2135 nn = addressbook_node_add_group( treeNode, ds, group );
2137 g_message("error adding addressbook group\n");
2140 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2143 folder = ( ItemFolder * ) aio;
2144 nn = addressbook_node_add_folder(
2145 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2147 g_message("error adding addressbook folder\n");
2150 node = g_list_next( node );
2154 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2155 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2159 * Cut from address list widget.
2161 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2162 _clipBoard_->cutFlag = TRUE;
2163 addrclip_clear( _clipBoard_ );
2164 addrclip_add( _clipBoard_, _addressSelect_ );
2165 /* addrclip_list_show( _clipBoard_, stdout ); */
2169 * Copy from address list widget.
2171 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2172 _clipBoard_->cutFlag = FALSE;
2173 addrclip_clear( _clipBoard_ );
2174 addrclip_add( _clipBoard_, _addressSelect_ );
2175 /* addrclip_list_show( _clipBoard_, stdout ); */
2179 * Paste clipboard into address list widget.
2181 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2182 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2183 AddressObject *pobj = NULL;
2184 AddressDataSource *ds = NULL;
2185 AddressBookFile *abf = NULL;
2186 ItemFolder *folder = NULL;
2187 GList *folderGroup = NULL;
2189 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2190 if( ds == NULL ) return;
2191 if( addrindex_ds_get_readonly( ds ) ) {
2192 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2196 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2198 if( pobj->type == ADDR_ITEM_FOLDER ) {
2199 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2201 else if( pobj->type == ADDR_ITEM_GROUP ) {
2202 alertpanel_error( _("Cannot paste into an address group.") );
2207 /* Get an address book */
2208 abf = addressbook_get_book_file();
2209 if( abf == NULL ) return;
2211 if( _clipBoard_->cutFlag ) {
2213 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2215 /* Remove all groups and folders in clipboard from tree node */
2216 addressbook_treenode_remove_item();
2218 /* Remove all "cut" items */
2219 addrclip_delete_item( _clipBoard_ );
2221 /* Clear clipboard - cut items??? */
2222 addrclip_clear( _clipBoard_ );
2226 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2229 /* addrclip_list_show( _clipBoard_, stdout ); */
2231 /* Update tree by inserting node for each folder or group */
2232 addressbook_treenode_add_list(
2233 addrbook.treeSelected, ds, folderGroup );
2234 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2235 g_list_free( folderGroup );
2239 /* Display items pasted */
2240 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2241 addressbook_set_clist(
2242 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2250 * Add current treenode object to clipboard. Note that widget only allows
2251 * one entry from the tree list to be selected.
2253 static void addressbook_treenode_to_clipboard( void ) {
2254 AddressObject *obj = NULL;
2255 AddressDataSource *ds = NULL;
2256 AddrSelectItem *item;
2257 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2258 GtkCMCTreeNode *node;
2260 node = addrbook.treeSelected;
2261 if( node == NULL ) return;
2262 obj = gtk_cmctree_node_get_row_data( ctree, node );
2263 if( obj == NULL ) return;
2265 ds = addressbook_find_datasource( node );
2266 if( ds == NULL ) return;
2269 if( obj->type == ADDR_ITEM_FOLDER ) {
2270 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2271 ItemFolder *folder = adapter->itemFolder;
2273 item = addrselect_create_node( obj );
2274 item->uid = g_strdup( ADDRITEM_ID(folder) );
2276 else if( obj->type == ADDR_ITEM_GROUP ) {
2277 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2278 ItemGroup *group = adapter->itemGroup;
2280 item = addrselect_create_node( obj );
2281 item->uid = g_strdup( ADDRITEM_ID(group) );
2283 else if( obj->type == ADDR_DATASOURCE ) {
2285 item = addrselect_create_node( obj );
2290 /* Clear existing list and add item into list */
2293 addressbook_list_select_clear();
2294 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2295 addrselect_list_add( _addressSelect_, item, cacheID );
2301 * Cut from tree widget.
2303 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2304 _clipBoard_->cutFlag = TRUE;
2305 addressbook_treenode_to_clipboard();
2306 addrclip_clear( _clipBoard_ );
2307 addrclip_add( _clipBoard_, _addressSelect_ );
2308 /* addrclip_list_show( _clipBoard_, stdout ); */
2312 * Copy from tree widget.
2314 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2315 _clipBoard_->cutFlag = FALSE;
2316 addressbook_treenode_to_clipboard();
2317 addrclip_clear( _clipBoard_ );
2318 addrclip_add( _clipBoard_, _addressSelect_ );
2319 /* addrclip_list_show( _clipBoard_, stdout ); */
2323 * Paste clipboard into address tree widget.
2325 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2326 addressbook_clip_paste_cb(NULL,NULL);
2330 * Clear selected entries in clipboard.
2332 static void addressbook_list_select_clear( void ) {
2333 addrselect_list_clear( _addressSelect_ );
2337 * Add specified address item to selected address list.
2338 * \param aio Address item object.
2339 * \param ds Datasource.
2341 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2344 if( ds == NULL ) return;
2345 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2346 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2351 * Remove specified address item from selected address list.
2352 * \param aio Address item object.
2354 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2355 addrselect_list_remove( _addressSelect_, aio );
2359 * Invoke EMail compose window with addresses in selected address list.
2361 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2364 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2365 listAddress = addrselect_build_list( _addressSelect_ );
2366 compose_new_with_list( NULL, listAddress );
2367 mgu_free_dlist( listAddress );
2372 static void addressbook_list_row_selected( GtkCMCTree *clist,
2373 GtkCMCTreeNode *node,
2377 AddrItemObject *aio = NULL;
2378 AddressObject *pobj = NULL;
2379 AdapterDSource *ads = NULL;
2380 AddressDataSource *ds = NULL;
2382 addrbook.listSelected = node;
2384 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2385 if( pobj == NULL ) return;
2387 if( pobj->type == ADDR_DATASOURCE ) {
2388 ads = ADAPTER_DSOURCE(pobj);
2389 ds = ads->dataSource;
2391 else if( pobj->type != ADDR_INTERFACE ) {
2392 ds = addressbook_find_datasource( addrbook.treeSelected );
2395 aio = gtk_cmctree_node_get_row_data( clist, node );
2397 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2398 addressbook_list_select_add( aio, ds );
2401 addressbook_list_menu_setup();
2403 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2404 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2406 if (obj && obj->type != ADDR_ITEM_GROUP)
2407 addressbook_edit_address(NULL, 0, NULL, FALSE);
2411 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2412 GtkCMCTreeNode *node,
2416 AddrItemObject *aio;
2418 aio = gtk_cmctree_node_get_row_data( ctree, node );
2420 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2421 addressbook_list_select_remove( aio );
2424 if (!prefs_common.addressbook_use_editaddress_dialog)
2425 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2428 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2430 addressbook_lup_clicked(NULL, NULL);
2433 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2434 GdkEventButton *event,
2437 if( ! event ) return FALSE;
2439 addressbook_list_menu_setup();
2441 if( event->button == 3 ) {
2442 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2443 event->button, event->time );
2444 } else if (event->button == 1) {
2445 if (event->type == GDK_2BUTTON_PRESS) {
2446 if (prefs_common.add_address_by_click &&
2447 addrbook.target_compose)
2448 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2450 if (prefs_common.addressbook_use_editaddress_dialog)
2451 addressbook_edit_address_cb(NULL, NULL);
2453 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2454 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2455 if( obj && obj->type == ADDR_ITEM_GROUP )
2456 addressbook_edit_address_cb(NULL, NULL);
2464 static gboolean addressbook_list_button_released(GtkWidget *widget,
2465 GdkEventButton *event,
2471 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2472 GdkEventButton *event,
2475 GtkCMCList *clist = GTK_CMCLIST(ctree);
2477 AddressObject *obj = NULL;
2478 AdapterDSource *ads = NULL;
2479 AddressInterface *iface = NULL;
2480 AddressDataSource *ds = NULL;
2481 gboolean canEdit = FALSE;
2482 gboolean canDelete = FALSE;
2483 gboolean canCut = FALSE;
2484 gboolean canCopy = FALSE;
2485 gboolean canPaste = FALSE;
2486 gboolean canTreeCut = FALSE;
2487 gboolean canTreeCopy = FALSE;
2488 gboolean canTreePaste = FALSE;
2489 gboolean canLookup = FALSE;
2490 GtkCMCTreeNode *node = NULL;
2492 if( ! event ) return FALSE;
2493 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2495 if (event->button == 1) {
2496 if (event->type == GDK_2BUTTON_PRESS) {
2497 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2498 gtkut_clist_set_focus_row(clist, row);
2499 obj = gtk_cmclist_get_row_data( clist, row );
2504 if (obj->type == ADDR_ITEM_GROUP ||
2505 obj->type == ADDR_DATASOURCE) {
2507 addressbook_treenode_edit_cb(NULL, NULL);
2509 /* expand pr collapse */
2510 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2511 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2517 addressbook_menubar_set_sensitive( FALSE );
2519 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2520 gtkut_clist_set_focus_row(clist, row);
2521 obj = gtk_cmclist_get_row_data( clist, row );
2524 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2528 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2530 if( ! addrclip_is_empty( _clipBoard_ ) )
2531 canTreePaste = TRUE;
2533 if (obj->type == ADDR_INTERFACE) {
2534 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2535 iface = adapter->interface;
2538 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2539 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2541 if( iface->externalQuery )
2544 if (obj->type == ADDR_DATASOURCE) {
2546 ads = ADAPTER_DSOURCE(obj);
2547 ds = ads->dataSource;
2550 iface = ds->interface;
2553 if( !iface->readOnly ) {
2554 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2555 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2556 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2562 else if (obj->type == ADDR_ITEM_FOLDER) {
2564 ds = addressbook_find_datasource( node );
2567 iface = ds->interface;
2570 if( !iface->readOnly ) {
2574 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2575 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2576 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2580 if( iface->externalQuery ) {
2581 /* Enable deletion of LDAP folder */
2585 else if (obj->type == ADDR_ITEM_GROUP) {
2587 ds = addressbook_find_datasource( node );
2590 iface = ds->interface;
2593 if( ! iface->readOnly ) {
2596 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2597 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2601 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2603 if( ! addrselect_test_empty( _addressSelect_ ) )
2605 if( ! addrclip_is_empty( _clipBoard_ ) )
2608 /* Forbid write changes when read-only */
2609 if( iface && iface->readOnly ) {
2611 canTreePaste = FALSE;
2618 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2619 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2620 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2621 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2622 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2624 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2625 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2626 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2627 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2628 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2630 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2631 addrbook.target_compose != NULL);
2633 if( event->button == 3 )
2634 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2635 event->button, event->time);
2640 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2641 GdkEventButton *event,
2644 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2648 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2650 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2651 AddressObject *obj = NULL;
2652 AddressDataSource *ds = NULL;
2653 AddressBookFile *abf = NULL;
2654 ItemFolder *parentFolder = NULL;
2655 ItemFolder *folder = NULL;
2657 if( ! addrbook.treeSelected ) return;
2658 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2659 if( obj == NULL ) return;
2660 ds = addressbook_find_datasource( addrbook.treeSelected );
2661 if( ds == NULL ) return;
2663 if( obj->type == ADDR_DATASOURCE ) {
2664 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2666 else if( obj->type == ADDR_ITEM_FOLDER ) {
2667 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2673 abf = ds->rawDataSource;
2674 if( abf == NULL ) return;
2675 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2678 nn = addressbook_node_add_folder(
2679 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2681 g_message("error adding addressbook folder\n");
2683 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2684 if( addrbook.treeSelected == addrbook.opened )
2685 addressbook_set_clist(obj, TRUE);
2689 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2691 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2692 AddressObject *obj = NULL;
2693 AddressDataSource *ds = NULL;
2694 AddressBookFile *abf = NULL;
2695 ItemFolder *parentFolder = NULL;
2696 ItemGroup *group = NULL;
2698 if( ! addrbook.treeSelected ) return;
2699 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2700 if( obj == NULL ) return;
2701 ds = addressbook_find_datasource( addrbook.treeSelected );
2702 if( ds == NULL ) return;
2704 if( obj->type == ADDR_DATASOURCE ) {
2705 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2707 else if( obj->type == ADDR_ITEM_FOLDER ) {
2708 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2714 abf = ds->rawDataSource;
2715 if( abf == NULL ) return;
2716 group = addressbook_edit_group( abf, parentFolder, NULL );
2719 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2721 g_message("error adding addressbook group\n");
2723 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2724 if( addrbook.treeSelected == addrbook.opened )
2725 addressbook_set_clist(obj, TRUE);
2729 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2731 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2734 GdkPixbuf *pix_cl, *pix_op;
2735 gboolean is_leaf, expanded;
2737 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2739 &is_leaf, &expanded);
2740 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2747 * \param obj Address object to edit.
2748 * \param node Node in tree.
2749 * \return New name of data source.
2751 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2752 gchar *newName = NULL;
2753 AddressDataSource *ds = NULL;
2754 AddressInterface *iface = NULL;
2755 AdapterDSource *ads = NULL;
2757 ds = addressbook_find_datasource( node );
2758 if( ds == NULL ) return NULL;
2759 iface = ds->interface;
2760 if( ! iface->haveLibrary ) return NULL;
2762 /* Read data from data source */
2763 if( addrindex_ds_get_modify_flag( ds ) ) {
2764 addrindex_ds_read_data( ds );
2767 if( ! addrindex_ds_get_read_flag( ds ) ) {
2768 addrindex_ds_read_data( ds );
2772 ads = ADAPTER_DSOURCE(obj);
2773 if( ads->subType == ADDR_BOOK ) {
2774 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2776 else if( ads->subType == ADDR_VCARD ) {
2777 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2780 else if( ads->subType == ADDR_JPILOT ) {
2781 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2785 else if( ads->subType == ADDR_LDAP ) {
2786 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2792 newName = obj->name;
2797 * Edit an object that is in the address tree area.
2799 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2801 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2803 AddressDataSource *ds = NULL;
2804 AddressBookFile *abf = NULL;
2805 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2808 if( ! addrbook.treeSelected ) return;
2809 node = addrbook.treeSelected;
2810 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2811 obj = gtk_cmctree_node_get_row_data( ctree, node );
2812 if( obj == NULL ) return;
2813 parentNode = GTK_CMCTREE_ROW(node)->parent;
2815 ds = addressbook_find_datasource( node );
2816 if( ds == NULL ) return;
2818 if( obj->type == ADDR_DATASOURCE ) {
2819 name = addressbook_edit_datasource( obj, node );
2820 if( name == NULL ) return;
2823 abf = ds->rawDataSource;
2824 if( abf == NULL ) return;
2825 if( obj->type == ADDR_ITEM_FOLDER ) {
2826 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2827 ItemFolder *item = adapter->itemFolder;
2828 ItemFolder *parentFolder = NULL;
2829 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2830 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2831 name = ADDRITEM_NAME(item);
2833 else if( obj->type == ADDR_ITEM_GROUP ) {
2834 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2835 ItemGroup *item = adapter->itemGroup;
2836 ItemFolder *parentFolder = NULL;
2837 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2838 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2839 name = ADDRITEM_NAME(item);
2842 if( name && parentNode ) {
2843 /* Update node in tree view */
2844 addressbook_change_node_name( node, name );
2845 gtk_sctree_sort_node(ctree, parentNode);
2846 gtk_cmctree_expand( ctree, node );
2847 gtk_sctree_select( GTK_SCTREE( ctree), node );
2854 ADDRTREE_DEL_FOLDER_ONLY,
2855 ADDRTREE_DEL_FOLDER_ADDR
2859 * Delete an item from the tree widget.
2860 * \param data Data passed in.
2861 * \param action Action.
2862 * \param widget Widget issuing callback.
2864 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2866 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2867 GtkCMCTreeNode *node = NULL;
2871 AddrBookBase *adbase;
2872 AddressCache *cache;
2873 AdapterDSource *ads = NULL;
2874 AddressInterface *iface = NULL;
2875 AddressDataSource *ds = NULL;
2876 gboolean remFlag = FALSE;
2877 TreeItemDelType delType;
2879 if( ! addrbook.treeSelected ) return;
2880 node = addrbook.treeSelected;
2881 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2883 obj = gtk_cmctree_node_get_row_data( ctree, node );
2884 cm_return_if_fail(obj != NULL);
2886 if( obj->type == ADDR_DATASOURCE ) {
2887 ads = ADAPTER_DSOURCE(obj);
2889 ds = ads->dataSource;
2890 if( ds == NULL ) return;
2893 /* Must be folder or something else */
2894 ds = addressbook_find_datasource( node );
2895 if( ds == NULL ) return;
2897 /* Only allow deletion from non-readOnly */
2898 iface = ds->interface;
2899 if( iface->readOnly ) {
2900 /* Allow deletion of query results */
2901 if( ! iface->externalQuery ) return;
2905 /* Confirm deletion */
2906 delType = ADDRTREE_DEL_NONE;
2907 if( obj->type == ADDR_ITEM_FOLDER ) {
2908 if( iface && iface->externalQuery ) {
2909 message = g_strdup_printf( _(
2910 "Do you want to delete the query " \
2911 "results and addresses in '%s'?" ),
2913 aval = alertpanel( _("Delete"), message,
2914 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2916 if( aval == G_ALERTALTERNATE ) {
2917 delType = ADDRTREE_DEL_FOLDER_ADDR;
2921 message = g_strdup_printf
2922 ( _( "Do you want to delete '%s'? "
2923 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2925 aval = alertpanel( _("Delete folder"), message,
2926 GTK_STOCK_CANCEL, g_strconcat("+",_("Delete _folder only"), NULL), _("Delete folder and _addresses"));
2928 if( aval == G_ALERTALTERNATE ) {
2929 delType = ADDRTREE_DEL_FOLDER_ONLY;
2931 else if( aval == G_ALERTOTHER ) {
2932 delType = ADDRTREE_DEL_FOLDER_ADDR;
2936 else if( obj->type == ADDR_ITEM_GROUP ) {
2937 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2938 "The addresses it contains will not be lost."), obj->name);
2939 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2940 "+" GTK_STOCK_DELETE, NULL);
2942 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2944 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2945 "The addresses it contains will be lost."), obj->name);
2946 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2947 "+" GTK_STOCK_DELETE, NULL);
2949 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2951 if( delType == ADDRTREE_DEL_NONE ) return;
2953 /* Proceed with deletion */
2954 if( obj->type == ADDR_DATASOURCE ) {
2955 /* Remove node from tree */
2956 gtk_cmctree_remove_node( ctree, node );
2958 if (delType == ADDRTREE_DEL_DATA &&
2959 ds->interface && ds->interface->type == ADDR_IF_BOOK)
2960 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
2962 /* Remove data source. */
2963 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2964 addrindex_free_datasource( ds );
2969 /* Get reference to cache */
2970 adbase = ( AddrBookBase * ) ds->rawDataSource;
2971 if( adbase == NULL ) return;
2972 cache = adbase->addressCache;
2974 /* Remove query results folder */
2975 if( iface && iface->externalQuery ) {
2976 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2977 ItemFolder *folder = adapter->itemFolder;
2979 adapter->itemFolder = NULL;
2981 g_print( "remove folder for ::%s::\n", obj->name );
2982 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2983 g_print( "-------------- remove results\n" );
2985 addrindex_remove_results( ds, folder );
2986 /* g_print( "-------------- remove node\n" ); */
2987 gtk_cmctree_remove_node( ctree, node );
2991 /* Code below is valid for regular address book deletion */
2992 if( obj->type == ADDR_ITEM_FOLDER ) {
2993 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2994 ItemFolder *item = adapter->itemFolder;
2996 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2997 /* Remove folder only */
2998 item = addrcache_remove_folder( cache, item );
3000 addritem_free_item_folder( item );
3001 addressbook_move_nodes_up( ctree, node );
3005 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3006 /* Remove folder and addresses */
3007 item = addrcache_remove_folder_delete( cache, item );
3009 addritem_free_item_folder( item );
3014 else if( obj->type == ADDR_ITEM_GROUP ) {
3015 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3016 ItemGroup *item = adapter->itemGroup;
3018 item = addrcache_remove_group( cache, item );
3020 addritem_free_item_group( item );
3027 gtk_cmctree_remove_node(ctree, node );
3031 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3033 if( person && addrbook.treeSelected == addrbook.opened ) {
3034 person->status = ADD_ENTRY;
3035 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3036 addressbook_folder_refresh_one_person(
3037 GTK_CMCTREE(addrbook.clist), person );
3039 addressbook_address_list_set_focus();
3042 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3044 if( person && addrbook.treeSelected == addrbook.opened) {
3045 person->status = ADD_ENTRY;
3046 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3047 addressbook_set_clist(
3048 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3052 addressbook_address_list_set_focus();
3056 * Label (a format string) that is used to name each folder.
3058 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3061 * Search ctree widget callback function.
3062 * \param pA Pointer to node.
3063 * \param pB Pointer to data item being sought.
3064 * \return Zero (0) if folder found.
3066 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3069 aoA = ( AddressObject * ) pA;
3070 if( aoA->type == ADDR_ITEM_FOLDER ) {
3071 ItemFolder *folder, *fld;
3073 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3074 folder = ( ItemFolder * ) pB;
3075 if( fld == folder ) return 0; /* Found folder */
3080 static ItemFolder * addressbook_setup_subf(
3081 AddressDataSource *ds, gchar *title,
3082 GtkCMCTreeNode *pNode )
3084 AddrBookBase *adbase;
3085 AddressCache *cache;
3088 GtkCMCTreeNode *nNode;
3090 AddressObjectType aoType = ADDR_NONE;
3093 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3095 if( ds && ds->type == ADDR_IF_LDAP ) {
3097 aoType = ADDR_LDAP_QUERY;
3104 ctree = GTK_CMCTREE(addrbook.ctree);
3105 /* Get reference to address cache */
3106 adbase = ( AddrBookBase * ) ds->rawDataSource;
3107 cache = adbase->addressCache;
3109 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3110 GList *cur = children;
3111 for (; cur; cur = cur->next) {
3112 ItemFolder *child = (ItemFolder *) cur->data;
3113 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3114 nNode = gtk_cmctree_find_by_row_data_custom(
3116 addressbook_treenode_find_folder_cb );
3118 addrindex_remove_results( ds, child );
3119 while( child->listPerson ) {
3120 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3121 item = addrcache_remove_person( cache, item );
3123 addritem_free_item_person( item );
3127 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3128 addrbook.treeSelected = nNode;
3135 /* Create a folder */
3136 folder = addrcache_add_new_folder( cache, NULL );
3137 name = g_strdup_printf( "%s", title );
3138 addritem_folder_set_name( folder, name );
3139 addritem_folder_set_remarks( folder, "" );
3142 /* Now let's see the folder */
3143 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3144 gtk_cmctree_expand( ctree, pNode );
3146 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3147 addrbook.treeSelected = nNode;
3153 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3154 AddressObject *pobj = NULL;
3155 AddressDataSource *ds = NULL;
3156 AddressBookFile *abf = NULL;
3157 debug_print("adding address\n");
3158 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3159 if( pobj == NULL ) {
3160 debug_print("no row data\n");
3163 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3165 debug_print("no datasource\n");
3169 abf = ds->rawDataSource;
3171 g_print("no addressbook file\n");
3175 if( pobj->type == ADDR_DATASOURCE ) {
3176 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3177 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3179 ItemFolder *folder = NULL;
3181 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3182 GtkCMCTreeNode *parentNode;
3183 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3184 if( ds == NULL ) return;
3186 /* We must have a datasource that is an external interface */
3187 if( ! ds->interface->haveLibrary ) return;
3188 if( ! ds->interface->externalQuery ) return;
3190 if( pobj->type == ADDR_ITEM_FOLDER ) {
3191 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3194 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3196 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3198 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3200 abf = ds->rawDataSource;
3203 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3204 addrbook.editaddress_vbox,
3205 addressbook_new_address_from_book_post_cb,
3208 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3209 LdapServer *server = ds->rawDataSource;
3210 ldapsvr_set_modified(server, TRUE);
3211 ldapsvr_update_book(server, NULL);
3212 if (server->retVal != LDAPRC_SUCCESS) {
3213 alertpanel( _("Add address(es)"),
3214 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3215 GTK_STOCK_CLOSE, NULL, NULL );
3216 server->retVal = LDAPRC_SUCCESS;
3221 if (prefs_common.addressbook_use_editaddress_dialog)
3222 addressbook_new_address_from_book_post_cb( person );
3225 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3227 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
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 );
3249 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3251 abf = ds->rawDataSource;
3254 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3255 addrbook.editaddress_vbox,
3256 addressbook_new_address_from_folder_post_cb,
3259 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3260 LdapServer *server = ds->rawDataSource;
3261 ldapsvr_set_modified(server, TRUE);
3262 ldapsvr_update_book(server, NULL);
3263 if (server->retVal != LDAPRC_SUCCESS) {
3264 alertpanel( _("Add address(es)"),
3265 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3266 GTK_STOCK_CLOSE, NULL, NULL );
3271 if (prefs_common.addressbook_use_editaddress_dialog)
3272 addressbook_new_address_from_folder_post_cb( person );
3274 else if( pobj->type == ADDR_ITEM_GROUP ) {
3275 /* New address in group */
3276 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3277 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3278 if (addrbook.treeSelected == addrbook.opened) {
3279 /* Change node name in tree. */
3280 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3281 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3282 addressbook_set_clist(
3283 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3291 * Search for specified child group node in address index tree.
3292 * \param parent Parent node.
3293 * \param group Group to find.
3295 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3296 GtkCMCTreeNode *node = NULL;
3297 GtkCMCTreeRow *currRow;
3299 currRow = GTK_CMCTREE_ROW( parent );
3301 node = currRow->children;
3305 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3306 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3307 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3308 if( g == group ) return node;
3310 currRow = GTK_CMCTREE_ROW(node);
3311 node = currRow->sibling;
3317 static AddressBookFile *addressbook_get_book_file() {
3318 AddressBookFile *abf = NULL;
3319 AddressDataSource *ds = NULL;
3321 ds = addressbook_find_datasource( addrbook.treeSelected );
3322 if( ds == NULL ) return NULL;
3323 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3327 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3328 GtkCMCTreeNode *node;
3331 /* Remove existing folders and groups */
3332 row = GTK_CMCTREE_ROW( parent );
3334 while( (node = row->children) ) {
3335 gtk_cmctree_remove_node( ctree, node );
3340 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3341 GtkCMCTreeNode *parent, *child;
3342 GtkCMCTreeRow *currRow;
3343 currRow = GTK_CMCTREE_ROW( node );
3345 parent = currRow->parent;
3346 while( (child = currRow->children) ) {
3347 gtk_cmctree_move( ctree, child, parent, node );
3349 gtk_sctree_sort_node( ctree, parent );
3353 static void addressbook_edit_address_post_cb( ItemPerson *person )
3357 AddressBookFile *abf = addressbook_get_book_file();
3359 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3360 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3361 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3364 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3365 invalidate_address_completion();
3367 addressbook_address_list_set_focus();
3370 void addressbook_address_list_set_focus( void )
3372 if (!prefs_common.addressbook_use_editaddress_dialog) {
3373 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3374 addressbook_list_menu_setup();
3378 void addressbook_address_list_disable_some_actions(void)
3380 /* disable address copy/pasting when editing contact's detail (embedded form) */
3381 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3382 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3383 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3386 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3387 addressbook_edit_address(data, 0, NULL, TRUE);
3390 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3391 gboolean force_focus ) {
3392 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3394 AddressObject *obj = NULL, *pobj = NULL;
3395 AddressDataSource *ds = NULL;
3396 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3398 AddressBookFile *abf = NULL;
3400 if( addrbook.listSelected == NULL ) return;
3401 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3402 cm_return_if_fail(obj != NULL);
3404 ctree = GTK_CMCTREE( addrbook.ctree );
3405 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3407 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3408 if( ds == NULL ) return;
3410 abf = addressbook_get_book_file();
3412 if( obj->type == ADDR_ITEM_EMAIL ) {
3413 ItemEMail *email = ( ItemEMail * ) obj;
3415 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3416 /* Edit parent group */
3417 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3418 ItemGroup *itemGrp = adapter->itemGroup;
3419 if( abf == NULL ) return;
3420 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3421 name = ADDRITEM_NAME(itemGrp);
3422 node = addrbook.treeSelected;
3423 parentNode = GTK_CMCTREE_ROW(node)->parent;
3426 /* Edit person - email page */
3428 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3429 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3430 addressbook_edit_address_post_cb,
3431 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3434 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3435 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3436 person->status = UPDATE_ENTRY;
3439 if (prefs_common.addressbook_use_editaddress_dialog)
3440 addressbook_edit_address_post_cb( person );
3445 else if( obj->type == ADDR_ITEM_PERSON ) {
3446 /* Edit person - basic page */
3447 ItemPerson *person = ( ItemPerson * ) obj;
3448 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3449 addressbook_edit_address_post_cb,
3450 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3453 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3454 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3455 person->status = UPDATE_ENTRY;
3458 if (prefs_common.addressbook_use_editaddress_dialog)
3459 addressbook_edit_address_post_cb( person );
3463 else if( obj->type == ADDR_ITEM_GROUP ) {
3464 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3465 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3466 parentNode = addrbook.treeSelected;
3467 node = addressbook_find_group_node( parentNode, itemGrp );
3468 name = ADDRITEM_NAME(itemGrp);
3469 invalidate_address_completion();
3475 /* Update tree node with node name */
3476 if( node == NULL ) return;
3477 addressbook_change_node_name( node, name );
3478 gtk_sctree_sort_node( ctree, parentNode );
3479 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3480 addressbook_set_clist(
3481 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3486 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3488 addressbook_del_clicked(NULL, NULL);
3491 static void close_cb(GtkAction *action, gpointer data)
3493 addressbook_close();
3496 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3497 addressbook_export_to_file();
3500 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3502 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3503 if( person ) addritem_person_set_opened( person, TRUE );
3507 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3509 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3510 if( person ) addritem_person_set_opened( person, FALSE );
3514 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3516 gchar *eMailAlias = ADDRITEM_NAME(email);
3517 if( eMailAlias && *eMailAlias != '\0' ) {
3519 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3522 str = g_strdup( eMailAlias );
3528 static gboolean addressbook_match_item(const gchar *name,
3529 const gchar *email_alias,
3531 const gchar *remarks,
3536 if (!str || str[0] == '\0')
3538 if (strcasestr(name, str))
3540 else if (email_alias && strcasestr(email_alias, str))
3542 else if (addr && strcasestr(addr, str))
3544 else if (remarks && strcasestr(remarks, str))
3550 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3551 GList *items = itemGroup->listEMail;
3552 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3553 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3554 for( ; items != NULL; items = g_list_next( items ) ) {
3555 GtkCMCTreeNode *nodeEMail = NULL;
3556 gchar *text[N_LIST_COLS];
3557 ItemEMail *email = items->data;
3561 if( ! email ) continue;
3563 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3565 if( !addressbook_match_item(ADDRITEM_NAME(person),
3566 ADDRITEM_NAME(email),
3567 email->address, email->remarks,
3571 str = addressbook_format_item_clist( person, email );
3573 text[COL_NAME] = addressbook_set_col_name_guard(str);
3576 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3578 text[COL_ADDRESS] = email->address;
3579 text[COL_REMARKS] = email->remarks;
3580 nodeEMail = gtk_sctree_insert_node(
3582 text, FOLDER_SPACING,
3586 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3592 gchar *addressbook_set_col_name_guard(gchar *value)
3594 gchar *ret = "<not set>";
3595 gchar *tmp = g_strdup(value);
3597 if (tmp !=NULL && *tmp != '\0')
3603 static void addressbook_folder_load_one_person(
3604 GtkCMCTree *clist, ItemPerson *person,
3605 AddressTypeControlItem *atci,
3606 AddressTypeControlItem *atciMail )
3608 GtkCMCTreeNode *nodePerson = NULL;
3609 GtkCMCTreeNode *nodeEMail = NULL;
3610 gchar *text[N_LIST_COLS];
3611 gboolean flgFirst = TRUE, haveAddr = FALSE;
3614 AddressBookFile *abf = addressbook_get_book_file();
3617 if( person == NULL ) return;
3619 text[COL_NAME] = "";
3620 node = person->listEMail;
3622 ItemEMail *email = node->data;
3623 gchar *eMailAddr = NULL;
3624 node = g_list_next( node );
3626 text[COL_ADDRESS] = email->address;
3627 text[COL_REMARKS] = email->remarks;
3628 eMailAddr = ADDRITEM_NAME(email);
3629 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3631 /* First email belongs with person */
3632 gchar *str = addressbook_format_item_clist( person, email );
3634 text[COL_NAME] = addressbook_set_col_name_guard(str);
3637 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3638 person && person->nickName ) {
3639 if (person->nickName) {
3640 if (strcmp(person->nickName, "") != 0) {
3641 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3644 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3650 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3652 nodePerson = gtk_sctree_insert_node(
3654 text, FOLDER_SPACING,
3657 FALSE, person->isOpened );
3660 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3663 /* Subsequent email is a child node of person */
3664 text[COL_NAME] = ADDRITEM_NAME(email);
3665 nodeEMail = gtk_sctree_insert_node(
3666 clist, nodePerson, NULL,
3667 text, FOLDER_SPACING,
3669 atciMail->iconXpmOpen,
3671 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3677 /* Have name without EMail */
3678 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3679 text[COL_ADDRESS] = "";
3680 text[COL_REMARKS] = "";
3681 nodePerson = gtk_sctree_insert_node(
3683 text, FOLDER_SPACING,
3686 FALSE, person->isOpened );
3687 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3692 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3694 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3695 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3696 const gchar *search_str;
3698 if( atci == NULL ) return;
3699 if( atciMail == NULL ) return;
3701 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3703 /* Load email addresses */
3704 items = addritem_folder_get_person_list( itemFolder );
3705 for( ; items != NULL; items = g_list_next( items ) ) {
3710 person = (ItemPerson *)items->data;
3713 node = person->listEMail;
3714 if (node && node->data) {
3716 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3719 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3723 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3725 /* Free up the list */
3726 mgu_clear_list( items );
3727 g_list_free( items );
3730 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3731 addrbook.listSelected = NULL;
3732 gtk_cmctree_remove_node( clist, node );
3733 addressbook_menubar_set_sensitive( FALSE );
3734 addressbook_menuitem_set_sensitive(
3735 gtk_cmctree_node_get_row_data(
3736 GTK_CMCTREE(clist), addrbook.treeSelected ),
3737 addrbook.treeSelected );
3740 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3741 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3742 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3743 GtkCMCTreeNode *node;
3744 if( atci == NULL ) return;
3745 if( atciMail == NULL ) return;
3746 if( person == NULL ) return;
3747 /* unload the person */
3749 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3751 addressbook_folder_remove_node( clist, node );
3752 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3753 gtk_sctree_sort_node( clist, NULL );
3754 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3756 gtk_sctree_select( GTK_SCTREE(clist), node );
3757 if (!gtk_cmctree_node_is_visible( clist, node ) )
3758 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3762 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3763 GtkCMCTreeNode *node;
3765 if( person == NULL ) return;
3766 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3768 addressbook_folder_remove_node( clist, node );
3772 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3774 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3775 const gchar *search_str;
3777 /* Load any groups */
3778 if( ! atci ) return;
3780 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3782 items = addritem_folder_get_group_list( itemFolder );
3783 for( ; items != NULL; items = g_list_next( items ) ) {
3784 GtkCMCTreeNode *nodeGroup = NULL;
3785 gchar *text[N_LIST_COLS];
3786 ItemGroup *group = items->data;
3787 if( group == NULL ) continue;
3788 if( !addressbook_match_item(ADDRITEM_NAME(group),
3789 NULL, NULL, NULL, search_str) )
3792 text[COL_NAME] = ADDRITEM_NAME(group);
3793 text[COL_ADDRESS] = "";
3794 text[COL_REMARKS] = "";
3795 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3796 text, FOLDER_SPACING,
3800 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3801 gtk_sctree_sort_node(clist, NULL);
3803 /* Free up the list */
3804 mgu_clear_list( items );
3805 g_list_free( items );
3809 * Search ctree widget callback function.
3810 * \param pA Pointer to node.
3811 * \param pB Pointer to data item being sought.
3812 * \return Zero (0) if group found.
3814 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3817 aoA = ( AddressObject * ) pA;
3818 if( aoA->type == ADDR_ITEM_GROUP ) {
3819 ItemGroup *group, *grp;
3821 grp = ADAPTER_GROUP(aoA)->itemGroup;
3822 group = ( ItemGroup * ) pB;
3823 if( grp == group ) return 0; /* Found group */
3829 * Remove folder and group nodes from tree widget for items contained ("cut")
3832 static void addressbook_treenode_remove_item( void ) {
3834 AddrSelectItem *cutItem;
3835 AddressCache *cache;
3836 AddrItemObject *aio;
3837 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3840 node = _clipBoard_->objectList;
3842 cutItem = node->data;
3843 node = g_list_next( node );
3844 cache = addrindex_get_cache(
3845 _clipBoard_->addressIndex, cutItem->cacheID );
3846 if( cache == NULL ) continue;
3847 aio = addrcache_get_object( cache, cutItem->uid );
3850 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3853 folder = ( ItemFolder * ) aio;
3854 tn = gtk_cmctree_find_by_row_data_custom(
3855 ctree, NULL, folder,
3856 addressbook_treenode_find_folder_cb );
3858 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3861 group = ( ItemGroup * ) aio;
3862 tn = gtk_cmctree_find_by_row_data_custom(
3864 addressbook_treenode_find_group_cb );
3868 /* Free up adapter and remove node. */
3869 gtk_cmctree_remove_node( ctree, tn );
3876 * Find parent datasource for specified tree node.
3877 * \param node Node to test.
3878 * \return Data source, or NULL if not found.
3880 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3881 AddressDataSource *ds = NULL;
3884 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3887 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3888 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3890 /* g_print( "ao->type = %d\n", ao->type ); */
3891 if( ao->type == ADDR_DATASOURCE ) {
3892 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3893 /* g_print( "found it\n" ); */
3894 ds = ads->dataSource;
3898 node = GTK_CMCTREE_ROW(node)->parent;
3904 * Load address list widget with children of specified object.
3905 * \param obj Parent object to be loaded.
3907 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3908 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3909 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3910 AddressDataSource *ds = NULL;
3911 AdapterDSource *ads = NULL;
3912 static AddressObject *last_obj = NULL;
3914 if (addrbook.clist == NULL) {
3917 if (obj == last_obj && !refresh)
3922 gtk_cmclist_clear(clist);
3926 if( obj->type == ADDR_INTERFACE ) {
3927 /* g_print( "set_clist: loading datasource...\n" ); */
3928 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3932 gtk_cmclist_freeze(clist);
3933 gtk_cmclist_clear(clist);
3935 if( obj->type == ADDR_DATASOURCE ) {
3936 ads = ADAPTER_DSOURCE(obj);
3937 ds = ads->dataSource;
3939 /* Load root folder */
3940 ItemFolder *rootFolder = NULL;
3941 rootFolder = addrindex_ds_get_root_folder( ds );
3942 addressbook_folder_load_person(
3943 ctreelist, rootFolder );
3944 addressbook_folder_load_group(
3945 ctreelist, rootFolder );
3949 if( obj->type == ADDR_ITEM_GROUP ) {
3951 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3952 addressbook_load_group( ctreelist, itemGroup );
3954 else if( obj->type == ADDR_ITEM_FOLDER ) {
3956 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3957 addressbook_folder_load_person( ctreelist, itemFolder );
3958 addressbook_folder_load_group( ctreelist, itemFolder );
3961 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3962 clist->focus_row = -1;
3963 gtk_cmclist_thaw(clist);
3967 * Call back function to free adaptor. Call back is setup by function
3968 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3969 * called when the address book tree widget node is removed by calling
3970 * function gtk_cmctree_remove_node().
3972 * \param data Tree node's row data.
3974 static void addressbook_free_treenode( gpointer data ) {
3977 ao = ( AddressObject * ) data;
3978 if( ao == NULL ) return;
3979 if( ao->type == ADDR_INTERFACE ) {
3980 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3981 addrbookctl_free_interface( ai );
3983 else if( ao->type == ADDR_DATASOURCE ) {
3984 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3985 addrbookctl_free_datasource( ads );
3987 else if( ao->type == ADDR_ITEM_FOLDER ) {
3988 AdapterFolder *af = ADAPTER_FOLDER(ao);
3989 addrbookctl_free_folder( af );
3991 else if( ao->type == ADDR_ITEM_GROUP ) {
3992 AdapterGroup *ag = ADAPTER_GROUP(ao);
3993 addrbookctl_free_group( ag );
3998 * Create new adaptor for specified data source.
4000 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4001 AddressObjectType otype, gchar *name )
4003 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4004 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4005 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4006 adapter->dataSource = ds;
4007 adapter->subType = otype;
4011 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4012 ADDRESS_OBJECT_NAME(adapter) =
4013 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4017 * Load tree from address index with the initial data.
4019 static void addressbook_load_tree( void ) {
4020 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4021 GList *nodeIf, *nodeDS;
4022 AdapterInterface *adapter;
4023 AddressInterface *iface;
4024 AddressTypeControlItem *atci;
4025 AddressDataSource *ds;
4026 AdapterDSource *ads;
4027 GtkCMCTreeNode *node, *newNode;
4030 nodeIf = _addressInterfaceList_;
4032 adapter = nodeIf->data;
4033 node = adapter->treeNode;
4034 iface = adapter->interface;
4035 atci = adapter->atci;
4037 if( iface->useInterface ) {
4038 /* Load data sources below interface node */
4039 nodeDS = iface->listSource;
4042 name = addrindex_ds_get_name( ds );
4043 ads = addressbook_create_ds_adapter(
4044 ds, atci->objectType, name );
4045 newNode = addressbook_add_object(
4046 node, ADDRESS_OBJECT(ads) );
4047 if (newNode == NULL) {
4048 g_message("error adding addressbook object\n");
4050 nodeDS = g_list_next( nodeDS );
4052 gtk_cmctree_expand( ctree, node );
4055 nodeIf = g_list_next( nodeIf );
4060 * Convert the old address book to new format.
4062 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4063 gboolean retVal = FALSE;
4064 gboolean errFlag = TRUE;
4067 /* Read old address book, performing conversion */
4068 debug_print( "Reading and converting old address book...\n" );
4069 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4070 addrindex_read_data( addrIndex );
4071 if( addrIndex->retVal == MGU_NO_FILE ) {
4072 /* We do not have a file - new user */
4073 debug_print( "New user... create new books...\n" );
4074 addrindex_create_new_books( addrIndex );
4075 if( addrIndex->retVal == MGU_SUCCESS ) {
4076 /* Save index file */
4077 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4078 addrindex_save_data( addrIndex );
4079 if( addrIndex->retVal == MGU_SUCCESS ) {
4084 msg = _( "New user, could not save index file." );
4088 msg = _( "New user, could not save address book files." );
4092 /* We have an old file */
4093 if( addrIndex->wasConverted ) {
4094 /* Converted successfully - save address index */
4095 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4096 addrindex_save_data( addrIndex );
4097 if( addrIndex->retVal == MGU_SUCCESS ) {
4098 msg = _( "Old address book converted successfully." );
4103 msg = _("Old address book converted,\n"
4104 "could not save new address index file." );
4108 /* File conversion failed - just create new books */
4109 debug_print( "File conversion failed... just create new books...\n" );
4110 addrindex_create_new_books( addrIndex );
4111 if( addrIndex->retVal == MGU_SUCCESS ) {
4113 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4114 addrindex_save_data( addrIndex );
4115 if( addrIndex->retVal == MGU_SUCCESS ) {
4116 msg = _("Could not convert address book,\n"
4117 "but created empty new address book files." );
4122 msg = _("Could not convert address book,\n"
4123 "could not save new address index file." );
4127 msg = _("Could not convert address book\n"
4128 "and could not create new address book files." );
4133 debug_print( "Error\n%s\n", msg );
4134 alertpanel_full(_("Addressbook conversion error"), msg,
4135 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4136 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4139 debug_print( "Warning\n%s\n", msg );
4140 alertpanel_full(_("Addressbook conversion error"), msg,
4141 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4142 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4148 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4152 gboolean failed = FALSE;
4153 GError *error = NULL;
4155 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4156 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4157 error->code, error->message);
4158 g_error_free(error);
4162 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4163 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4166 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4168 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4170 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4183 /* all copies succeeded, we can remove source files */
4184 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4185 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4186 error->code, error->message);
4187 g_error_free(error);
4190 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4191 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4194 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4196 claws_unlink(orig_file);
4206 void addressbook_read_file( void ) {
4207 AddressIndex *addrIndex = NULL;
4208 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4210 debug_print( "Reading address index...\n" );
4211 if( _addressIndex_ ) {
4212 debug_print( "address book already read!!!\n" );
4216 addrIndex = addrindex_create_index();
4217 addrindex_initialize();
4219 /* Use new address book index. */
4221 if ( !is_dir_exist(indexdir) ) {
4222 if ( make_dir(indexdir) < 0 ) {
4223 addrindex_set_file_path( addrIndex, get_rc_dir() );
4224 g_warning( "couldn't create dir '%s'", indexdir);
4226 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4227 remove_dir_recursive(indexdir);
4228 addrindex_set_file_path( addrIndex, get_rc_dir() );
4229 g_error("couldn't migrate dir %s", indexdir);
4231 addrindex_set_file_path( addrIndex, indexdir);
4235 addrindex_set_file_path( addrIndex, indexdir);
4238 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4239 addrindex_read_data( addrIndex );
4240 if( addrIndex->retVal == MGU_NO_FILE ) {
4241 /* Conversion required */
4242 debug_print( "Converting...\n" );
4243 if( addressbook_convert( addrIndex ) ) {
4244 _addressIndex_ = addrIndex;
4247 else if( addrIndex->retVal == MGU_SUCCESS ) {
4248 _addressIndex_ = addrIndex;
4251 /* Error reading address book */
4252 debug_print( "Could not read address index.\n" );
4253 addrindex_print_index( addrIndex, stdout );
4254 alertpanel_full(_("Addressbook Error"),
4255 _("Could not read address index"),
4256 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4257 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4259 debug_print( "done.\n" );
4263 * Add object into the address index tree widget.
4264 * Enter: node Parent node.
4265 * obj Object to add.
4266 * Return: Node that was added, or NULL if object not added.
4268 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4271 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4272 GtkCMCTreeNode *added;
4273 AddressObject *pobj;
4274 AddressObjectType otype;
4275 AddressTypeControlItem *atci = NULL;
4277 cm_return_val_if_fail(node != NULL, NULL);
4278 cm_return_val_if_fail(obj != NULL, NULL);
4280 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4281 cm_return_val_if_fail(pobj != NULL, NULL);
4283 /* Determine object type to be displayed */
4284 if( obj->type == ADDR_DATASOURCE ) {
4285 otype = ADAPTER_DSOURCE(obj)->subType;
4291 /* Handle any special conditions. */
4293 atci = addrbookctl_lookup( otype );
4295 if( atci->showInTree ) {
4296 /* Add object to tree */
4299 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4300 atci->iconXpm, atci->iconXpmOpen,
4301 atci->treeLeaf, atci->treeExpand );
4302 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4303 addressbook_free_treenode );
4307 gtk_sctree_sort_node(ctree, node);
4313 * Add group into the address index tree.
4314 * \param node Parent node.
4315 * \param ds Data source.
4316 * \param itemGroup Group to add.
4317 * \return Inserted node.
4319 static GtkCMCTreeNode *addressbook_node_add_group(
4320 GtkCMCTreeNode *node, AddressDataSource *ds,
4321 ItemGroup *itemGroup )
4323 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4324 GtkCMCTreeNode *newNode;
4325 AdapterGroup *adapter;
4326 AddressTypeControlItem *atci = NULL;
4329 if( ds == NULL ) return NULL;
4330 if( node == NULL || itemGroup == NULL ) return NULL;
4332 name = &itemGroup->obj.name;
4334 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4336 adapter = g_new0( AdapterGroup, 1 );
4337 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4338 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4339 adapter->itemGroup = itemGroup;
4341 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4342 atci->iconXpm, atci->iconXpm,
4343 atci->treeLeaf, atci->treeExpand );
4344 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4345 addressbook_free_treenode );
4346 gtk_sctree_sort_node( ctree, node );
4351 * Add folder into the address index tree. Only visible folders are loaded into
4352 * the address index tree. Note that the root folder is not inserted into the
4355 * \param node Parent node.
4356 * \param ds Data source.
4357 * \param itemFolder Folder to add.
4358 * \param otype Object type to display.
4359 * \return Inserted node for the folder.
4361 static GtkCMCTreeNode *addressbook_node_add_folder(
4362 GtkCMCTreeNode *node, AddressDataSource *ds,
4363 ItemFolder *itemFolder, AddressObjectType otype )
4365 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4366 GtkCMCTreeNode *newNode = NULL;
4367 AdapterFolder *adapter;
4368 AddressTypeControlItem *atci = NULL;
4369 GList *listItems = NULL;
4371 ItemFolder *rootFolder;
4373 /* Only visible folders */
4374 if( itemFolder == NULL || itemFolder->isHidden )
4379 if( node == NULL || itemFolder == NULL )
4382 /* Determine object type */
4383 atci = addrbookctl_lookup( otype );
4387 rootFolder = addrindex_ds_get_root_folder( ds );
4388 if( itemFolder == rootFolder ) {
4392 adapter = g_new0( AdapterFolder, 1 );
4393 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4394 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4395 adapter->itemFolder = itemFolder;
4397 name = ADDRITEM_NAME(itemFolder);
4398 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4399 atci->iconXpm, atci->iconXpm,
4400 atci->treeLeaf, atci->treeExpand );
4402 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4403 addressbook_free_treenode );
4407 listItems = itemFolder->listFolder;
4408 while( listItems ) {
4409 ItemFolder *item = listItems->data;
4410 addressbook_node_add_folder( newNode, ds, item, otype );
4411 listItems = g_list_next( listItems );
4413 listItems = itemFolder->listGroup;
4414 while( listItems ) {
4415 ItemGroup *item = listItems->data;
4416 addressbook_node_add_group( newNode, ds, item );
4417 listItems = g_list_next( listItems );
4419 gtk_sctree_sort_node( ctree, node );
4423 void addressbook_export_to_file( void ) {
4424 if( _addressIndex_ ) {
4425 /* Save all new address book data */
4426 debug_print( "Saving address books...\n" );
4427 addrindex_save_all_books( _addressIndex_ );
4429 debug_print( "Exporting addressbook to file...\n" );
4430 addrindex_save_data( _addressIndex_ );
4431 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4432 addrindex_print_index( _addressIndex_, stdout );
4435 /* Notify address completion of new data */
4436 invalidate_address_completion();
4440 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4442 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4443 addressbook_lup_clicked(NULL, NULL);
4448 * Comparison using cell contents (text in first column). Used for sort
4449 * address index widget.
4451 static gint addressbook_treenode_compare_func(
4452 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4454 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4455 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4456 gchar *name1 = NULL, *name2 = NULL;
4457 if( cell1 ) name1 = cell1->u.text;
4458 if( cell2 ) name2 = cell2->u.text;
4459 if( ! name1 ) return ( name2 != NULL );
4460 if( ! name2 ) return -1;
4461 return g_utf8_collate( name1, name2 );
4464 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4465 AdapterDSource *ads;
4466 AdapterInterface *adapter;
4467 GtkCMCTreeNode *newNode;
4469 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4470 if( adapter == NULL ) return;
4471 ads = addressbook_edit_book( _addressIndex_, NULL );
4473 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4475 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4476 addrbook.treeSelected = newNode;
4481 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4482 AdapterDSource *ads;
4483 AdapterInterface *adapter;
4484 GtkCMCTreeNode *newNode;
4486 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4487 if( adapter == NULL ) return;
4488 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4490 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4492 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4493 addrbook.treeSelected = newNode;
4499 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4500 AdapterDSource *ads;
4501 AdapterInterface *adapter;
4502 AddressInterface *iface;
4503 GtkCMCTreeNode *newNode;
4505 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4506 if( adapter == NULL ) return;
4507 iface = adapter->interface;
4508 if( ! iface->haveLibrary ) return;
4509 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4511 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4513 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4514 addrbook.treeSelected = newNode;
4521 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4522 AdapterDSource *ads;
4523 AdapterInterface *adapter;
4524 AddressInterface *iface;
4525 GtkCMCTreeNode *newNode;
4527 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4528 if( adapter == NULL ) return;
4529 iface = adapter->interface;
4530 if( ! iface->haveLibrary ) return;
4531 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4533 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4535 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4536 addrbook.treeSelected = newNode;
4543 * Display address search status message.
4544 * \param queryType Query type.
4545 * \param status Status/Error code.
4547 static void addressbook_search_message( gint queryType, gint sts ) {
4549 *addressbook_msgbuf = '\0';
4551 if( sts != MGU_SUCCESS ) {
4552 if( queryType == ADDRQUERY_LDAP ) {
4554 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4559 g_snprintf( addressbook_msgbuf,
4560 sizeof(addressbook_msgbuf), "%s", desc );
4561 addressbook_status_show( addressbook_msgbuf );
4564 addressbook_status_show( "" );
4569 * Refresh addressbook by forcing refresh of current selected object in
4572 static void addressbook_refresh_current( void ) {
4576 ctree = GTK_CMCTREE(addrbook.ctree);
4577 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4578 if( obj == NULL ) return;
4579 addressbook_set_clist( obj, TRUE );
4583 * Message that is displayed whilst a query is executing in a background
4586 static gchar *_tempMessage_ = N_( "Busy searching..." );
4589 * Address search idle function. This function is called during UI idle time
4590 * while a search is in progress.
4592 * \param data Idler data.
4594 static void addressbook_search_idle( gpointer data ) {
4598 queryID = GPOINTER_TO_INT( data );
4599 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4604 * Search completion callback function. This removes the query from the idle
4607 * \param sender Sender of query.
4608 * \param queryID Query ID of search request.
4609 * \param status Search status.
4610 * \param data Query data.
4612 static void addressbook_search_callback_end(
4613 gpointer sender, gint queryID, gint status, gpointer data )
4617 AddrQueryObject *aqo;
4619 /* Remove idler function */
4620 ptrQID = GINT_TO_POINTER( queryID );
4622 g_idle_remove_by_data( ptrQID );
4625 /* Refresh addressbook contents */
4626 addressbook_refresh_current();
4627 req = qrymgr_find_request( queryID );
4629 aqo = ( AddrQueryObject * ) req->queryList->data;
4630 addressbook_search_message( aqo->queryType, status );
4633 /* Stop the search */
4634 addrindex_stop_search( queryID );
4640 * \param ds Data source to search.
4641 * \param searchTerm String to lookup.
4642 * \param pNode Parent data source node.
4644 static void addressbook_perform_search(
4645 AddressDataSource *ds, gchar *searchTerm,
4646 GtkCMCTreeNode *pNode )
4654 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4656 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4658 /* Create a folder for the search results */
4659 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4660 folder = addressbook_setup_subf(ds, name, pNode);
4663 /* Setup the search */
4664 queryID = addrindex_setup_explicit_search(
4665 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4666 if( queryID == 0 ) return;
4668 /* Set up idler function */
4669 idleID = g_idle_add(
4670 (GSourceFunc) addressbook_search_idle,
4671 GINT_TO_POINTER( queryID ) );
4673 g_message("error adding addressbook_search_idle\n");
4676 /* Start search, sit back and wait for something to happen */
4677 addrindex_start_search( queryID );
4679 addressbook_status_show( _tempMessage_ );
4683 * Lookup button handler. Address search is only performed against
4684 * address interfaces for external queries.
4686 * \param button Lookup button widget.
4687 * \param data Data object.
4689 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4692 AddressDataSource *ds;
4693 AddressInterface *iface;
4695 GtkCMCTreeNode *node, *parentNode;
4697 node = addrbook.treeSelected;
4698 if( ! node ) return;
4699 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4701 ctree = GTK_CMCTREE(addrbook.ctree);
4702 obj = gtk_cmctree_node_get_row_data( ctree, node );
4703 if( obj == NULL ) return;
4705 if (obj->type != ADDR_DATASOURCE ||
4706 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4707 addressbook_set_clist(
4708 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4709 addrbook.treeSelected),
4713 ds = addressbook_find_datasource( node );
4714 if( ds == NULL ) return;
4716 /* We must have a datasource that is an external interface */
4717 iface = ds->interface;
4718 if( ! iface->haveLibrary ) return;
4719 if( ! iface->externalQuery ) return;
4722 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4723 g_strchomp( searchTerm );
4725 if( obj->type == ADDR_ITEM_FOLDER ) {
4726 parentNode = GTK_CMCTREE_ROW(node)->parent;
4731 addressbook_perform_search( ds, searchTerm, parentNode );
4733 gtk_widget_grab_focus( addrbook.entry );
4735 g_free( searchTerm );
4738 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4739 addressbook_close();
4744 * Browse address entry for highlighted entry.
4746 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4748 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4750 AddressDataSource *ds;
4751 AddressInterface *iface;
4755 if(addrbook.listSelected == NULL)
4758 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4762 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4766 iface = ds->interface;
4767 if(!iface || !iface->haveLibrary )
4771 if (obj->type == ADDR_ITEM_EMAIL) {
4772 email = ( ItemEMail * ) obj;
4774 person = (ItemPerson *) ADDRITEM_PARENT(email);
4776 else if (obj->type == ADDR_ITEM_PERSON) {
4777 person = (ItemPerson *) obj;
4784 if( iface && iface->type == ADDR_IF_LDAP ) {
4785 browseldap_entry(ds, person->externalID);
4790 /* **********************************************************************
4791 * Build lookup tables.
4792 * ***********************************************************************
4796 * Remap object types.
4797 * Enter: abType AddressObjectType (used in tree node).
4798 * Return: ItemObjectType (used in address cache data).
4800 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4801 ItemObjectType ioType;
4804 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4805 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4806 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4807 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4808 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4809 default: ioType = ITEMTYPE_NONE; break;
4814 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4815 atci = addrbookctl_lookup(id); \
4817 atci->iconXpm = icon; \
4818 atci->iconXpmOpen = iconopen; \
4820 g_warning("can't get atci %d", id); \
4825 * Build table that controls the rendering of object types.
4827 static void addrbookctl_build_icons( GtkWidget *window ) {
4828 AddressTypeControlItem *atci;
4832 g_object_unref(interfacexpm);
4834 g_object_unref(folderxpm);
4836 g_object_unref(folderopenxpm);
4838 g_object_unref(groupxpm);
4840 g_object_unref(vcardxpm);
4842 g_object_unref(bookxpm);
4844 g_object_unref(addressxpm);
4846 g_object_unref(jpilotxpm);
4848 g_object_unref(categoryxpm);
4850 g_object_unref(ldapxpm);
4852 g_object_unref(addrsearchxpm);
4853 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4854 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4855 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4856 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4857 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4858 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4859 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4860 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4861 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4862 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4863 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4865 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4866 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4867 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4868 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4869 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4870 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4871 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4872 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4873 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4874 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4875 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4880 * Build table that controls the rendering of object types.
4882 static void addrbookctl_build_map( GtkWidget *window ) {
4883 AddressTypeControlItem *atci;
4885 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4886 _addressBookTypeList_ = NULL;
4889 atci = g_new0( AddressTypeControlItem, 1 );
4890 atci->objectType = ADDR_INTERFACE;
4891 atci->interfaceType = ADDR_IF_NONE;
4892 atci->showInTree = TRUE;
4893 atci->treeExpand = TRUE;
4894 atci->treeLeaf = FALSE;
4895 atci->displayName = _( "Interface" );
4896 atci->menuCommand = NULL;
4897 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4898 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4901 atci = g_new0( AddressTypeControlItem, 1 );
4902 atci->objectType = ADDR_BOOK;
4903 atci->interfaceType = ADDR_IF_BOOK;
4904 atci->showInTree = TRUE;
4905 atci->treeExpand = TRUE;
4906 atci->treeLeaf = FALSE;
4907 atci->displayName = _("Address Books");
4908 atci->menuCommand = "Menu/Book/NewBook";
4909 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4910 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4913 atci = g_new0( AddressTypeControlItem, 1 );
4914 atci->objectType = ADDR_ITEM_PERSON;
4915 atci->interfaceType = ADDR_IF_NONE;
4916 atci->showInTree = FALSE;
4917 atci->treeExpand = FALSE;
4918 atci->treeLeaf = FALSE;
4919 atci->displayName = _( "Person" );
4920 atci->menuCommand = NULL;
4921 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4922 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4925 atci = g_new0( AddressTypeControlItem, 1 );
4926 atci->objectType = ADDR_ITEM_EMAIL;
4927 atci->interfaceType = ADDR_IF_NONE;
4928 atci->showInTree = FALSE;
4929 atci->treeExpand = FALSE;
4930 atci->treeLeaf = TRUE;
4931 atci->displayName = _( "Email Address" );
4932 atci->menuCommand = NULL;
4933 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4934 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4937 atci = g_new0( AddressTypeControlItem, 1 );
4938 atci->objectType = ADDR_ITEM_GROUP;
4939 atci->interfaceType = ADDR_IF_BOOK;
4940 atci->showInTree = TRUE;
4941 atci->treeExpand = FALSE;
4942 atci->treeLeaf = FALSE;
4943 atci->displayName = _( "Group" );
4944 atci->menuCommand = NULL;
4945 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4946 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4949 atci = g_new0( AddressTypeControlItem, 1 );
4950 atci->objectType = ADDR_ITEM_FOLDER;
4951 atci->interfaceType = ADDR_IF_BOOK;
4952 atci->showInTree = TRUE;
4953 atci->treeExpand = FALSE;
4954 atci->treeLeaf = FALSE;
4955 atci->displayName = _( "Folder" );
4956 atci->menuCommand = NULL;
4957 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4958 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4961 atci = g_new0( AddressTypeControlItem, 1 );
4962 atci->objectType = ADDR_VCARD;
4963 atci->interfaceType = ADDR_IF_VCARD;
4964 atci->showInTree = TRUE;
4965 atci->treeExpand = TRUE;
4966 atci->treeLeaf = TRUE;
4967 atci->displayName = _( "vCard" );
4968 atci->menuCommand = "Menu/Book/NewVCard";
4969 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4970 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4973 atci = g_new0( AddressTypeControlItem, 1 );
4974 atci->objectType = ADDR_JPILOT;
4975 atci->interfaceType = ADDR_IF_JPILOT;
4976 atci->showInTree = TRUE;
4977 atci->treeExpand = TRUE;
4978 atci->treeLeaf = FALSE;
4979 atci->displayName = _( "JPilot" );
4980 atci->menuCommand = "Menu/Book/NewJPilot";
4981 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4982 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4985 atci = g_new0( AddressTypeControlItem, 1 );
4986 atci->objectType = ADDR_CATEGORY;
4987 atci->interfaceType = ADDR_IF_JPILOT;
4988 atci->showInTree = TRUE;
4989 atci->treeExpand = TRUE;
4990 atci->treeLeaf = TRUE;
4991 atci->displayName = _( "JPilot" );
4992 atci->menuCommand = NULL;
4993 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4994 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4997 atci = g_new0( AddressTypeControlItem, 1 );
4998 atci->objectType = ADDR_LDAP;
4999 atci->interfaceType = ADDR_IF_LDAP;
5000 atci->showInTree = TRUE;
5001 atci->treeExpand = TRUE;
5002 atci->treeLeaf = FALSE;
5003 atci->displayName = _( "LDAP servers" );
5004 atci->menuCommand = "Menu/Book/NewLDAPServer";
5005 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5006 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5009 atci = g_new0( AddressTypeControlItem, 1 );
5010 atci->objectType = ADDR_LDAP_QUERY;
5011 atci->interfaceType = ADDR_IF_LDAP;
5012 atci->showInTree = TRUE;
5013 atci->treeExpand = FALSE;
5014 atci->treeLeaf = TRUE;
5015 atci->displayName = _( "LDAP Query" );
5016 atci->menuCommand = NULL;
5017 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5018 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5020 addrbookctl_build_icons(window);
5023 void addressbook_reflect_prefs_pixmap_theme(void)
5025 if (addrbook.window)
5026 addrbookctl_build_icons(addrbook.window);
5030 * Search for specified object type.
5032 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5034 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5038 * Search for specified interface type.
5040 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5041 GList *node = _addressBookTypeList_;
5043 AddressTypeControlItem *atci = node->data;
5044 if( atci->interfaceType == ifType ) return atci;
5045 node = g_list_next( node );
5050 static void addrbookctl_free_address( AddressObject *obj ) {
5051 g_free( obj->name );
5052 obj->type = ADDR_NONE;
5056 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5057 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5058 adapter->interface = NULL;
5059 adapter->interfaceType = ADDR_IF_NONE;
5060 adapter->atci = NULL;
5061 adapter->enabled = FALSE;
5062 adapter->haveLibrary = FALSE;
5063 adapter->treeNode = NULL;
5067 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5068 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5069 adapter->dataSource = NULL;
5070 adapter->subType = ADDR_NONE;
5074 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5075 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5076 adapter->itemFolder = NULL;
5080 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5081 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5082 adapter->itemGroup = NULL;
5087 * Build GUI interface list.
5089 static void addrbookctl_build_iflist( void ) {
5090 AddressTypeControlItem *atci;
5091 AdapterInterface *adapter;
5094 if( _addressIndex_ == NULL ) {
5095 _addressIndex_ = addrindex_create_index();
5096 if( _clipBoard_ == NULL ) {
5097 _clipBoard_ = addrclip_create();
5099 addrclip_set_index( _clipBoard_, _addressIndex_ );
5101 _addressInterfaceList_ = NULL;
5102 list = addrindex_get_interface_list( _addressIndex_ );
5104 AddressInterface *interface = list->data;
5105 atci = addrbookctl_lookup_iface( interface->type );
5107 adapter = g_new0( AdapterInterface, 1 );
5108 adapter->interfaceType = interface->type;
5109 adapter->atci = atci;
5110 adapter->interface = interface;
5111 adapter->treeNode = NULL;
5112 adapter->enabled = TRUE;
5113 adapter->haveLibrary = interface->haveLibrary;
5114 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5115 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5116 _addressInterfaceList_ =
5117 g_list_append( _addressInterfaceList_, adapter );
5119 list = g_list_next( list );
5124 * Find GUI interface type specified interface type.
5125 * \param ifType Interface type.
5126 * \return Interface item, or NULL if not found.
5128 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5129 GList *node = _addressInterfaceList_;
5131 AdapterInterface *adapter = node->data;
5132 if( adapter->interfaceType == ifType ) return adapter;
5133 node = g_list_next( node );
5139 * Build interface list selection.
5141 static void addrbookctl_build_ifselect( void ) {
5142 GList *newList = NULL;
5147 gchar *endptr = NULL;
5148 /* gboolean enabled; */
5149 AdapterInterface *adapter;
5151 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5154 splitStr = g_strsplit( selectStr, ",", -1 );
5155 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5157 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5158 ifType = strtol( splitStr[i], &endptr, 10 );
5161 if( strcmp( endptr, "/n" ) == 0 ) {
5166 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5167 adapter = addrbookctl_find_interface( ifType );
5169 newList = g_list_append( newList, adapter );
5176 /* g_print( "i=%d\n", i ); */
5177 g_strfreev( splitStr );
5178 g_free( selectStr );
5180 /* Replace existing list */
5181 mgu_clear_list( _addressIFaceSelection_ );
5182 g_list_free( _addressIFaceSelection_ );
5183 _addressIFaceSelection_ = newList;
5187 /* ***********************************************************************
5188 * Add sender to address book.
5189 * ***********************************************************************
5193 * This function is used by the Add sender to address book function.
5195 gboolean addressbook_add_contact(
5196 const gchar *name, const gchar *address, const gchar *remarks,
5197 GdkPixbuf *picture )
5199 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5200 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5201 debug_print( "addressbook_add_contact - added\n" );
5202 addressbook_refresh();
5207 /* ***********************************************************************
5208 * Book/folder selection.
5209 * ***********************************************************************
5213 * This function is used by the matcher dialog to select a book/folder.
5215 gchar *addressbook_folder_selection( const gchar *folderpath)
5217 AddressBookFile *book = NULL;
5218 ItemFolder *folder = NULL;
5221 cm_return_val_if_fail( folderpath != NULL, NULL);
5223 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5225 if ( folder != NULL) {
5227 gchar *oldtmp = NULL;
5228 AddrItemObject *obj = NULL;
5230 /* walk thru folder->parent to build the full folder path */
5231 /* TODO: wwp: optimize this */
5233 tmp = g_strdup(obj->uid);
5234 while ( obj->parent ) {
5236 if ( obj->name != NULL ) {
5237 oldtmp = g_strdup(tmp);
5239 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5243 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5246 path = g_strdup_printf("%s", book->fileName);
5248 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5254 /* ***********************************************************************
5255 * Book/folder checking.
5256 * ***********************************************************************
5259 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5261 FolderInfo *fi = g_new0( FolderInfo, 1 );
5263 fi->folder = folder;
5267 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5268 FolderInfo *fiParent, FolderPathMatch *match )
5274 FolderPathMatch *nextmatch = NULL;
5279 list = parentFolder->listFolder;
5281 folder = list->data;
5282 fName = g_strdup( ADDRITEM_NAME(folder) );
5284 /* match folder name, match pointer will be set to NULL if next recursive call
5285 doesn't need to match subfolder name */
5286 if ( match != NULL &&
5287 match->matched == FALSE ) {
5288 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5289 /* folder name matches, prepare next subfolder match */
5290 debug_print("matched folder name '%s'\n", fName);
5292 if ( match->folder_path[match->index] == NULL ) {
5293 /* we've matched all elements */
5294 match->matched = TRUE;
5295 match->folder = folder;
5296 debug_print("book/folder path matched!\n");
5298 /* keep on matching */
5306 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5307 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5309 list = g_list_next( list );
5314 * This function is used by to check if a matcher book/folder path corresponds to an
5315 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5316 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5317 if book AND folder are NULL this means that folderpath was empty or Any.
5318 If folderpath is a simple book name (without folder), book will not be NULL and folder
5319 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5322 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5323 AddressDataSource **book,
5324 ItemFolder **folder )
5326 AddressDataSource *ds;
5327 GList *list, *nodeDS;
5328 ItemFolder *rootFolder;
5329 AddressBookFile *abf;
5331 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5338 if ( folderpath == NULL )
5341 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5344 /* split the folder path we've received, we'll try to match this path, subpath by
5345 subpath against the book/folder structure in order */
5346 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5347 if (!folder_path_match.folder_path)
5350 list = addrindex_get_interface_list( _addressIndex_ );
5351 while ( list && !folder_path_match.matched ) {
5352 AddressInterface *interface = list->data;
5353 if ( interface && interface->type == ADDR_IF_BOOK ) {
5354 nodeDS = interface->listSource;
5355 while ( nodeDS && !folder_path_match.matched ) {
5358 /* Read address book */
5359 if( ! addrindex_ds_get_read_flag( ds ) ) {
5360 addrindex_ds_read_data( ds );
5363 /* Add node for address book */
5364 abf = ds->rawDataSource;
5366 /* match book name */
5367 if ( abf && abf->fileName &&
5368 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5370 debug_print("matched book name '%s'\n", abf->fileName);
5371 folder_path_match.book = ds;
5373 if ( folder_path_match.folder_path[1] == NULL ) {
5374 /* no folder part to match */
5376 folder_path_match.matched = TRUE;
5377 folder_path_match.folder = NULL;
5378 debug_print("book path matched!\n");
5381 /* match folder part */
5383 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5384 rootFolder = addrindex_ds_get_root_folder( ds );
5386 /* prepare for recursive call */
5387 folder_path_match.index = 1;
5388 /* this call will set folder_path_match.matched and folder_path_match.folder */
5389 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5394 nodeDS = g_list_next( nodeDS );
5397 list = g_list_next( list );
5400 g_strfreev( folder_path_match.folder_path );
5403 *book = folder_path_match.book;
5405 *folder = folder_path_match.folder;
5406 return folder_path_match.matched;
5410 /* **********************************************************************
5412 * ***********************************************************************
5418 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5419 AddressDataSource *ds = NULL;
5420 AdapterDSource *ads = NULL;
5421 AddressBookFile *abf = NULL;
5422 AdapterInterface *adapter;
5423 GtkCMCTreeNode *newNode;
5425 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5427 if( adapter->treeNode ) {
5428 abf = addressbook_imp_ldif( _addressIndex_ );
5430 ds = addrindex_index_add_datasource(
5431 _addressIndex_, ADDR_IF_BOOK, abf );
5432 ads = addressbook_create_ds_adapter(
5433 ds, ADDR_BOOK, NULL );
5434 addressbook_ads_set_name(
5435 ads, addrbook_get_name( abf ) );
5436 newNode = addressbook_add_object(
5438 ADDRESS_OBJECT(ads) );
5440 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5442 addrbook.treeSelected = newNode;
5445 /* Notify address completion */
5446 invalidate_address_completion();
5455 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5456 AddressDataSource *ds = NULL;
5457 AdapterDSource *ads = NULL;
5458 AddressBookFile *abf = NULL;
5459 AdapterInterface *adapter;
5460 GtkCMCTreeNode *newNode;
5462 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5464 if( adapter->treeNode ) {
5465 abf = addressbook_imp_mutt( _addressIndex_ );
5467 ds = addrindex_index_add_datasource(
5468 _addressIndex_, ADDR_IF_BOOK, abf );
5469 ads = addressbook_create_ds_adapter(
5470 ds, ADDR_BOOK, NULL );
5471 addressbook_ads_set_name(
5472 ads, addrbook_get_name( abf ) );
5473 newNode = addressbook_add_object(
5475 ADDRESS_OBJECT(ads) );
5477 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5479 addrbook.treeSelected = newNode;
5482 /* Notify address completion */
5483 invalidate_address_completion();
5492 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5493 AddressDataSource *ds = NULL;
5494 AdapterDSource *ads = NULL;
5495 AddressBookFile *abf = NULL;
5496 AdapterInterface *adapter;
5497 GtkCMCTreeNode *newNode;
5499 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5501 if( adapter->treeNode ) {
5502 abf = addressbook_imp_pine( _addressIndex_ );
5504 ds = addrindex_index_add_datasource(
5505 _addressIndex_, ADDR_IF_BOOK, abf );
5506 ads = addressbook_create_ds_adapter(
5507 ds, ADDR_BOOK, NULL );
5508 addressbook_ads_set_name(
5509 ads, addrbook_get_name( abf ) );
5510 newNode = addressbook_add_object(
5512 ADDRESS_OBJECT(ads) );
5514 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5516 addrbook.treeSelected = newNode;
5519 /* Notify address completion */
5520 invalidate_address_completion();
5527 * Harvest addresses.
5528 * \param folderItem Folder to import.
5529 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5530 * \param msgList List of message numbers, or NULL to process folder.
5532 void addressbook_harvest(
5533 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5535 AddressDataSource *ds = NULL;
5536 AdapterDSource *ads = NULL;
5537 AddressBookFile *abf = NULL;
5538 AdapterInterface *adapter;
5539 GtkCMCTreeNode *newNode;
5541 abf = addrgather_dlg_execute(
5542 folderItem, _addressIndex_, sourceInd, msgList );
5544 ds = addrindex_index_add_datasource(
5545 _addressIndex_, ADDR_IF_BOOK, abf );
5547 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5549 if( adapter->treeNode ) {
5550 ads = addressbook_create_ds_adapter(
5551 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5552 newNode = addressbook_add_object(
5554 ADDRESS_OBJECT(ads) );
5555 if (newNode == NULL) {
5556 g_message("error adding addressbook object\n");
5561 /* Notify address completion */
5562 invalidate_address_completion();
5569 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5570 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5572 AddressDataSource *ds = NULL;
5573 AddrBookBase *adbase;
5574 AddressCache *cache;
5575 GtkCMCTreeNode *node = NULL;
5577 if( ! addrbook.treeSelected ) return;
5578 node = addrbook.treeSelected;
5579 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5580 obj = gtk_cmctree_node_get_row_data( ctree, node );
5581 if( obj == NULL ) return;
5583 ds = addressbook_find_datasource( node );
5584 if( ds == NULL ) return;
5585 adbase = ( AddrBookBase * ) ds->rawDataSource;
5586 cache = adbase->addressCache;
5587 addressbook_exp_html( cache );
5593 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5594 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5596 AddressDataSource *ds = NULL;
5597 AddrBookBase *adbase;
5598 AddressCache *cache;
5599 GtkCMCTreeNode *node = NULL;
5601 if( ! addrbook.treeSelected ) return;
5602 node = addrbook.treeSelected;
5603 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5604 obj = gtk_cmctree_node_get_row_data( ctree, node );
5605 if( obj == NULL ) return;
5607 ds = addressbook_find_datasource( node );
5608 if( ds == NULL ) return;
5609 adbase = ( AddrBookBase * ) ds->rawDataSource;
5610 cache = adbase->addressCache;
5611 addressbook_exp_ldif( cache );
5614 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5616 addrduplicates_find(GTK_WINDOW(addrbook.window));
5619 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5621 addressbook_custom_attr_edit();
5624 static void addressbook_start_drag(GtkWidget *widget, gint button,
5628 GdkDragContext *context;
5629 if (addressbook_target_list == NULL)
5630 addressbook_target_list = gtk_target_list_new(
5631 addressbook_drag_types, 1);
5632 context = gtk_drag_begin(widget, addressbook_target_list,
5633 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5634 gtk_drag_set_icon_default(context);
5637 static void addressbook_drag_data_get(GtkWidget *widget,
5638 GdkDragContext *drag_context,
5639 GtkSelectionData *selection_data,
5644 AddrItemObject *aio = NULL;
5645 AddressObject *pobj = NULL;
5646 AdapterDSource *ads = NULL;
5647 AddressDataSource *ds = NULL;
5650 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5652 if( pobj == NULL ) return;
5654 if( pobj->type == ADDR_DATASOURCE ) {
5655 ads = ADAPTER_DSOURCE(pobj);
5656 ds = ads->dataSource;
5657 } else if (pobj->type == ADDR_ITEM_GROUP) {
5662 else if( pobj->type != ADDR_INTERFACE ) {
5663 ds = addressbook_find_datasource( addrbook.treeSelected );
5669 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5670 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5671 GTK_CMCTREE_NODE(cur->data));
5672 while (aio && aio->type != ITEMTYPE_PERSON) {
5677 if (aio && aio->type == ITEMTYPE_PERSON) {
5678 if( ds && ds->interface && ds->interface->readOnly)
5679 gtk_selection_data_set(selection_data,
5680 gtk_selection_data_get_target(selection_data), 8,
5681 (const guchar *)"Dummy_addr_copy", 15);
5683 gtk_selection_data_set(selection_data,
5684 gtk_selection_data_get_target(selection_data), 8,
5685 (const guchar *)"Dummy_addr_move", 15);
5689 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5690 GdkDragContext *context,
5696 GtkAllocation allocation;
5697 GtkRequisition requisition;
5699 GtkCMCTreeNode *node = NULL;
5700 gboolean acceptable = FALSE;
5701 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5702 gint height = allocation.height;
5703 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5704 gint total_height = requisition.height;
5705 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5706 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5707 gfloat vpos = gtk_adjustment_get_value(pos);
5709 if (gtk_cmclist_get_selection_info
5710 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5712 if (y > height - 24 && height + vpos < total_height) {
5713 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5714 gtk_adjustment_changed(pos);
5716 if (y < 24 && y > 0) {
5717 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5718 gtk_adjustment_changed(pos);
5720 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5723 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5724 if( obj->type == ADDR_ITEM_FOLDER
5725 || obj->type == ADDR_ITEM_GROUP)
5728 AdapterDSource *ads = NULL;
5729 AddressDataSource *ds = NULL;
5730 ads = ADAPTER_DSOURCE(obj);
5731 if (ads == NULL ){ return FALSE;}
5732 ds = ads->dataSource;
5733 if (ds == NULL ) { return FALSE;}
5741 g_signal_handlers_block_by_func
5743 G_CALLBACK(addressbook_tree_selected), NULL);
5744 gtk_sctree_select( GTK_SCTREE(widget), node);
5745 g_signal_handlers_unblock_by_func
5747 G_CALLBACK(addressbook_tree_selected), NULL);
5748 gdk_drag_status(context,
5749 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5750 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5752 gdk_drag_status(context, 0, time);
5757 static void addressbook_drag_leave_cb(GtkWidget *widget,
5758 GdkDragContext *context,
5762 if (addrbook.treeSelected) {
5763 g_signal_handlers_block_by_func
5765 G_CALLBACK(addressbook_tree_selected), NULL);
5766 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5767 g_signal_handlers_unblock_by_func
5769 G_CALLBACK(addressbook_tree_selected), NULL);
5774 static void addressbook_drag_received_cb(GtkWidget *widget,
5775 GdkDragContext *drag_context,
5778 GtkSelectionData *data,
5784 GtkCMCTreeNode *node;
5785 GtkCMCTreeNode *lastopened = addrbook.opened;
5787 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5788 if (gtk_cmclist_get_selection_info
5789 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5793 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5794 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5797 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5798 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5799 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5800 addressbook_clip_copy_cb(NULL, NULL);
5802 addressbook_clip_cut_cb(NULL, NULL);
5803 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5804 addressbook_clip_paste_cb(NULL,NULL);
5805 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5806 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5807 gtk_drag_finish(drag_context, TRUE, TRUE, time);