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"
55 #include "addressitem.h"
57 #include "addrcache.h"
59 #include "addrindex.h"
60 #include "addressadd.h"
61 #include "addrduplicates.h"
62 #include "addressbook_foldersel.h"
64 #include "editvcard.h"
65 #include "editgroup.h"
66 #include "editaddress.h"
68 #include "importldif.h"
69 #include "importmutt.h"
70 #include "importpine.h"
75 #include "editjpilot.h"
80 #include "ldapserver.h"
82 #include "ldapupdate.h"
84 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
87 #include "addrquery.h"
88 #include "addrselect.h"
90 #include "addrgather.h"
91 #include "adbookbase.h"
92 #include "exphtmldlg.h"
93 #include "expldifdlg.h"
94 #include "browseldap.h"
95 #include "addrcustomattr.h"
103 } AddressIndexColumns;
111 } AddressListColumns;
114 AddressBookFile *book;
122 AddressDataSource *book;
126 static gchar *list_titles[] = { N_("Name"),
130 #define COL_NAME_WIDTH 164
131 #define COL_ADDRESS_WIDTH 156
133 #define COL_FOLDER_WIDTH 170
134 #define ADDRESSBOOK_WIDTH 640
135 #define ADDRESSBOOK_HEIGHT 360
137 #define ADDRESSBOOK_MSGBUF_SIZE 2048
139 static GdkPixbuf *folderxpm = NULL;
140 static GdkPixbuf *folderopenxpm = NULL;
141 static GdkPixbuf *groupxpm = NULL;
142 static GdkPixbuf *interfacexpm = NULL;
143 static GdkPixbuf *bookxpm = NULL;
144 static GdkPixbuf *addressxpm = NULL;
145 static GdkPixbuf *vcardxpm = NULL;
146 static GdkPixbuf *jpilotxpm = NULL;
147 static GdkPixbuf *categoryxpm = NULL;
148 static GdkPixbuf *ldapxpm = NULL;
149 static GdkPixbuf *addrsearchxpm = NULL;
152 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
154 /* Address list selection */
155 static AddrSelectList *_addressSelect_ = NULL;
156 static AddressClipboard *_clipBoard_ = NULL;
158 /* Address index file and interfaces */
159 static AddressIndex *_addressIndex_ = NULL;
160 static GList *_addressInterfaceList_ = NULL;
161 static GList *_addressIFaceSelection_ = NULL;
162 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
164 static AddressBook_win addrbook;
166 static GHashTable *_addressBookTypeHash_ = NULL;
167 static GList *_addressBookTypeList_ = NULL;
169 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
170 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
171 static void addressbook_edit_address_post_cb( ItemPerson *person );
173 static void addressbook_create (void);
174 static gint addressbook_close (void);
176 static gboolean address_index_has_focus = FALSE;
177 static gboolean address_list_has_focus = FALSE;
179 /* callback functions */
180 static void addressbook_del_clicked (GtkButton *button,
182 static void addressbook_reg_clicked (GtkButton *button,
184 static void addressbook_to_clicked (GtkButton *button,
186 static void addressbook_lup_clicked (GtkButton *button,
188 static void addressbook_close_clicked (GtkButton *button,
191 static void addressbook_tree_selected (GtkCMCTree *ctree,
192 GtkCMCTreeNode *node,
195 static void addressbook_select_row_tree (GtkCMCTree *ctree,
196 GtkCMCTreeNode *node,
199 static void addressbook_list_row_selected (GtkCMCTree *clist,
200 GtkCMCTreeNode *node,
203 static void addressbook_list_row_unselected (GtkCMCTree *clist,
204 GtkCMCTreeNode *node,
207 static void addressbook_person_expand_node (GtkCMCTree *ctree,
210 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
214 static void addressbook_entry_activated (GtkWidget *widget,
217 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
218 GdkEventButton *event,
220 static gboolean addressbook_list_button_released(GtkWidget *widget,
221 GdkEventButton *event,
223 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
224 GdkEventButton *event,
226 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
227 GdkEventButton *event,
230 static void addressbook_new_folder_cb (GtkAction *action,
232 static void addressbook_new_group_cb (GtkAction *action,
234 static void addressbook_treenode_edit_cb (GtkAction *action,
236 static void addressbook_treenode_delete_cb (GtkAction *action,
239 static void addressbook_change_node_name (GtkCMCTreeNode *node,
242 static void addressbook_new_address_cb (GtkAction *action,
244 static void addressbook_edit_address_cb (GtkAction *action,
246 static void addressbook_delete_address_cb (GtkAction *action,
249 static void close_cb (GtkAction *action,
251 static void addressbook_file_save_cb (GtkAction *action,
254 /* Data source edit stuff */
255 static void addressbook_new_book_cb (GtkAction *action,
257 static void addressbook_new_vcard_cb (GtkAction *action,
261 static void addressbook_new_jpilot_cb (GtkAction *action,
266 static void addressbook_new_ldap_cb (GtkAction *action,
270 static void addressbook_set_clist (AddressObject *obj,
273 static void addressbook_load_tree (void);
274 void addressbook_read_file (void);
276 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
278 static void addressbook_treenode_remove_item ( void );
280 static AddressDataSource *addressbook_find_datasource
281 (GtkCMCTreeNode *node );
283 static AddressBookFile *addressbook_get_book_file(void);
285 static GtkCMCTreeNode *addressbook_node_add_folder
286 (GtkCMCTreeNode *node,
287 AddressDataSource *ds,
288 ItemFolder *itemFolder,
289 AddressObjectType otype);
290 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
291 AddressDataSource *ds,
292 ItemGroup *itemGroup);
293 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
294 GtkCMCTreeNode *parent);
295 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
296 GtkCMCTreeNode *node);
297 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
299 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
302 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
305 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
307 AddressTypeControlItem *atci,
308 AddressTypeControlItem *atciMail);
309 static void addressbook_folder_refresh_one_person(GtkCMCTree *clist,
311 static void addressbook_folder_remove_one_person(GtkCMCTree *clist,
313 static void addressbook_folder_remove_node (GtkCMCTree *clist,
314 GtkCMCTreeNode *node);
316 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
317 gboolean force_focus );
319 /* LUT's and IF stuff */
320 static void addressbook_free_treenode ( gpointer data );
321 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
322 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
324 static void addrbookctl_build_map (GtkWidget *window);
325 static void addrbookctl_build_iflist (void);
326 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
327 static void addrbookctl_build_ifselect (void);
329 static void addrbookctl_free_interface (AdapterInterface *adapter);
330 static void addrbookctl_free_datasource (AdapterDSource *adapter);
331 static void addrbookctl_free_folder (AdapterFolder *adapter);
332 static void addrbookctl_free_group (AdapterGroup *adapter);
334 static void addressbook_list_select_clear ( void );
335 static void addressbook_list_select_add ( AddrItemObject *aio,
336 AddressDataSource *ds );
337 static void addressbook_list_select_remove ( AddrItemObject *aio );
339 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
340 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
341 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
342 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
343 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
344 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
345 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
346 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
347 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
348 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
349 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
350 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
351 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
352 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
354 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
357 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
359 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
361 static void addressbook_start_drag(GtkWidget *widget, gint button,
364 static void addressbook_drag_data_get(GtkWidget *widget,
365 GdkDragContext *drag_context,
366 GtkSelectionData *selection_data,
370 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
371 GdkDragContext *context,
376 static void addressbook_drag_leave_cb(GtkWidget *widget,
377 GdkDragContext *context,
380 static void addressbook_drag_received_cb(GtkWidget *widget,
381 GdkDragContext *drag_context,
384 GtkSelectionData *data,
388 static void addressbook_list_menu_setup( void );
390 static GtkTargetEntry addressbook_drag_types[] =
392 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
395 static GtkTargetList *addressbook_target_list = NULL;
397 static void about_show_cb(GtkAction *action, gpointer data)
402 static GtkActionEntry addressbook_entries[] =
404 {"Menu", NULL, "Menu" },
406 {"Book", NULL, N_("_Book") },
407 {"Address", NULL, N_("_Edit") },
408 {"Tools", NULL, N_("_Tools") },
409 {"Help", NULL, N_("_Help") },
412 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
413 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
414 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
418 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
421 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
423 {"Book/---", NULL, "---", NULL, NULL, NULL },
425 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
426 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
427 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
428 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
429 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
432 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
433 {"Address/---", NULL, "---", NULL, NULL, NULL },
434 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
435 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
436 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
437 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
438 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
439 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
440 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
441 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
442 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
443 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
444 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
448 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
449 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
450 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
451 {"Tools/---", NULL, "---", NULL, NULL, NULL },
452 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
453 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
454 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
455 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
456 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
459 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
463 static GtkActionEntry addressbook_tree_popup_entries[] =
465 {"ABTreePopup", NULL, "ABTreePopup" },
466 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
467 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
468 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
469 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
470 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
471 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
472 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
473 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
474 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
475 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
478 static GtkActionEntry addressbook_list_popup_entries[] =
480 {"ABListPopup", NULL, "ABListPopup" },
481 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
482 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
483 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
484 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
485 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
486 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
487 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
488 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
489 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
490 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
491 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
492 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
493 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
495 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
500 * Structure of error message table.
502 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
503 struct _ErrMsgTableEntry {
508 static gchar *_errMsgUnknown_ = N_( "Unknown" );
511 * Lookup table of error messages for general errors. Note that a NULL
512 * description signifies the end of the table.
514 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
515 { MGU_SUCCESS, N_("Success") },
516 { MGU_BAD_ARGS, N_("Bad arguments") },
517 { MGU_NO_FILE, N_("File not specified") },
518 { MGU_OPEN_FILE, N_("Error opening file") },
519 { MGU_ERROR_READ, N_("Error reading file") },
520 { MGU_EOF, N_("End of file encountered") },
521 { MGU_OO_MEMORY, N_("Error allocating memory") },
522 { MGU_BAD_FORMAT, N_("Bad file format") },
523 { MGU_ERROR_WRITE, N_("Error writing to file") },
524 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
525 { MGU_NO_PATH, N_("No path specified") },
531 * Lookup table of error messages for LDAP errors.
533 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
534 { LDAPRC_SUCCESS, N_("Success") },
535 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
536 { LDAPRC_INIT, N_("Error initializing LDAP") },
537 { LDAPRC_BIND, N_("Error binding to LDAP server") },
538 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
539 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
540 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
541 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
542 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
543 { LDAPRC_TLS, N_("Error starting STARTTLS connection") },
544 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
545 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
546 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
547 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
553 * Lookup message for specified error code.
554 * \param lut Lookup table.
555 * \param code Code to lookup.
556 * \return Description associated to code.
558 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
560 ErrMsgTableEntry entry;
563 for( i = 0; ; i++ ) {
565 if( entry.description == NULL ) break;
566 if( entry.code == code ) {
567 desc = entry.description;
572 desc = _errMsgUnknown_;
577 static gboolean lastCanLookup = FALSE;
579 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
581 if (add_and_delete) {
582 gtk_widget_show(addrbook.edit_btn);
583 gtk_widget_show(addrbook.del_btn);
584 gtk_widget_show(addrbook.reg_btn);
586 gtk_widget_hide(addrbook.edit_btn);
587 gtk_widget_hide(addrbook.del_btn);
588 gtk_widget_hide(addrbook.reg_btn);
592 gtk_widget_show(addrbook.lup_btn);
593 gtk_widget_show(addrbook.entry);
594 gtk_widget_show(addrbook.label);
596 gtk_widget_hide(addrbook.lup_btn);
597 gtk_widget_hide(addrbook.entry);
598 gtk_widget_hide(addrbook.label);
601 lastCanLookup = lookup;
604 gtk_widget_show(addrbook.to_btn);
605 gtk_widget_show(addrbook.cc_btn);
606 gtk_widget_show(addrbook.bcc_btn);
608 gtk_widget_hide(addrbook.to_btn);
609 gtk_widget_hide(addrbook.cc_btn);
610 gtk_widget_hide(addrbook.bcc_btn);
614 void addressbook_open(Compose *target)
616 /* Initialize all static members */
617 if( _clipBoard_ == NULL ) {
618 _clipBoard_ = addrclip_create();
620 if( _addressIndex_ != NULL ) {
621 addrclip_set_index( _clipBoard_, _addressIndex_ );
623 if( _addressSelect_ == NULL ) {
624 _addressSelect_ = addrselect_list_create();
626 if (!addrbook.window) {
627 addressbook_read_file();
628 addressbook_create();
629 addressbook_load_tree();
630 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
631 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
634 gtk_widget_hide(addrbook.window);
637 gtk_widget_show_all(addrbook.window);
639 if (!prefs_common.addressbook_use_editaddress_dialog)
640 addressbook_edit_person_widgetset_hide();
642 address_completion_start(addrbook.window);
644 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
645 addressbook_set_target_compose(target);
649 * Destroy addressbook.
651 void addressbook_destroy( void ) {
652 /* Free up address stuff */
653 if( _addressSelect_ != NULL ) {
654 addrselect_list_free( _addressSelect_ );
656 if( _clipBoard_ != NULL ) {
657 addrclip_free( _clipBoard_ );
660 if( _addressIndex_ != NULL ) {
661 addrindex_free_index( _addressIndex_ );
662 addrindex_teardown();
664 _addressSelect_ = NULL;
666 _addressIndex_ = NULL;
669 void addressbook_set_target_compose(Compose *target)
671 addrbook.target_compose = target;
674 Compose *addressbook_get_target_compose(void)
676 return addrbook.target_compose;
680 * Refresh addressbook and save to file(s).
682 void addressbook_refresh( void )
684 if (addrbook.window) {
685 if (addrbook.treeSelected) {
686 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
687 addrbook.treeSelected);
688 addressbook_set_clist(
689 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
690 addrbook.treeSelected),
695 addressbook_export_to_file();
698 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
700 if (event && event->keyval == GDK_KEY_Escape)
702 else if (event && event->keyval == GDK_KEY_Delete) {
703 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
704 if ( /* address_index_has_focus || */ address_list_has_focus )
705 addressbook_del_clicked(NULL, NULL);
711 *\brief Save Gtk object size to prefs dataset
713 static void addressbook_size_allocate_cb(GtkWidget *widget,
714 GtkAllocation *allocation)
716 cm_return_if_fail(allocation != NULL);
718 prefs_common.addressbookwin_width = allocation->width;
719 prefs_common.addressbookwin_height = allocation->height;
722 static gint sort_column_number = 0;
723 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
725 static gint list_case_sort(
726 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
728 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
729 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
730 gchar *name1 = NULL, *name2 = NULL;
731 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
732 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
734 if( aio1->type == aio2->type ) {
736 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
738 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
739 if( ! name1 ) return ( name2 != NULL );
740 if( ! name2 ) return -1;
741 return g_utf8_collate( name1, name2 );
743 /* Order groups before person */
744 if( aio1->type == ITEMTYPE_GROUP ) {
745 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
746 } else if( aio2->type == ITEMTYPE_GROUP ) {
747 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
753 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
754 const GtkSortType sort_type)
757 GtkWidget *hbox, *label, *arrow;
759 sort_column_number = col;
760 sort_column_type = sort_type;
761 gtk_cmclist_set_compare_func(clist, list_case_sort);
762 gtk_cmclist_set_sort_type(clist, sort_type);
763 gtk_cmclist_set_sort_column(clist, col);
765 gtk_cmclist_freeze(clist);
766 gtk_cmclist_sort(clist);
768 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
769 hbox = gtk_hbox_new(FALSE, 4);
770 label = gtk_label_new(gettext(list_titles[pos]));
771 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
774 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
775 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
776 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
779 gtk_widget_show_all(hbox);
780 gtk_cmclist_set_column_widget(clist, pos, hbox);
783 gtk_cmclist_thaw(clist);
786 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
788 static GtkSortType sort_type = GTK_SORT_ASCENDING;
790 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
792 addressbook_sort_list(clist, COL_NAME, sort_type);
795 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
797 static GtkSortType sort_type = GTK_SORT_ASCENDING;
799 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
801 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
804 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
806 static GtkSortType sort_type = GTK_SORT_ASCENDING;
808 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
810 addressbook_sort_list(clist, COL_REMARKS, sort_type);
813 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
816 address_index_has_focus = TRUE;
820 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
823 address_index_has_focus = FALSE;
824 if (!prefs_common.addressbook_use_editaddress_dialog
825 && !address_list_has_focus)
826 addressbook_address_list_disable_some_actions();
830 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
833 address_list_has_focus = TRUE;
837 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
840 address_list_has_focus = FALSE;
841 if (!prefs_common.addressbook_use_editaddress_dialog
842 && !address_index_has_focus)
843 addressbook_address_list_disable_some_actions();
847 /* save hpane and vpane's handle position when it moves */
848 static void addressbook_pane_save_position(void)
851 prefs_common.addressbook_hpaned_pos =
852 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
854 prefs_common.addressbook_vpaned_pos =
855 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
859 * Create the address book widgets. The address book contains two CTree widgets: the
860 * address index tree on the left and the address list on the right.
862 * The address index tree displays a hierarchy of interfaces and groups. Each node in
863 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
864 * data sources and folder objects.
866 * The address list displays group, person and email objects. These items are linked
867 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
870 * In the tradition of MVC architecture, the data stores have been separated from the
871 * GUI components. The addrindex.c file provides the interface to all data stores.
873 static void addressbook_create(void)
879 GtkWidget *ctree_swin;
881 GtkWidget *editaddress_vbox;
882 GtkWidget *clist_vbox;
883 GtkWidget *clist_swin;
890 GtkWidget *statusbar;
901 GtkWidget *close_btn;
902 GtkWidget *tree_popup;
903 GtkWidget *list_popup;
905 GtkUIManager *ui_manager;
906 GtkActionGroup *action_group;
907 gchar *index_titles[N_INDEX_COLS];
911 static GdkGeometry geometry;
913 debug_print("Creating addressbook window...\n");
915 index_titles[COL_SOURCES] = _("Sources");
917 /* Address book window */
918 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
919 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
920 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
921 gtk_widget_realize(window);
923 g_signal_connect(G_OBJECT(window), "delete_event",
924 G_CALLBACK(addressbook_close), NULL);
925 g_signal_connect(G_OBJECT(window), "size_allocate",
926 G_CALLBACK(addressbook_size_allocate_cb), NULL);
927 g_signal_connect(G_OBJECT(window), "key_press_event",
928 G_CALLBACK(key_pressed), NULL);
929 MANAGE_WINDOW_SIGNALS_CONNECT(window);
931 vbox = gtk_vbox_new(FALSE, 0);
932 gtk_container_add(GTK_CONTAINER(window), vbox);
935 ui_manager = gtk_ui_manager_new();
936 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
937 G_N_ELEMENTS(addressbook_entries), NULL);
938 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
939 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
940 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
941 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
945 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
955 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
990 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
991 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
994 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
996 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
998 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1000 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1001 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1002 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1004 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1005 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1006 GTK_POLICY_AUTOMATIC,
1007 GTK_POLICY_AUTOMATIC);
1008 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1011 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1012 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1014 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1015 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1016 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1017 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1018 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1019 GTK_CMCTREE_EXPANDER_TRIANGLE);
1020 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1021 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1022 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1023 addressbook_treenode_compare_func);
1025 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1026 G_CALLBACK(addressbook_tree_selected), NULL);
1027 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1028 G_CALLBACK(addressbook_tree_button_pressed),
1030 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1031 G_CALLBACK(addressbook_tree_button_released),
1034 g_signal_connect(G_OBJECT(ctree), "select_row",
1035 G_CALLBACK(addressbook_select_row_tree), NULL);
1037 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1038 addressbook_drag_types, 1,
1039 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1040 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1041 G_CALLBACK(addressbook_drag_motion_cb),
1043 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1044 G_CALLBACK(addressbook_drag_leave_cb),
1046 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1047 G_CALLBACK(addressbook_drag_received_cb),
1049 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1050 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1051 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1052 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1054 clist_vbox = gtk_vbox_new(FALSE, 4);
1056 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1057 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1058 GTK_POLICY_AUTOMATIC,
1059 GTK_POLICY_AUTOMATIC);
1060 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1063 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1064 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1065 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_MULTIPLE);
1066 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1067 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1068 GTK_CMCTREE_EXPANDER_TRIANGLE);
1069 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1070 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1071 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1073 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1075 gtk_widget_set_size_request(clist, -1, 80);
1077 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1078 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1079 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1080 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1081 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1082 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1083 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1084 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1085 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1086 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1087 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1089 for (i = 0; i < N_LIST_COLS; i++)
1090 gtkut_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1093 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1094 G_CALLBACK(addressbook_list_row_selected), NULL);
1095 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1096 G_CALLBACK(addressbook_list_row_unselected), NULL);
1097 g_signal_connect(G_OBJECT(clist), "button_press_event",
1098 G_CALLBACK(addressbook_list_button_pressed),
1100 g_signal_connect(G_OBJECT(clist), "button_release_event",
1101 G_CALLBACK(addressbook_list_button_released),
1103 g_signal_connect(G_OBJECT(clist), "tree_expand",
1104 G_CALLBACK(addressbook_person_expand_node), NULL );
1105 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1106 G_CALLBACK(addressbook_person_collapse_node), NULL );
1107 g_signal_connect(G_OBJECT(clist), "start_drag",
1108 G_CALLBACK(addressbook_start_drag), NULL);
1109 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1110 G_CALLBACK(addressbook_drag_data_get), NULL);
1111 hbox = gtk_hbox_new(FALSE, 4);
1112 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1114 label = gtk_label_new(_("Search"));
1115 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1117 entry = gtk_entry_new();
1118 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1120 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1122 g_signal_connect(G_OBJECT(entry), "key_press_event",
1123 G_CALLBACK(addressbook_entry_key_pressed),
1125 g_signal_connect(G_OBJECT(entry), "activate",
1126 G_CALLBACK(addressbook_entry_activated), NULL);
1128 if (!prefs_common.addressbook_use_editaddress_dialog) {
1129 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1130 vpaned = gtk_vpaned_new();
1131 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1132 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1135 editaddress_vbox = NULL;
1137 hpaned = gtk_hpaned_new();
1138 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1139 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1140 if (prefs_common.addressbook_use_editaddress_dialog)
1141 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1143 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1146 hsbox = gtk_hbox_new(FALSE, 0);
1147 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1148 statusbar = gtk_statusbar_new();
1149 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1152 hbbox = gtk_hbutton_box_new();
1153 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1154 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1155 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1156 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1158 gtkut_stock_button_add_help(hbbox, &help_btn);
1160 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1161 gtkut_widget_set_can_default(edit_btn, TRUE);
1162 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1163 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1164 gtkut_widget_set_can_default(del_btn, TRUE);
1165 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1166 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1167 gtkut_widget_set_can_default(reg_btn, TRUE);
1168 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1171 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1172 gtkut_widget_set_can_default(lup_btn, TRUE);
1173 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1175 g_signal_connect(G_OBJECT(help_btn), "clicked",
1176 G_CALLBACK(manual_open_with_anchor_cb),
1177 MANUAL_ANCHOR_ADDRBOOK);
1179 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1180 G_CALLBACK(addressbook_edit_clicked), NULL);
1181 g_signal_connect(G_OBJECT(del_btn), "clicked",
1182 G_CALLBACK(addressbook_del_clicked), NULL);
1183 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1184 G_CALLBACK(addressbook_reg_clicked), NULL);
1185 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1186 G_CALLBACK(addressbook_lup_clicked), NULL);
1188 to_btn = gtk_button_new_with_label
1189 (prefs_common_translated_header_name("To:"));
1190 gtkut_widget_set_can_default(to_btn, TRUE);
1191 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1192 cc_btn = gtk_button_new_with_label
1193 (prefs_common_translated_header_name("Cc:"));
1194 gtkut_widget_set_can_default(cc_btn, TRUE);
1195 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1196 bcc_btn = gtk_button_new_with_label
1197 (prefs_common_translated_header_name("Bcc:"));
1198 gtkut_widget_set_can_default(bcc_btn, TRUE);
1199 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1201 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1202 gtkut_widget_set_can_default(close_btn, TRUE);
1203 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1205 g_signal_connect(G_OBJECT(to_btn), "clicked",
1206 G_CALLBACK(addressbook_to_clicked),
1207 GINT_TO_POINTER(COMPOSE_TO));
1208 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1209 G_CALLBACK(addressbook_to_clicked),
1210 GINT_TO_POINTER(COMPOSE_CC));
1211 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1212 G_CALLBACK(addressbook_to_clicked),
1213 GINT_TO_POINTER(COMPOSE_BCC));
1214 g_signal_connect(G_OBJECT(close_btn), "clicked",
1215 G_CALLBACK(addressbook_close_clicked), NULL);
1217 /* Build icons for interface */
1219 /* Build control tables */
1220 addrbookctl_build_map(window);
1221 addrbookctl_build_iflist();
1222 addrbookctl_build_ifselect();
1224 addrbook.clist = NULL;
1226 /* Add each interface into the tree as a root level folder */
1227 nodeIf = _addressInterfaceList_;
1229 AdapterInterface *adapter = nodeIf->data;
1230 AddressInterface *iface = adapter->interface;
1231 nodeIf = g_list_next(nodeIf);
1233 if(iface->useInterface) {
1234 AddressTypeControlItem *atci = adapter->atci;
1235 text = atci->displayName;
1237 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1238 NULL, NULL, &text, FOLDER_SPACING,
1242 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1243 gtk_cmctree_node_set_row_data_full(
1244 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1245 addressbook_free_treenode );
1251 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1252 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1253 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1264 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1265 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1284 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1285 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1287 addrbook.window = window;
1288 addrbook.hpaned = hpaned;
1289 addrbook.vpaned = vpaned;
1290 addrbook.menubar = menubar;
1291 addrbook.ctree = ctree;
1294 addrbook.editaddress_vbox = editaddress_vbox;
1295 addrbook.clist = clist;
1296 addrbook.label = label;
1297 addrbook.entry = entry;
1298 addrbook.statusbar = statusbar;
1299 addrbook.status_cid = gtk_statusbar_get_context_id(
1300 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1302 addrbook.help_btn = help_btn;
1303 addrbook.edit_btn = edit_btn;
1304 addrbook.del_btn = del_btn;
1305 addrbook.reg_btn = reg_btn;
1306 addrbook.lup_btn = lup_btn;
1307 addrbook.to_btn = to_btn;
1308 addrbook.cc_btn = cc_btn;
1309 addrbook.bcc_btn = bcc_btn;
1311 addrbook.tree_popup = tree_popup;
1312 addrbook.list_popup = list_popup;
1313 addrbook.ui_manager = ui_manager;
1315 addrbook.listSelected = NULL;
1317 if (!geometry.min_height) {
1318 geometry.min_width = ADDRESSBOOK_WIDTH;
1319 geometry.min_height = ADDRESSBOOK_HEIGHT;
1322 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1324 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1325 prefs_common.addressbookwin_height);
1327 gtk_window_move(GTK_WINDOW(window), 48, 48);
1330 if (!prefs_common.addressbook_use_editaddress_dialog) {
1331 if (prefs_common.addressbook_vpaned_pos > 0)
1332 gtk_paned_set_position(GTK_PANED(vpaned),
1333 prefs_common.addressbook_vpaned_pos);
1335 if (prefs_common.addressbook_hpaned_pos > 0)
1336 gtk_paned_set_position(GTK_PANED(hpaned),
1337 prefs_common.addressbook_hpaned_pos);
1340 gtk_widget_show_all(window);
1344 * Close address book window and save to file(s).
1346 static gint addressbook_close( void ) {
1347 address_completion_end(addrbook.window);
1348 if (!prefs_common.addressbook_use_editaddress_dialog)
1349 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1351 addressbook_pane_save_position();
1353 gtk_widget_hide(addrbook.window);
1354 addressbook_export_to_file();
1359 * Display message in status line.
1360 * \param msg Message to display.
1362 static void addressbook_status_show( gchar *msg ) {
1363 if( addrbook.statusbar != NULL ) {
1365 GTK_STATUSBAR(addrbook.statusbar),
1366 addrbook.status_cid );
1369 GTK_STATUSBAR(addrbook.statusbar),
1370 addrbook.status_cid, msg );
1375 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1379 *addressbook_msgbuf = '\0';
1381 name = addrindex_ds_get_name( ds );
1382 retVal = addrindex_ds_get_status_code( ds );
1383 if( retVal == MGU_SUCCESS ) {
1384 g_snprintf( addressbook_msgbuf,
1385 sizeof(addressbook_msgbuf), "%s", name );
1388 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1389 g_snprintf( addressbook_msgbuf,
1390 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1393 addressbook_status_show( addressbook_msgbuf );
1396 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1398 addressbook_edit_address_cb(NULL, NULL);
1401 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1403 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1407 * Delete one or more objects from address list.
1409 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1411 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1412 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1413 AddressObject *pobj;
1414 AdapterDSource *ads = NULL;
1415 GtkCMCTreeNode *nodeList;
1418 AddressBookFile *abf = NULL;
1419 AddressDataSource *ds = NULL;
1420 AddressInterface *iface;
1421 AddrItemObject *aio;
1422 AddrSelectItem *item;
1424 gboolean refreshList = FALSE;
1426 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1427 cm_return_if_fail(pobj != NULL);
1429 /* Test whether anything selected for deletion */
1430 nodeList = addrbook.listSelected;
1432 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1433 if( aio == NULL) return;
1434 ds = addressbook_find_datasource( addrbook.treeSelected );
1435 if( ds == NULL ) return;
1437 /* Test for read only */
1438 iface = ds->interface;
1439 if( iface->readOnly ) {
1440 alertpanel( _("Delete address(es)"),
1441 _("This address data is readonly and cannot be deleted."),
1442 GTK_STOCK_CLOSE, NULL, NULL );
1446 /* Test whether Ok to proceed */
1448 if( pobj->type == ADDR_DATASOURCE ) {
1449 ads = ADAPTER_DSOURCE(pobj);
1450 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1452 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1455 else if( pobj->type == ADDR_ITEM_GROUP ) {
1458 if( ! procFlag ) return;
1459 abf = ds->rawDataSource;
1460 if( abf == NULL ) return;
1462 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1463 g_signal_handlers_block_by_func
1464 (G_OBJECT(addrbook.clist),
1465 G_CALLBACK(addressbook_list_row_unselected), NULL);
1467 /* Process deletions */
1468 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1469 GList *groups = NULL, *persons = NULL, *emails = NULL;
1470 gboolean group_delete = TRUE;
1471 /* Items inside folders */
1472 list = addrselect_get_list( _addressSelect_ );
1473 /* Confirm deletion */
1477 node = g_list_next( node );
1478 aio = ( AddrItemObject * ) item->addressItem;
1479 if( aio->type == ITEMTYPE_PERSON || aio->type == ITEMTYPE_EMAIL ) {
1480 group_delete = FALSE;
1485 aval = alertpanel( _("Delete group"),
1486 _("Really delete the group(s)?\n"
1487 "The addresses it contains will not be lost."),
1488 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1489 if( aval != G_ALERTALTERNATE ) {
1493 aval = alertpanel( _("Delete address(es)"),
1494 _("Really delete the address(es)?"),
1495 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1496 if( aval != G_ALERTALTERNATE ) {
1501 /* first, set lists of groups and persons to remove */
1505 node = g_list_next( node );
1506 aio = ( AddrItemObject * ) item->addressItem;
1509 if( aio->type == ITEMTYPE_GROUP ) {
1510 groups = g_list_prepend(groups, item);
1512 else if( aio->type == ITEMTYPE_PERSON ) {
1513 persons = g_list_prepend(persons, item);
1516 /* then set list of emails to remove *if* they're not children of
1517 * persons to remove */
1521 node = g_list_next( node );
1522 aio = ( AddrItemObject * ) item->addressItem;
1525 if( aio->type == ITEMTYPE_EMAIL ) {
1526 ItemEMail *sitem = ( ItemEMail * ) aio;
1527 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1528 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1529 emails = g_list_prepend(emails, item);
1531 /* else, the email will be removed via the parent person */
1534 /* then delete groups */
1538 node = g_list_next( node );
1539 aio = ( AddrItemObject * ) item->addressItem;
1542 if( aio->type == ITEMTYPE_GROUP ) {
1543 ItemGroup *item = ( ItemGroup * ) aio;
1544 GtkCMCTreeNode *nd = NULL;
1545 nd = addressbook_find_group_node( addrbook.opened, item );
1546 item = addrbook_remove_group( abf, item );
1548 addritem_free_item_group( item );
1550 /* Remove group from parent node */
1551 gtk_cmctree_remove_node( ctree, nd );
1555 /* then delete persons */
1559 node = g_list_next( node );
1560 aio = ( AddrItemObject * ) item->addressItem;
1563 if( aio->type == ITEMTYPE_PERSON ) {
1564 ItemPerson *item = ( ItemPerson * ) aio;
1565 item->status = DELETE_ENTRY;
1566 addressbook_folder_remove_one_person( clist, item );
1567 if (pobj->type == ADDR_ITEM_FOLDER)
1568 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1569 item = addrbook_remove_person( abf, item );
1571 if (ds && ds->type == ADDR_IF_LDAP) {
1572 LdapServer *server = ds->rawDataSource;
1573 ldapsvr_set_modified(server, TRUE);
1574 ldapsvr_update_book(server, item);
1578 addritem_person_remove_picture(item);
1579 addritem_free_item_person( item );
1583 /* then delete emails */
1587 node = g_list_next( node );
1588 aio = ( AddrItemObject * ) item->addressItem;
1592 if( aio->type == ITEMTYPE_EMAIL ) {
1593 ItemEMail *sitem = ( ItemEMail * ) aio;
1594 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1595 sitem = addrbook_person_remove_email( abf, person, sitem );
1597 addrcache_remove_email(abf->addressCache, sitem);
1598 addritem_free_item_email( sitem );
1600 addressbook_folder_refresh_one_person( clist, person );
1603 g_list_free( groups );
1604 g_list_free( persons );
1605 g_list_free( emails );
1606 g_list_free( list );
1607 addressbook_list_select_clear();
1609 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1610 addressbook_set_clist(
1611 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1615 addrbook_set_dirty(abf, TRUE);
1616 addressbook_export_to_file();
1617 addressbook_list_menu_setup();
1620 else if( pobj->type == ADDR_ITEM_GROUP ) {
1621 /* Items inside groups */
1622 list = addrselect_get_list( _addressSelect_ );
1626 node = g_list_next( node );
1627 aio = ( AddrItemObject * ) item->addressItem;
1628 if( aio->type == ITEMTYPE_EMAIL ) {
1629 ItemEMail *item = ( ItemEMail * ) aio;
1630 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1631 item = addrbook_person_remove_email( abf, person, item );
1633 addritem_free_item_email( item );
1637 g_list_free( list );
1638 addressbook_list_select_clear();
1639 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1640 addressbook_set_clist(
1641 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1645 addrbook_set_dirty(abf, TRUE);
1646 addressbook_export_to_file();
1647 addressbook_list_menu_setup();
1651 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1652 gtk_cmctree_remove_node( clist, nodeList );
1654 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1655 g_signal_handlers_unblock_by_func
1656 (G_OBJECT(addrbook.clist),
1657 G_CALLBACK(addressbook_list_row_unselected), NULL);
1660 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1662 addressbook_new_address_cb( NULL, NULL );
1665 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1668 gchar *address = NULL;
1670 if( aio->type == ITEMTYPE_EMAIL ) {
1671 ItemPerson *person = NULL;
1672 ItemEMail *email = ( ItemEMail * ) aio;
1674 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1675 if( email->address ) {
1676 if( ADDRITEM_NAME(email) ) {
1677 name = ADDRITEM_NAME(email);
1678 if( *name == '\0' ) {
1679 name = ADDRITEM_NAME(person);
1682 else if( ADDRITEM_NAME(person) ) {
1683 name = ADDRITEM_NAME(person);
1686 buf = g_strdup( email->address );
1688 address = email->address;
1691 else if( aio->type == ITEMTYPE_PERSON ) {
1692 ItemPerson *person = ( ItemPerson * ) aio;
1693 GList *node = person->listEMail;
1695 name = ADDRITEM_NAME(person);
1697 ItemEMail *email = ( ItemEMail * ) node->data;
1698 address = email->address;
1702 if( name && name[0] != '\0' ) {
1703 if( strchr_with_skip_quote( name, '"', ',' ) )
1704 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1706 buf = g_strdup_printf( "%s <%s>", name, address );
1709 buf = g_strdup( address );
1716 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1720 AddrSelectItem *item;
1721 AddrItemObject *aio;
1724 compose = addrbook.target_compose;
1725 if( ! compose ) return;
1727 /* Nothing selected, but maybe there is something in text entry */
1728 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1730 compose_entry_append(
1731 compose, addr, (ComposeEntryType)data , PREF_NONE);
1734 /* Select from address list */
1735 list = addrselect_get_list( _addressSelect_ );
1740 node = g_list_next( node );
1741 aio = item->addressItem;
1742 if( aio->type == ITEMTYPE_PERSON ||
1743 aio->type == ITEMTYPE_EMAIL ) {
1744 addr = addressbook_format_address( aio );
1745 compose_entry_append(
1746 compose, addr, (ComposeEntryType) data, PREF_NONE );
1749 else if( aio->type == ITEMTYPE_GROUP ) {
1750 ItemGroup *group = ( ItemGroup * ) aio;
1751 GList *nodeMail = group->listEMail;
1753 ItemEMail *email = nodeMail->data;
1755 addr = addressbook_format_address(
1756 ( AddrItemObject * ) email );
1757 compose_entry_append(
1758 compose, addr, (ComposeEntryType) data, PREF_NONE );
1760 nodeMail = g_list_next( nodeMail );
1765 AddressObject *obj = NULL;
1767 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1769 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1770 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1771 GList *nodeMail = itemGroup->listEMail;
1773 ItemEMail *email = nodeMail->data;
1775 addr = addressbook_format_address(
1776 ( AddrItemObject * ) email );
1777 compose_entry_append(
1778 compose, addr, (ComposeEntryType) data, PREF_NONE );
1780 nodeMail = g_list_next( nodeMail );
1784 g_list_free( list );
1787 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1788 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1789 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1790 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1792 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1793 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1797 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1798 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1799 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1800 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1801 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1804 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1805 gboolean canEdit = FALSE;
1806 gboolean canDelete = TRUE;
1807 gboolean canAdd = FALSE;
1808 gboolean canEditTr = TRUE;
1809 gboolean editAddress = FALSE;
1810 gboolean canExport = TRUE;
1811 AddressTypeControlItem *atci = NULL;
1812 AddressDataSource *ds = NULL;
1813 AddressInterface *iface = NULL;
1815 if( obj == NULL ) return;
1816 if( obj->type == ADDR_INTERFACE ) {
1817 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1818 iface = adapter->interface;
1820 if( iface->haveLibrary ) {
1821 /* Enable appropriate File / New command */
1822 atci = adapter->atci;
1823 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1826 canEditTr = canExport = FALSE;
1828 else if( obj->type == ADDR_DATASOURCE ) {
1829 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1830 ds = ads->dataSource;
1831 iface = ds->interface;
1832 if( ! iface->readOnly ) {
1833 canAdd = canEdit = editAddress = canDelete = TRUE;
1835 if( ! iface->haveLibrary ) {
1836 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1839 else if( obj->type == ADDR_ITEM_FOLDER ) {
1840 ds = addressbook_find_datasource( addrbook.treeSelected );
1842 iface = ds->interface;
1843 if( iface->readOnly ) {
1848 canAdd = editAddress = TRUE;
1852 else if( obj->type == ADDR_ITEM_GROUP ) {
1853 ds = addressbook_find_datasource( addrbook.treeSelected );
1855 iface = ds->interface;
1856 if( ! iface->readOnly ) {
1862 if( addrbook.listSelected == NULL )
1866 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1867 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1868 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1869 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1872 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1873 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1874 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1875 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1877 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1878 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1881 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1882 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1886 * Address book tree callback function that responds to selection of tree
1889 * \param ctree Tree widget.
1890 * \param node Node that was selected.
1891 * \param column Column number where selected occurred.
1892 * \param data Pointer to user data.
1894 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1895 gint column, gpointer data)
1897 AddressObject *obj = NULL;
1898 AdapterDSource *ads = NULL;
1899 AddressDataSource *ds = NULL;
1900 ItemFolder *rootFolder = NULL;
1901 AddressObjectType aot;
1903 addrbook.treeSelected = node;
1904 addrbook.listSelected = NULL;
1905 addressbook_status_show( "" );
1906 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1908 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1910 addressbook_set_clist(NULL, TRUE);
1913 addrbook.opened = node;
1915 if( obj->type == ADDR_DATASOURCE ) {
1916 /* Read from file */
1917 static gboolean tVal = TRUE;
1919 ads = ADAPTER_DSOURCE(obj);
1921 ds = ads->dataSource;
1922 if( ds == NULL ) return;
1924 if( addrindex_ds_get_modify_flag( ds ) ) {
1925 addrindex_ds_read_data( ds );
1928 if( ! addrindex_ds_get_read_flag( ds ) ) {
1929 addrindex_ds_read_data( ds );
1931 addressbook_ds_show_message( ds );
1933 if( ! addrindex_ds_get_access_flag( ds ) ) {
1934 /* Remove existing folders and groups */
1935 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1936 addressbook_tree_remove_children( ctree, node );
1937 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1939 /* Load folders into the tree */
1940 rootFolder = addrindex_ds_get_root_folder( ds );
1941 if( ds && ds->type == ADDR_IF_JPILOT ) {
1942 aot = ADDR_CATEGORY;
1944 else if( ds && ds->type == ADDR_IF_LDAP ) {
1945 aot = ADDR_LDAP_QUERY;
1948 aot = ADDR_ITEM_FOLDER;
1950 addressbook_node_add_folder( node, ds, rootFolder, aot );
1951 addrindex_ds_set_access_flag( ds, &tVal );
1952 gtk_cmctree_expand( ctree, node );
1955 addressbook_set_clist(NULL, TRUE);
1958 /* Update address list */
1959 g_signal_handlers_block_by_func
1961 G_CALLBACK(addressbook_tree_selected), NULL);
1962 addressbook_set_clist( obj, FALSE );
1963 g_signal_handlers_unblock_by_func
1965 G_CALLBACK(addressbook_tree_selected), NULL);
1966 if (!prefs_common.addressbook_use_editaddress_dialog)
1967 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1969 /* Setup main menu selections */
1970 addressbook_menubar_set_sensitive( FALSE );
1971 addressbook_menuitem_set_sensitive( obj, node );
1972 addressbook_list_select_clear();
1973 addressbook_list_menu_setup();
1978 * Setup address list popup menu items. Items are enabled or disabled as
1981 static void addressbook_list_menu_setup( void ) {
1982 GtkCMCTree *clist = NULL;
1983 AddressObject *pobj = NULL;
1984 AddressObject *obj = NULL;
1985 AdapterDSource *ads = NULL;
1986 AddressInterface *iface = NULL;
1987 AddressDataSource *ds = NULL;
1988 gboolean canEdit = FALSE;
1989 gboolean canDelete = FALSE;
1990 gboolean canCut = FALSE;
1991 gboolean canCopy = FALSE;
1992 gboolean canPaste = FALSE;
1993 gboolean canBrowse = FALSE;
1995 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1996 if( pobj == NULL ) return;
1998 clist = GTK_CMCTREE(addrbook.clist);
1999 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2000 if( obj == NULL ) canEdit = FALSE;
2002 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2003 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2005 if( pobj->type == ADDR_DATASOURCE ) {
2006 /* Parent object is a data source */
2007 ads = ADAPTER_DSOURCE(pobj);
2008 ds = ads->dataSource;
2011 iface = ds->interface;
2014 if( ! iface->readOnly ) {
2015 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2016 if (iface->type != ADDR_IF_LDAP)
2017 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2018 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2021 canDelete = canEdit;
2024 else if( pobj->type != ADDR_INTERFACE ) {
2025 /* Parent object is not an interface */
2026 ds = addressbook_find_datasource( addrbook.treeSelected );
2029 iface = ds->interface;
2032 if( ! iface->readOnly ) {
2033 /* Folder or group */
2034 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2035 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2036 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2037 if( obj ) canEdit = TRUE;
2040 if( pobj->type == ADDR_ITEM_FOLDER ) {
2041 if (iface->type != ADDR_IF_LDAP)
2042 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2043 if( obj ) canEdit = TRUE;
2045 canDelete = canEdit;
2047 if( iface->type == ADDR_IF_LDAP ) {
2048 if( obj ) canBrowse = TRUE;
2055 /* Enable cut and paste */
2056 if( ! addrclip_is_empty( _clipBoard_ ) )
2058 if( ! addrselect_test_empty( _addressSelect_ ) )
2060 /* Enable copy if something is selected */
2061 if( ! addrselect_test_empty( _addressSelect_ ) )
2065 /* Disable edit or browse if more than one row selected */
2066 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2071 /* Forbid write changes when read-only */
2072 if( iface && iface->readOnly ) {
2078 /* Now go finalize menu items */
2079 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2080 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2082 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2083 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2084 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2086 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2088 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2089 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2090 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2092 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2093 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2094 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2096 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2097 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2099 if (addrbook.target_compose) {
2100 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2101 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2102 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2105 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2109 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2110 GtkCMCTreeNode *node,
2117 * Add list of items into tree node below specified tree node.
2118 * \param treeNode Tree node.
2119 * \param ds Data source.
2120 * \param listItems List of items.
2122 static void addressbook_treenode_add_list(
2123 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2129 AddrItemObject *aio;
2133 if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_GROUP ) {
2136 group = ( ItemGroup * ) aio;
2137 nn = addressbook_node_add_group( treeNode, ds, group );
2139 g_message("error adding addressbook group\n");
2142 else if( ADDRESS_OBJECT_TYPE(aio) == ADDR_ITEM_FOLDER ) {
2145 folder = ( ItemFolder * ) aio;
2146 nn = addressbook_node_add_folder(
2147 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2149 g_message("error adding addressbook folder\n");
2152 node = g_list_next( node );
2156 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2157 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2161 * Cut from address list widget.
2163 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2164 _clipBoard_->cutFlag = TRUE;
2165 addrclip_clear( _clipBoard_ );
2166 addrclip_add( _clipBoard_, _addressSelect_ );
2167 /* addrclip_list_show( _clipBoard_, stdout ); */
2171 * Copy from address list widget.
2173 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2174 _clipBoard_->cutFlag = FALSE;
2175 addrclip_clear( _clipBoard_ );
2176 addrclip_add( _clipBoard_, _addressSelect_ );
2177 /* addrclip_list_show( _clipBoard_, stdout ); */
2181 * Paste clipboard into address list widget.
2183 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2184 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2185 AddressObject *pobj = NULL;
2186 AddressDataSource *ds = NULL;
2187 AddressBookFile *abf = NULL;
2188 ItemFolder *folder = NULL;
2189 GList *folderGroup = NULL;
2191 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2192 if( ds == NULL ) return;
2193 if( addrindex_ds_get_readonly( ds ) ) {
2194 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2198 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2200 if( pobj->type == ADDR_ITEM_FOLDER ) {
2201 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2203 else if( pobj->type == ADDR_ITEM_GROUP ) {
2204 alertpanel_error( _("Cannot paste into an address group.") );
2209 /* Get an address book */
2210 abf = addressbook_get_book_file();
2211 if( abf == NULL ) return;
2213 if( _clipBoard_->cutFlag ) {
2215 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2217 /* Remove all groups and folders in clipboard from tree node */
2218 addressbook_treenode_remove_item();
2220 /* Remove all "cut" items */
2221 addrclip_delete_item( _clipBoard_ );
2223 /* Clear clipboard - cut items??? */
2224 addrclip_clear( _clipBoard_ );
2228 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2231 /* addrclip_list_show( _clipBoard_, stdout ); */
2233 /* Update tree by inserting node for each folder or group */
2234 addressbook_treenode_add_list(
2235 addrbook.treeSelected, ds, folderGroup );
2236 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2237 g_list_free( folderGroup );
2241 /* Display items pasted */
2242 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2243 addressbook_set_clist(
2244 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2252 * Add current treenode object to clipboard. Note that widget only allows
2253 * one entry from the tree list to be selected.
2255 static void addressbook_treenode_to_clipboard( void ) {
2256 AddressObject *obj = NULL;
2257 AddressDataSource *ds = NULL;
2258 AddrSelectItem *item;
2259 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2260 GtkCMCTreeNode *node;
2262 node = addrbook.treeSelected;
2263 if( node == NULL ) return;
2264 obj = gtk_cmctree_node_get_row_data( ctree, node );
2265 if( obj == NULL ) return;
2267 ds = addressbook_find_datasource( node );
2268 if( ds == NULL ) return;
2271 if( obj->type == ADDR_ITEM_FOLDER ) {
2272 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2273 ItemFolder *folder = adapter->itemFolder;
2275 item = addrselect_create_node( obj );
2276 item->uid = g_strdup( ADDRITEM_ID(folder) );
2278 else if( obj->type == ADDR_ITEM_GROUP ) {
2279 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2280 ItemGroup *group = adapter->itemGroup;
2282 item = addrselect_create_node( obj );
2283 item->uid = g_strdup( ADDRITEM_ID(group) );
2285 else if( obj->type == ADDR_DATASOURCE ) {
2287 item = addrselect_create_node( obj );
2292 /* Clear existing list and add item into list */
2295 addressbook_list_select_clear();
2296 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2297 addrselect_list_add( _addressSelect_, item, cacheID );
2303 * Cut from tree widget.
2305 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2306 _clipBoard_->cutFlag = TRUE;
2307 addressbook_treenode_to_clipboard();
2308 addrclip_clear( _clipBoard_ );
2309 addrclip_add( _clipBoard_, _addressSelect_ );
2310 /* addrclip_list_show( _clipBoard_, stdout ); */
2314 * Copy from tree widget.
2316 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2317 _clipBoard_->cutFlag = FALSE;
2318 addressbook_treenode_to_clipboard();
2319 addrclip_clear( _clipBoard_ );
2320 addrclip_add( _clipBoard_, _addressSelect_ );
2321 /* addrclip_list_show( _clipBoard_, stdout ); */
2325 * Paste clipboard into address tree widget.
2327 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2328 addressbook_clip_paste_cb(NULL,NULL);
2332 * Clear selected entries in clipboard.
2334 static void addressbook_list_select_clear( void ) {
2335 addrselect_list_clear( _addressSelect_ );
2339 * Add specified address item to selected address list.
2340 * \param aio Address item object.
2341 * \param ds Datasource.
2343 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2346 if( ds == NULL ) return;
2347 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2348 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2353 * Remove specified address item from selected address list.
2354 * \param aio Address item object.
2356 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2357 addrselect_list_remove( _addressSelect_, aio );
2361 * Invoke EMail compose window with addresses in selected address list.
2363 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2366 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2367 listAddress = addrselect_build_list( _addressSelect_ );
2368 compose_new_with_list( NULL, listAddress );
2369 mgu_free_dlist( listAddress );
2374 static void addressbook_list_row_selected( GtkCMCTree *clist,
2375 GtkCMCTreeNode *node,
2379 AddrItemObject *aio = NULL;
2380 AddressObject *pobj = NULL;
2381 AdapterDSource *ads = NULL;
2382 AddressDataSource *ds = NULL;
2384 addrbook.listSelected = node;
2386 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2387 if( pobj == NULL ) return;
2389 if( pobj->type == ADDR_DATASOURCE ) {
2390 ads = ADAPTER_DSOURCE(pobj);
2391 ds = ads->dataSource;
2393 else if( pobj->type != ADDR_INTERFACE ) {
2394 ds = addressbook_find_datasource( addrbook.treeSelected );
2397 aio = gtk_cmctree_node_get_row_data( clist, node );
2399 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2400 addressbook_list_select_add( aio, ds );
2403 addressbook_list_menu_setup();
2405 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2406 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2408 if (obj && obj->type != ADDR_ITEM_GROUP)
2409 addressbook_edit_address(NULL, 0, NULL, FALSE);
2413 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2414 GtkCMCTreeNode *node,
2418 AddrItemObject *aio;
2420 aio = gtk_cmctree_node_get_row_data( ctree, node );
2422 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2423 addressbook_list_select_remove( aio );
2426 if (!prefs_common.addressbook_use_editaddress_dialog)
2427 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2430 static void addressbook_entry_activated(GtkWidget *widget, gpointer data)
2432 addressbook_lup_clicked(NULL, NULL);
2435 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2436 GdkEventButton *event,
2439 if( ! event ) return FALSE;
2441 addressbook_list_menu_setup();
2443 if( event->button == 3 ) {
2444 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2445 event->button, event->time );
2446 } else if (event->button == 1) {
2447 if (event->type == GDK_2BUTTON_PRESS) {
2448 if (prefs_common.add_address_by_click &&
2449 addrbook.target_compose)
2450 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2452 if (prefs_common.addressbook_use_editaddress_dialog)
2453 addressbook_edit_address_cb(NULL, NULL);
2455 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2456 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2457 if( obj && obj->type == ADDR_ITEM_GROUP )
2458 addressbook_edit_address_cb(NULL, NULL);
2466 static gboolean addressbook_list_button_released(GtkWidget *widget,
2467 GdkEventButton *event,
2473 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2474 GdkEventButton *event,
2477 GtkCMCList *clist = GTK_CMCLIST(ctree);
2479 AddressObject *obj = NULL;
2480 AdapterDSource *ads = NULL;
2481 AddressInterface *iface = NULL;
2482 AddressDataSource *ds = NULL;
2483 gboolean canEdit = FALSE;
2484 gboolean canDelete = FALSE;
2485 gboolean canCut = FALSE;
2486 gboolean canCopy = FALSE;
2487 gboolean canPaste = FALSE;
2488 gboolean canTreeCut = FALSE;
2489 gboolean canTreeCopy = FALSE;
2490 gboolean canTreePaste = FALSE;
2491 gboolean canLookup = FALSE;
2492 GtkCMCTreeNode *node = NULL;
2494 if( ! event ) return FALSE;
2495 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2497 if (event->button == 1) {
2498 if (event->type == GDK_2BUTTON_PRESS) {
2499 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2500 gtkut_clist_set_focus_row(clist, row);
2501 obj = gtk_cmclist_get_row_data( clist, row );
2506 if (obj->type == ADDR_ITEM_GROUP ||
2507 obj->type == ADDR_DATASOURCE) {
2509 addressbook_treenode_edit_cb(NULL, NULL);
2511 /* expand pr collapse */
2512 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2513 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2519 addressbook_menubar_set_sensitive( FALSE );
2521 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2522 gtkut_clist_set_focus_row(clist, row);
2523 obj = gtk_cmclist_get_row_data( clist, row );
2526 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2530 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2532 if( ! addrclip_is_empty( _clipBoard_ ) )
2533 canTreePaste = TRUE;
2535 if (obj->type == ADDR_INTERFACE) {
2536 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2537 iface = adapter->interface;
2540 if( !iface->readOnly && iface->type == ADDR_IF_BOOK) {
2541 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2543 if( iface->externalQuery )
2546 if (obj->type == ADDR_DATASOURCE) {
2548 ads = ADAPTER_DSOURCE(obj);
2549 ds = ads->dataSource;
2552 iface = ds->interface;
2555 if( !iface->readOnly ) {
2556 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2557 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2558 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2564 else if (obj->type == ADDR_ITEM_FOLDER) {
2566 ds = addressbook_find_datasource( node );
2569 iface = ds->interface;
2572 if( !iface->readOnly ) {
2576 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2577 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2578 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2582 if( iface->externalQuery ) {
2583 /* Enable deletion of LDAP folder */
2587 else if (obj->type == ADDR_ITEM_GROUP) {
2589 ds = addressbook_find_datasource( node );
2592 iface = ds->interface;
2595 if( ! iface->readOnly ) {
2598 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2599 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2603 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2605 if( ! addrselect_test_empty( _addressSelect_ ) )
2607 if( ! addrclip_is_empty( _clipBoard_ ) )
2610 /* Forbid write changes when read-only */
2611 if( iface && iface->readOnly ) {
2613 canTreePaste = FALSE;
2620 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2621 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2622 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2623 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2624 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2626 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2627 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canDelete );
2628 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2629 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2630 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2632 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2633 addrbook.target_compose != NULL);
2635 if( event->button == 3 )
2636 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2637 event->button, event->time);
2642 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2643 GdkEventButton *event,
2646 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2650 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2652 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2653 AddressObject *obj = NULL;
2654 AddressDataSource *ds = NULL;
2655 AddressBookFile *abf = NULL;
2656 ItemFolder *parentFolder = NULL;
2657 ItemFolder *folder = NULL;
2659 if( ! addrbook.treeSelected ) return;
2660 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2661 if( obj == NULL ) return;
2662 ds = addressbook_find_datasource( addrbook.treeSelected );
2663 if( ds == NULL ) return;
2665 if( obj->type == ADDR_DATASOURCE ) {
2666 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2668 else if( obj->type == ADDR_ITEM_FOLDER ) {
2669 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2675 abf = ds->rawDataSource;
2676 if( abf == NULL ) return;
2677 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2680 nn = addressbook_node_add_folder(
2681 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2683 g_message("error adding addressbook folder\n");
2685 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2686 if( addrbook.treeSelected == addrbook.opened )
2687 addressbook_set_clist(obj, TRUE);
2691 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2693 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2694 AddressObject *obj = NULL;
2695 AddressDataSource *ds = NULL;
2696 AddressBookFile *abf = NULL;
2697 ItemFolder *parentFolder = NULL;
2698 ItemGroup *group = NULL;
2700 if( ! addrbook.treeSelected ) return;
2701 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2702 if( obj == NULL ) return;
2703 ds = addressbook_find_datasource( addrbook.treeSelected );
2704 if( ds == NULL ) return;
2706 if( obj->type == ADDR_DATASOURCE ) {
2707 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2709 else if( obj->type == ADDR_ITEM_FOLDER ) {
2710 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2716 abf = ds->rawDataSource;
2717 if( abf == NULL ) return;
2718 group = addressbook_edit_group( abf, parentFolder, NULL );
2721 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2723 g_message("error adding addressbook group\n");
2725 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2726 if( addrbook.treeSelected == addrbook.opened )
2727 addressbook_set_clist(obj, TRUE);
2731 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2733 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2736 GdkPixbuf *pix_cl, *pix_op;
2737 gboolean is_leaf, expanded;
2739 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2741 &is_leaf, &expanded);
2742 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2749 * \param obj Address object to edit.
2750 * \param node Node in tree.
2751 * \return New name of data source.
2753 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2754 gchar *newName = NULL;
2755 AddressDataSource *ds = NULL;
2756 AddressInterface *iface = NULL;
2757 AdapterDSource *ads = NULL;
2759 ds = addressbook_find_datasource( node );
2760 if( ds == NULL ) return NULL;
2761 iface = ds->interface;
2762 if( ! iface->haveLibrary ) return NULL;
2764 /* Read data from data source */
2765 if( addrindex_ds_get_modify_flag( ds ) ) {
2766 addrindex_ds_read_data( ds );
2769 if( ! addrindex_ds_get_read_flag( ds ) ) {
2770 addrindex_ds_read_data( ds );
2774 ads = ADAPTER_DSOURCE(obj);
2775 if( ads->subType == ADDR_BOOK ) {
2776 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2778 else if( ads->subType == ADDR_VCARD ) {
2779 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2782 else if( ads->subType == ADDR_JPILOT ) {
2783 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2787 else if( ads->subType == ADDR_LDAP ) {
2788 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2794 newName = obj->name;
2799 * Edit an object that is in the address tree area.
2801 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2803 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2805 AddressDataSource *ds = NULL;
2806 AddressBookFile *abf = NULL;
2807 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2810 if( ! addrbook.treeSelected ) return;
2811 node = addrbook.treeSelected;
2812 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2813 obj = gtk_cmctree_node_get_row_data( ctree, node );
2814 if( obj == NULL ) return;
2815 parentNode = GTK_CMCTREE_ROW(node)->parent;
2817 ds = addressbook_find_datasource( node );
2818 if( ds == NULL ) return;
2820 if( obj->type == ADDR_DATASOURCE ) {
2821 name = addressbook_edit_datasource( obj, node );
2822 if( name == NULL ) return;
2825 abf = ds->rawDataSource;
2826 if( abf == NULL ) return;
2827 if( obj->type == ADDR_ITEM_FOLDER ) {
2828 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2829 ItemFolder *item = adapter->itemFolder;
2830 ItemFolder *parentFolder = NULL;
2831 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2832 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2833 name = ADDRITEM_NAME(item);
2835 else if( obj->type == ADDR_ITEM_GROUP ) {
2836 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2837 ItemGroup *item = adapter->itemGroup;
2838 ItemFolder *parentFolder = NULL;
2839 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2840 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2841 name = ADDRITEM_NAME(item);
2844 if( name && parentNode ) {
2845 /* Update node in tree view */
2846 addressbook_change_node_name( node, name );
2847 gtk_sctree_sort_node(ctree, parentNode);
2848 gtk_cmctree_expand( ctree, node );
2849 gtk_sctree_select( GTK_SCTREE( ctree), node );
2856 ADDRTREE_DEL_FOLDER_ONLY,
2857 ADDRTREE_DEL_FOLDER_ADDR
2861 * Delete an item from the tree widget.
2862 * \param data Data passed in.
2863 * \param action Action.
2864 * \param widget Widget issuing callback.
2866 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2868 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2869 GtkCMCTreeNode *node = NULL;
2873 AddrBookBase *adbase;
2874 AddressCache *cache;
2875 AdapterDSource *ads = NULL;
2876 AddressInterface *iface = NULL;
2877 AddressDataSource *ds = NULL;
2878 gboolean remFlag = FALSE;
2879 TreeItemDelType delType;
2881 if( ! addrbook.treeSelected ) return;
2882 node = addrbook.treeSelected;
2883 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2885 obj = gtk_cmctree_node_get_row_data( ctree, node );
2886 cm_return_if_fail(obj != NULL);
2888 if( obj->type == ADDR_DATASOURCE ) {
2889 ads = ADAPTER_DSOURCE(obj);
2891 ds = ads->dataSource;
2892 if( ds == NULL ) return;
2895 /* Must be folder or something else */
2896 ds = addressbook_find_datasource( node );
2897 if( ds == NULL ) return;
2899 /* Only allow deletion from non-readOnly */
2900 iface = ds->interface;
2901 if( iface->readOnly ) {
2902 /* Allow deletion of query results */
2903 if( ! iface->externalQuery ) return;
2907 /* Confirm deletion */
2908 delType = ADDRTREE_DEL_NONE;
2909 if( obj->type == ADDR_ITEM_FOLDER ) {
2910 if( iface && iface->externalQuery ) {
2911 message = g_strdup_printf( _(
2912 "Do you want to delete the query " \
2913 "results and addresses in '%s'?" ),
2915 aval = alertpanel( _("Delete"), message,
2916 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2918 if( aval == G_ALERTALTERNATE ) {
2919 delType = ADDRTREE_DEL_FOLDER_ADDR;
2923 message = g_strdup_printf
2924 ( _( "Do you want to delete '%s'? "
2925 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2927 aval = alertpanel( _("Delete folder"), message,
2928 GTK_STOCK_CANCEL, g_strconcat("+",_("Delete _folder only"), NULL), _("Delete folder and _addresses"));
2930 if( aval == G_ALERTALTERNATE ) {
2931 delType = ADDRTREE_DEL_FOLDER_ONLY;
2933 else if( aval == G_ALERTOTHER ) {
2934 delType = ADDRTREE_DEL_FOLDER_ADDR;
2938 else if( obj->type == ADDR_ITEM_GROUP ) {
2939 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2940 "The addresses it contains will not be lost."), obj->name);
2941 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2942 "+" GTK_STOCK_DELETE, NULL);
2944 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2946 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2947 "The addresses it contains will be lost."), obj->name);
2948 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2949 "+" GTK_STOCK_DELETE, NULL);
2951 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2953 if( delType == ADDRTREE_DEL_NONE ) return;
2955 /* Proceed with deletion */
2956 if( obj->type == ADDR_DATASOURCE ) {
2957 /* Remove node from tree */
2958 gtk_cmctree_remove_node( ctree, node );
2960 if (delType == ADDRTREE_DEL_DATA &&
2961 ds->interface && ds->interface->type == ADDR_IF_BOOK)
2962 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
2964 /* Remove data source. */
2965 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2966 addrindex_free_datasource( ds );
2971 /* Get reference to cache */
2972 adbase = ( AddrBookBase * ) ds->rawDataSource;
2973 if( adbase == NULL ) return;
2974 cache = adbase->addressCache;
2976 /* Remove query results folder */
2977 if( iface && iface->externalQuery ) {
2978 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2979 ItemFolder *folder = adapter->itemFolder;
2981 adapter->itemFolder = NULL;
2983 g_print( "remove folder for ::%s::\n", obj->name );
2984 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2985 g_print( "-------------- remove results\n" );
2987 addrindex_remove_results( ds, folder );
2988 /* g_print( "-------------- remove node\n" ); */
2989 gtk_cmctree_remove_node( ctree, node );
2993 /* Code below is valid for regular address book deletion */
2994 if( obj->type == ADDR_ITEM_FOLDER ) {
2995 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2996 ItemFolder *item = adapter->itemFolder;
2998 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2999 /* Remove folder only */
3000 item = addrcache_remove_folder( cache, item );
3002 addritem_free_item_folder( item );
3003 addressbook_move_nodes_up( ctree, node );
3007 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3008 /* Remove folder and addresses */
3009 item = addrcache_remove_folder_delete( cache, item );
3011 addritem_free_item_folder( item );
3016 else if( obj->type == ADDR_ITEM_GROUP ) {
3017 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3018 ItemGroup *item = adapter->itemGroup;
3020 item = addrcache_remove_group( cache, item );
3022 addritem_free_item_group( item );
3029 gtk_cmctree_remove_node(ctree, node );
3033 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3035 if( person && addrbook.treeSelected == addrbook.opened ) {
3036 person->status = ADD_ENTRY;
3037 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3038 addressbook_folder_refresh_one_person(
3039 GTK_CMCTREE(addrbook.clist), person );
3041 addressbook_address_list_set_focus();
3044 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3046 if( person && addrbook.treeSelected == addrbook.opened) {
3047 person->status = ADD_ENTRY;
3048 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3049 addressbook_set_clist(
3050 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3054 addressbook_address_list_set_focus();
3058 * Label (a format string) that is used to name each folder.
3060 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3063 * Search ctree widget callback function.
3064 * \param pA Pointer to node.
3065 * \param pB Pointer to data item being sought.
3066 * \return Zero (0) if folder found.
3068 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3071 aoA = ( AddressObject * ) pA;
3072 if( aoA->type == ADDR_ITEM_FOLDER ) {
3073 ItemFolder *folder, *fld;
3075 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3076 folder = ( ItemFolder * ) pB;
3077 if( fld == folder ) return 0; /* Found folder */
3082 static ItemFolder * addressbook_setup_subf(
3083 AddressDataSource *ds, gchar *title,
3084 GtkCMCTreeNode *pNode )
3086 AddrBookBase *adbase;
3087 AddressCache *cache;
3090 GtkCMCTreeNode *nNode;
3092 AddressObjectType aoType = ADDR_NONE;
3095 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3097 if( ds && ds->type == ADDR_IF_LDAP ) {
3099 aoType = ADDR_LDAP_QUERY;
3106 ctree = GTK_CMCTREE(addrbook.ctree);
3107 /* Get reference to address cache */
3108 adbase = ( AddrBookBase * ) ds->rawDataSource;
3109 cache = adbase->addressCache;
3111 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3112 GList *cur = children;
3113 for (; cur; cur = cur->next) {
3114 ItemFolder *child = (ItemFolder *) cur->data;
3115 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3116 nNode = gtk_cmctree_find_by_row_data_custom(
3118 addressbook_treenode_find_folder_cb );
3120 addrindex_remove_results( ds, child );
3121 while( child->listPerson ) {
3122 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3123 item = addrcache_remove_person( cache, item );
3125 addritem_free_item_person( item );
3129 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3130 addrbook.treeSelected = nNode;
3137 /* Create a folder */
3138 folder = addrcache_add_new_folder( cache, NULL );
3139 name = g_strdup_printf( "%s", title );
3140 addritem_folder_set_name( folder, name );
3141 addritem_folder_set_remarks( folder, "" );
3144 /* Now let's see the folder */
3145 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3146 gtk_cmctree_expand( ctree, pNode );
3148 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3149 addrbook.treeSelected = nNode;
3155 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3156 AddressObject *pobj = NULL;
3157 AddressDataSource *ds = NULL;
3158 AddressBookFile *abf = NULL;
3159 debug_print("adding address\n");
3160 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3161 if( pobj == NULL ) {
3162 debug_print("no row data\n");
3165 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3167 debug_print("no datasource\n");
3171 abf = ds->rawDataSource;
3173 g_print("no addressbook file\n");
3177 if( pobj->type == ADDR_DATASOURCE ) {
3178 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3179 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3181 ItemFolder *folder = NULL;
3183 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3184 GtkCMCTreeNode *parentNode;
3185 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3186 if( ds == NULL ) return;
3188 /* We must have a datasource that is an external interface */
3189 if( ! ds->interface->haveLibrary ) return;
3190 if( ! ds->interface->externalQuery ) return;
3192 if( pobj->type == ADDR_ITEM_FOLDER ) {
3193 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3196 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3198 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3200 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3202 abf = ds->rawDataSource;
3205 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3206 addrbook.editaddress_vbox,
3207 addressbook_new_address_from_book_post_cb,
3210 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3211 LdapServer *server = ds->rawDataSource;
3212 ldapsvr_set_modified(server, TRUE);
3213 ldapsvr_update_book(server, NULL);
3214 if (server->retVal != LDAPRC_SUCCESS) {
3215 alertpanel( _("Add address(es)"),
3216 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3217 GTK_STOCK_CLOSE, NULL, NULL );
3218 server->retVal = LDAPRC_SUCCESS;
3223 if (prefs_common.addressbook_use_editaddress_dialog)
3224 addressbook_new_address_from_book_post_cb( person );
3227 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3229 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3232 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3233 GtkCMCTreeNode *parentNode;
3234 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3235 if( ds == NULL ) return;
3237 /* We must have a datasource that is an external interface */
3238 if( ! ds->interface->haveLibrary ) return;
3239 if( ! ds->interface->externalQuery ) return;
3241 if( pobj->type == ADDR_ITEM_FOLDER ) {
3242 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3245 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3247 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3251 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3253 abf = ds->rawDataSource;
3256 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3257 addrbook.editaddress_vbox,
3258 addressbook_new_address_from_folder_post_cb,
3261 if (ds && abf && abf->type == ADBOOKTYPE_LDAP) {
3262 LdapServer *server = ds->rawDataSource;
3263 ldapsvr_set_modified(server, TRUE);
3264 ldapsvr_update_book(server, NULL);
3265 if (server->retVal != LDAPRC_SUCCESS) {
3266 alertpanel( _("Add address(es)"),
3267 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3268 GTK_STOCK_CLOSE, NULL, NULL );
3273 if (prefs_common.addressbook_use_editaddress_dialog)
3274 addressbook_new_address_from_folder_post_cb( person );
3276 else if( pobj->type == ADDR_ITEM_GROUP ) {
3277 /* New address in group */
3278 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3279 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3280 if (addrbook.treeSelected == addrbook.opened) {
3281 /* Change node name in tree. */
3282 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3283 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3284 addressbook_set_clist(
3285 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3293 * Search for specified child group node in address index tree.
3294 * \param parent Parent node.
3295 * \param group Group to find.
3297 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3298 GtkCMCTreeNode *node = NULL;
3299 GtkCMCTreeRow *currRow;
3301 currRow = GTK_CMCTREE_ROW( parent );
3303 node = currRow->children;
3307 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3308 if(obj && obj->type == ADDR_ITEM_GROUP ) {
3309 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3310 if( g == group ) return node;
3312 currRow = GTK_CMCTREE_ROW(node);
3313 node = currRow->sibling;
3319 static AddressBookFile *addressbook_get_book_file() {
3320 AddressBookFile *abf = NULL;
3321 AddressDataSource *ds = NULL;
3323 ds = addressbook_find_datasource( addrbook.treeSelected );
3324 if( ds == NULL ) return NULL;
3325 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3329 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3330 GtkCMCTreeNode *node;
3333 /* Remove existing folders and groups */
3334 row = GTK_CMCTREE_ROW( parent );
3336 while( (node = row->children) ) {
3337 gtk_cmctree_remove_node( ctree, node );
3342 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3343 GtkCMCTreeNode *parent, *child;
3344 GtkCMCTreeRow *currRow;
3345 currRow = GTK_CMCTREE_ROW( node );
3347 parent = currRow->parent;
3348 while( (child = currRow->children) ) {
3349 gtk_cmctree_move( ctree, child, parent, node );
3351 gtk_sctree_sort_node( ctree, parent );
3355 static void addressbook_edit_address_post_cb( ItemPerson *person )
3359 AddressBookFile *abf = addressbook_get_book_file();
3361 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3362 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3363 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3366 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3367 invalidate_address_completion();
3369 addressbook_address_list_set_focus();
3372 void addressbook_address_list_set_focus( void )
3374 if (!prefs_common.addressbook_use_editaddress_dialog) {
3375 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3376 addressbook_list_menu_setup();
3380 void addressbook_address_list_disable_some_actions(void)
3382 /* disable address copy/pasting when editing contact's detail (embedded form) */
3383 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3384 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3385 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3388 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3389 addressbook_edit_address(data, 0, NULL, TRUE);
3392 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3393 gboolean force_focus ) {
3394 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3396 AddressObject *obj = NULL, *pobj = NULL;
3397 AddressDataSource *ds = NULL;
3398 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3400 AddressBookFile *abf = NULL;
3402 if( addrbook.listSelected == NULL ) return;
3403 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3404 cm_return_if_fail(obj != NULL);
3406 ctree = GTK_CMCTREE( addrbook.ctree );
3407 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3409 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3410 if( ds == NULL ) return;
3412 abf = addressbook_get_book_file();
3414 if( obj->type == ADDR_ITEM_EMAIL ) {
3415 ItemEMail *email = ( ItemEMail * ) obj;
3417 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3418 /* Edit parent group */
3419 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3420 ItemGroup *itemGrp = adapter->itemGroup;
3421 if( abf == NULL ) return;
3422 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3423 name = ADDRITEM_NAME(itemGrp);
3424 node = addrbook.treeSelected;
3425 parentNode = GTK_CMCTREE_ROW(node)->parent;
3428 /* Edit person - email page */
3430 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3431 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3432 addressbook_edit_address_post_cb,
3433 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3436 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3437 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3438 person->status = UPDATE_ENTRY;
3441 if (prefs_common.addressbook_use_editaddress_dialog)
3442 addressbook_edit_address_post_cb( person );
3447 else if( obj->type == ADDR_ITEM_PERSON ) {
3448 /* Edit person - basic page */
3449 ItemPerson *person = ( ItemPerson * ) obj;
3450 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3451 addressbook_edit_address_post_cb,
3452 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3455 if (abf && abf->type == ADBOOKTYPE_LDAP) {
3456 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3457 person->status = UPDATE_ENTRY;
3460 if (prefs_common.addressbook_use_editaddress_dialog)
3461 addressbook_edit_address_post_cb( person );
3465 else if( obj->type == ADDR_ITEM_GROUP ) {
3466 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3467 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3468 parentNode = addrbook.treeSelected;
3469 node = addressbook_find_group_node( parentNode, itemGrp );
3470 name = ADDRITEM_NAME(itemGrp);
3471 invalidate_address_completion();
3477 /* Update tree node with node name */
3478 if( node == NULL ) return;
3479 addressbook_change_node_name( node, name );
3480 gtk_sctree_sort_node( ctree, parentNode );
3481 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3482 addressbook_set_clist(
3483 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3488 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3490 addressbook_del_clicked(NULL, NULL);
3493 static void close_cb(GtkAction *action, gpointer data)
3495 addressbook_close();
3498 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3499 addressbook_export_to_file();
3502 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3504 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3505 if( person ) addritem_person_set_opened( person, TRUE );
3509 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3511 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3512 if( person ) addritem_person_set_opened( person, FALSE );
3516 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3518 gchar *eMailAlias = ADDRITEM_NAME(email);
3519 if( eMailAlias && *eMailAlias != '\0' ) {
3521 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3524 str = g_strdup( eMailAlias );
3530 static gboolean addressbook_match_item(const gchar *name,
3531 const gchar *email_alias,
3533 const gchar *remarks,
3538 if (!str || str[0] == '\0')
3540 if (strcasestr(name, str))
3542 else if (email_alias && strcasestr(email_alias, str))
3544 else if (addr && strcasestr(addr, str))
3546 else if (remarks && strcasestr(remarks, str))
3552 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3553 GList *items = itemGroup->listEMail;
3554 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3555 const gchar *search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3556 for( ; items != NULL; items = g_list_next( items ) ) {
3557 GtkCMCTreeNode *nodeEMail = NULL;
3558 gchar *text[N_LIST_COLS];
3559 ItemEMail *email = items->data;
3563 if( ! email ) continue;
3565 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3567 if( !addressbook_match_item(ADDRITEM_NAME(person),
3568 ADDRITEM_NAME(email),
3569 email->address, email->remarks,
3573 str = addressbook_format_item_clist( person, email );
3575 text[COL_NAME] = addressbook_set_col_name_guard(str);
3578 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3580 text[COL_ADDRESS] = email->address;
3581 text[COL_REMARKS] = email->remarks;
3582 nodeEMail = gtk_sctree_insert_node(
3584 text, FOLDER_SPACING,
3588 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3594 gchar *addressbook_set_col_name_guard(gchar *value)
3596 gchar *ret = "<not set>";
3597 gchar *tmp = g_strdup(value);
3599 if (tmp !=NULL && *tmp != '\0')
3605 static void addressbook_folder_load_one_person(
3606 GtkCMCTree *clist, ItemPerson *person,
3607 AddressTypeControlItem *atci,
3608 AddressTypeControlItem *atciMail )
3610 GtkCMCTreeNode *nodePerson = NULL;
3611 GtkCMCTreeNode *nodeEMail = NULL;
3612 gchar *text[N_LIST_COLS];
3613 gboolean flgFirst = TRUE, haveAddr = FALSE;
3616 AddressBookFile *abf = addressbook_get_book_file();
3619 if( person == NULL ) return;
3621 text[COL_NAME] = "";
3622 node = person->listEMail;
3624 ItemEMail *email = node->data;
3625 gchar *eMailAddr = NULL;
3626 node = g_list_next( node );
3628 text[COL_ADDRESS] = email->address;
3629 text[COL_REMARKS] = email->remarks;
3630 eMailAddr = ADDRITEM_NAME(email);
3631 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3633 /* First email belongs with person */
3634 gchar *str = addressbook_format_item_clist( person, email );
3636 text[COL_NAME] = addressbook_set_col_name_guard(str);
3639 else if( abf && abf->type == ADBOOKTYPE_LDAP &&
3640 person && person->nickName ) {
3641 if (person->nickName) {
3642 if (strcmp(person->nickName, "") != 0) {
3643 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3646 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3652 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3654 nodePerson = gtk_sctree_insert_node(
3656 text, FOLDER_SPACING,
3659 FALSE, person->isOpened );
3662 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3665 /* Subsequent email is a child node of person */
3666 text[COL_NAME] = ADDRITEM_NAME(email);
3667 nodeEMail = gtk_sctree_insert_node(
3668 clist, nodePerson, NULL,
3669 text, FOLDER_SPACING,
3671 atciMail->iconXpmOpen,
3673 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3679 /* Have name without EMail */
3680 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3681 text[COL_ADDRESS] = "";
3682 text[COL_REMARKS] = "";
3683 nodePerson = gtk_sctree_insert_node(
3685 text, FOLDER_SPACING,
3688 FALSE, person->isOpened );
3689 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3694 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3696 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3697 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3698 const gchar *search_str;
3700 if( atci == NULL ) return;
3701 if( atciMail == NULL ) return;
3703 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3705 /* Load email addresses */
3706 items = addritem_folder_get_person_list( itemFolder );
3707 for(cur = items ; cur != NULL; cur = g_list_next( cur ) ) {
3712 person = (ItemPerson *)cur->data;
3715 node = person->listEMail;
3716 if (node && node->data) {
3718 if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str))
3721 if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str))
3725 addressbook_folder_load_one_person( clist, cur->data, atci, atciMail );
3727 /* Free up the list */
3728 mgu_clear_list( items );
3729 g_list_free( items );
3732 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3733 addrbook.listSelected = NULL;
3734 gtk_cmctree_remove_node( clist, node );
3735 addressbook_menubar_set_sensitive( FALSE );
3736 addressbook_menuitem_set_sensitive(
3737 gtk_cmctree_node_get_row_data(
3738 GTK_CMCTREE(clist), addrbook.treeSelected ),
3739 addrbook.treeSelected );
3742 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3743 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3744 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3745 GtkCMCTreeNode *node;
3746 if( atci == NULL ) return;
3747 if( atciMail == NULL ) return;
3748 if( person == NULL ) return;
3749 /* unload the person */
3751 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3753 addressbook_folder_remove_node( clist, node );
3754 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3755 gtk_sctree_sort_node( clist, NULL );
3756 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3758 gtk_sctree_select( GTK_SCTREE(clist), node );
3759 if (!gtk_cmctree_node_is_visible( clist, node ) )
3760 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3764 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3765 GtkCMCTreeNode *node;
3767 if( person == NULL ) return;
3768 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3770 addressbook_folder_remove_node( clist, node );
3774 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3776 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3777 const gchar *search_str;
3779 /* Load any groups */
3780 if( ! atci ) return;
3782 search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry));
3784 items = addritem_folder_get_group_list( itemFolder );
3785 for( ; items != NULL; items = g_list_next( items ) ) {
3786 GtkCMCTreeNode *nodeGroup = NULL;
3787 gchar *text[N_LIST_COLS];
3788 ItemGroup *group = items->data;
3789 if( group == NULL ) continue;
3790 if( !addressbook_match_item(ADDRITEM_NAME(group),
3791 NULL, NULL, NULL, search_str) )
3794 text[COL_NAME] = ADDRITEM_NAME(group);
3795 text[COL_ADDRESS] = "";
3796 text[COL_REMARKS] = "";
3797 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3798 text, FOLDER_SPACING,
3802 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3803 gtk_sctree_sort_node(clist, NULL);
3805 /* Free up the list */
3806 mgu_clear_list( items );
3807 g_list_free( items );
3811 * Search ctree widget callback function.
3812 * \param pA Pointer to node.
3813 * \param pB Pointer to data item being sought.
3814 * \return Zero (0) if group found.
3816 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3819 aoA = ( AddressObject * ) pA;
3820 if( aoA->type == ADDR_ITEM_GROUP ) {
3821 ItemGroup *group, *grp;
3823 grp = ADAPTER_GROUP(aoA)->itemGroup;
3824 group = ( ItemGroup * ) pB;
3825 if( grp == group ) return 0; /* Found group */
3831 * Remove folder and group nodes from tree widget for items contained ("cut")
3834 static void addressbook_treenode_remove_item( void ) {
3836 AddrSelectItem *cutItem;
3837 AddressCache *cache;
3838 AddrItemObject *aio;
3839 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3842 node = _clipBoard_->objectList;
3844 cutItem = node->data;
3845 node = g_list_next( node );
3846 cache = addrindex_get_cache(
3847 _clipBoard_->addressIndex, cutItem->cacheID );
3848 if( cache == NULL ) continue;
3849 aio = addrcache_get_object( cache, cutItem->uid );
3852 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3855 folder = ( ItemFolder * ) aio;
3856 tn = gtk_cmctree_find_by_row_data_custom(
3857 ctree, NULL, folder,
3858 addressbook_treenode_find_folder_cb );
3860 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3863 group = ( ItemGroup * ) aio;
3864 tn = gtk_cmctree_find_by_row_data_custom(
3866 addressbook_treenode_find_group_cb );
3870 /* Free up adapter and remove node. */
3871 gtk_cmctree_remove_node( ctree, tn );
3878 * Find parent datasource for specified tree node.
3879 * \param node Node to test.
3880 * \return Data source, or NULL if not found.
3882 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3883 AddressDataSource *ds = NULL;
3886 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3889 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3890 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3892 /* g_print( "ao->type = %d\n", ao->type ); */
3893 if( ao->type == ADDR_DATASOURCE ) {
3894 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3895 /* g_print( "found it\n" ); */
3896 ds = ads->dataSource;
3900 node = GTK_CMCTREE_ROW(node)->parent;
3906 * Load address list widget with children of specified object.
3907 * \param obj Parent object to be loaded.
3909 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3910 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3911 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3912 AddressDataSource *ds = NULL;
3913 AdapterDSource *ads = NULL;
3914 static AddressObject *last_obj = NULL;
3916 if (addrbook.clist == NULL) {
3919 if (obj == last_obj && !refresh)
3924 gtk_cmclist_clear(clist);
3928 if( obj->type == ADDR_INTERFACE ) {
3929 /* g_print( "set_clist: loading datasource...\n" ); */
3930 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3934 gtk_cmclist_freeze(clist);
3935 gtk_cmclist_clear(clist);
3937 if( obj->type == ADDR_DATASOURCE ) {
3938 ads = ADAPTER_DSOURCE(obj);
3939 ds = ads->dataSource;
3941 /* Load root folder */
3942 ItemFolder *rootFolder = NULL;
3943 rootFolder = addrindex_ds_get_root_folder( ds );
3944 addressbook_folder_load_person(
3945 ctreelist, rootFolder );
3946 addressbook_folder_load_group(
3947 ctreelist, rootFolder );
3951 if( obj->type == ADDR_ITEM_GROUP ) {
3953 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3954 addressbook_load_group( ctreelist, itemGroup );
3956 else if( obj->type == ADDR_ITEM_FOLDER ) {
3958 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3959 addressbook_folder_load_person( ctreelist, itemFolder );
3960 addressbook_folder_load_group( ctreelist, itemFolder );
3963 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3964 clist->focus_row = -1;
3965 gtk_cmclist_thaw(clist);
3969 * Call back function to free adaptor. Call back is setup by function
3970 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3971 * called when the address book tree widget node is removed by calling
3972 * function gtk_cmctree_remove_node().
3974 * \param data Tree node's row data.
3976 static void addressbook_free_treenode( gpointer data ) {
3979 ao = ( AddressObject * ) data;
3980 if( ao == NULL ) return;
3981 if( ao->type == ADDR_INTERFACE ) {
3982 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3983 addrbookctl_free_interface( ai );
3985 else if( ao->type == ADDR_DATASOURCE ) {
3986 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3987 addrbookctl_free_datasource( ads );
3989 else if( ao->type == ADDR_ITEM_FOLDER ) {
3990 AdapterFolder *af = ADAPTER_FOLDER(ao);
3991 addrbookctl_free_folder( af );
3993 else if( ao->type == ADDR_ITEM_GROUP ) {
3994 AdapterGroup *ag = ADAPTER_GROUP(ao);
3995 addrbookctl_free_group( ag );
4000 * Create new adaptor for specified data source.
4002 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
4003 AddressObjectType otype, gchar *name )
4005 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
4006 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
4007 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
4008 adapter->dataSource = ds;
4009 adapter->subType = otype;
4013 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
4014 ADDRESS_OBJECT_NAME(adapter) =
4015 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
4019 * Load tree from address index with the initial data.
4021 static void addressbook_load_tree( void ) {
4022 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
4023 GList *nodeIf, *nodeDS;
4024 AdapterInterface *adapter;
4025 AddressInterface *iface;
4026 AddressTypeControlItem *atci;
4027 AddressDataSource *ds;
4028 AdapterDSource *ads;
4029 GtkCMCTreeNode *node, *newNode;
4032 nodeIf = _addressInterfaceList_;
4034 adapter = nodeIf->data;
4035 node = adapter->treeNode;
4036 iface = adapter->interface;
4037 atci = adapter->atci;
4039 if( iface->useInterface ) {
4040 /* Load data sources below interface node */
4041 nodeDS = iface->listSource;
4044 name = addrindex_ds_get_name( ds );
4045 ads = addressbook_create_ds_adapter(
4046 ds, atci->objectType, name );
4047 newNode = addressbook_add_object(
4048 node, ADDRESS_OBJECT(ads) );
4049 if (newNode == NULL) {
4050 g_message("error adding addressbook object\n");
4052 nodeDS = g_list_next( nodeDS );
4054 gtk_cmctree_expand( ctree, node );
4057 nodeIf = g_list_next( nodeIf );
4062 * Convert the old address book to new format.
4064 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4065 gboolean retVal = FALSE;
4066 gboolean errFlag = TRUE;
4069 /* Read old address book, performing conversion */
4070 debug_print( "Reading and converting old address book...\n" );
4071 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4072 addrindex_read_data( addrIndex );
4073 if( addrIndex->retVal == MGU_NO_FILE ) {
4074 /* We do not have a file - new user */
4075 debug_print( "New user... create new books...\n" );
4076 addrindex_create_new_books( addrIndex );
4077 if( addrIndex->retVal == MGU_SUCCESS ) {
4078 /* Save index file */
4079 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4080 addrindex_save_data( addrIndex );
4081 if( addrIndex->retVal == MGU_SUCCESS ) {
4086 msg = _( "New user, could not save index file." );
4090 msg = _( "New user, could not save address book files." );
4094 /* We have an old file */
4095 if( addrIndex->wasConverted ) {
4096 /* Converted successfully - save address index */
4097 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4098 addrindex_save_data( addrIndex );
4099 if( addrIndex->retVal == MGU_SUCCESS ) {
4100 msg = _( "Old address book converted successfully." );
4105 msg = _("Old address book converted,\n"
4106 "could not save new address index file." );
4110 /* File conversion failed - just create new books */
4111 debug_print( "File conversion failed... just create new books...\n" );
4112 addrindex_create_new_books( addrIndex );
4113 if( addrIndex->retVal == MGU_SUCCESS ) {
4115 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4116 addrindex_save_data( addrIndex );
4117 if( addrIndex->retVal == MGU_SUCCESS ) {
4118 msg = _("Could not convert address book,\n"
4119 "but created empty new address book files." );
4124 msg = _("Could not convert address book,\n"
4125 "could not save new address index file." );
4129 msg = _("Could not convert address book\n"
4130 "and could not create new address book files." );
4135 debug_print( "Error\n%s\n", msg );
4136 alertpanel_full(_("Addressbook conversion error"), msg,
4137 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4138 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4141 debug_print( "Warning\n%s\n", msg );
4142 alertpanel_full(_("Addressbook conversion error"), msg,
4143 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4144 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4150 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4154 gboolean failed = FALSE;
4155 GError *error = NULL;
4157 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4158 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4159 error->code, error->message);
4160 g_error_free(error);
4164 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4165 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4168 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4170 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4172 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4185 /* all copies succeeded, we can remove source files */
4186 if( ( dp = g_dir_open( origdir, 0, &error ) ) == NULL ) {
4187 debug_print("opening '%s' failed: %d (%s)\n", origdir,
4188 error->code, error->message);
4189 g_error_free(error);
4192 while( ( d = g_dir_read_name( dp ) ) != NULL ) {
4193 if (strncmp(d, "addrbook-", strlen("addrbook-")))
4196 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4198 claws_unlink(orig_file);
4208 void addressbook_read_file( void ) {
4209 AddressIndex *addrIndex = NULL;
4210 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4212 debug_print( "Reading address index...\n" );
4213 if( _addressIndex_ ) {
4214 debug_print( "address book already read!!!\n" );
4219 addrIndex = addrindex_create_index();
4220 addrindex_initialize();
4222 /* Use new address book index. */
4224 if ( !is_dir_exist(indexdir) ) {
4225 if ( make_dir(indexdir) < 0 ) {
4226 addrindex_set_file_path( addrIndex, get_rc_dir() );
4227 g_warning( "couldn't create dir '%s'", indexdir);
4229 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4230 remove_dir_recursive(indexdir);
4231 addrindex_set_file_path( addrIndex, get_rc_dir() );
4232 g_error("couldn't migrate dir %s", indexdir);
4234 addrindex_set_file_path( addrIndex, indexdir);
4238 addrindex_set_file_path( addrIndex, indexdir);
4241 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4242 addrindex_read_data( addrIndex );
4243 if( addrIndex->retVal == MGU_NO_FILE ) {
4244 /* Conversion required */
4245 debug_print( "Converting...\n" );
4246 if( addressbook_convert( addrIndex ) ) {
4247 _addressIndex_ = addrIndex;
4250 else if( addrIndex->retVal == MGU_SUCCESS ) {
4251 _addressIndex_ = addrIndex;
4254 /* Error reading address book */
4255 debug_print( "Could not read address index.\n" );
4256 addrindex_print_index( addrIndex, stdout );
4257 alertpanel_full(_("Addressbook Error"),
4258 _("Could not read address index"),
4259 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4260 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4262 debug_print( "done.\n" );
4266 * Add object into the address index tree widget.
4267 * Enter: node Parent node.
4268 * obj Object to add.
4269 * Return: Node that was added, or NULL if object not added.
4271 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4274 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4275 GtkCMCTreeNode *added;
4276 AddressObject *pobj;
4277 AddressObjectType otype;
4278 AddressTypeControlItem *atci = NULL;
4280 cm_return_val_if_fail(node != NULL, NULL);
4281 cm_return_val_if_fail(obj != NULL, NULL);
4283 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4284 cm_return_val_if_fail(pobj != NULL, NULL);
4286 /* Determine object type to be displayed */
4287 if( obj->type == ADDR_DATASOURCE ) {
4288 otype = ADAPTER_DSOURCE(obj)->subType;
4294 /* Handle any special conditions. */
4296 atci = addrbookctl_lookup( otype );
4298 if( atci->showInTree ) {
4299 /* Add object to tree */
4302 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4303 atci->iconXpm, atci->iconXpmOpen,
4304 atci->treeLeaf, atci->treeExpand );
4305 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4306 addressbook_free_treenode );
4310 gtk_sctree_sort_node(ctree, node);
4316 * Add group into the address index tree.
4317 * \param node Parent node.
4318 * \param ds Data source.
4319 * \param itemGroup Group to add.
4320 * \return Inserted node.
4322 static GtkCMCTreeNode *addressbook_node_add_group(
4323 GtkCMCTreeNode *node, AddressDataSource *ds,
4324 ItemGroup *itemGroup )
4326 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4327 GtkCMCTreeNode *newNode;
4328 AdapterGroup *adapter;
4329 AddressTypeControlItem *atci = NULL;
4332 if( ds == NULL ) return NULL;
4333 if( node == NULL || itemGroup == NULL ) return NULL;
4335 name = &itemGroup->obj.name;
4337 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4339 adapter = g_new0( AdapterGroup, 1 );
4340 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4341 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4342 adapter->itemGroup = itemGroup;
4344 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4345 atci->iconXpm, atci->iconXpm,
4346 atci->treeLeaf, atci->treeExpand );
4347 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4348 addressbook_free_treenode );
4349 gtk_sctree_sort_node( ctree, node );
4354 * Add folder into the address index tree. Only visible folders are loaded into
4355 * the address index tree. Note that the root folder is not inserted into the
4358 * \param node Parent node.
4359 * \param ds Data source.
4360 * \param itemFolder Folder to add.
4361 * \param otype Object type to display.
4362 * \return Inserted node for the folder.
4364 static GtkCMCTreeNode *addressbook_node_add_folder(
4365 GtkCMCTreeNode *node, AddressDataSource *ds,
4366 ItemFolder *itemFolder, AddressObjectType otype )
4368 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4369 GtkCMCTreeNode *newNode = NULL;
4370 AdapterFolder *adapter;
4371 AddressTypeControlItem *atci = NULL;
4372 GList *listItems = NULL;
4374 ItemFolder *rootFolder;
4376 /* Only visible folders */
4377 if( itemFolder == NULL || itemFolder->isHidden )
4382 if( node == NULL || itemFolder == NULL )
4385 /* Determine object type */
4386 atci = addrbookctl_lookup( otype );
4390 rootFolder = addrindex_ds_get_root_folder( ds );
4391 if( itemFolder == rootFolder ) {
4395 adapter = g_new0( AdapterFolder, 1 );
4396 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4397 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4398 adapter->itemFolder = itemFolder;
4400 name = ADDRITEM_NAME(itemFolder);
4401 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4402 atci->iconXpm, atci->iconXpm,
4403 atci->treeLeaf, atci->treeExpand );
4405 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4406 addressbook_free_treenode );
4410 listItems = itemFolder->listFolder;
4411 while( listItems ) {
4412 ItemFolder *item = listItems->data;
4413 addressbook_node_add_folder( newNode, ds, item, otype );
4414 listItems = g_list_next( listItems );
4416 listItems = itemFolder->listGroup;
4417 while( listItems ) {
4418 ItemGroup *item = listItems->data;
4419 addressbook_node_add_group( newNode, ds, item );
4420 listItems = g_list_next( listItems );
4422 gtk_sctree_sort_node( ctree, node );
4426 void addressbook_export_to_file( void ) {
4427 if( _addressIndex_ ) {
4428 /* Save all new address book data */
4429 debug_print( "Saving address books...\n" );
4430 addrindex_save_all_books( _addressIndex_ );
4432 debug_print( "Exporting addressbook to file...\n" );
4433 addrindex_save_data( _addressIndex_ );
4434 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4435 addrindex_print_index( _addressIndex_, stdout );
4438 /* Notify address completion of new data */
4439 invalidate_address_completion();
4443 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4445 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4446 addressbook_lup_clicked(NULL, NULL);
4451 * Comparison using cell contents (text in first column). Used for sort
4452 * address index widget.
4454 static gint addressbook_treenode_compare_func(
4455 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4457 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4458 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4459 gchar *name1 = NULL, *name2 = NULL;
4460 if( cell1 ) name1 = cell1->u.text;
4461 if( cell2 ) name2 = cell2->u.text;
4462 if( ! name1 ) return ( name2 != NULL );
4463 if( ! name2 ) return -1;
4464 return g_utf8_collate( name1, name2 );
4467 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4468 AdapterDSource *ads;
4469 AdapterInterface *adapter;
4470 GtkCMCTreeNode *newNode;
4472 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4473 if( adapter == NULL ) return;
4474 ads = addressbook_edit_book( _addressIndex_, NULL );
4476 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4478 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4479 addrbook.treeSelected = newNode;
4484 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4485 AdapterDSource *ads;
4486 AdapterInterface *adapter;
4487 GtkCMCTreeNode *newNode;
4489 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4490 if( adapter == NULL ) return;
4491 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4493 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4495 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4496 addrbook.treeSelected = newNode;
4502 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4503 AdapterDSource *ads;
4504 AdapterInterface *adapter;
4505 AddressInterface *iface;
4506 GtkCMCTreeNode *newNode;
4508 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4509 if( adapter == NULL ) return;
4510 iface = adapter->interface;
4511 if( ! iface->haveLibrary ) return;
4512 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4514 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4516 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4517 addrbook.treeSelected = newNode;
4524 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4525 AdapterDSource *ads;
4526 AdapterInterface *adapter;
4527 AddressInterface *iface;
4528 GtkCMCTreeNode *newNode;
4530 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4531 if( adapter == NULL ) return;
4532 iface = adapter->interface;
4533 if( ! iface->haveLibrary ) return;
4534 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4536 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4538 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4539 addrbook.treeSelected = newNode;
4546 * Display address search status message.
4547 * \param queryType Query type.
4548 * \param status Status/Error code.
4550 static void addressbook_search_message( gint queryType, gint sts ) {
4552 *addressbook_msgbuf = '\0';
4554 if( sts != MGU_SUCCESS ) {
4555 if( queryType == ADDRQUERY_LDAP ) {
4557 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4562 g_snprintf( addressbook_msgbuf,
4563 sizeof(addressbook_msgbuf), "%s", desc );
4564 addressbook_status_show( addressbook_msgbuf );
4567 addressbook_status_show( "" );
4572 * Refresh addressbook by forcing refresh of current selected object in
4575 static void addressbook_refresh_current( void ) {
4579 ctree = GTK_CMCTREE(addrbook.ctree);
4580 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4581 if( obj == NULL ) return;
4582 addressbook_set_clist( obj, TRUE );
4586 * Message that is displayed whilst a query is executing in a background
4589 static gchar *_tempMessage_ = N_( "Busy searching..." );
4592 * Address search idle function. This function is called during UI idle time
4593 * while a search is in progress.
4595 * \param data Idler data.
4597 static void addressbook_search_idle( gpointer data ) {
4601 queryID = GPOINTER_TO_INT( data );
4602 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4607 * Search completion callback function. This removes the query from the idle
4610 * \param sender Sender of query.
4611 * \param queryID Query ID of search request.
4612 * \param status Search status.
4613 * \param data Query data.
4615 static void addressbook_search_callback_end(
4616 gpointer sender, gint queryID, gint status, gpointer data )
4620 AddrQueryObject *aqo;
4622 /* Remove idler function */
4623 ptrQID = GINT_TO_POINTER( queryID );
4625 g_idle_remove_by_data( ptrQID );
4628 /* Refresh addressbook contents */
4629 addressbook_refresh_current();
4630 req = qrymgr_find_request( queryID );
4632 aqo = ( AddrQueryObject * ) req->queryList->data;
4633 addressbook_search_message( aqo->queryType, status );
4636 /* Stop the search */
4637 addrindex_stop_search( queryID );
4643 * \param ds Data source to search.
4644 * \param searchTerm String to lookup.
4645 * \param pNode Parent data source node.
4647 static void addressbook_perform_search(
4648 AddressDataSource *ds, gchar *searchTerm,
4649 GtkCMCTreeNode *pNode )
4657 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4659 if( !ds || ds->type != ADDR_IF_LDAP ) return;
4661 /* Create a folder for the search results */
4662 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4663 folder = addressbook_setup_subf(ds, name, pNode);
4666 /* Setup the search */
4667 queryID = addrindex_setup_explicit_search(
4668 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4669 if( queryID == 0 ) return;
4671 /* Set up idler function */
4672 idleID = g_idle_add(
4673 (GSourceFunc) addressbook_search_idle,
4674 GINT_TO_POINTER( queryID ) );
4676 g_message("error adding addressbook_search_idle\n");
4679 /* Start search, sit back and wait for something to happen */
4680 addrindex_start_search( queryID );
4682 addressbook_status_show( _tempMessage_ );
4686 * Lookup button handler. Address search is only performed against
4687 * address interfaces for external queries.
4689 * \param button Lookup button widget.
4690 * \param data Data object.
4692 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4695 AddressDataSource *ds;
4696 AddressInterface *iface;
4698 GtkCMCTreeNode *node, *parentNode;
4700 LdapServer *ldap_server;
4701 LdapControl *ldap_ctl;
4704 node = addrbook.treeSelected;
4705 if( ! node ) return;
4706 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4708 ctree = GTK_CMCTREE(addrbook.ctree);
4709 obj = gtk_cmctree_node_get_row_data( ctree, node );
4710 if( obj == NULL ) return;
4712 if (obj->type != ADDR_DATASOURCE ||
4713 ADAPTER_DSOURCE(obj)->subType != ADDR_LDAP) {
4714 addressbook_set_clist(
4715 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
4716 addrbook.treeSelected),
4720 ds = addressbook_find_datasource( node );
4721 if( ds == NULL ) return;
4723 /* We must have a datasource that is an external interface */
4724 iface = ds->interface;
4725 if( ! iface->haveLibrary ) return;
4726 if( ! iface->externalQuery ) return;
4729 if (iface->type == ADDR_IF_LDAP) {
4730 ldap_server = ds->rawDataSource;
4731 ldap_ctl = ldap_server->control;
4732 if (ldap_ctl != NULL &&
4733 ldap_ctl->bindDN != NULL && strlen(ldap_ctl->bindDN) > 0) {
4734 #ifndef PASSWORD_CRYPTO_OLD
4735 /* LDAP server is password-protected. */
4736 if (master_passphrase() == NULL) {
4737 /* User did not enter master passphrase, do not start a search. */
4740 #endif /* PASSWORD_CRYPTO_OLD */
4743 #endif /* USE_LDAP */
4746 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4747 g_strchomp( searchTerm );
4749 if( obj->type == ADDR_ITEM_FOLDER ) {
4750 parentNode = GTK_CMCTREE_ROW(node)->parent;
4755 addressbook_perform_search( ds, searchTerm, parentNode );
4757 gtk_widget_grab_focus( addrbook.entry );
4759 g_free( searchTerm );
4762 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4763 addressbook_close();
4768 * Browse address entry for highlighted entry.
4770 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4772 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4774 AddressDataSource *ds;
4775 AddressInterface *iface;
4779 if(addrbook.listSelected == NULL)
4782 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4786 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4790 iface = ds->interface;
4791 if(!iface || !iface->haveLibrary )
4795 if (obj->type == ADDR_ITEM_EMAIL) {
4796 email = ( ItemEMail * ) obj;
4798 person = (ItemPerson *) ADDRITEM_PARENT(email);
4800 else if (obj->type == ADDR_ITEM_PERSON) {
4801 person = (ItemPerson *) obj;
4808 if( iface && iface->type == ADDR_IF_LDAP ) {
4809 browseldap_entry(ds, person->externalID);
4814 /* **********************************************************************
4815 * Build lookup tables.
4816 * ***********************************************************************
4820 * Remap object types.
4821 * Enter: abType AddressObjectType (used in tree node).
4822 * Return: ItemObjectType (used in address cache data).
4824 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4825 ItemObjectType ioType;
4828 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4829 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4830 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4831 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4832 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4833 default: ioType = ITEMTYPE_NONE; break;
4838 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4839 atci = addrbookctl_lookup(id); \
4841 atci->iconXpm = icon; \
4842 atci->iconXpmOpen = iconopen; \
4844 g_warning("can't get atci %d", id); \
4849 * Build table that controls the rendering of object types.
4851 static void addrbookctl_build_icons( GtkWidget *window ) {
4852 AddressTypeControlItem *atci;
4856 g_object_unref(interfacexpm);
4858 g_object_unref(folderxpm);
4860 g_object_unref(folderopenxpm);
4862 g_object_unref(groupxpm);
4864 g_object_unref(vcardxpm);
4866 g_object_unref(bookxpm);
4868 g_object_unref(addressxpm);
4870 g_object_unref(jpilotxpm);
4872 g_object_unref(categoryxpm);
4874 g_object_unref(ldapxpm);
4876 g_object_unref(addrsearchxpm);
4877 stock_pixbuf_gdk(STOCK_PIXMAP_INTERFACE, &interfacexpm );
4878 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4879 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4880 stock_pixbuf_gdk(STOCK_PIXMAP_GROUP, &groupxpm);
4881 stock_pixbuf_gdk(STOCK_PIXMAP_VCARD, &vcardxpm);
4882 stock_pixbuf_gdk(STOCK_PIXMAP_BOOK, &bookxpm);
4883 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS, &addressxpm);
4884 stock_pixbuf_gdk(STOCK_PIXMAP_JPILOT, &jpilotxpm);
4885 stock_pixbuf_gdk(STOCK_PIXMAP_CATEGORY, &categoryxpm);
4886 stock_pixbuf_gdk(STOCK_PIXMAP_LDAP, &ldapxpm);
4887 stock_pixbuf_gdk(STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4889 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4890 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4891 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4892 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4893 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4894 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4895 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4896 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4897 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4898 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4899 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4904 * Build table that controls the rendering of object types.
4906 static void addrbookctl_build_map( GtkWidget *window ) {
4907 AddressTypeControlItem *atci;
4909 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4910 _addressBookTypeList_ = NULL;
4913 atci = g_new0( AddressTypeControlItem, 1 );
4914 atci->objectType = ADDR_INTERFACE;
4915 atci->interfaceType = ADDR_IF_NONE;
4916 atci->showInTree = TRUE;
4917 atci->treeExpand = TRUE;
4918 atci->treeLeaf = FALSE;
4919 atci->displayName = _( "Interface" );
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_BOOK;
4927 atci->interfaceType = ADDR_IF_BOOK;
4928 atci->showInTree = TRUE;
4929 atci->treeExpand = TRUE;
4930 atci->treeLeaf = FALSE;
4931 atci->displayName = _("Address Books");
4932 atci->menuCommand = "Menu/Book/NewBook";
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_PERSON;
4939 atci->interfaceType = ADDR_IF_NONE;
4940 atci->showInTree = FALSE;
4941 atci->treeExpand = FALSE;
4942 atci->treeLeaf = FALSE;
4943 atci->displayName = _( "Person" );
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_EMAIL;
4951 atci->interfaceType = ADDR_IF_NONE;
4952 atci->showInTree = FALSE;
4953 atci->treeExpand = FALSE;
4954 atci->treeLeaf = TRUE;
4955 atci->displayName = _( "Email Address" );
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_ITEM_GROUP;
4963 atci->interfaceType = ADDR_IF_BOOK;
4964 atci->showInTree = TRUE;
4965 atci->treeExpand = FALSE;
4966 atci->treeLeaf = FALSE;
4967 atci->displayName = _( "Group" );
4968 atci->menuCommand = NULL;
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_ITEM_FOLDER;
4975 atci->interfaceType = ADDR_IF_BOOK;
4976 atci->showInTree = TRUE;
4977 atci->treeExpand = FALSE;
4978 atci->treeLeaf = FALSE;
4979 atci->displayName = _( "Folder" );
4980 atci->menuCommand = NULL;
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_VCARD;
4987 atci->interfaceType = ADDR_IF_VCARD;
4988 atci->showInTree = TRUE;
4989 atci->treeExpand = TRUE;
4990 atci->treeLeaf = TRUE;
4991 atci->displayName = _( "vCard" );
4992 atci->menuCommand = "Menu/Book/NewVCard";
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_JPILOT;
4999 atci->interfaceType = ADDR_IF_JPILOT;
5000 atci->showInTree = TRUE;
5001 atci->treeExpand = TRUE;
5002 atci->treeLeaf = FALSE;
5003 atci->displayName = _( "JPilot" );
5004 atci->menuCommand = "Menu/Book/NewJPilot";
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_CATEGORY;
5011 atci->interfaceType = ADDR_IF_JPILOT;
5012 atci->showInTree = TRUE;
5013 atci->treeExpand = TRUE;
5014 atci->treeLeaf = TRUE;
5015 atci->displayName = _( "JPilot" );
5016 atci->menuCommand = NULL;
5017 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5018 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5021 atci = g_new0( AddressTypeControlItem, 1 );
5022 atci->objectType = ADDR_LDAP;
5023 atci->interfaceType = ADDR_IF_LDAP;
5024 atci->showInTree = TRUE;
5025 atci->treeExpand = TRUE;
5026 atci->treeLeaf = FALSE;
5027 atci->displayName = _( "LDAP servers" );
5028 atci->menuCommand = "Menu/Book/NewLDAPServer";
5029 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5030 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5033 atci = g_new0( AddressTypeControlItem, 1 );
5034 atci->objectType = ADDR_LDAP_QUERY;
5035 atci->interfaceType = ADDR_IF_LDAP;
5036 atci->showInTree = TRUE;
5037 atci->treeExpand = FALSE;
5038 atci->treeLeaf = TRUE;
5039 atci->displayName = _( "LDAP Query" );
5040 atci->menuCommand = NULL;
5041 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
5042 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
5044 addrbookctl_build_icons(window);
5047 void addressbook_reflect_prefs_pixmap_theme(void)
5049 if (addrbook.window)
5050 addrbookctl_build_icons(addrbook.window);
5054 * Search for specified object type.
5056 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
5058 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
5062 * Search for specified interface type.
5064 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
5065 GList *node = _addressBookTypeList_;
5067 AddressTypeControlItem *atci = node->data;
5068 if( atci->interfaceType == ifType ) return atci;
5069 node = g_list_next( node );
5074 static void addrbookctl_free_address( AddressObject *obj ) {
5075 g_free( obj->name );
5076 obj->type = ADDR_NONE;
5080 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5081 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5082 adapter->interface = NULL;
5083 adapter->interfaceType = ADDR_IF_NONE;
5084 adapter->atci = NULL;
5085 adapter->enabled = FALSE;
5086 adapter->haveLibrary = FALSE;
5087 adapter->treeNode = NULL;
5091 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5092 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5093 adapter->dataSource = NULL;
5094 adapter->subType = ADDR_NONE;
5098 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5099 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5100 adapter->itemFolder = NULL;
5104 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5105 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5106 adapter->itemGroup = NULL;
5111 * Build GUI interface list.
5113 static void addrbookctl_build_iflist( void ) {
5114 AddressTypeControlItem *atci;
5115 AdapterInterface *adapter;
5118 if( _addressIndex_ == NULL ) {
5119 _addressIndex_ = addrindex_create_index();
5120 if( _clipBoard_ == NULL ) {
5121 _clipBoard_ = addrclip_create();
5123 addrclip_set_index( _clipBoard_, _addressIndex_ );
5125 _addressInterfaceList_ = NULL;
5126 list = addrindex_get_interface_list( _addressIndex_ );
5128 AddressInterface *interface = list->data;
5129 atci = addrbookctl_lookup_iface( interface->type );
5131 adapter = g_new0( AdapterInterface, 1 );
5132 adapter->interfaceType = interface->type;
5133 adapter->atci = atci;
5134 adapter->interface = interface;
5135 adapter->treeNode = NULL;
5136 adapter->enabled = TRUE;
5137 adapter->haveLibrary = interface->haveLibrary;
5138 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5139 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5140 _addressInterfaceList_ =
5141 g_list_append( _addressInterfaceList_, adapter );
5143 list = g_list_next( list );
5148 * Find GUI interface type specified interface type.
5149 * \param ifType Interface type.
5150 * \return Interface item, or NULL if not found.
5152 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5153 GList *node = _addressInterfaceList_;
5155 AdapterInterface *adapter = node->data;
5156 if( adapter->interfaceType == ifType ) return adapter;
5157 node = g_list_next( node );
5163 * Build interface list selection.
5165 static void addrbookctl_build_ifselect( void ) {
5166 GList *newList = NULL;
5171 gchar *endptr = NULL;
5172 /* gboolean enabled; */
5173 AdapterInterface *adapter;
5175 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5178 splitStr = g_strsplit( selectStr, ",", -1 );
5179 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5181 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5182 ifType = strtol( splitStr[i], &endptr, 10 );
5185 if( strcmp( endptr, "/n" ) == 0 ) {
5190 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5191 adapter = addrbookctl_find_interface( ifType );
5193 newList = g_list_append( newList, adapter );
5200 /* g_print( "i=%d\n", i ); */
5201 g_strfreev( splitStr );
5202 g_free( selectStr );
5204 /* Replace existing list */
5205 mgu_clear_list( _addressIFaceSelection_ );
5206 g_list_free( _addressIFaceSelection_ );
5207 _addressIFaceSelection_ = newList;
5211 /* ***********************************************************************
5212 * Add sender to address book.
5213 * ***********************************************************************
5217 * This function is used by the Add sender to address book function.
5219 gboolean addressbook_add_contact(
5220 const gchar *name, const gchar *address, const gchar *remarks,
5221 GdkPixbuf *picture )
5223 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5224 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5225 debug_print( "addressbook_add_contact - added\n" );
5226 addressbook_refresh();
5231 /* ***********************************************************************
5232 * Book/folder selection.
5233 * ***********************************************************************
5237 * This function is used by the matcher dialog to select a book/folder.
5239 gchar *addressbook_folder_selection( const gchar *folderpath)
5241 AddressBookFile *book = NULL;
5242 ItemFolder *folder = NULL;
5245 cm_return_val_if_fail( folderpath != NULL, NULL);
5247 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5249 if ( folder != NULL) {
5251 gchar *oldtmp = NULL;
5252 AddrItemObject *obj = NULL;
5254 /* walk thru folder->parent to build the full folder path */
5255 /* TODO: wwp: optimize this */
5257 tmp = g_strdup(obj->uid);
5258 while ( obj->parent ) {
5260 if ( obj->name != NULL ) {
5261 oldtmp = g_strdup(tmp);
5263 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5267 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5270 path = g_strdup_printf("%s", book->fileName);
5272 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5278 /* ***********************************************************************
5279 * Book/folder checking.
5280 * ***********************************************************************
5283 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5285 FolderInfo *fi = g_new0( FolderInfo, 1 );
5287 fi->folder = folder;
5291 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5292 FolderInfo *fiParent, FolderPathMatch *match )
5298 FolderPathMatch *nextmatch = NULL;
5303 list = parentFolder->listFolder;
5305 folder = list->data;
5306 fName = g_strdup( ADDRITEM_NAME(folder) );
5308 /* match folder name, match pointer will be set to NULL if next recursive call
5309 doesn't need to match subfolder name */
5310 if ( match != NULL &&
5311 match->matched == FALSE ) {
5312 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5313 /* folder name matches, prepare next subfolder match */
5314 debug_print("matched folder name '%s'\n", fName);
5316 if ( match->folder_path[match->index] == NULL ) {
5317 /* we've matched all elements */
5318 match->matched = TRUE;
5319 match->folder = folder;
5320 debug_print("book/folder path matched!\n");
5322 /* keep on matching */
5330 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5331 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5333 list = g_list_next( list );
5338 * This function is used by to check if a matcher book/folder path corresponds to an
5339 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5340 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5341 if book AND folder are NULL this means that folderpath was empty or Any.
5342 If folderpath is a simple book name (without folder), book will not be NULL and folder
5343 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5346 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5347 AddressDataSource **book,
5348 ItemFolder **folder )
5350 AddressDataSource *ds;
5351 GList *list, *nodeDS;
5352 ItemFolder *rootFolder;
5353 AddressBookFile *abf;
5355 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5362 if ( folderpath == NULL )
5365 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5368 /* split the folder path we've received, we'll try to match this path, subpath by
5369 subpath against the book/folder structure in order */
5370 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5371 if (!folder_path_match.folder_path)
5374 list = addrindex_get_interface_list( _addressIndex_ );
5375 while ( list && !folder_path_match.matched ) {
5376 AddressInterface *interface = list->data;
5377 if ( interface && interface->type == ADDR_IF_BOOK ) {
5378 nodeDS = interface->listSource;
5379 while ( nodeDS && !folder_path_match.matched ) {
5382 /* Read address book */
5383 if( ! addrindex_ds_get_read_flag( ds ) ) {
5384 addrindex_ds_read_data( ds );
5387 /* Add node for address book */
5388 abf = ds->rawDataSource;
5390 /* match book name */
5391 if ( abf && abf->fileName &&
5392 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5394 debug_print("matched book name '%s'\n", abf->fileName);
5395 folder_path_match.book = ds;
5397 if ( folder_path_match.folder_path[1] == NULL ) {
5398 /* no folder part to match */
5400 folder_path_match.matched = TRUE;
5401 folder_path_match.folder = NULL;
5402 debug_print("book path matched!\n");
5405 /* match folder part */
5407 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5408 rootFolder = addrindex_ds_get_root_folder( ds );
5410 /* prepare for recursive call */
5411 folder_path_match.index = 1;
5412 /* this call will set folder_path_match.matched and folder_path_match.folder */
5413 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5418 nodeDS = g_list_next( nodeDS );
5421 list = g_list_next( list );
5424 g_strfreev( folder_path_match.folder_path );
5427 *book = folder_path_match.book;
5429 *folder = folder_path_match.folder;
5430 return folder_path_match.matched;
5434 /* **********************************************************************
5436 * ***********************************************************************
5442 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5443 AddressDataSource *ds = NULL;
5444 AdapterDSource *ads = NULL;
5445 AddressBookFile *abf = NULL;
5446 AdapterInterface *adapter;
5447 GtkCMCTreeNode *newNode;
5449 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5451 if( adapter->treeNode ) {
5452 abf = addressbook_imp_ldif( _addressIndex_ );
5454 ds = addrindex_index_add_datasource(
5455 _addressIndex_, ADDR_IF_BOOK, abf );
5456 ads = addressbook_create_ds_adapter(
5457 ds, ADDR_BOOK, NULL );
5458 addressbook_ads_set_name(
5459 ads, addrbook_get_name( abf ) );
5460 newNode = addressbook_add_object(
5462 ADDRESS_OBJECT(ads) );
5464 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5466 addrbook.treeSelected = newNode;
5469 /* Notify address completion */
5470 invalidate_address_completion();
5479 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5480 AddressDataSource *ds = NULL;
5481 AdapterDSource *ads = NULL;
5482 AddressBookFile *abf = NULL;
5483 AdapterInterface *adapter;
5484 GtkCMCTreeNode *newNode;
5486 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5488 if( adapter->treeNode ) {
5489 abf = addressbook_imp_mutt( _addressIndex_ );
5491 ds = addrindex_index_add_datasource(
5492 _addressIndex_, ADDR_IF_BOOK, abf );
5493 ads = addressbook_create_ds_adapter(
5494 ds, ADDR_BOOK, NULL );
5495 addressbook_ads_set_name(
5496 ads, addrbook_get_name( abf ) );
5497 newNode = addressbook_add_object(
5499 ADDRESS_OBJECT(ads) );
5501 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5503 addrbook.treeSelected = newNode;
5506 /* Notify address completion */
5507 invalidate_address_completion();
5516 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5517 AddressDataSource *ds = NULL;
5518 AdapterDSource *ads = NULL;
5519 AddressBookFile *abf = NULL;
5520 AdapterInterface *adapter;
5521 GtkCMCTreeNode *newNode;
5523 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5525 if( adapter->treeNode ) {
5526 abf = addressbook_imp_pine( _addressIndex_ );
5528 ds = addrindex_index_add_datasource(
5529 _addressIndex_, ADDR_IF_BOOK, abf );
5530 ads = addressbook_create_ds_adapter(
5531 ds, ADDR_BOOK, NULL );
5532 addressbook_ads_set_name(
5533 ads, addrbook_get_name( abf ) );
5534 newNode = addressbook_add_object(
5536 ADDRESS_OBJECT(ads) );
5538 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5540 addrbook.treeSelected = newNode;
5543 /* Notify address completion */
5544 invalidate_address_completion();
5551 * Harvest addresses.
5552 * \param folderItem Folder to import.
5553 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5554 * \param msgList List of message numbers, or NULL to process folder.
5556 void addressbook_harvest(
5557 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5559 AddressDataSource *ds = NULL;
5560 AdapterDSource *ads = NULL;
5561 AddressBookFile *abf = NULL;
5562 AdapterInterface *adapter;
5563 GtkCMCTreeNode *newNode;
5565 abf = addrgather_dlg_execute(
5566 folderItem, _addressIndex_, sourceInd, msgList );
5568 ds = addrindex_index_add_datasource(
5569 _addressIndex_, ADDR_IF_BOOK, abf );
5571 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5573 if( adapter->treeNode ) {
5574 ads = addressbook_create_ds_adapter(
5575 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5576 newNode = addressbook_add_object(
5578 ADDRESS_OBJECT(ads) );
5579 if (newNode == NULL) {
5580 g_message("error adding addressbook object\n");
5585 /* Notify address completion */
5586 invalidate_address_completion();
5593 static void addressbook_export_html_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_html( cache );
5617 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5618 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5620 AddressDataSource *ds = NULL;
5621 AddrBookBase *adbase;
5622 AddressCache *cache;
5623 GtkCMCTreeNode *node = NULL;
5625 if( ! addrbook.treeSelected ) return;
5626 node = addrbook.treeSelected;
5627 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5628 obj = gtk_cmctree_node_get_row_data( ctree, node );
5629 if( obj == NULL ) return;
5631 ds = addressbook_find_datasource( node );
5632 if( ds == NULL ) return;
5633 adbase = ( AddrBookBase * ) ds->rawDataSource;
5634 cache = adbase->addressCache;
5635 addressbook_exp_ldif( cache );
5638 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5640 addrduplicates_find(GTK_WINDOW(addrbook.window));
5643 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5645 addressbook_custom_attr_edit();
5648 static void addressbook_start_drag(GtkWidget *widget, gint button,
5652 GdkDragContext *context;
5653 if (addressbook_target_list == NULL)
5654 addressbook_target_list = gtk_target_list_new(
5655 addressbook_drag_types, 1);
5656 context = gtk_drag_begin(widget, addressbook_target_list,
5657 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5658 gtk_drag_set_icon_default(context);
5661 static void addressbook_drag_data_get(GtkWidget *widget,
5662 GdkDragContext *drag_context,
5663 GtkSelectionData *selection_data,
5668 AddrItemObject *aio = NULL;
5669 AddressObject *pobj = NULL;
5670 AdapterDSource *ads = NULL;
5671 AddressDataSource *ds = NULL;
5674 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5676 if( pobj == NULL ) return;
5678 if( pobj->type == ADDR_DATASOURCE ) {
5679 ads = ADAPTER_DSOURCE(pobj);
5680 ds = ads->dataSource;
5681 } else if (pobj->type == ADDR_ITEM_GROUP) {
5686 else if( pobj->type != ADDR_INTERFACE ) {
5687 ds = addressbook_find_datasource( addrbook.treeSelected );
5693 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5694 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5695 GTK_CMCTREE_NODE(cur->data));
5696 while (aio && aio->type != ITEMTYPE_PERSON) {
5701 if (aio && aio->type == ITEMTYPE_PERSON) {
5702 if( ds && ds->interface && ds->interface->readOnly)
5703 gtk_selection_data_set(selection_data,
5704 gtk_selection_data_get_target(selection_data), 8,
5705 (const guchar *)"Dummy_addr_copy", 15);
5707 gtk_selection_data_set(selection_data,
5708 gtk_selection_data_get_target(selection_data), 8,
5709 (const guchar *)"Dummy_addr_move", 15);
5713 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5714 GdkDragContext *context,
5720 GtkAllocation allocation;
5721 GtkRequisition requisition;
5723 GtkCMCTreeNode *node = NULL;
5724 gboolean acceptable = FALSE;
5725 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5726 gint height = allocation.height;
5727 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5728 gint total_height = requisition.height;
5729 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5730 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5731 gfloat vpos = gtk_adjustment_get_value(pos);
5733 if (gtk_cmclist_get_selection_info
5734 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5736 if (y > height - 24 && height + vpos < total_height) {
5737 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5738 gtk_adjustment_changed(pos);
5740 if (y < 24 && y > 0) {
5741 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5742 gtk_adjustment_changed(pos);
5744 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5747 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5748 if( obj->type == ADDR_ITEM_FOLDER
5749 || obj->type == ADDR_ITEM_GROUP)
5752 AdapterDSource *ads = NULL;
5753 AddressDataSource *ds = NULL;
5754 ads = ADAPTER_DSOURCE(obj);
5755 if (ads == NULL ){ return FALSE;}
5756 ds = ads->dataSource;
5757 if (ds == NULL ) { return FALSE;}
5765 g_signal_handlers_block_by_func
5767 G_CALLBACK(addressbook_tree_selected), NULL);
5768 gtk_sctree_select( GTK_SCTREE(widget), node);
5769 g_signal_handlers_unblock_by_func
5771 G_CALLBACK(addressbook_tree_selected), NULL);
5772 gdk_drag_status(context,
5773 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5774 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5776 gdk_drag_status(context, 0, time);
5781 static void addressbook_drag_leave_cb(GtkWidget *widget,
5782 GdkDragContext *context,
5786 if (addrbook.treeSelected) {
5787 g_signal_handlers_block_by_func
5789 G_CALLBACK(addressbook_tree_selected), NULL);
5790 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5791 g_signal_handlers_unblock_by_func
5793 G_CALLBACK(addressbook_tree_selected), NULL);
5798 static void addressbook_drag_received_cb(GtkWidget *widget,
5799 GdkDragContext *drag_context,
5802 GtkSelectionData *data,
5808 GtkCMCTreeNode *node;
5809 GtkCMCTreeNode *lastopened = addrbook.opened;
5811 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5812 if (gtk_cmclist_get_selection_info
5813 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5817 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5818 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5821 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5822 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5823 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5824 addressbook_clip_copy_cb(NULL, NULL);
5826 addressbook_clip_cut_cb(NULL, NULL);
5827 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5828 addressbook_clip_paste_cb(NULL,NULL);
5829 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5830 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5831 gtk_drag_finish(drag_context, TRUE, TRUE, time);