2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2009 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/>.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
32 #include <sys/types.h>
36 #include "addressbook.h"
37 #include "manage_window.h"
38 #include "prefs_common.h"
39 #include "alertpanel.h"
40 #include "inputdialog.h"
42 #include "stock_pixmap.h"
44 #include "prefs_gtk.h"
50 #include "addr_compl.h"
53 #include "addressitem.h"
55 #include "addrcache.h"
57 #include "addrindex.h"
58 #include "addressadd.h"
59 #include "addrduplicates.h"
60 #include "addressbook_foldersel.h"
62 #include "editvcard.h"
63 #include "editgroup.h"
64 #include "editaddress.h"
66 #include "importldif.h"
67 #include "importmutt.h"
68 #include "importpine.h"
73 #include "editjpilot.h"
78 #include "ldapserver.h"
80 #include "ldapupdate.h"
82 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
85 #include "addrquery.h"
86 #include "addrselect.h"
88 #include "addrgather.h"
89 #include "adbookbase.h"
90 #include "exphtmldlg.h"
91 #include "expldifdlg.h"
92 #include "browseldap.h"
93 #include "addrcustomattr.h"
99 } AddressIndexColumns;
107 } AddressListColumns;
110 AddressBookFile *book;
118 AddressDataSource *book;
122 static gchar *list_titles[] = { N_("Name"),
126 #define COL_NAME_WIDTH 164
127 #define COL_ADDRESS_WIDTH 156
129 #define COL_FOLDER_WIDTH 170
130 #define ADDRESSBOOK_WIDTH 640
131 #define ADDRESSBOOK_HEIGHT 360
133 #define ADDRESSBOOK_MSGBUF_SIZE 2048
135 static GdkPixbuf *folderxpm = NULL;
136 static GdkPixbuf *folderopenxpm = NULL;
137 static GdkPixbuf *groupxpm = NULL;
138 static GdkPixbuf *interfacexpm = NULL;
139 static GdkPixbuf *bookxpm = NULL;
140 static GdkPixbuf *addressxpm = NULL;
141 static GdkPixbuf *vcardxpm = NULL;
142 static GdkPixbuf *jpilotxpm = NULL;
143 static GdkPixbuf *categoryxpm = NULL;
144 static GdkPixbuf *ldapxpm = NULL;
145 static GdkPixbuf *addrsearchxpm = NULL;
148 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
150 /* Address list selection */
151 static AddrSelectList *_addressSelect_ = NULL;
152 static AddressClipboard *_clipBoard_ = NULL;
154 /* Address index file and interfaces */
155 static AddressIndex *_addressIndex_ = NULL;
156 static GList *_addressInterfaceList_ = NULL;
157 static GList *_addressIFaceSelection_ = NULL;
158 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
160 static AddressBook_win addrbook;
162 static GHashTable *_addressBookTypeHash_ = NULL;
163 static GList *_addressBookTypeList_ = NULL;
165 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
166 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
167 static void addressbook_edit_address_post_cb( ItemPerson *person );
169 static void addressbook_create (void);
170 static gint addressbook_close (void);
172 static gboolean address_index_has_focus = FALSE;
173 static gboolean address_list_has_focus = FALSE;
175 /* callback functions */
176 static void addressbook_del_clicked (GtkButton *button,
178 static void addressbook_reg_clicked (GtkButton *button,
180 static void addressbook_to_clicked (GtkButton *button,
182 static void addressbook_lup_clicked (GtkButton *button,
184 static void addressbook_close_clicked (GtkButton *button,
187 static void addressbook_tree_selected (GtkCMCTree *ctree,
188 GtkCMCTreeNode *node,
191 static void addressbook_select_row_tree (GtkCMCTree *ctree,
192 GtkCMCTreeNode *node,
195 static void addressbook_list_row_selected (GtkCMCTree *clist,
196 GtkCMCTreeNode *node,
199 static void addressbook_list_row_unselected (GtkCMCTree *clist,
200 GtkCMCTreeNode *node,
203 static void addressbook_person_expand_node (GtkCMCTree *ctree,
206 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
210 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
211 GdkEventButton *event,
213 static gboolean addressbook_list_button_released(GtkWidget *widget,
214 GdkEventButton *event,
216 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
217 GdkEventButton *event,
219 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
220 GdkEventButton *event,
223 static void addressbook_new_folder_cb (GtkAction *action,
225 static void addressbook_new_group_cb (GtkAction *action,
227 static void addressbook_treenode_edit_cb (GtkAction *action,
229 static void addressbook_treenode_delete_cb (GtkAction *action,
232 static void addressbook_change_node_name (GtkCMCTreeNode *node,
235 static void addressbook_new_address_cb (GtkAction *action,
237 static void addressbook_edit_address_cb (GtkAction *action,
239 static void addressbook_delete_address_cb (GtkAction *action,
242 static void close_cb (GtkAction *action,
244 static void addressbook_file_save_cb (GtkAction *action,
247 /* Data source edit stuff */
248 static void addressbook_new_book_cb (GtkAction *action,
250 static void addressbook_new_vcard_cb (GtkAction *action,
254 static void addressbook_new_jpilot_cb (GtkAction *action,
259 static void addressbook_new_ldap_cb (GtkAction *action,
263 static void addressbook_set_clist (AddressObject *obj,
266 static void addressbook_load_tree (void);
267 void addressbook_read_file (void);
269 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
271 static void addressbook_treenode_remove_item ( void );
273 static AddressDataSource *addressbook_find_datasource
274 (GtkCMCTreeNode *node );
276 static AddressBookFile *addressbook_get_book_file(void);
278 static GtkCMCTreeNode *addressbook_node_add_folder
279 (GtkCMCTreeNode *node,
280 AddressDataSource *ds,
281 ItemFolder *itemFolder,
282 AddressObjectType otype);
283 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
284 AddressDataSource *ds,
285 ItemGroup *itemGroup);
286 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
287 GtkCMCTreeNode *parent);
288 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
289 GtkCMCTreeNode *node);
290 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
292 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
295 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
298 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
300 AddressTypeControlItem *atci,
301 AddressTypeControlItem *atciMail);
302 static void addressbook_folder_refresh_one_person(GtkCMCTree *clist,
304 static void addressbook_folder_remove_one_person(GtkCMCTree *clist,
306 static void addressbook_folder_remove_node (GtkCMCTree *clist,
307 GtkCMCTreeNode *node);
309 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
310 gboolean force_focus );
312 /* LUT's and IF stuff */
313 static void addressbook_free_treenode ( gpointer data );
314 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
315 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
317 static void addrbookctl_build_map (GtkWidget *window);
318 static void addrbookctl_build_iflist (void);
319 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
320 static void addrbookctl_build_ifselect (void);
322 static void addrbookctl_free_interface (AdapterInterface *adapter);
323 static void addrbookctl_free_datasource (AdapterDSource *adapter);
324 static void addrbookctl_free_folder (AdapterFolder *adapter);
325 static void addrbookctl_free_group (AdapterGroup *adapter);
327 static void addressbook_list_select_clear ( void );
328 static void addressbook_list_select_add ( AddrItemObject *aio,
329 AddressDataSource *ds );
330 static void addressbook_list_select_remove ( AddrItemObject *aio );
332 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
333 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
334 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
335 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
336 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
337 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
338 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
339 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
340 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
341 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
342 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
343 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
344 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
345 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
347 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
350 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
352 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
354 static void addressbook_start_drag(GtkWidget *widget, gint button,
357 static void addressbook_drag_data_get(GtkWidget *widget,
358 GdkDragContext *drag_context,
359 GtkSelectionData *selection_data,
363 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
364 GdkDragContext *context,
369 static void addressbook_drag_leave_cb(GtkWidget *widget,
370 GdkDragContext *context,
373 static void addressbook_drag_received_cb(GtkWidget *widget,
374 GdkDragContext *drag_context,
377 GtkSelectionData *data,
381 static void addressbook_list_menu_setup( void );
383 static GtkTargetEntry addressbook_drag_types[] =
385 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
388 static GtkTargetList *addressbook_target_list = NULL;
390 static void about_show_cb(GtkAction *action, gpointer data)
395 static GtkActionEntry addressbook_entries[] =
397 {"Menu", NULL, "Menu" },
399 {"Book", NULL, N_("_Book") },
400 {"Address", NULL, N_("_Edit") },
401 {"Tools", NULL, N_("_Tools") },
402 {"Help", NULL, N_("_Help") },
405 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
406 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
407 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
411 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
414 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
416 {"Book/---", NULL, "---", NULL, NULL, NULL },
418 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
419 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
420 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
421 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
422 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
425 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
426 {"Address/---", NULL, "---", NULL, NULL, NULL },
427 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
428 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
429 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
430 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
431 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
432 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
433 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
434 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
435 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
436 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
437 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
441 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
442 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
443 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
444 {"Tools/---", NULL, "---", NULL, NULL, NULL },
445 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
446 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
447 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
448 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
449 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
452 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
456 static GtkActionEntry addressbook_tree_popup_entries[] =
458 {"ABTreePopup", NULL, "ABTreePopup" },
459 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
460 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
461 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
462 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
463 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
464 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
465 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
466 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
467 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
468 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
471 static GtkActionEntry addressbook_list_popup_entries[] =
473 {"ABListPopup", NULL, "ABListPopup" },
474 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
475 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
476 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
477 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
478 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
479 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
480 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
481 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
482 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
483 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
484 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
485 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
486 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
488 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
493 * Structure of error message table.
495 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
496 struct _ErrMsgTableEntry {
501 static gchar *_errMsgUnknown_ = N_( "Unknown" );
504 * Lookup table of error messages for general errors. Note that a NULL
505 * description signifies the end of the table.
507 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
508 { MGU_SUCCESS, N_("Success") },
509 { MGU_BAD_ARGS, N_("Bad arguments") },
510 { MGU_NO_FILE, N_("File not specified") },
511 { MGU_OPEN_FILE, N_("Error opening file") },
512 { MGU_ERROR_READ, N_("Error reading file") },
513 { MGU_EOF, N_("End of file encountered") },
514 { MGU_OO_MEMORY, N_("Error allocating memory") },
515 { MGU_BAD_FORMAT, N_("Bad file format") },
516 { MGU_ERROR_WRITE, N_("Error writing to file") },
517 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
518 { MGU_NO_PATH, N_("No path specified") },
524 * Lookup table of error messages for LDAP errors.
526 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
527 { LDAPRC_SUCCESS, N_("Success") },
528 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
529 { LDAPRC_INIT, N_("Error initializing LDAP") },
530 { LDAPRC_BIND, N_("Error binding to LDAP server") },
531 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
532 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
533 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
534 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
535 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
536 { LDAPRC_TLS, N_("Error starting TLS connection") },
537 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
538 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
539 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
540 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
546 * Lookup message for specified error code.
547 * \param lut Lookup table.
548 * \param code Code to lookup.
549 * \return Description associated to code.
551 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
553 ErrMsgTableEntry entry;
556 for( i = 0; ; i++ ) {
558 if( entry.description == NULL ) break;
559 if( entry.code == code ) {
560 desc = entry.description;
565 desc = _errMsgUnknown_;
570 static gboolean lastCanLookup = FALSE;
572 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
574 if (add_and_delete) {
575 gtk_widget_show(addrbook.edit_btn);
576 gtk_widget_show(addrbook.del_btn);
577 gtk_widget_show(addrbook.reg_btn);
579 gtk_widget_hide(addrbook.edit_btn);
580 gtk_widget_hide(addrbook.del_btn);
581 gtk_widget_hide(addrbook.reg_btn);
585 gtk_widget_show(addrbook.lup_btn);
586 gtk_widget_show(addrbook.entry);
587 gtk_widget_show(addrbook.label);
589 gtk_widget_hide(addrbook.lup_btn);
590 gtk_widget_hide(addrbook.entry);
591 gtk_widget_hide(addrbook.label);
594 lastCanLookup = lookup;
597 gtk_widget_show(addrbook.to_btn);
598 gtk_widget_show(addrbook.cc_btn);
599 gtk_widget_show(addrbook.bcc_btn);
601 gtk_widget_hide(addrbook.to_btn);
602 gtk_widget_hide(addrbook.cc_btn);
603 gtk_widget_hide(addrbook.bcc_btn);
607 void addressbook_open(Compose *target)
609 /* Initialize all static members */
610 if( _clipBoard_ == NULL ) {
611 _clipBoard_ = addrclip_create();
613 if( _addressIndex_ != NULL ) {
614 addrclip_set_index( _clipBoard_, _addressIndex_ );
616 if( _addressSelect_ == NULL ) {
617 _addressSelect_ = addrselect_list_create();
619 if (!addrbook.window) {
620 addressbook_read_file();
621 addressbook_create();
622 addressbook_load_tree();
623 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
624 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
627 gtk_widget_hide(addrbook.window);
630 gtk_widget_show_all(addrbook.window);
632 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
633 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
635 if (!prefs_common.addressbook_use_editaddress_dialog)
636 addressbook_edit_person_widgetset_hide();
638 address_completion_start(addrbook.window);
640 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
641 addressbook_set_target_compose(target);
645 * Destroy addressbook.
647 void addressbook_destroy( void ) {
648 /* Free up address stuff */
649 if( _addressSelect_ != NULL ) {
650 addrselect_list_free( _addressSelect_ );
652 if( _clipBoard_ != NULL ) {
653 addrclip_free( _clipBoard_ );
655 if( _addressIndex_ != NULL ) {
656 addrindex_free_index( _addressIndex_ );
657 addrindex_teardown();
659 _addressSelect_ = NULL;
661 _addressIndex_ = NULL;
664 void addressbook_set_target_compose(Compose *target)
666 addrbook.target_compose = target;
669 Compose *addressbook_get_target_compose(void)
671 return addrbook.target_compose;
675 * Refresh addressbook and save to file(s).
677 void addressbook_refresh( void )
679 if (addrbook.window) {
680 if (addrbook.treeSelected) {
681 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
682 addrbook.treeSelected);
683 addressbook_set_clist(
684 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
685 addrbook.treeSelected),
690 addressbook_export_to_file();
693 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
695 if (event && event->keyval == GDK_Escape)
697 else if (event && event->keyval == GDK_Delete) {
698 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
699 if ( /* address_index_has_focus || */ address_list_has_focus )
700 addressbook_del_clicked(NULL, NULL);
706 *\brief Save Gtk object size to prefs dataset
708 static void addressbook_size_allocate_cb(GtkWidget *widget,
709 GtkAllocation *allocation)
711 cm_return_if_fail(allocation != NULL);
713 prefs_common.addressbookwin_width = allocation->width;
714 prefs_common.addressbookwin_height = allocation->height;
717 static gint sort_column_number = 0;
718 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
720 static gint list_case_sort(
721 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
723 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
724 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
725 gchar *name1 = NULL, *name2 = NULL;
726 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
727 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
729 if( aio1->type == aio2->type ) {
731 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
733 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
734 if( ! name1 ) return ( name2 != NULL );
735 if( ! name2 ) return -1;
736 return g_utf8_collate( name1, name2 );
738 /* Order groups before person */
739 if( aio1->type == ITEMTYPE_GROUP ) {
740 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
741 } else if( aio2->type == ITEMTYPE_GROUP ) {
742 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
748 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
749 const GtkSortType sort_type)
752 GtkWidget *hbox, *label, *arrow;
754 sort_column_number = col;
755 sort_column_type = sort_type;
756 gtk_cmclist_set_compare_func(clist, list_case_sort);
757 gtk_cmclist_set_sort_type(clist, sort_type);
758 gtk_cmclist_set_sort_column(clist, col);
760 gtk_cmclist_freeze(clist);
761 gtk_cmclist_sort(clist);
763 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
764 hbox = gtk_hbox_new(FALSE, 4);
765 label = gtk_label_new(gettext(list_titles[pos]));
766 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
769 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
770 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
771 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
774 gtk_widget_show_all(hbox);
775 gtk_cmclist_set_column_widget(clist, pos, hbox);
778 gtk_cmclist_thaw(clist);
781 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
783 static GtkSortType sort_type = GTK_SORT_ASCENDING;
785 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
787 addressbook_sort_list(clist, COL_NAME, sort_type);
790 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
792 static GtkSortType sort_type = GTK_SORT_ASCENDING;
794 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
796 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
799 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
801 static GtkSortType sort_type = GTK_SORT_ASCENDING;
803 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
805 addressbook_sort_list(clist, COL_REMARKS, sort_type);
808 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
811 address_index_has_focus = TRUE;
815 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
818 address_index_has_focus = FALSE;
819 if (!prefs_common.addressbook_use_editaddress_dialog
820 && !address_list_has_focus)
821 addressbook_address_list_disable_some_actions();
825 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
828 address_list_has_focus = TRUE;
832 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
835 address_list_has_focus = FALSE;
836 if (!prefs_common.addressbook_use_editaddress_dialog
837 && !address_index_has_focus)
838 addressbook_address_list_disable_some_actions();
842 /* save hpane and vpane's handle position when it moves */
843 static void addressbook_pane_save_position(void)
846 prefs_common.addressbook_hpaned_pos =
847 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
849 prefs_common.addressbook_vpaned_pos =
850 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
854 * Create the address book widgets. The address book contains two CTree widgets: the
855 * address index tree on the left and the address list on the right.
857 * The address index tree displays a hierarchy of interfaces and groups. Each node in
858 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
859 * data sources and folder objects.
861 * The address list displays group, person and email objects. These items are linked
862 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
865 * In the tradition of MVC architecture, the data stores have been separated from the
866 * GUI components. The addrindex.c file provides the interface to all data stores.
868 static void addressbook_create(void)
874 GtkWidget *ctree_swin;
876 GtkWidget *editaddress_vbox;
877 GtkWidget *clist_vbox;
878 GtkWidget *clist_swin;
885 GtkWidget *statusbar;
896 GtkWidget *close_btn;
897 GtkWidget *tree_popup;
898 GtkWidget *list_popup;
900 GtkUIManager *ui_manager;
901 GtkActionGroup *action_group;
902 gchar *index_titles[N_INDEX_COLS];
906 static GdkGeometry geometry;
908 debug_print("Creating addressbook window...\n");
910 index_titles[COL_SOURCES] = _("Sources");
912 /* Address book window */
913 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
914 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
915 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
916 gtk_widget_realize(window);
918 g_signal_connect(G_OBJECT(window), "delete_event",
919 G_CALLBACK(addressbook_close), NULL);
920 g_signal_connect(G_OBJECT(window), "size_allocate",
921 G_CALLBACK(addressbook_size_allocate_cb), NULL);
922 g_signal_connect(G_OBJECT(window), "key_press_event",
923 G_CALLBACK(key_pressed), NULL);
924 MANAGE_WINDOW_SIGNALS_CONNECT(window);
926 vbox = gtk_vbox_new(FALSE, 0);
927 gtk_container_add(GTK_CONTAINER(window), vbox);
930 ui_manager = gtk_ui_manager_new();
931 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
932 G_N_ELEMENTS(addressbook_entries), NULL);
933 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
934 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
935 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
936 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
939 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
941 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_POPUP)
944 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
945 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
950 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
957 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
967 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
982 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
990 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
993 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
995 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
998 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1000 hildon_window_set_menu(HILDON_WINDOW(window), GTK_MENU(menubar));
1003 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1004 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1005 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1007 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1008 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1009 GTK_POLICY_AUTOMATIC,
1010 GTK_POLICY_AUTOMATIC);
1011 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1014 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1015 GTK_WIDGET_UNSET_FLAGS(GTK_CMCLIST(ctree)->column[0].button,
1018 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1019 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1020 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1021 if (prefs_common.enable_dotted_lines) {
1022 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_DOTTED);
1023 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1024 GTK_CMCTREE_EXPANDER_SQUARE);
1026 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1027 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1028 GTK_CMCTREE_EXPANDER_TRIANGLE);
1030 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1031 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1032 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1033 addressbook_treenode_compare_func);
1035 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1036 G_CALLBACK(addressbook_tree_selected), NULL);
1037 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1038 G_CALLBACK(addressbook_tree_button_pressed),
1040 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1041 G_CALLBACK(addressbook_tree_button_released),
1044 g_signal_connect(G_OBJECT(ctree), "select_row",
1045 G_CALLBACK(addressbook_select_row_tree), NULL);
1047 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1048 addressbook_drag_types, 1,
1049 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1050 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1051 G_CALLBACK(addressbook_drag_motion_cb),
1053 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1054 G_CALLBACK(addressbook_drag_leave_cb),
1056 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1057 G_CALLBACK(addressbook_drag_received_cb),
1059 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1060 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1061 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1062 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1064 clist_vbox = gtk_vbox_new(FALSE, 4);
1066 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1067 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1068 GTK_POLICY_AUTOMATIC,
1069 GTK_POLICY_AUTOMATIC);
1070 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1073 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1074 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1075 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_EXTENDED);
1076 if (prefs_common.enable_dotted_lines) {
1077 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_DOTTED);
1078 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1079 GTK_CMCTREE_EXPANDER_SQUARE);
1081 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1082 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1083 GTK_CMCTREE_EXPANDER_TRIANGLE);
1085 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1086 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1087 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1089 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1091 gtk_widget_set_size_request(clist, -1, 80);
1093 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1094 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1095 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1096 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1097 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1098 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1099 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1100 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1101 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1102 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1103 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1105 for (i = 0; i < N_LIST_COLS; i++)
1106 GTK_WIDGET_UNSET_FLAGS(GTK_CMCLIST(clist)->column[i].button,
1109 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1110 G_CALLBACK(addressbook_list_row_selected), NULL);
1111 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1112 G_CALLBACK(addressbook_list_row_unselected), NULL);
1113 g_signal_connect(G_OBJECT(clist), "button_press_event",
1114 G_CALLBACK(addressbook_list_button_pressed),
1116 g_signal_connect(G_OBJECT(clist), "button_release_event",
1117 G_CALLBACK(addressbook_list_button_released),
1119 g_signal_connect(G_OBJECT(clist), "tree_expand",
1120 G_CALLBACK(addressbook_person_expand_node), NULL );
1121 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1122 G_CALLBACK(addressbook_person_collapse_node), NULL );
1123 g_signal_connect(G_OBJECT(clist), "start_drag",
1124 G_CALLBACK(addressbook_start_drag), NULL);
1125 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1126 G_CALLBACK(addressbook_drag_data_get), NULL);
1127 hbox = gtk_hbox_new(FALSE, 4);
1128 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1130 label = gtk_label_new(_("Lookup name:"));
1131 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1133 entry = gtk_entry_new();
1134 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1136 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1138 g_signal_connect(G_OBJECT(entry), "key_press_event",
1139 G_CALLBACK(addressbook_entry_key_pressed),
1142 if (!prefs_common.addressbook_use_editaddress_dialog) {
1143 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1144 vpaned = gtk_vpaned_new();
1145 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1146 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1149 editaddress_vbox = NULL;
1151 hpaned = gtk_hpaned_new();
1152 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1153 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1154 if (prefs_common.addressbook_use_editaddress_dialog)
1155 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1157 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1160 hsbox = gtk_hbox_new(FALSE, 0);
1161 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1162 statusbar = gtk_statusbar_new();
1163 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1166 hbbox = gtk_hbutton_box_new();
1167 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1168 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1169 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1170 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1172 gtkut_stock_button_add_help(hbbox, &help_btn);
1174 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1175 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1176 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1177 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1178 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1179 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1180 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1181 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1182 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1185 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1186 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1187 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1189 g_signal_connect(G_OBJECT(help_btn), "clicked",
1190 G_CALLBACK(manual_open_with_anchor_cb),
1191 MANUAL_ANCHOR_ADDRBOOK);
1193 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1194 G_CALLBACK(addressbook_edit_clicked), NULL);
1195 g_signal_connect(G_OBJECT(del_btn), "clicked",
1196 G_CALLBACK(addressbook_del_clicked), NULL);
1197 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1198 G_CALLBACK(addressbook_reg_clicked), NULL);
1199 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1200 G_CALLBACK(addressbook_lup_clicked), NULL);
1202 to_btn = gtk_button_new_with_label
1203 (prefs_common_translated_header_name("To:"));
1204 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1205 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1206 cc_btn = gtk_button_new_with_label
1207 (prefs_common_translated_header_name("Cc:"));
1208 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1209 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1210 bcc_btn = gtk_button_new_with_label
1211 (prefs_common_translated_header_name("Bcc:"));
1212 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1213 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1215 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1216 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1217 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1219 g_signal_connect(G_OBJECT(to_btn), "clicked",
1220 G_CALLBACK(addressbook_to_clicked),
1221 GINT_TO_POINTER(COMPOSE_TO));
1222 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1223 G_CALLBACK(addressbook_to_clicked),
1224 GINT_TO_POINTER(COMPOSE_CC));
1225 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1226 G_CALLBACK(addressbook_to_clicked),
1227 GINT_TO_POINTER(COMPOSE_BCC));
1228 g_signal_connect(G_OBJECT(close_btn), "clicked",
1229 G_CALLBACK(addressbook_close_clicked), NULL);
1231 /* Build icons for interface */
1233 /* Build control tables */
1234 addrbookctl_build_map(window);
1235 addrbookctl_build_iflist();
1236 addrbookctl_build_ifselect();
1238 addrbook.clist = NULL;
1240 /* Add each interface into the tree as a root level folder */
1241 nodeIf = _addressInterfaceList_;
1243 AdapterInterface *adapter = nodeIf->data;
1244 AddressInterface *iface = adapter->interface;
1245 nodeIf = g_list_next(nodeIf);
1247 if(iface->useInterface) {
1248 AddressTypeControlItem *atci = adapter->atci;
1249 text = atci->displayName;
1251 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1252 NULL, NULL, &text, FOLDER_SPACING,
1256 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1257 gtk_cmctree_node_set_row_data_full(
1258 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1259 addressbook_free_treenode );
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1278 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1279 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1281 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1284 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1285 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1286 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1287 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1288 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1289 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1290 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1291 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1292 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1293 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1294 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1296 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1298 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1299 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1301 addrbook.window = window;
1302 addrbook.hpaned = hpaned;
1303 addrbook.vpaned = vpaned;
1304 addrbook.menubar = menubar;
1305 addrbook.ctree = ctree;
1308 addrbook.editaddress_vbox = editaddress_vbox;
1309 addrbook.clist = clist;
1310 addrbook.label = label;
1311 addrbook.entry = entry;
1312 addrbook.statusbar = statusbar;
1313 addrbook.status_cid = gtk_statusbar_get_context_id(
1314 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1316 addrbook.help_btn = help_btn;
1317 addrbook.edit_btn = edit_btn;
1318 addrbook.del_btn = del_btn;
1319 addrbook.reg_btn = reg_btn;
1320 addrbook.lup_btn = lup_btn;
1321 addrbook.to_btn = to_btn;
1322 addrbook.cc_btn = cc_btn;
1323 addrbook.bcc_btn = bcc_btn;
1325 addrbook.tree_popup = tree_popup;
1326 addrbook.list_popup = list_popup;
1327 addrbook.ui_manager = ui_manager;
1329 addrbook.listSelected = NULL;
1331 if (!geometry.min_height) {
1332 geometry.min_width = ADDRESSBOOK_WIDTH;
1333 geometry.min_height = ADDRESSBOOK_HEIGHT;
1336 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1338 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1339 prefs_common.addressbookwin_height);
1341 gtk_window_move(GTK_WINDOW(window), 48, 48);
1344 if (!prefs_common.addressbook_use_editaddress_dialog) {
1345 if (prefs_common.addressbook_vpaned_pos > 0)
1346 gtk_paned_set_position(GTK_PANED(vpaned),
1347 prefs_common.addressbook_vpaned_pos);
1349 if (prefs_common.addressbook_hpaned_pos > 0)
1350 gtk_paned_set_position(GTK_PANED(hpaned),
1351 prefs_common.addressbook_hpaned_pos);
1354 gtk_widget_show_all(window);
1358 * Close address book window and save to file(s).
1360 static gint addressbook_close( void ) {
1361 address_completion_end(addrbook.window);
1362 if (!prefs_common.addressbook_use_editaddress_dialog)
1363 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1365 addressbook_pane_save_position();
1367 gtk_widget_hide(addrbook.window);
1368 addressbook_export_to_file();
1373 * Display message in status line.
1374 * \param msg Message to display.
1376 static void addressbook_status_show( gchar *msg ) {
1377 if( addrbook.statusbar != NULL ) {
1379 GTK_STATUSBAR(addrbook.statusbar),
1380 addrbook.status_cid );
1383 GTK_STATUSBAR(addrbook.statusbar),
1384 addrbook.status_cid, msg );
1389 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1393 *addressbook_msgbuf = '\0';
1395 name = addrindex_ds_get_name( ds );
1396 retVal = addrindex_ds_get_status_code( ds );
1397 if( retVal == MGU_SUCCESS ) {
1398 g_snprintf( addressbook_msgbuf,
1399 sizeof(addressbook_msgbuf), "%s", name );
1402 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1403 g_snprintf( addressbook_msgbuf,
1404 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1407 addressbook_status_show( addressbook_msgbuf );
1410 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1412 addressbook_edit_address_cb(NULL, NULL);
1415 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1417 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1421 * Delete one or more objects from address list.
1423 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1425 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1426 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1427 AddressObject *pobj;
1428 AdapterDSource *ads = NULL;
1429 GtkCMCTreeNode *nodeList;
1432 AddressBookFile *abf = NULL;
1433 AddressDataSource *ds = NULL;
1434 AddressInterface *iface;
1435 AddrItemObject *aio;
1436 AddrSelectItem *item;
1438 gboolean refreshList = FALSE;
1440 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1441 cm_return_if_fail(pobj != NULL);
1443 /* Test whether anything selected for deletion */
1444 nodeList = addrbook.listSelected;
1446 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1447 if( aio == NULL) return;
1448 ds = addressbook_find_datasource( addrbook.treeSelected );
1449 if( ds == NULL ) return;
1451 /* Test for read only */
1452 iface = ds->interface;
1453 if( iface->readOnly ) {
1454 alertpanel( _("Delete address(es)"),
1455 _("This address data is readonly and cannot be deleted."),
1456 GTK_STOCK_CLOSE, NULL, NULL );
1460 /* Test whether Ok to proceed */
1462 if( pobj->type == ADDR_DATASOURCE ) {
1463 ads = ADAPTER_DSOURCE(pobj);
1464 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1466 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1469 else if( pobj->type == ADDR_ITEM_GROUP ) {
1472 if( ! procFlag ) return;
1473 abf = ds->rawDataSource;
1474 if( abf == NULL ) return;
1476 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1477 g_signal_handlers_block_by_func
1478 (G_OBJECT(addrbook.clist),
1479 G_CALLBACK(addressbook_list_row_unselected), NULL);
1481 /* Process deletions */
1482 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1483 GList *groups = NULL, *persons = NULL, *emails = NULL;
1484 gboolean group_delete = TRUE;
1485 /* Items inside folders */
1486 list = addrselect_get_list( _addressSelect_ );
1487 /* Confirm deletion */
1491 node = g_list_next( node );
1492 aio = ( AddrItemObject * ) item->addressItem;
1493 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1494 group_delete = FALSE;
1499 aval = alertpanel( _("Delete group"),
1500 _("Really delete the group(s)?\n"
1501 "The addresses it contains will not be lost."),
1502 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1503 if( aval != G_ALERTALTERNATE ) {
1507 aval = alertpanel( _("Delete address(es)"),
1508 _("Really delete the address(es)?"),
1509 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1510 if( aval != G_ALERTALTERNATE ) {
1515 /* first, set lists of groups and persons to remove */
1519 node = g_list_next( node );
1520 aio = ( AddrItemObject * ) item->addressItem;
1523 if( aio->type == ADDR_ITEM_GROUP ) {
1524 groups = g_list_prepend(groups, item);
1526 else if( aio->type == ADDR_ITEM_PERSON ) {
1527 persons = g_list_prepend(persons, item);
1530 /* then set list of emails to remove *if* they're not children of
1531 * persons to remove */
1535 node = g_list_next( node );
1536 aio = ( AddrItemObject * ) item->addressItem;
1539 if( aio->type == ADDR_ITEM_EMAIL ) {
1540 ItemEMail *sitem = ( ItemEMail * ) aio;
1541 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1542 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1543 emails = g_list_prepend(emails, item);
1545 /* else, the email will be removed via the parent person */
1548 /* then delete groups */
1552 node = g_list_next( node );
1553 aio = ( AddrItemObject * ) item->addressItem;
1556 if( aio->type == ADDR_ITEM_GROUP ) {
1557 ItemGroup *item = ( ItemGroup * ) aio;
1558 GtkCMCTreeNode *nd = NULL;
1559 nd = addressbook_find_group_node( addrbook.opened, item );
1560 item = addrbook_remove_group( abf, item );
1562 addritem_free_item_group( item );
1564 /* Remove group from parent node */
1565 gtk_cmctree_remove_node( ctree, nd );
1569 /* then delete persons */
1573 node = g_list_next( node );
1574 aio = ( AddrItemObject * ) item->addressItem;
1577 if( aio->type == ADDR_ITEM_PERSON ) {
1578 ItemPerson *item = ( ItemPerson * ) aio;
1579 item->status = DELETE_ENTRY;
1580 addressbook_folder_remove_one_person( clist, item );
1581 if (pobj->type == ADDR_ITEM_FOLDER)
1582 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1583 item = addrbook_remove_person( abf, item );
1585 if (ds && ds->type == ADDR_IF_LDAP) {
1586 LdapServer *server = ds->rawDataSource;
1587 ldapsvr_set_modified(server, TRUE);
1588 ldapsvr_update_book(server, item);
1592 gchar *filename = addritem_person_get_picture(item);
1593 if (filename && is_file_exist(filename))
1594 claws_unlink(filename);
1596 addritem_free_item_person( item );
1600 /* then delete emails */
1604 node = g_list_next( node );
1605 aio = ( AddrItemObject * ) item->addressItem;
1609 if( aio->type == ADDR_ITEM_EMAIL ) {
1610 ItemEMail *sitem = ( ItemEMail * ) aio;
1611 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1612 sitem = addrbook_person_remove_email( abf, person, sitem );
1614 addrcache_remove_email(abf->addressCache, sitem);
1615 addritem_free_item_email( sitem );
1617 addressbook_folder_refresh_one_person( clist, person );
1620 g_list_free( groups );
1621 g_list_free( persons );
1622 g_list_free( emails );
1623 g_list_free( list );
1624 addressbook_list_select_clear();
1626 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1627 addressbook_set_clist(
1628 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1632 addrbook_set_dirty(abf, TRUE);
1633 addressbook_export_to_file();
1634 addressbook_list_menu_setup();
1637 else if( pobj->type == ADDR_ITEM_GROUP ) {
1638 /* Items inside groups */
1639 list = addrselect_get_list( _addressSelect_ );
1643 node = g_list_next( node );
1644 aio = ( AddrItemObject * ) item->addressItem;
1645 if( aio->type == ADDR_ITEM_EMAIL ) {
1646 ItemEMail *item = ( ItemEMail * ) aio;
1647 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1648 item = addrbook_person_remove_email( abf, person, item );
1650 addritem_free_item_email( item );
1654 g_list_free( list );
1655 addressbook_list_select_clear();
1656 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1657 addressbook_set_clist(
1658 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1662 addrbook_set_dirty(abf, TRUE);
1663 addressbook_export_to_file();
1664 addressbook_list_menu_setup();
1668 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1669 gtk_cmctree_remove_node( clist, nodeList );
1671 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1672 g_signal_handlers_unblock_by_func
1673 (G_OBJECT(addrbook.clist),
1674 G_CALLBACK(addressbook_list_row_unselected), NULL);
1677 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1679 addressbook_new_address_cb( NULL, NULL );
1682 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1685 gchar *address = NULL;
1687 if( aio->type == ADDR_ITEM_EMAIL ) {
1688 ItemPerson *person = NULL;
1689 ItemEMail *email = ( ItemEMail * ) aio;
1691 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1692 if( email->address ) {
1693 if( ADDRITEM_NAME(email) ) {
1694 name = ADDRITEM_NAME(email);
1695 if( *name == '\0' ) {
1696 name = ADDRITEM_NAME(person);
1699 else if( ADDRITEM_NAME(person) ) {
1700 name = ADDRITEM_NAME(person);
1703 buf = g_strdup( email->address );
1705 address = email->address;
1708 else if( aio->type == ADDR_ITEM_PERSON ) {
1709 ItemPerson *person = ( ItemPerson * ) aio;
1710 GList *node = person->listEMail;
1712 name = ADDRITEM_NAME(person);
1714 ItemEMail *email = ( ItemEMail * ) node->data;
1715 address = email->address;
1719 if( name && name[0] != '\0' ) {
1720 if( strchr_with_skip_quote( name, '"', ',' ) )
1721 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1723 buf = g_strdup_printf( "%s <%s>", name, address );
1726 buf = g_strdup( address );
1733 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1737 AddrSelectItem *item;
1738 AddrItemObject *aio;
1741 compose = addrbook.target_compose;
1742 if( ! compose ) return;
1744 /* Nothing selected, but maybe there is something in text entry */
1745 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1747 compose_entry_append(
1748 compose, addr, (ComposeEntryType)data , PREF_NONE);
1751 /* Select from address list */
1752 list = addrselect_get_list( _addressSelect_ );
1757 node = g_list_next( node );
1758 aio = item->addressItem;
1759 if( aio->type == ADDR_ITEM_PERSON ||
1760 aio->type == ADDR_ITEM_EMAIL ) {
1761 addr = addressbook_format_address( aio );
1762 compose_entry_append(
1763 compose, addr, (ComposeEntryType) data, PREF_NONE );
1766 else if( aio->type == ADDR_ITEM_GROUP ) {
1767 ItemGroup *group = ( ItemGroup * ) aio;
1768 GList *nodeMail = group->listEMail;
1770 ItemEMail *email = nodeMail->data;
1772 addr = addressbook_format_address(
1773 ( AddrItemObject * ) email );
1774 compose_entry_append(
1775 compose, addr, (ComposeEntryType) data, PREF_NONE );
1777 nodeMail = g_list_next( nodeMail );
1782 AddressObject *obj = NULL;
1784 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1786 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1787 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1788 GList *nodeMail = itemGroup->listEMail;
1790 ItemEMail *email = nodeMail->data;
1792 addr = addressbook_format_address(
1793 ( AddrItemObject * ) email );
1794 compose_entry_append(
1795 compose, addr, (ComposeEntryType) data, PREF_NONE );
1797 nodeMail = g_list_next( nodeMail );
1801 g_list_free( list );
1804 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1805 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1806 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1807 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1809 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1810 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1811 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1812 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1814 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1815 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1816 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1817 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1818 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1821 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1822 gboolean canEdit = FALSE;
1823 gboolean canDelete = TRUE;
1824 gboolean canAdd = FALSE;
1825 gboolean canEditTr = TRUE;
1826 gboolean editAddress = FALSE;
1827 gboolean canExport = TRUE;
1828 AddressTypeControlItem *atci = NULL;
1829 AddressDataSource *ds = NULL;
1830 AddressInterface *iface = NULL;
1832 if( obj == NULL ) return;
1833 if( obj->type == ADDR_INTERFACE ) {
1834 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1835 iface = adapter->interface;
1837 if( iface->haveLibrary ) {
1838 /* Enable appropriate File / New command */
1839 atci = adapter->atci;
1840 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1843 canEditTr = canExport = FALSE;
1845 else if( obj->type == ADDR_DATASOURCE ) {
1846 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1847 ds = ads->dataSource;
1848 iface = ds->interface;
1849 if( ! iface->readOnly ) {
1850 canAdd = canEdit = editAddress = canDelete = TRUE;
1852 if( ! iface->haveLibrary ) {
1853 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1856 else if( obj->type == ADDR_ITEM_FOLDER ) {
1857 ds = addressbook_find_datasource( addrbook.treeSelected );
1859 iface = ds->interface;
1860 if( iface->readOnly ) {
1865 canAdd = editAddress = TRUE;
1869 else if( obj->type == ADDR_ITEM_GROUP ) {
1870 ds = addressbook_find_datasource( addrbook.treeSelected );
1872 iface = ds->interface;
1873 if( ! iface->readOnly ) {
1879 if( addrbook.listSelected == NULL )
1883 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1884 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1885 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1886 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1889 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1890 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1891 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1892 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1894 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1895 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1898 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1899 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1903 * Address book tree callback function that responds to selection of tree
1906 * \param ctree Tree widget.
1907 * \param node Node that was selected.
1908 * \param column Column number where selected occurred.
1909 * \param data Pointer to user data.
1911 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1912 gint column, gpointer data)
1914 AddressObject *obj = NULL;
1915 AdapterDSource *ads = NULL;
1916 AddressDataSource *ds = NULL;
1917 ItemFolder *rootFolder = NULL;
1918 AddressObjectType aot;
1920 addrbook.treeSelected = node;
1921 addrbook.listSelected = NULL;
1922 addressbook_status_show( "" );
1923 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1925 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1927 addressbook_set_clist(NULL, TRUE);
1930 addrbook.opened = node;
1932 if( obj->type == ADDR_DATASOURCE ) {
1933 /* Read from file */
1934 static gboolean tVal = TRUE;
1936 ads = ADAPTER_DSOURCE(obj);
1937 if( ads == NULL ) return;
1938 ds = ads->dataSource;
1939 if( ds == NULL ) return;
1941 if( addrindex_ds_get_modify_flag( ds ) ) {
1942 addrindex_ds_read_data( ds );
1945 if( ! addrindex_ds_get_read_flag( ds ) ) {
1946 addrindex_ds_read_data( ds );
1948 addressbook_ds_show_message( ds );
1950 if( ! addrindex_ds_get_access_flag( ds ) ) {
1951 /* Remove existing folders and groups */
1952 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1953 addressbook_tree_remove_children( ctree, node );
1954 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1956 /* Load folders into the tree */
1957 rootFolder = addrindex_ds_get_root_folder( ds );
1958 if( ds && ds->type == ADDR_IF_JPILOT ) {
1959 aot = ADDR_CATEGORY;
1961 else if( ds && ds->type == ADDR_IF_LDAP ) {
1962 aot = ADDR_LDAP_QUERY;
1965 aot = ADDR_ITEM_FOLDER;
1967 addressbook_node_add_folder( node, ds, rootFolder, aot );
1968 addrindex_ds_set_access_flag( ds, &tVal );
1969 gtk_cmctree_expand( ctree, node );
1972 addressbook_set_clist(NULL, TRUE);
1975 /* Update address list */
1976 g_signal_handlers_block_by_func
1978 G_CALLBACK(addressbook_tree_selected), NULL);
1979 addressbook_set_clist( obj, FALSE );
1980 g_signal_handlers_unblock_by_func
1982 G_CALLBACK(addressbook_tree_selected), NULL);
1983 if (!prefs_common.addressbook_use_editaddress_dialog)
1984 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1986 /* Setup main menu selections */
1987 addressbook_menubar_set_sensitive( FALSE );
1988 addressbook_menuitem_set_sensitive( obj, node );
1989 addressbook_list_select_clear();
1990 addressbook_list_menu_setup();
1995 * Setup address list popup menu items. Items are enabled or disabled as
1998 static void addressbook_list_menu_setup( void ) {
1999 GtkCMCTree *clist = NULL;
2000 AddressObject *pobj = NULL;
2001 AddressObject *obj = NULL;
2002 AdapterDSource *ads = NULL;
2003 AddressInterface *iface = NULL;
2004 AddressDataSource *ds = NULL;
2005 gboolean canEdit = FALSE;
2006 gboolean canDelete = FALSE;
2007 gboolean canCut = FALSE;
2008 gboolean canCopy = FALSE;
2009 gboolean canPaste = FALSE;
2010 gboolean canBrowse = FALSE;
2012 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2013 if( pobj == NULL ) return;
2015 clist = GTK_CMCTREE(addrbook.clist);
2016 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2017 if( obj == NULL ) canEdit = FALSE;
2019 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2020 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2022 if( pobj->type == ADDR_DATASOURCE ) {
2023 /* Parent object is a data source */
2024 ads = ADAPTER_DSOURCE(pobj);
2025 ds = ads->dataSource;
2028 iface = ds->interface;
2031 if( ! iface->readOnly ) {
2032 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2033 if (iface->type != ADDR_IF_LDAP)
2034 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2035 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2038 canDelete = canEdit;
2041 else if( pobj->type != ADDR_INTERFACE ) {
2042 /* Parent object is not an interface */
2043 ds = addressbook_find_datasource( addrbook.treeSelected );
2046 iface = ds->interface;
2049 if( ! iface->readOnly ) {
2050 /* Folder or group */
2051 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2052 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2053 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2054 if( obj ) canEdit = TRUE;
2057 if( pobj->type == ADDR_ITEM_FOLDER ) {
2058 if (iface->type != ADDR_IF_LDAP)
2059 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2060 if( obj ) canEdit = TRUE;
2062 canDelete = canEdit;
2064 if( iface->type == ADDR_IF_LDAP ) {
2065 if( obj ) canBrowse = TRUE;
2072 /* Enable cut and paste */
2073 if( ! addrclip_is_empty( _clipBoard_ ) )
2075 if( ! addrselect_test_empty( _addressSelect_ ) )
2077 /* Enable copy if something is selected */
2078 if( ! addrselect_test_empty( _addressSelect_ ) )
2082 /* Disable edit or browse if more than one row selected */
2083 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2088 /* Forbid write changes when read-only */
2089 if( iface && iface->readOnly ) {
2095 /* Now go finalize menu items */
2096 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2097 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2099 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2101 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2103 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2105 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2106 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2107 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2109 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2110 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2111 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2113 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2114 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2116 if (addrbook.target_compose) {
2117 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2118 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2119 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2122 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2126 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2127 GtkCMCTreeNode *node,
2134 * Add list of items into tree node below specified tree node.
2135 * \param treeNode Tree node.
2136 * \param ds Data source.
2137 * \param listItems List of items.
2139 static void addressbook_treenode_add_list(
2140 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2146 AddrItemObject *aio;
2150 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2153 group = ( ItemGroup * ) aio;
2154 nn = addressbook_node_add_group( treeNode, ds, group );
2156 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2159 folder = ( ItemFolder * ) aio;
2160 nn = addressbook_node_add_folder(
2161 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2163 node = g_list_next( node );
2167 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2168 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2172 * Cut from address list widget.
2174 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2175 _clipBoard_->cutFlag = TRUE;
2176 addrclip_clear( _clipBoard_ );
2177 addrclip_add( _clipBoard_, _addressSelect_ );
2178 /* addrclip_list_show( _clipBoard_, stdout ); */
2182 * Copy from address list widget.
2184 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2185 _clipBoard_->cutFlag = FALSE;
2186 addrclip_clear( _clipBoard_ );
2187 addrclip_add( _clipBoard_, _addressSelect_ );
2188 /* addrclip_list_show( _clipBoard_, stdout ); */
2192 * Paste clipboard into address list widget.
2194 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2195 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2196 AddressObject *pobj = NULL;
2197 AddressDataSource *ds = NULL;
2198 AddressBookFile *abf = NULL;
2199 ItemFolder *folder = NULL;
2200 GList *folderGroup = NULL;
2202 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2203 if( ds == NULL ) return;
2204 if( addrindex_ds_get_readonly( ds ) ) {
2205 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2209 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2211 if( pobj->type == ADDR_ITEM_FOLDER ) {
2212 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2214 else if( pobj->type == ADDR_ITEM_GROUP ) {
2215 alertpanel_error( _("Cannot paste into an address group.") );
2220 /* Get an address book */
2221 abf = addressbook_get_book_file();
2222 if( abf == NULL ) return;
2224 if( _clipBoard_->cutFlag ) {
2226 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2228 /* Remove all groups and folders in clipboard from tree node */
2229 addressbook_treenode_remove_item();
2231 /* Remove all "cut" items */
2232 addrclip_delete_item( _clipBoard_ );
2234 /* Clear clipboard - cut items??? */
2235 addrclip_clear( _clipBoard_ );
2239 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2242 /* addrclip_list_show( _clipBoard_, stdout ); */
2244 /* Update tree by inserting node for each folder or group */
2245 addressbook_treenode_add_list(
2246 addrbook.treeSelected, ds, folderGroup );
2247 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2248 g_list_free( folderGroup );
2252 /* Display items pasted */
2253 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2254 addressbook_set_clist(
2255 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2263 * Add current treenode object to clipboard. Note that widget only allows
2264 * one entry from the tree list to be selected.
2266 static void addressbook_treenode_to_clipboard( void ) {
2267 AddressObject *obj = NULL;
2268 AddressDataSource *ds = NULL;
2269 AddrSelectItem *item;
2270 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2271 GtkCMCTreeNode *node;
2273 node = addrbook.treeSelected;
2274 if( node == NULL ) return;
2275 obj = gtk_cmctree_node_get_row_data( ctree, node );
2276 if( obj == NULL ) return;
2278 ds = addressbook_find_datasource( node );
2279 if( ds == NULL ) return;
2282 if( obj->type == ADDR_ITEM_FOLDER ) {
2283 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2284 ItemFolder *folder = adapter->itemFolder;
2286 item = addrselect_create_node( obj );
2287 item->uid = g_strdup( ADDRITEM_ID(folder) );
2289 else if( obj->type == ADDR_ITEM_GROUP ) {
2290 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2291 ItemGroup *group = adapter->itemGroup;
2293 item = addrselect_create_node( obj );
2294 item->uid = g_strdup( ADDRITEM_ID(group) );
2296 else if( obj->type == ADDR_DATASOURCE ) {
2298 item = addrselect_create_node( obj );
2303 /* Clear existing list and add item into list */
2306 addressbook_list_select_clear();
2307 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2308 addrselect_list_add( _addressSelect_, item, cacheID );
2314 * Cut from tree widget.
2316 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2317 _clipBoard_->cutFlag = TRUE;
2318 addressbook_treenode_to_clipboard();
2319 addrclip_clear( _clipBoard_ );
2320 addrclip_add( _clipBoard_, _addressSelect_ );
2321 /* addrclip_list_show( _clipBoard_, stdout ); */
2325 * Copy from tree widget.
2327 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2328 _clipBoard_->cutFlag = FALSE;
2329 addressbook_treenode_to_clipboard();
2330 addrclip_clear( _clipBoard_ );
2331 addrclip_add( _clipBoard_, _addressSelect_ );
2332 /* addrclip_list_show( _clipBoard_, stdout ); */
2336 * Paste clipboard into address tree widget.
2338 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2339 addressbook_clip_paste_cb(NULL,NULL);
2343 * Clear selected entries in clipboard.
2345 static void addressbook_list_select_clear( void ) {
2346 addrselect_list_clear( _addressSelect_ );
2350 * Add specified address item to selected address list.
2351 * \param aio Address item object.
2352 * \param ds Datasource.
2354 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2357 if( ds == NULL ) return;
2358 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2359 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2364 * Remove specified address item from selected address list.
2365 * \param aio Address item object.
2367 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2368 addrselect_list_remove( _addressSelect_, aio );
2372 * Invoke EMail compose window with addresses in selected address list.
2374 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2377 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2378 listAddress = addrselect_build_list( _addressSelect_ );
2379 compose_new_with_list( NULL, listAddress );
2380 mgu_free_dlist( listAddress );
2385 static void addressbook_list_row_selected( GtkCMCTree *clist,
2386 GtkCMCTreeNode *node,
2390 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2391 AddrItemObject *aio = NULL;
2392 AddressObject *pobj = NULL;
2393 AdapterDSource *ads = NULL;
2394 AddressDataSource *ds = NULL;
2396 gtk_entry_set_text( entry, "" );
2397 addrbook.listSelected = node;
2399 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2400 if( pobj == NULL ) return;
2402 if( pobj->type == ADDR_DATASOURCE ) {
2403 ads = ADAPTER_DSOURCE(pobj);
2404 ds = ads->dataSource;
2406 else if( pobj->type != ADDR_INTERFACE ) {
2407 ds = addressbook_find_datasource( addrbook.treeSelected );
2410 aio = gtk_cmctree_node_get_row_data( clist, node );
2412 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2413 addressbook_list_select_add( aio, ds );
2416 addressbook_list_menu_setup();
2418 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2419 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2421 if (obj && obj->type != ADDR_ITEM_GROUP)
2422 addressbook_edit_address(NULL, 0, NULL, FALSE);
2426 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2427 GtkCMCTreeNode *node,
2431 AddrItemObject *aio;
2433 aio = gtk_cmctree_node_get_row_data( ctree, node );
2435 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2436 addressbook_list_select_remove( aio );
2439 if (!prefs_common.addressbook_use_editaddress_dialog)
2440 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2443 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2444 GdkEventButton *event,
2447 if( ! event ) return FALSE;
2449 addressbook_list_menu_setup();
2451 if( event->button == 3 ) {
2452 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2453 event->button, event->time );
2454 } else if (event->button == 1) {
2455 if (event->type == GDK_2BUTTON_PRESS) {
2456 if (prefs_common.add_address_by_click &&
2457 addrbook.target_compose)
2458 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2460 if (prefs_common.addressbook_use_editaddress_dialog)
2461 addressbook_edit_address_cb(NULL, NULL);
2463 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2464 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2465 if( obj && obj->type == ADDR_ITEM_GROUP )
2466 addressbook_edit_address_cb(NULL, NULL);
2474 static gboolean addressbook_list_button_released(GtkWidget *widget,
2475 GdkEventButton *event,
2481 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2482 GdkEventButton *event,
2485 GtkCMCList *clist = GTK_CMCLIST(ctree);
2487 AddressObject *obj = NULL;
2488 AdapterDSource *ads = NULL;
2489 AddressInterface *iface = NULL;
2490 AddressDataSource *ds = NULL;
2491 gboolean canEdit = FALSE;
2492 gboolean canDelete = FALSE;
2493 gboolean canCut = FALSE;
2494 gboolean canCopy = FALSE;
2495 gboolean canPaste = FALSE;
2496 gboolean canTreeCut = FALSE;
2497 gboolean canTreeCopy = FALSE;
2498 gboolean canTreePaste = FALSE;
2499 gboolean canLookup = FALSE;
2500 GtkCMCTreeNode *node = NULL;
2502 if( ! event ) return FALSE;
2503 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2505 if (event->button == 1) {
2506 if (event->type == GDK_2BUTTON_PRESS) {
2507 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2508 gtkut_clist_set_focus_row(clist, row);
2509 obj = gtk_cmclist_get_row_data( clist, row );
2514 if (obj->type == ADDR_ITEM_GROUP) {
2516 addressbook_treenode_edit_cb(NULL, NULL);
2518 /* expand pr collapse */
2519 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2520 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2526 addressbook_menubar_set_sensitive( FALSE );
2528 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2529 gtkut_clist_set_focus_row(clist, row);
2530 obj = gtk_cmclist_get_row_data( clist, row );
2533 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2537 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2539 if( ! addrclip_is_empty( _clipBoard_ ) )
2540 canTreePaste = TRUE;
2542 if (obj->type == ADDR_INTERFACE) {
2543 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2544 iface = adapter->interface;
2547 if( !iface->readOnly ) {
2548 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2549 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2551 if( iface->externalQuery )
2554 if (obj->type == ADDR_DATASOURCE) {
2555 ads = ADAPTER_DSOURCE(obj);
2556 ds = ads->dataSource;
2559 iface = ds->interface;
2562 if( !iface->readOnly ) {
2564 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2565 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2566 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2570 if( iface->externalQuery )
2573 else if (obj->type == ADDR_ITEM_FOLDER) {
2574 ds = addressbook_find_datasource( node );
2577 iface = ds->interface;
2580 if( !iface->readOnly ) {
2584 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2585 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2586 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2590 if( iface->externalQuery ) {
2591 /* Enable deletion of LDAP folder */
2596 else if (obj->type == ADDR_ITEM_GROUP) {
2597 ds = addressbook_find_datasource( node );
2600 iface = ds->interface;
2603 if( ! iface->readOnly ) {
2606 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2607 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2611 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2613 if( ! addrselect_test_empty( _addressSelect_ ) )
2615 if( ! addrclip_is_empty( _clipBoard_ ) )
2618 /* Forbid write changes when read-only */
2619 if( iface && iface->readOnly ) {
2621 canTreePaste = FALSE;
2629 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2630 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2631 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2632 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2633 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2635 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2636 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2637 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2638 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2639 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2641 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2642 addrbook.target_compose != NULL);
2644 if( event->button == 3 )
2645 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2646 event->button, event->time);
2651 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2652 GdkEventButton *event,
2655 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2659 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2661 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2662 AddressObject *obj = NULL;
2663 AddressDataSource *ds = NULL;
2664 AddressBookFile *abf = NULL;
2665 ItemFolder *parentFolder = NULL;
2666 ItemFolder *folder = NULL;
2668 if( ! addrbook.treeSelected ) return;
2669 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2670 if( obj == NULL ) return;
2671 ds = addressbook_find_datasource( addrbook.treeSelected );
2672 if( ds == NULL ) return;
2674 if( obj->type == ADDR_DATASOURCE ) {
2675 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2677 else if( obj->type == ADDR_ITEM_FOLDER ) {
2678 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2684 abf = ds->rawDataSource;
2685 if( abf == NULL ) return;
2686 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2689 nn = addressbook_node_add_folder(
2690 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2691 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2692 if( addrbook.treeSelected == addrbook.opened )
2693 addressbook_set_clist(obj, TRUE);
2697 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2699 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2700 AddressObject *obj = NULL;
2701 AddressDataSource *ds = NULL;
2702 AddressBookFile *abf = NULL;
2703 ItemFolder *parentFolder = NULL;
2704 ItemGroup *group = NULL;
2706 if( ! addrbook.treeSelected ) return;
2707 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2708 if( obj == NULL ) return;
2709 ds = addressbook_find_datasource( addrbook.treeSelected );
2710 if( ds == NULL ) return;
2712 if( obj->type == ADDR_DATASOURCE ) {
2713 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2715 else if( obj->type == ADDR_ITEM_FOLDER ) {
2716 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2722 abf = ds->rawDataSource;
2723 if( abf == NULL ) return;
2724 group = addressbook_edit_group( abf, parentFolder, NULL );
2727 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2728 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2729 if( addrbook.treeSelected == addrbook.opened )
2730 addressbook_set_clist(obj, TRUE);
2734 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2736 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2739 GdkPixbuf *pix_cl, *pix_op;
2740 gboolean is_leaf, expanded;
2742 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2744 &is_leaf, &expanded);
2745 gtk_sctree_set_node_info(ctree, node, name, spacing,
2752 * \param obj Address object to edit.
2753 * \param node Node in tree.
2754 * \return New name of data source.
2756 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2757 gchar *newName = NULL;
2758 AddressDataSource *ds = NULL;
2759 AddressInterface *iface = NULL;
2760 AdapterDSource *ads = NULL;
2762 ds = addressbook_find_datasource( node );
2763 if( ds == NULL ) return NULL;
2764 iface = ds->interface;
2765 if( ! iface->haveLibrary ) return NULL;
2767 /* Read data from data source */
2768 if( addrindex_ds_get_modify_flag( ds ) ) {
2769 addrindex_ds_read_data( ds );
2772 if( ! addrindex_ds_get_read_flag( ds ) ) {
2773 addrindex_ds_read_data( ds );
2777 ads = ADAPTER_DSOURCE(obj);
2778 if( ads->subType == ADDR_BOOK ) {
2779 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2781 else if( ads->subType == ADDR_VCARD ) {
2782 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2785 else if( ads->subType == ADDR_JPILOT ) {
2786 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2790 else if( ads->subType == ADDR_LDAP ) {
2791 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2797 newName = obj->name;
2802 * Edit an object that is in the address tree area.
2804 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2806 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2808 AddressDataSource *ds = NULL;
2809 AddressBookFile *abf = NULL;
2810 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2813 if( ! addrbook.treeSelected ) return;
2814 node = addrbook.treeSelected;
2815 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2816 obj = gtk_cmctree_node_get_row_data( ctree, node );
2817 if( obj == NULL ) return;
2818 parentNode = GTK_CMCTREE_ROW(node)->parent;
2820 ds = addressbook_find_datasource( node );
2821 if( ds == NULL ) return;
2823 if( obj->type == ADDR_DATASOURCE ) {
2824 name = addressbook_edit_datasource( obj, node );
2825 if( name == NULL ) return;
2828 abf = ds->rawDataSource;
2829 if( abf == NULL ) return;
2830 if( obj->type == ADDR_ITEM_FOLDER ) {
2831 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2832 ItemFolder *item = adapter->itemFolder;
2833 ItemFolder *parentFolder = NULL;
2834 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2835 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2836 name = ADDRITEM_NAME(item);
2838 else if( obj->type == ADDR_ITEM_GROUP ) {
2839 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2840 ItemGroup *item = adapter->itemGroup;
2841 ItemFolder *parentFolder = NULL;
2842 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2843 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2844 name = ADDRITEM_NAME(item);
2847 if( name && parentNode ) {
2848 /* Update node in tree view */
2849 addressbook_change_node_name( node, name );
2850 gtk_sctree_sort_node(ctree, parentNode);
2851 gtk_cmctree_expand( ctree, node );
2852 gtk_sctree_select( GTK_SCTREE( ctree), node );
2859 ADDRTREE_DEL_FOLDER_ONLY,
2860 ADDRTREE_DEL_FOLDER_ADDR
2864 * Delete an item from the tree widget.
2865 * \param data Data passed in.
2866 * \param action Action.
2867 * \param widget Widget issuing callback.
2869 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2871 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2872 GtkCMCTreeNode *node = NULL;
2876 AddrBookBase *adbase;
2877 AddressCache *cache;
2878 AdapterDSource *ads = NULL;
2879 AddressInterface *iface = NULL;
2880 AddressDataSource *ds = NULL;
2881 gboolean remFlag = FALSE;
2882 TreeItemDelType delType;
2884 if( ! addrbook.treeSelected ) return;
2885 node = addrbook.treeSelected;
2886 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2888 obj = gtk_cmctree_node_get_row_data( ctree, node );
2889 cm_return_if_fail(obj != NULL);
2891 if( obj->type == ADDR_DATASOURCE ) {
2892 ads = ADAPTER_DSOURCE(obj);
2893 if( ads == NULL ) return;
2894 ds = ads->dataSource;
2895 if( ds == NULL ) return;
2898 /* Must be folder or something else */
2899 ds = addressbook_find_datasource( node );
2900 if( ds == NULL ) return;
2902 /* Only allow deletion from non-readOnly */
2903 iface = ds->interface;
2904 if( iface->readOnly ) {
2905 /* Allow deletion of query results */
2906 if( ! iface->externalQuery ) return;
2910 /* Confirm deletion */
2911 delType = ADDRTREE_DEL_NONE;
2912 if( obj->type == ADDR_ITEM_FOLDER ) {
2913 if( iface->externalQuery ) {
2914 message = g_strdup_printf( _(
2915 "Do you want to delete the query " \
2916 "results and addresses in '%s' ?" ),
2918 aval = alertpanel( _("Delete"), message,
2919 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2921 if( aval == G_ALERTALTERNATE ) {
2922 delType = ADDRTREE_DEL_FOLDER_ADDR;
2926 message = g_strdup_printf
2927 ( _( "Do you want to delete '%s' ? "
2928 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2930 aval = alertpanel( _("Delete folder"), message,
2931 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2933 if( aval == G_ALERTALTERNATE ) {
2934 delType = ADDRTREE_DEL_FOLDER_ONLY;
2936 else if( aval == G_ALERTOTHER ) {
2937 delType = ADDRTREE_DEL_FOLDER_ADDR;
2941 else if( obj->type == ADDR_ITEM_GROUP ) {
2942 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2943 "The addresses it contains will not be lost."), obj->name);
2944 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2945 "+" GTK_STOCK_DELETE, NULL);
2947 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2949 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2950 "The addresses it contains will be lost."), obj->name);
2951 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2952 "+" GTK_STOCK_DELETE, NULL);
2954 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2956 if( delType == ADDRTREE_DEL_NONE ) return;
2958 /* Proceed with deletion */
2959 if( obj->type == ADDR_DATASOURCE ) {
2960 /* Remove node from tree */
2961 gtk_cmctree_remove_node( ctree, node );
2963 /* Remove data source. */
2964 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2965 addrindex_free_datasource( ds );
2970 /* Get reference to cache */
2971 adbase = ( AddrBookBase * ) ds->rawDataSource;
2972 if( adbase == NULL ) return;
2973 cache = adbase->addressCache;
2975 /* Remove query results folder */
2976 if( iface->externalQuery ) {
2977 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2978 ItemFolder *folder = adapter->itemFolder;
2980 adapter->itemFolder = NULL;
2982 g_print( "remove folder for ::%s::\n", obj->name );
2983 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2984 g_print( "-------------- remove results\n" );
2986 addrindex_remove_results( ds, folder );
2987 /* g_print( "-------------- remove node\n" ); */
2988 gtk_cmctree_remove_node( ctree, node );
2992 /* Code below is valid for regular address book deletion */
2993 if( obj->type == ADDR_ITEM_FOLDER ) {
2994 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2995 ItemFolder *item = adapter->itemFolder;
2997 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2998 /* Remove folder only */
2999 item = addrcache_remove_folder( cache, item );
3001 addritem_free_item_folder( item );
3002 addressbook_move_nodes_up( ctree, node );
3006 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3007 /* Remove folder and addresses */
3008 item = addrcache_remove_folder_delete( cache, item );
3010 addritem_free_item_folder( item );
3015 else if( obj->type == ADDR_ITEM_GROUP ) {
3016 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3017 ItemGroup *item = adapter->itemGroup;
3019 item = addrcache_remove_group( cache, item );
3021 addritem_free_item_group( item );
3028 gtk_cmctree_remove_node(ctree, node );
3032 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3034 if( person && addrbook.treeSelected == addrbook.opened ) {
3035 person->status = ADD_ENTRY;
3036 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3037 addressbook_folder_refresh_one_person(
3038 GTK_CMCTREE(addrbook.clist), person );
3040 addressbook_address_list_set_focus();
3043 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3045 if( person && addrbook.treeSelected == addrbook.opened) {
3046 person->status = ADD_ENTRY;
3047 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3048 addressbook_set_clist(
3049 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3053 addressbook_address_list_set_focus();
3057 * Label (a format string) that is used to name each folder.
3059 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3062 * Search ctree widget callback function.
3063 * \param pA Pointer to node.
3064 * \param pB Pointer to data item being sought.
3065 * \return Zero (0) if folder found.
3067 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3070 aoA = ( AddressObject * ) pA;
3071 if( aoA->type == ADDR_ITEM_FOLDER ) {
3072 ItemFolder *folder, *fld;
3074 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3075 folder = ( ItemFolder * ) pB;
3076 if( fld == folder ) return 0; /* Found folder */
3081 static ItemFolder * addressbook_setup_subf(
3082 AddressDataSource *ds, gchar *title,
3083 GtkCMCTreeNode *pNode )
3085 AddrBookBase *adbase;
3086 AddressCache *cache;
3089 GtkCMCTreeNode *nNode;
3091 AddressObjectType aoType = ADDR_NONE;
3094 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3096 if( ds && ds->type == ADDR_IF_LDAP ) {
3098 aoType = ADDR_LDAP_QUERY;
3105 ctree = GTK_CMCTREE(addrbook.ctree);
3106 /* Get reference to address cache */
3107 adbase = ( AddrBookBase * ) ds->rawDataSource;
3108 cache = adbase->addressCache;
3110 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3111 GList *cur = children;
3112 for (; cur; cur = cur->next) {
3113 ItemFolder *child = (ItemFolder *) cur->data;
3114 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3115 nNode = gtk_cmctree_find_by_row_data_custom(
3117 addressbook_treenode_find_folder_cb );
3119 addrindex_remove_results( ds, child );
3120 while( child->listPerson ) {
3121 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3122 item = addrcache_remove_person( cache, item );
3124 addritem_free_item_person( item );
3128 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3129 addrbook.treeSelected = nNode;
3136 /* Create a folder */
3137 folder = addrcache_add_new_folder( cache, NULL );
3138 name = g_strdup_printf( "%s", title );
3139 addritem_folder_set_name( folder, name );
3140 addritem_folder_set_remarks( folder, "" );
3143 /* Now let's see the folder */
3144 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3145 gtk_cmctree_expand( ctree, pNode );
3147 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3148 addrbook.treeSelected = nNode;
3154 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3155 AddressObject *pobj = NULL;
3156 AddressDataSource *ds = NULL;
3157 AddressBookFile *abf = NULL;
3158 debug_print("adding address\n");
3159 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3160 if( pobj == NULL ) {
3161 debug_print("no row data\n");
3164 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3166 debug_print("no datasource\n");
3170 abf = ds->rawDataSource;
3172 g_print("no addressbook file\n");
3176 if( pobj->type == ADDR_DATASOURCE ) {
3177 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3178 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3180 ItemFolder *folder = NULL;
3182 if (abf && abf->type == ADDR_IF_LDAP) {
3183 GtkCMCTreeNode *parentNode;
3184 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3185 if( ds == NULL ) return;
3187 /* We must have a datasource that is an external interface */
3188 if( ! ds->interface->haveLibrary ) return;
3189 if( ! ds->interface->externalQuery ) return;
3191 if( pobj->type == ADDR_ITEM_FOLDER ) {
3192 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3195 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3197 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3199 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
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 == ADDR_IF_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 == ADDR_IF_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 );
3250 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
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 == ADDR_IF_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->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 == ADDR_IF_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 );
3408 node = gtk_cmctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3410 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3411 if( ds == NULL ) return;
3413 abf = addressbook_get_book_file();
3415 if( obj->type == ADDR_ITEM_EMAIL ) {
3416 ItemEMail *email = ( ItemEMail * ) obj;
3417 if( email == NULL ) return;
3418 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3419 /* Edit parent group */
3420 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3421 ItemGroup *itemGrp = adapter->itemGroup;
3422 if( abf == NULL ) return;
3423 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3424 name = ADDRITEM_NAME(itemGrp);
3425 node = addrbook.treeSelected;
3426 parentNode = GTK_CMCTREE_ROW(node)->parent;
3429 /* Edit person - email page */
3431 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3432 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3433 addressbook_edit_address_post_cb,
3434 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3437 if (abf && abf->type == ADDR_IF_LDAP) {
3438 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3439 person->status = UPDATE_ENTRY;
3442 if (prefs_common.addressbook_use_editaddress_dialog)
3443 addressbook_edit_address_post_cb( person );
3448 else if( obj->type == ADDR_ITEM_PERSON ) {
3449 /* Edit person - basic page */
3450 ItemPerson *person = ( ItemPerson * ) obj;
3451 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3452 addressbook_edit_address_post_cb,
3453 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3456 if (abf && abf->type == ADDR_IF_LDAP) {
3457 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3458 person->status = UPDATE_ENTRY;
3461 if (prefs_common.addressbook_use_editaddress_dialog)
3462 addressbook_edit_address_post_cb( person );
3466 else if( obj->type == ADDR_ITEM_GROUP ) {
3467 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3468 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3469 parentNode = addrbook.treeSelected;
3470 node = addressbook_find_group_node( parentNode, itemGrp );
3471 name = ADDRITEM_NAME(itemGrp);
3472 invalidate_address_completion();
3478 /* Update tree node with node name */
3479 if( node == NULL ) return;
3480 addressbook_change_node_name( node, name );
3481 gtk_sctree_sort_node( ctree, parentNode );
3482 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3483 addressbook_set_clist(
3484 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3489 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3491 addressbook_del_clicked(NULL, NULL);
3494 static void close_cb(GtkAction *action, gpointer data)
3496 addressbook_close();
3499 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3500 addressbook_export_to_file();
3503 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3505 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3506 if( person ) addritem_person_set_opened( person, TRUE );
3510 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3512 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3513 if( person ) addritem_person_set_opened( person, FALSE );
3517 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3519 gchar *eMailAlias = ADDRITEM_NAME(email);
3520 if( eMailAlias && *eMailAlias != '\0' ) {
3522 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3525 str = g_strdup( eMailAlias );
3531 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3532 GList *items = itemGroup->listEMail;
3533 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3534 for( ; items != NULL; items = g_list_next( items ) ) {
3535 GtkCMCTreeNode *nodeEMail = NULL;
3536 gchar *text[N_LIST_COLS];
3537 ItemEMail *email = items->data;
3541 if( ! email ) continue;
3543 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3544 str = addressbook_format_item_clist( person, email );
3546 text[COL_NAME] = addressbook_set_col_name_guard(str);
3549 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3551 text[COL_ADDRESS] = email->address;
3552 text[COL_REMARKS] = email->remarks;
3553 nodeEMail = gtk_sctree_insert_node(
3555 text, FOLDER_SPACING,
3559 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3565 gchar *addressbook_set_col_name_guard(gchar *value)
3567 gchar *ret = "<not set>";
3568 gchar *tmp = g_strdup(value);
3570 if (tmp !=NULL && *tmp != '\0')
3576 static void addressbook_folder_load_one_person(
3577 GtkCMCTree *clist, ItemPerson *person,
3578 AddressTypeControlItem *atci,
3579 AddressTypeControlItem *atciMail )
3581 GtkCMCTreeNode *nodePerson = NULL;
3582 GtkCMCTreeNode *nodeEMail = NULL;
3583 gchar *text[N_LIST_COLS];
3584 gboolean flgFirst = TRUE, haveAddr = FALSE;
3587 AddressBookFile *abf = addressbook_get_book_file();
3590 if( person == NULL ) return;
3592 text[COL_NAME] = "";
3593 node = person->listEMail;
3595 ItemEMail *email = node->data;
3596 gchar *eMailAddr = NULL;
3597 node = g_list_next( node );
3599 text[COL_ADDRESS] = email->address;
3600 text[COL_REMARKS] = email->remarks;
3601 eMailAddr = ADDRITEM_NAME(email);
3602 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3604 /* First email belongs with person */
3605 gchar *str = addressbook_format_item_clist( person, email );
3607 text[COL_NAME] = addressbook_set_col_name_guard(str);
3610 else if( abf && abf->type == ADDR_IF_LDAP &&
3611 person && person->nickName ) {
3612 if (person->nickName) {
3613 if (strcmp(person->nickName, "") != 0) {
3614 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3617 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3623 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3625 nodePerson = gtk_sctree_insert_node(
3627 text, FOLDER_SPACING,
3630 FALSE, person->isOpened );
3633 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3636 /* Subsequent email is a child node of person */
3637 text[COL_NAME] = ADDRITEM_NAME(email);
3638 nodeEMail = gtk_sctree_insert_node(
3639 clist, nodePerson, NULL,
3640 text, FOLDER_SPACING,
3642 atciMail->iconXpmOpen,
3644 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3650 /* Have name without EMail */
3651 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3652 text[COL_ADDRESS] = "";
3653 text[COL_REMARKS] = "";
3654 nodePerson = gtk_sctree_insert_node(
3656 text, FOLDER_SPACING,
3659 FALSE, person->isOpened );
3660 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3665 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3667 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3668 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3670 if( atci == NULL ) return;
3671 if( atciMail == NULL ) return;
3673 /* Load email addresses */
3674 items = addritem_folder_get_person_list( itemFolder );
3675 for( ; items != NULL; items = g_list_next( items ) ) {
3676 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3678 /* Free up the list */
3679 mgu_clear_list( items );
3680 g_list_free( items );
3683 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3684 addrbook.listSelected = NULL;
3685 gtk_cmctree_remove_node( clist, node );
3686 addressbook_menubar_set_sensitive( FALSE );
3687 addressbook_menuitem_set_sensitive(
3688 gtk_cmctree_node_get_row_data(
3689 GTK_CMCTREE(clist), addrbook.treeSelected ),
3690 addrbook.treeSelected );
3693 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3694 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3695 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3696 GtkCMCTreeNode *node;
3697 if( atci == NULL ) return;
3698 if( atciMail == NULL ) return;
3699 if( person == NULL ) return;
3700 /* unload the person */
3702 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3704 addressbook_folder_remove_node( clist, node );
3705 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3706 gtk_sctree_sort_node( clist, NULL );
3707 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3709 gtk_sctree_select( GTK_SCTREE(clist), node );
3710 if (!gtk_cmctree_node_is_visible( clist, node ) )
3711 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3715 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3716 GtkCMCTreeNode *node;
3719 if( person == NULL ) return;
3720 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3721 row = gtk_cmclist_find_row_from_data( GTK_CMCLIST(clist), person );
3723 addressbook_folder_remove_node( clist, node );
3727 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3729 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3731 /* Load any groups */
3732 if( ! atci ) return;
3733 items = addritem_folder_get_group_list( itemFolder );
3734 for( ; items != NULL; items = g_list_next( items ) ) {
3735 GtkCMCTreeNode *nodeGroup = NULL;
3736 gchar *text[N_LIST_COLS];
3737 ItemGroup *group = items->data;
3738 if( group == NULL ) continue;
3739 text[COL_NAME] = ADDRITEM_NAME(group);
3740 text[COL_ADDRESS] = "";
3741 text[COL_REMARKS] = "";
3742 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3743 text, FOLDER_SPACING,
3747 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3748 gtk_sctree_sort_node(clist, NULL);
3750 /* Free up the list */
3751 mgu_clear_list( items );
3752 g_list_free( items );
3756 * Search ctree widget callback function.
3757 * \param pA Pointer to node.
3758 * \param pB Pointer to data item being sought.
3759 * \return Zero (0) if group found.
3761 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3764 aoA = ( AddressObject * ) pA;
3765 if( aoA->type == ADDR_ITEM_GROUP ) {
3766 ItemGroup *group, *grp;
3768 grp = ADAPTER_GROUP(aoA)->itemGroup;
3769 group = ( ItemGroup * ) pB;
3770 if( grp == group ) return 0; /* Found group */
3776 * Remove folder and group nodes from tree widget for items contained ("cut")
3779 static void addressbook_treenode_remove_item( void ) {
3781 AddrSelectItem *cutItem;
3782 AddressCache *cache;
3783 AddrItemObject *aio;
3784 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3787 node = _clipBoard_->objectList;
3789 cutItem = node->data;
3790 node = g_list_next( node );
3791 cache = addrindex_get_cache(
3792 _clipBoard_->addressIndex, cutItem->cacheID );
3793 if( cache == NULL ) continue;
3794 aio = addrcache_get_object( cache, cutItem->uid );
3797 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3800 folder = ( ItemFolder * ) aio;
3801 tn = gtk_cmctree_find_by_row_data_custom(
3802 ctree, NULL, folder,
3803 addressbook_treenode_find_folder_cb );
3805 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3808 group = ( ItemGroup * ) aio;
3809 tn = gtk_cmctree_find_by_row_data_custom(
3811 addressbook_treenode_find_group_cb );
3815 /* Free up adapter and remove node. */
3816 gtk_cmctree_remove_node( ctree, tn );
3823 * Find parent datasource for specified tree node.
3824 * \param node Node to test.
3825 * \return Data source, or NULL if not found.
3827 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3828 AddressDataSource *ds = NULL;
3831 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3834 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3835 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3837 /* g_print( "ao->type = %d\n", ao->type ); */
3838 if( ao->type == ADDR_DATASOURCE ) {
3839 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3840 /* g_print( "found it\n" ); */
3841 ds = ads->dataSource;
3845 node = GTK_CMCTREE_ROW(node)->parent;
3851 * Load address list widget with children of specified object.
3852 * \param obj Parent object to be loaded.
3854 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3855 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3856 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3857 AddressDataSource *ds = NULL;
3858 AdapterDSource *ads = NULL;
3859 static AddressObject *last_obj = NULL;
3861 if (addrbook.clist == NULL) {
3864 if (obj == last_obj && !refresh)
3869 gtk_cmclist_clear(clist);
3873 if( obj->type == ADDR_INTERFACE ) {
3874 /* g_print( "set_clist: loading datasource...\n" ); */
3875 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3879 gtk_cmclist_freeze(clist);
3880 gtk_cmclist_clear(clist);
3882 if( obj->type == ADDR_DATASOURCE ) {
3883 ads = ADAPTER_DSOURCE(obj);
3884 ds = ADAPTER_DSOURCE(obj)->dataSource;
3886 /* Load root folder */
3887 ItemFolder *rootFolder = NULL;
3888 rootFolder = addrindex_ds_get_root_folder( ds );
3889 addressbook_folder_load_person(
3890 ctreelist, addrindex_ds_get_root_folder( ds ) );
3891 addressbook_folder_load_group(
3892 ctreelist, addrindex_ds_get_root_folder( ds ) );
3896 if( obj->type == ADDR_ITEM_GROUP ) {
3898 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3899 addressbook_load_group( ctreelist, itemGroup );
3901 else if( obj->type == ADDR_ITEM_FOLDER ) {
3903 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3904 addressbook_folder_load_person( ctreelist, itemFolder );
3905 addressbook_folder_load_group( ctreelist, itemFolder );
3908 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3909 clist->focus_row = -1;
3910 gtk_cmclist_thaw(clist);
3914 * Call back function to free adaptor. Call back is setup by function
3915 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3916 * called when the address book tree widget node is removed by calling
3917 * function gtk_cmctree_remove_node().
3919 * \param data Tree node's row data.
3921 static void addressbook_free_treenode( gpointer data ) {
3924 ao = ( AddressObject * ) data;
3925 if( ao == NULL ) return;
3926 if( ao->type == ADDR_INTERFACE ) {
3927 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3928 addrbookctl_free_interface( ai );
3930 else if( ao->type == ADDR_DATASOURCE ) {
3931 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3932 addrbookctl_free_datasource( ads );
3934 else if( ao->type == ADDR_ITEM_FOLDER ) {
3935 AdapterFolder *af = ADAPTER_FOLDER(ao);
3936 addrbookctl_free_folder( af );
3938 else if( ao->type == ADDR_ITEM_GROUP ) {
3939 AdapterGroup *ag = ADAPTER_GROUP(ao);
3940 addrbookctl_free_group( ag );
3945 * Create new adaptor for specified data source.
3947 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3948 AddressObjectType otype, gchar *name )
3950 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3951 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3952 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3953 adapter->dataSource = ds;
3954 adapter->subType = otype;
3958 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3959 ADDRESS_OBJECT_NAME(adapter) =
3960 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3964 * Load tree from address index with the initial data.
3966 static void addressbook_load_tree( void ) {
3967 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3968 GList *nodeIf, *nodeDS;
3969 AdapterInterface *adapter;
3970 AddressInterface *iface;
3971 AddressTypeControlItem *atci;
3972 AddressDataSource *ds;
3973 AdapterDSource *ads;
3974 GtkCMCTreeNode *node, *newNode;
3977 nodeIf = _addressInterfaceList_;
3979 adapter = nodeIf->data;
3980 node = adapter->treeNode;
3981 iface = adapter->interface;
3982 atci = adapter->atci;
3984 if( iface->useInterface ) {
3985 /* Load data sources below interface node */
3986 nodeDS = iface->listSource;
3990 name = addrindex_ds_get_name( ds );
3991 ads = addressbook_create_ds_adapter(
3992 ds, atci->objectType, name );
3993 newNode = addressbook_add_object(
3994 node, ADDRESS_OBJECT(ads) );
3995 nodeDS = g_list_next( nodeDS );
3997 gtk_cmctree_expand( ctree, node );
4000 nodeIf = g_list_next( nodeIf );
4005 * Convert the old address book to new format.
4007 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4008 gboolean retVal = FALSE;
4009 gboolean errFlag = TRUE;
4012 /* Read old address book, performing conversion */
4013 debug_print( "Reading and converting old address book...\n" );
4014 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4015 addrindex_read_data( addrIndex );
4016 if( addrIndex->retVal == MGU_NO_FILE ) {
4017 /* We do not have a file - new user */
4018 debug_print( "New user... create new books...\n" );
4019 addrindex_create_new_books( addrIndex );
4020 if( addrIndex->retVal == MGU_SUCCESS ) {
4021 /* Save index file */
4022 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4023 addrindex_save_data( addrIndex );
4024 if( addrIndex->retVal == MGU_SUCCESS ) {
4029 msg = _( "New user, could not save index file." );
4033 msg = _( "New user, could not save address book files." );
4037 /* We have an old file */
4038 if( addrIndex->wasConverted ) {
4039 /* Converted successfully - save address index */
4040 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4041 addrindex_save_data( addrIndex );
4042 if( addrIndex->retVal == MGU_SUCCESS ) {
4043 msg = _( "Old address book converted successfully." );
4048 msg = _("Old address book converted,\n"
4049 "could not save new address index file." );
4053 /* File conversion failed - just create new books */
4054 debug_print( "File conversion failed... just create new books...\n" );
4055 addrindex_create_new_books( addrIndex );
4056 if( addrIndex->retVal == MGU_SUCCESS ) {
4058 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4059 addrindex_save_data( addrIndex );
4060 if( addrIndex->retVal == MGU_SUCCESS ) {
4061 msg = _("Could not convert address book,\n"
4062 "but created empty new address book files." );
4067 msg = _("Could not convert address book,\n"
4068 "could not save new address index file." );
4072 msg = _("Could not convert address book\n"
4073 "and could not create new address book files." );
4078 debug_print( "Error\n%s\n", msg );
4079 alertpanel_full(_("Addressbook conversion error"), msg,
4080 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4081 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4084 debug_print( "Warning\n%s\n", msg );
4085 alertpanel_full(_("Addressbook conversion error"), msg,
4086 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4087 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4093 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4097 gboolean failed = FALSE;
4099 if( ( dp = opendir( origdir ) ) == NULL ) {
4103 while( ( d = readdir( dp ) ) != NULL ) {
4104 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4107 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4109 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4111 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4124 /* all copies succeeded, we can remove source files */
4125 if( ( dp = opendir( origdir ) ) == NULL ) {
4128 while( ( d = readdir( dp ) ) != NULL ) {
4129 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4132 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4134 claws_unlink(orig_file);
4144 void addressbook_read_file( void ) {
4145 AddressIndex *addrIndex = NULL;
4146 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4148 debug_print( "Reading address index...\n" );
4149 if( _addressIndex_ ) {
4150 debug_print( "address book already read!!!\n" );
4154 addrIndex = addrindex_create_index();
4155 addrindex_initialize();
4157 /* Use new address book index. */
4159 if ( !is_dir_exist(indexdir) ) {
4160 if ( make_dir(indexdir) < 0 ) {
4161 addrindex_set_file_path( addrIndex, get_rc_dir() );
4162 g_warning( "couldn't create dir %s\n", indexdir);
4164 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4165 remove_dir_recursive(indexdir);
4166 addrindex_set_file_path( addrIndex, get_rc_dir() );
4167 g_error("couldn't migrate dir %s", indexdir);
4169 addrindex_set_file_path( addrIndex, indexdir);
4173 addrindex_set_file_path( addrIndex, indexdir);
4176 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4177 addrindex_read_data( addrIndex );
4178 if( addrIndex->retVal == MGU_NO_FILE ) {
4179 /* Conversion required */
4180 debug_print( "Converting...\n" );
4181 if( addressbook_convert( addrIndex ) ) {
4182 _addressIndex_ = addrIndex;
4185 else if( addrIndex->retVal == MGU_SUCCESS ) {
4186 _addressIndex_ = addrIndex;
4189 /* Error reading address book */
4190 debug_print( "Could not read address index.\n" );
4191 addrindex_print_index( addrIndex, stdout );
4192 alertpanel_full(_("Addressbook Error"),
4193 _("Could not read address index"),
4194 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4195 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4197 debug_print( "done.\n" );
4201 * Add object into the address index tree widget.
4202 * Enter: node Parent node.
4203 * obj Object to add.
4204 * Return: Node that was added, or NULL if object not added.
4206 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4209 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4210 GtkCMCTreeNode *added;
4211 AddressObject *pobj;
4212 AddressObjectType otype;
4213 AddressTypeControlItem *atci = NULL;
4215 cm_return_val_if_fail(node != NULL, NULL);
4216 cm_return_val_if_fail(obj != NULL, NULL);
4218 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4219 cm_return_val_if_fail(pobj != NULL, NULL);
4221 /* Determine object type to be displayed */
4222 if( obj->type == ADDR_DATASOURCE ) {
4223 otype = ADAPTER_DSOURCE(obj)->subType;
4229 /* Handle any special conditions. */
4231 atci = addrbookctl_lookup( otype );
4233 if( atci->showInTree ) {
4234 /* Add object to tree */
4237 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4238 atci->iconXpm, atci->iconXpmOpen,
4239 atci->treeLeaf, atci->treeExpand );
4240 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4241 addressbook_free_treenode );
4245 gtk_sctree_sort_node(ctree, node);
4251 * Add group into the address index tree.
4252 * \param node Parent node.
4253 * \param ds Data source.
4254 * \param itemGroup Group to add.
4255 * \return Inserted node.
4257 static GtkCMCTreeNode *addressbook_node_add_group(
4258 GtkCMCTreeNode *node, AddressDataSource *ds,
4259 ItemGroup *itemGroup )
4261 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4262 GtkCMCTreeNode *newNode;
4263 AdapterGroup *adapter;
4264 AddressTypeControlItem *atci = NULL;
4267 if( ds == NULL ) return NULL;
4268 if( node == NULL || itemGroup == NULL ) return NULL;
4270 name = &itemGroup->obj.name;
4272 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4274 adapter = g_new0( AdapterGroup, 1 );
4275 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4276 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4277 adapter->itemGroup = itemGroup;
4279 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4280 atci->iconXpm, atci->iconXpm,
4281 atci->treeLeaf, atci->treeExpand );
4282 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4283 addressbook_free_treenode );
4284 gtk_sctree_sort_node( ctree, node );
4289 * Add folder into the address index tree. Only visible folders are loaded into
4290 * the address index tree. Note that the root folder is not inserted into the
4293 * \param node Parent node.
4294 * \param ds Data source.
4295 * \param itemFolder Folder to add.
4296 * \param otype Object type to display.
4297 * \return Inserted node for the folder.
4299 static GtkCMCTreeNode *addressbook_node_add_folder(
4300 GtkCMCTreeNode *node, AddressDataSource *ds,
4301 ItemFolder *itemFolder, AddressObjectType otype )
4303 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4304 GtkCMCTreeNode *newNode = NULL;
4305 AdapterFolder *adapter;
4306 AddressTypeControlItem *atci = NULL;
4307 GList *listItems = NULL;
4309 ItemFolder *rootFolder;
4311 /* Only visible folders */
4312 if( itemFolder == NULL || itemFolder->isHidden )
4317 if( node == NULL || itemFolder == NULL )
4320 /* Determine object type */
4321 atci = addrbookctl_lookup( otype );
4325 rootFolder = addrindex_ds_get_root_folder( ds );
4326 if( itemFolder == rootFolder ) {
4330 adapter = g_new0( AdapterFolder, 1 );
4331 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4332 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4333 adapter->itemFolder = itemFolder;
4335 name = ADDRITEM_NAME(itemFolder);
4336 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4337 atci->iconXpm, atci->iconXpm,
4338 atci->treeLeaf, atci->treeExpand );
4340 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4341 addressbook_free_treenode );
4345 listItems = itemFolder->listFolder;
4346 while( listItems ) {
4347 ItemFolder *item = listItems->data;
4348 addressbook_node_add_folder( newNode, ds, item, otype );
4349 listItems = g_list_next( listItems );
4351 listItems = itemFolder->listGroup;
4352 while( listItems ) {
4353 ItemGroup *item = listItems->data;
4354 addressbook_node_add_group( newNode, ds, item );
4355 listItems = g_list_next( listItems );
4357 gtk_sctree_sort_node( ctree, node );
4361 void addressbook_export_to_file( void ) {
4362 if( _addressIndex_ ) {
4363 /* Save all new address book data */
4364 debug_print( "Saving address books...\n" );
4365 addrindex_save_all_books( _addressIndex_ );
4367 debug_print( "Exporting addressbook to file...\n" );
4368 addrindex_save_data( _addressIndex_ );
4369 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4370 addrindex_print_index( _addressIndex_, stdout );
4373 /* Notify address completion of new data */
4374 invalidate_address_completion();
4378 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4380 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4381 addressbook_lup_clicked(NULL, NULL);
4386 * Comparison using cell contents (text in first column). Used for sort
4387 * address index widget.
4389 static gint addressbook_treenode_compare_func(
4390 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4392 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4393 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4394 gchar *name1 = NULL, *name2 = NULL;
4395 if( cell1 ) name1 = cell1->u.text;
4396 if( cell2 ) name2 = cell2->u.text;
4397 if( ! name1 ) return ( name2 != NULL );
4398 if( ! name2 ) return -1;
4399 return g_utf8_collate( name1, name2 );
4402 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4403 AdapterDSource *ads;
4404 AdapterInterface *adapter;
4405 GtkCMCTreeNode *newNode;
4407 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4408 if( adapter == NULL ) return;
4409 ads = addressbook_edit_book( _addressIndex_, NULL );
4411 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4413 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4414 addrbook.treeSelected = newNode;
4419 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4420 AdapterDSource *ads;
4421 AdapterInterface *adapter;
4422 GtkCMCTreeNode *newNode;
4424 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4425 if( adapter == NULL ) return;
4426 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4428 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4430 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4431 addrbook.treeSelected = newNode;
4437 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4438 AdapterDSource *ads;
4439 AdapterInterface *adapter;
4440 AddressInterface *iface;
4441 GtkCMCTreeNode *newNode;
4443 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4444 if( adapter == NULL ) return;
4445 iface = adapter->interface;
4446 if( ! iface->haveLibrary ) return;
4447 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4449 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4451 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4452 addrbook.treeSelected = newNode;
4459 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4460 AdapterDSource *ads;
4461 AdapterInterface *adapter;
4462 AddressInterface *iface;
4463 GtkCMCTreeNode *newNode;
4465 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4466 if( adapter == NULL ) return;
4467 iface = adapter->interface;
4468 if( ! iface->haveLibrary ) return;
4469 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4471 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4473 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4474 addrbook.treeSelected = newNode;
4481 * Display address search status message.
4482 * \param queryType Query type.
4483 * \param status Status/Error code.
4485 static void addressbook_search_message( gint queryType, gint sts ) {
4487 *addressbook_msgbuf = '\0';
4489 if( sts != MGU_SUCCESS ) {
4490 if( queryType == ADDRQUERY_LDAP ) {
4492 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4497 g_snprintf( addressbook_msgbuf,
4498 sizeof(addressbook_msgbuf), "%s", desc );
4499 addressbook_status_show( addressbook_msgbuf );
4502 addressbook_status_show( "" );
4507 * Refresh addressbook by forcing refresh of current selected object in
4510 static void addressbook_refresh_current( void ) {
4514 ctree = GTK_CMCTREE(addrbook.ctree);
4515 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4516 if( obj == NULL ) return;
4517 addressbook_set_clist( obj, TRUE );
4521 * Message that is displayed whilst a query is executing in a background
4524 static gchar *_tempMessage_ = N_( "Busy searching..." );
4527 * Address search idle function. This function is called during UI idle time
4528 * while a search is in progress.
4530 * \param data Idler data.
4532 static void addressbook_search_idle( gpointer data ) {
4536 queryID = GPOINTER_TO_INT( data );
4537 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4542 * Search completion callback function. This removes the query from the idle
4545 * \param sender Sender of query.
4546 * \param queryID Query ID of search request.
4547 * \param status Search status.
4548 * \param data Query data.
4550 static void addressbook_search_callback_end(
4551 gpointer sender, gint queryID, gint status, gpointer data )
4555 AddrQueryObject *aqo;
4557 /* Remove idler function */
4558 ptrQID = GINT_TO_POINTER( queryID );
4560 g_idle_remove_by_data( ptrQID );
4563 /* Refresh addressbook contents */
4564 addressbook_refresh_current();
4565 req = qrymgr_find_request( queryID );
4567 aqo = ( AddrQueryObject * ) req->queryList->data;
4568 addressbook_search_message( aqo->queryType, status );
4571 /* Stop the search */
4572 addrindex_stop_search( queryID );
4578 * \param ds Data source to search.
4579 * \param searchTerm String to lookup.
4580 * \param pNode Parent data source node.
4582 static void addressbook_perform_search(
4583 AddressDataSource *ds, gchar *searchTerm,
4584 GtkCMCTreeNode *pNode )
4586 AddrBookBase *adbase;
4587 AddressCache *cache;
4593 AddressObjectType aoType = ADDR_NONE;
4597 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4599 if( ds && ds->type == ADDR_IF_LDAP ) {
4601 aoType = ADDR_LDAP_QUERY;
4607 /* Get reference to address cache */
4608 adbase = ( AddrBookBase * ) ds->rawDataSource;
4609 cache = adbase->addressCache;
4611 /* Create a folder for the search results */
4612 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4613 folder = addressbook_setup_subf(ds, name, pNode);
4616 /* Setup the search */
4617 queryID = addrindex_setup_explicit_search(
4618 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4619 if( queryID == 0 ) return;
4621 /* Set up idler function */
4622 idleID = g_idle_add(
4623 ( GtkFunction ) addressbook_search_idle,
4624 GINT_TO_POINTER( queryID ) );
4626 /* Start search, sit back and wait for something to happen */
4627 addrindex_start_search( queryID );
4629 addressbook_status_show( _tempMessage_ );
4633 * Lookup button handler. Address search is only performed against
4634 * address interfaces for external queries.
4636 * \param button Lookup button widget.
4637 * \param data Data object.
4639 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4642 AddressDataSource *ds;
4643 AddressInterface *iface;
4645 GtkCMCTreeNode *node, *parentNode;
4647 node = addrbook.treeSelected;
4648 if( ! node ) return;
4649 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4651 ctree = GTK_CMCTREE(addrbook.ctree);
4652 obj = gtk_cmctree_node_get_row_data( ctree, node );
4653 if( obj == NULL ) return;
4655 ds = addressbook_find_datasource( node );
4656 if( ds == NULL ) return;
4658 /* We must have a datasource that is an external interface */
4659 iface = ds->interface;
4660 if( ! iface->haveLibrary ) return;
4661 if( ! iface->externalQuery ) return;
4664 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4665 g_strchomp( searchTerm );
4667 if( obj->type == ADDR_ITEM_FOLDER ) {
4668 parentNode = GTK_CMCTREE_ROW(node)->parent;
4673 addressbook_perform_search( ds, searchTerm, parentNode );
4675 gtk_widget_grab_focus( addrbook.entry );
4677 g_free( searchTerm );
4680 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4681 addressbook_close();
4686 * Browse address entry for highlighted entry.
4688 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4690 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4692 AddressDataSource *ds;
4693 AddressInterface *iface;
4697 if(addrbook.listSelected == NULL)
4700 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4704 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4708 iface = ds->interface;
4709 if(!iface || !iface->haveLibrary )
4713 if (obj->type == ADDR_ITEM_EMAIL) {
4714 email = ( ItemEMail * ) obj;
4718 person = (ItemPerson *) ADDRITEM_PARENT(email);
4720 else if (obj->type == ADDR_ITEM_PERSON) {
4721 person = (ItemPerson *) obj;
4728 if( iface && iface->type == ADDR_IF_LDAP ) {
4729 browseldap_entry(ds, person->externalID);
4734 /* **********************************************************************
4735 * Build lookup tables.
4736 * ***********************************************************************
4740 * Remap object types.
4741 * Enter: abType AddressObjectType (used in tree node).
4742 * Return: ItemObjectType (used in address cache data).
4744 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4745 ItemObjectType ioType;
4748 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4749 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4750 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4751 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4752 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4753 default: ioType = ITEMTYPE_NONE; break;
4758 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4759 atci = addrbookctl_lookup(id); \
4761 atci->iconXpm = icon; \
4762 atci->iconXpmOpen = iconopen; \
4764 g_warning("can't get atci %d\n", id); \
4769 * Build table that controls the rendering of object types.
4771 static void addrbookctl_build_icons( GtkWidget *window ) {
4772 AddressTypeControlItem *atci;
4776 g_object_unref(interfacexpm);
4778 g_object_unref(folderxpm);
4780 g_object_unref(folderopenxpm);
4782 g_object_unref(groupxpm);
4784 g_object_unref(vcardxpm);
4786 g_object_unref(bookxpm);
4788 g_object_unref(addressxpm);
4790 g_object_unref(jpilotxpm);
4792 g_object_unref(categoryxpm);
4794 g_object_unref(ldapxpm);
4796 g_object_unref(addrsearchxpm);
4797 stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacexpm );
4798 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4799 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4800 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4801 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4802 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4803 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4804 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4805 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4806 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4807 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4809 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4810 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4811 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4812 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4813 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4814 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4815 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4816 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4817 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4818 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4819 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4824 * Build table that controls the rendering of object types.
4826 static void addrbookctl_build_map( GtkWidget *window ) {
4827 AddressTypeControlItem *atci;
4829 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4830 _addressBookTypeList_ = NULL;
4833 atci = g_new0( AddressTypeControlItem, 1 );
4834 atci->objectType = ADDR_INTERFACE;
4835 atci->interfaceType = ADDR_IF_NONE;
4836 atci->showInTree = TRUE;
4837 atci->treeExpand = TRUE;
4838 atci->treeLeaf = FALSE;
4839 atci->displayName = _( "Interface" );
4840 atci->menuCommand = NULL;
4841 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4842 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4845 atci = g_new0( AddressTypeControlItem, 1 );
4846 atci->objectType = ADDR_BOOK;
4847 atci->interfaceType = ADDR_IF_BOOK;
4848 atci->showInTree = TRUE;
4849 atci->treeExpand = TRUE;
4850 atci->treeLeaf = FALSE;
4851 atci->displayName = _( "Address Book" );
4852 atci->menuCommand = "Menu/Book/NewBook";
4853 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4854 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4857 atci = g_new0( AddressTypeControlItem, 1 );
4858 atci->objectType = ADDR_ITEM_PERSON;
4859 atci->interfaceType = ADDR_IF_NONE;
4860 atci->showInTree = FALSE;
4861 atci->treeExpand = FALSE;
4862 atci->treeLeaf = FALSE;
4863 atci->displayName = _( "Person" );
4864 atci->menuCommand = NULL;
4865 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4866 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4869 atci = g_new0( AddressTypeControlItem, 1 );
4870 atci->objectType = ADDR_ITEM_EMAIL;
4871 atci->interfaceType = ADDR_IF_NONE;
4872 atci->showInTree = FALSE;
4873 atci->treeExpand = FALSE;
4874 atci->treeLeaf = TRUE;
4875 atci->displayName = _( "Email Address" );
4876 atci->menuCommand = NULL;
4877 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4878 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4881 atci = g_new0( AddressTypeControlItem, 1 );
4882 atci->objectType = ADDR_ITEM_GROUP;
4883 atci->interfaceType = ADDR_IF_BOOK;
4884 atci->showInTree = TRUE;
4885 atci->treeExpand = FALSE;
4886 atci->treeLeaf = FALSE;
4887 atci->displayName = _( "Group" );
4888 atci->menuCommand = NULL;
4889 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4890 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4893 atci = g_new0( AddressTypeControlItem, 1 );
4894 atci->objectType = ADDR_ITEM_FOLDER;
4895 atci->interfaceType = ADDR_IF_BOOK;
4896 atci->showInTree = TRUE;
4897 atci->treeExpand = FALSE;
4898 atci->treeLeaf = FALSE;
4899 atci->displayName = _( "Folder" );
4900 atci->menuCommand = NULL;
4901 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4902 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4905 atci = g_new0( AddressTypeControlItem, 1 );
4906 atci->objectType = ADDR_VCARD;
4907 atci->interfaceType = ADDR_IF_VCARD;
4908 atci->showInTree = TRUE;
4909 atci->treeExpand = TRUE;
4910 atci->treeLeaf = TRUE;
4911 atci->displayName = _( "vCard" );
4912 atci->menuCommand = "Menu/Book/NewVCard";
4913 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4914 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4917 atci = g_new0( AddressTypeControlItem, 1 );
4918 atci->objectType = ADDR_JPILOT;
4919 atci->interfaceType = ADDR_IF_JPILOT;
4920 atci->showInTree = TRUE;
4921 atci->treeExpand = TRUE;
4922 atci->treeLeaf = FALSE;
4923 atci->displayName = _( "JPilot" );
4924 atci->menuCommand = "Menu/Book/NewJPilot";
4925 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4926 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4929 atci = g_new0( AddressTypeControlItem, 1 );
4930 atci->objectType = ADDR_CATEGORY;
4931 atci->interfaceType = ADDR_IF_JPILOT;
4932 atci->showInTree = TRUE;
4933 atci->treeExpand = TRUE;
4934 atci->treeLeaf = TRUE;
4935 atci->displayName = _( "JPilot" );
4936 atci->menuCommand = NULL;
4937 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4938 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4941 atci = g_new0( AddressTypeControlItem, 1 );
4942 atci->objectType = ADDR_LDAP;
4943 atci->interfaceType = ADDR_IF_LDAP;
4944 atci->showInTree = TRUE;
4945 atci->treeExpand = TRUE;
4946 atci->treeLeaf = FALSE;
4947 atci->displayName = _( "LDAP servers" );
4948 atci->menuCommand = "Menu/Book/NewLDAPServer";
4949 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4950 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4953 atci = g_new0( AddressTypeControlItem, 1 );
4954 atci->objectType = ADDR_LDAP_QUERY;
4955 atci->interfaceType = ADDR_IF_LDAP;
4956 atci->showInTree = TRUE;
4957 atci->treeExpand = FALSE;
4958 atci->treeLeaf = TRUE;
4959 atci->displayName = _( "LDAP Query" );
4960 atci->menuCommand = NULL;
4961 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4962 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4964 addrbookctl_build_icons(window);
4967 void addressbook_reflect_prefs_pixmap_theme(void)
4969 if (addrbook.window)
4970 addrbookctl_build_icons(addrbook.window);
4974 * Search for specified object type.
4976 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4978 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4982 * Search for specified interface type.
4984 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4985 GList *node = _addressBookTypeList_;
4987 AddressTypeControlItem *atci = node->data;
4988 if( atci->interfaceType == ifType ) return atci;
4989 node = g_list_next( node );
4994 static void addrbookctl_free_address( AddressObject *obj ) {
4995 g_free( obj->name );
4996 obj->type = ADDR_NONE;
5000 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5001 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5002 adapter->interface = NULL;
5003 adapter->interfaceType = ADDR_IF_NONE;
5004 adapter->atci = NULL;
5005 adapter->enabled = FALSE;
5006 adapter->haveLibrary = FALSE;
5007 adapter->treeNode = NULL;
5011 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5012 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5013 adapter->dataSource = NULL;
5014 adapter->subType = ADDR_NONE;
5018 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5019 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5020 adapter->itemFolder = NULL;
5024 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5025 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5026 adapter->itemGroup = NULL;
5031 * Build GUI interface list.
5033 static void addrbookctl_build_iflist( void ) {
5034 AddressTypeControlItem *atci;
5035 AdapterInterface *adapter;
5038 if( _addressIndex_ == NULL ) {
5039 _addressIndex_ = addrindex_create_index();
5040 if( _clipBoard_ == NULL ) {
5041 _clipBoard_ = addrclip_create();
5043 addrclip_set_index( _clipBoard_, _addressIndex_ );
5045 _addressInterfaceList_ = NULL;
5046 list = addrindex_get_interface_list( _addressIndex_ );
5048 AddressInterface *interface = list->data;
5049 atci = addrbookctl_lookup_iface( interface->type );
5051 adapter = g_new0( AdapterInterface, 1 );
5052 adapter->interfaceType = interface->type;
5053 adapter->atci = atci;
5054 adapter->interface = interface;
5055 adapter->treeNode = NULL;
5056 adapter->enabled = TRUE;
5057 adapter->haveLibrary = interface->haveLibrary;
5058 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5059 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5060 _addressInterfaceList_ =
5061 g_list_append( _addressInterfaceList_, adapter );
5063 list = g_list_next( list );
5068 * Find GUI interface type specified interface type.
5069 * \param ifType Interface type.
5070 * \return Interface item, or NULL if not found.
5072 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5073 GList *node = _addressInterfaceList_;
5075 AdapterInterface *adapter = node->data;
5076 if( adapter->interfaceType == ifType ) return adapter;
5077 node = g_list_next( node );
5083 * Build interface list selection.
5085 static void addrbookctl_build_ifselect( void ) {
5086 GList *newList = NULL;
5091 gchar *endptr = NULL;
5093 AdapterInterface *adapter;
5095 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5098 splitStr = g_strsplit( selectStr, ",", -1 );
5099 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5101 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5102 ifType = strtol( splitStr[i], &endptr, 10 );
5105 if( strcmp( endptr, "/n" ) == 0 ) {
5109 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5110 adapter = addrbookctl_find_interface( ifType );
5112 newList = g_list_append( newList, adapter );
5119 /* g_print( "i=%d\n", i ); */
5120 g_strfreev( splitStr );
5121 g_free( selectStr );
5123 /* Replace existing list */
5124 mgu_clear_list( _addressIFaceSelection_ );
5125 g_list_free( _addressIFaceSelection_ );
5126 _addressIFaceSelection_ = newList;
5130 /* ***********************************************************************
5131 * Add sender to address book.
5132 * ***********************************************************************
5136 * This function is used by the Add sender to address book function.
5138 gboolean addressbook_add_contact(
5139 const gchar *name, const gchar *address, const gchar *remarks,
5140 GdkPixbuf *picture )
5142 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5143 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5144 debug_print( "addressbook_add_contact - added\n" );
5145 addressbook_refresh();
5150 /* ***********************************************************************
5151 * Book/folder selection.
5152 * ***********************************************************************
5156 * This function is used by the matcher dialog to select a book/folder.
5158 gchar *addressbook_folder_selection( const gchar *folderpath)
5160 AddressBookFile *book = NULL;
5161 ItemFolder *folder = NULL;
5164 cm_return_val_if_fail( folderpath != NULL, NULL);
5166 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5168 if ( folder != NULL) {
5170 gchar *oldtmp = NULL;
5171 AddrItemObject *obj = NULL;
5173 /* walk thru folder->parent to build the full folder path */
5174 /* TODO: wwp: optimize this */
5176 tmp = g_strdup(obj->uid);
5177 while ( obj->parent ) {
5179 if ( obj->name != NULL ) {
5180 oldtmp = g_strdup(tmp);
5182 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5186 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5189 path = g_strdup_printf("%s", book->fileName);
5191 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5197 /* ***********************************************************************
5198 * Book/folder checking.
5199 * ***********************************************************************
5202 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5204 FolderInfo *fi = g_new0( FolderInfo, 1 );
5206 fi->folder = folder;
5210 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5211 FolderInfo *fiParent, FolderPathMatch *match )
5217 FolderPathMatch *nextmatch = NULL;
5222 list = parentFolder->listFolder;
5224 folder = list->data;
5225 fName = g_strdup( ADDRITEM_NAME(folder) );
5227 /* match folder name, match pointer will be set to NULL if next recursive call
5228 doesn't need to match subfolder name */
5229 if ( match != NULL &&
5230 match->matched == FALSE ) {
5231 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5232 /* folder name matches, prepare next subfolder match */
5233 debug_print("matched folder name '%s'\n", fName);
5235 if ( match->folder_path[match->index] == NULL ) {
5236 /* we've matched all elements */
5237 match->matched = TRUE;
5238 match->folder = folder;
5239 debug_print("book/folder path matched!\n");
5241 /* keep on matching */
5249 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5250 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5252 list = g_list_next( list );
5257 * This function is used by to check if a matcher book/folder path corresponds to an
5258 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5259 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5260 if book AND folder are NULL this means that folderpath was empty or Any.
5261 If folderpath is a simple book name (without folder), book will not be NULL and folder
5262 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5265 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5266 AddressDataSource **book,
5267 ItemFolder **folder )
5269 AddressDataSource *ds;
5270 GList *list, *nodeDS;
5271 ItemFolder *rootFolder;
5272 AddressBookFile *abf;
5274 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5281 if ( folderpath == NULL )
5284 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5287 /* split the folder path we've received, we'll try to match this path, subpath by
5288 subpath against the book/folder structure in order */
5289 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5290 if (!folder_path_match.folder_path)
5293 list = addrindex_get_interface_list( _addressIndex_ );
5294 while ( list && !folder_path_match.matched ) {
5295 AddressInterface *interface = list->data;
5296 if ( interface && interface->type == ADDR_IF_BOOK ) {
5297 nodeDS = interface->listSource;
5298 while ( nodeDS && !folder_path_match.matched ) {
5301 /* Read address book */
5302 if( ! addrindex_ds_get_read_flag( ds ) ) {
5303 addrindex_ds_read_data( ds );
5306 /* Add node for address book */
5307 abf = ds->rawDataSource;
5309 /* match book name */
5310 if ( abf && abf->fileName &&
5311 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5313 debug_print("matched book name '%s'\n", abf->fileName);
5314 folder_path_match.book = ds;
5316 if ( folder_path_match.folder_path[1] == NULL ) {
5317 /* no folder part to match */
5319 folder_path_match.matched = TRUE;
5320 folder_path_match.folder = NULL;
5321 debug_print("book path matched!\n");
5324 /* match folder part */
5326 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5327 rootFolder = addrindex_ds_get_root_folder( ds );
5329 /* prepare for recursive call */
5330 folder_path_match.index = 1;
5331 /* this call will set folder_path_match.matched and folder_path_match.folder */
5332 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5337 nodeDS = g_list_next( nodeDS );
5340 list = g_list_next( list );
5343 g_strfreev( folder_path_match.folder_path );
5346 *book = folder_path_match.book;
5348 *folder = folder_path_match.folder;
5349 return folder_path_match.matched;
5353 /* **********************************************************************
5355 * ***********************************************************************
5361 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5362 AddressDataSource *ds = NULL;
5363 AdapterDSource *ads = NULL;
5364 AddressBookFile *abf = NULL;
5365 AdapterInterface *adapter;
5366 GtkCMCTreeNode *newNode;
5368 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5370 if( adapter->treeNode ) {
5371 abf = addressbook_imp_ldif( _addressIndex_ );
5373 ds = addrindex_index_add_datasource(
5374 _addressIndex_, ADDR_IF_BOOK, abf );
5375 ads = addressbook_create_ds_adapter(
5376 ds, ADDR_BOOK, NULL );
5377 addressbook_ads_set_name(
5378 ads, addrbook_get_name( abf ) );
5379 newNode = addressbook_add_object(
5381 ADDRESS_OBJECT(ads) );
5383 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5385 addrbook.treeSelected = newNode;
5388 /* Notify address completion */
5389 invalidate_address_completion();
5398 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5399 AddressDataSource *ds = NULL;
5400 AdapterDSource *ads = NULL;
5401 AddressBookFile *abf = NULL;
5402 AdapterInterface *adapter;
5403 GtkCMCTreeNode *newNode;
5405 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5407 if( adapter->treeNode ) {
5408 abf = addressbook_imp_mutt( _addressIndex_ );
5410 ds = addrindex_index_add_datasource(
5411 _addressIndex_, ADDR_IF_BOOK, abf );
5412 ads = addressbook_create_ds_adapter(
5413 ds, ADDR_BOOK, NULL );
5414 addressbook_ads_set_name(
5415 ads, addrbook_get_name( abf ) );
5416 newNode = addressbook_add_object(
5418 ADDRESS_OBJECT(ads) );
5420 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5422 addrbook.treeSelected = newNode;
5425 /* Notify address completion */
5426 invalidate_address_completion();
5435 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5436 AddressDataSource *ds = NULL;
5437 AdapterDSource *ads = NULL;
5438 AddressBookFile *abf = NULL;
5439 AdapterInterface *adapter;
5440 GtkCMCTreeNode *newNode;
5442 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5444 if( adapter->treeNode ) {
5445 abf = addressbook_imp_pine( _addressIndex_ );
5447 ds = addrindex_index_add_datasource(
5448 _addressIndex_, ADDR_IF_BOOK, abf );
5449 ads = addressbook_create_ds_adapter(
5450 ds, ADDR_BOOK, NULL );
5451 addressbook_ads_set_name(
5452 ads, addrbook_get_name( abf ) );
5453 newNode = addressbook_add_object(
5455 ADDRESS_OBJECT(ads) );
5457 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5459 addrbook.treeSelected = newNode;
5462 /* Notify address completion */
5463 invalidate_address_completion();
5470 * Harvest addresses.
5471 * \param folderItem Folder to import.
5472 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5473 * \param msgList List of message numbers, or NULL to process folder.
5475 void addressbook_harvest(
5476 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5478 AddressDataSource *ds = NULL;
5479 AdapterDSource *ads = NULL;
5480 AddressBookFile *abf = NULL;
5481 AdapterInterface *adapter;
5482 GtkCMCTreeNode *newNode;
5484 abf = addrgather_dlg_execute(
5485 folderItem, _addressIndex_, sourceInd, msgList );
5487 ds = addrindex_index_add_datasource(
5488 _addressIndex_, ADDR_IF_BOOK, abf );
5490 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5492 if( adapter->treeNode ) {
5493 ads = addressbook_create_ds_adapter(
5494 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5495 newNode = addressbook_add_object(
5497 ADDRESS_OBJECT(ads) );
5501 /* Notify address completion */
5502 invalidate_address_completion();
5509 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5510 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5512 AddressDataSource *ds = NULL;
5513 AddrBookBase *adbase;
5514 AddressCache *cache;
5515 GtkCMCTreeNode *node = NULL;
5517 if( ! addrbook.treeSelected ) return;
5518 node = addrbook.treeSelected;
5519 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5520 obj = gtk_cmctree_node_get_row_data( ctree, node );
5521 if( obj == NULL ) return;
5523 ds = addressbook_find_datasource( node );
5524 if( ds == NULL ) return;
5525 adbase = ( AddrBookBase * ) ds->rawDataSource;
5526 cache = adbase->addressCache;
5527 addressbook_exp_html( cache );
5533 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5534 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5536 AddressDataSource *ds = NULL;
5537 AddrBookBase *adbase;
5538 AddressCache *cache;
5539 GtkCMCTreeNode *node = NULL;
5541 if( ! addrbook.treeSelected ) return;
5542 node = addrbook.treeSelected;
5543 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5544 obj = gtk_cmctree_node_get_row_data( ctree, node );
5545 if( obj == NULL ) return;
5547 ds = addressbook_find_datasource( node );
5548 if( ds == NULL ) return;
5549 adbase = ( AddrBookBase * ) ds->rawDataSource;
5550 cache = adbase->addressCache;
5551 addressbook_exp_ldif( cache );
5554 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5556 addrduplicates_find(GTK_WINDOW(addrbook.window));
5559 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5561 addressbook_custom_attr_edit();
5564 static void addressbook_start_drag(GtkWidget *widget, gint button,
5568 GdkDragContext *context;
5569 if (addressbook_target_list == NULL)
5570 addressbook_target_list = gtk_target_list_new(
5571 addressbook_drag_types, 1);
5572 context = gtk_drag_begin(widget, addressbook_target_list,
5573 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5574 gtk_drag_set_icon_default(context);
5577 static void addressbook_drag_data_get(GtkWidget *widget,
5578 GdkDragContext *drag_context,
5579 GtkSelectionData *selection_data,
5584 AddrItemObject *aio = NULL;
5585 AddressObject *pobj = NULL;
5586 AdapterDSource *ads = NULL;
5587 AddressDataSource *ds = NULL;
5590 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5592 if( pobj == NULL ) return;
5594 if( pobj->type == ADDR_DATASOURCE ) {
5595 ads = ADAPTER_DSOURCE(pobj);
5596 ds = ads->dataSource;
5597 } else if (pobj->type == ADDR_ITEM_GROUP) {
5602 else if( pobj->type != ADDR_INTERFACE ) {
5603 ds = addressbook_find_datasource( addrbook.treeSelected );
5609 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5610 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5611 GTK_CMCTREE_NODE(cur->data));
5612 while (aio && aio->type != ADDR_ITEM_PERSON) {
5617 if (aio && aio->type == ADDR_ITEM_PERSON) {
5618 if( ds && ds->interface && ds->interface->readOnly)
5619 gtk_selection_data_set(selection_data,
5620 selection_data->target, 8,
5621 (const guchar *)"Dummy_addr_copy", 15);
5623 gtk_selection_data_set(selection_data,
5624 selection_data->target, 8,
5625 (const guchar *)"Dummy_addr_move", 15);
5629 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5630 GdkDragContext *context,
5637 GtkCMCTreeNode *node = NULL;
5638 gboolean acceptable = FALSE;
5639 gint height = addrbook.ctree->allocation.height;
5640 gint total_height = addrbook.ctree->requisition.height;
5641 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5642 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5643 gfloat vpos = pos->value;
5645 if (gtk_cmclist_get_selection_info
5646 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5648 if (y > height - 24 && height + vpos < total_height) {
5649 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5650 gtk_adjustment_changed(pos);
5652 if (y < 24 && y > 0) {
5653 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5654 gtk_adjustment_changed(pos);
5656 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5659 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5660 if( obj->type == ADDR_ITEM_FOLDER
5661 || obj->type == ADDR_ITEM_GROUP)
5664 AdapterDSource *ads = NULL;
5665 AddressDataSource *ds = NULL;
5666 ads = ADAPTER_DSOURCE(obj);
5667 if (ads == NULL ){ return FALSE;}
5668 ds = ads->dataSource;
5669 if (ds == NULL ) { return FALSE;}
5677 g_signal_handlers_block_by_func
5679 G_CALLBACK(addressbook_tree_selected), NULL);
5680 gtk_sctree_select( GTK_SCTREE(widget), node);
5681 g_signal_handlers_unblock_by_func
5683 G_CALLBACK(addressbook_tree_selected), NULL);
5684 gdk_drag_status(context,
5685 (context->actions == GDK_ACTION_COPY ?
5686 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5688 gdk_drag_status(context, 0, time);
5693 static void addressbook_drag_leave_cb(GtkWidget *widget,
5694 GdkDragContext *context,
5698 if (addrbook.treeSelected) {
5699 g_signal_handlers_block_by_func
5701 G_CALLBACK(addressbook_tree_selected), NULL);
5702 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5703 g_signal_handlers_unblock_by_func
5705 G_CALLBACK(addressbook_tree_selected), NULL);
5710 static void addressbook_drag_received_cb(GtkWidget *widget,
5711 GdkDragContext *drag_context,
5714 GtkSelectionData *data,
5720 GtkCMCTreeNode *node;
5721 GtkCMCTreeNode *lastopened = addrbook.opened;
5723 if (!strncmp(data->data, "Dummy_addr", 10)) {
5724 if (gtk_cmclist_get_selection_info
5725 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5729 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5730 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5733 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5734 if (drag_context->action == GDK_ACTION_COPY ||
5735 !strcmp(data->data, "Dummy_addr_copy"))
5736 addressbook_clip_copy_cb(NULL, NULL);
5738 addressbook_clip_cut_cb(NULL, NULL);
5739 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5740 addressbook_clip_paste_cb(NULL,NULL);
5741 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5742 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5743 gtk_drag_finish(drag_context, TRUE, TRUE, time);