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 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1017 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1018 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1019 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1020 if (prefs_common.enable_dotted_lines) {
1021 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_DOTTED);
1022 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1023 GTK_CMCTREE_EXPANDER_SQUARE);
1025 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1026 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1027 GTK_CMCTREE_EXPANDER_TRIANGLE);
1029 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1030 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1031 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1032 addressbook_treenode_compare_func);
1034 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1035 G_CALLBACK(addressbook_tree_selected), NULL);
1036 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1037 G_CALLBACK(addressbook_tree_button_pressed),
1039 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1040 G_CALLBACK(addressbook_tree_button_released),
1043 g_signal_connect(G_OBJECT(ctree), "select_row",
1044 G_CALLBACK(addressbook_select_row_tree), NULL);
1046 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1047 addressbook_drag_types, 1,
1048 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1049 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1050 G_CALLBACK(addressbook_drag_motion_cb),
1052 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1053 G_CALLBACK(addressbook_drag_leave_cb),
1055 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1056 G_CALLBACK(addressbook_drag_received_cb),
1058 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1059 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1060 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1061 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1063 clist_vbox = gtk_vbox_new(FALSE, 4);
1065 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1066 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1067 GTK_POLICY_AUTOMATIC,
1068 GTK_POLICY_AUTOMATIC);
1069 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1072 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1073 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1074 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_EXTENDED);
1075 if (prefs_common.enable_dotted_lines) {
1076 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_DOTTED);
1077 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1078 GTK_CMCTREE_EXPANDER_SQUARE);
1080 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1081 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1082 GTK_CMCTREE_EXPANDER_TRIANGLE);
1084 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1085 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1086 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1088 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1090 gtk_widget_set_size_request(clist, -1, 80);
1092 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1093 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1094 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1095 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1096 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1097 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1098 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1099 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1100 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1101 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1102 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1104 for (i = 0; i < N_LIST_COLS; i++)
1105 gtkut_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1108 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1109 G_CALLBACK(addressbook_list_row_selected), NULL);
1110 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1111 G_CALLBACK(addressbook_list_row_unselected), NULL);
1112 g_signal_connect(G_OBJECT(clist), "button_press_event",
1113 G_CALLBACK(addressbook_list_button_pressed),
1115 g_signal_connect(G_OBJECT(clist), "button_release_event",
1116 G_CALLBACK(addressbook_list_button_released),
1118 g_signal_connect(G_OBJECT(clist), "tree_expand",
1119 G_CALLBACK(addressbook_person_expand_node), NULL );
1120 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1121 G_CALLBACK(addressbook_person_collapse_node), NULL );
1122 g_signal_connect(G_OBJECT(clist), "start_drag",
1123 G_CALLBACK(addressbook_start_drag), NULL);
1124 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1125 G_CALLBACK(addressbook_drag_data_get), NULL);
1126 hbox = gtk_hbox_new(FALSE, 4);
1127 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1129 label = gtk_label_new(_("Lookup name:"));
1130 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1132 entry = gtk_entry_new();
1133 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1135 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1137 g_signal_connect(G_OBJECT(entry), "key_press_event",
1138 G_CALLBACK(addressbook_entry_key_pressed),
1141 if (!prefs_common.addressbook_use_editaddress_dialog) {
1142 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1143 vpaned = gtk_vpaned_new();
1144 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1145 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1148 editaddress_vbox = NULL;
1150 hpaned = gtk_hpaned_new();
1151 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1152 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1153 if (prefs_common.addressbook_use_editaddress_dialog)
1154 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1156 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1159 hsbox = gtk_hbox_new(FALSE, 0);
1160 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1161 statusbar = gtk_statusbar_new();
1162 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1165 hbbox = gtk_hbutton_box_new();
1166 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1167 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1168 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1169 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1171 gtkut_stock_button_add_help(hbbox, &help_btn);
1173 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1174 gtkut_widget_set_can_default(edit_btn, TRUE);
1175 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1176 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1177 gtkut_widget_set_can_default(del_btn, TRUE);
1178 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1179 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1180 gtkut_widget_set_can_default(reg_btn, TRUE);
1181 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1184 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1185 gtkut_widget_set_can_default(lup_btn, TRUE);
1186 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1188 g_signal_connect(G_OBJECT(help_btn), "clicked",
1189 G_CALLBACK(manual_open_with_anchor_cb),
1190 MANUAL_ANCHOR_ADDRBOOK);
1192 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1193 G_CALLBACK(addressbook_edit_clicked), NULL);
1194 g_signal_connect(G_OBJECT(del_btn), "clicked",
1195 G_CALLBACK(addressbook_del_clicked), NULL);
1196 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1197 G_CALLBACK(addressbook_reg_clicked), NULL);
1198 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1199 G_CALLBACK(addressbook_lup_clicked), NULL);
1201 to_btn = gtk_button_new_with_label
1202 (prefs_common_translated_header_name("To:"));
1203 gtkut_widget_set_can_default(to_btn, TRUE);
1204 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1205 cc_btn = gtk_button_new_with_label
1206 (prefs_common_translated_header_name("Cc:"));
1207 gtkut_widget_set_can_default(cc_btn, TRUE);
1208 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1209 bcc_btn = gtk_button_new_with_label
1210 (prefs_common_translated_header_name("Bcc:"));
1211 gtkut_widget_set_can_default(bcc_btn, TRUE);
1212 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1214 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1215 gtkut_widget_set_can_default(close_btn, TRUE);
1216 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1218 g_signal_connect(G_OBJECT(to_btn), "clicked",
1219 G_CALLBACK(addressbook_to_clicked),
1220 GINT_TO_POINTER(COMPOSE_TO));
1221 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1222 G_CALLBACK(addressbook_to_clicked),
1223 GINT_TO_POINTER(COMPOSE_CC));
1224 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1225 G_CALLBACK(addressbook_to_clicked),
1226 GINT_TO_POINTER(COMPOSE_BCC));
1227 g_signal_connect(G_OBJECT(close_btn), "clicked",
1228 G_CALLBACK(addressbook_close_clicked), NULL);
1230 /* Build icons for interface */
1232 /* Build control tables */
1233 addrbookctl_build_map(window);
1234 addrbookctl_build_iflist();
1235 addrbookctl_build_ifselect();
1237 addrbook.clist = NULL;
1239 /* Add each interface into the tree as a root level folder */
1240 nodeIf = _addressInterfaceList_;
1242 AdapterInterface *adapter = nodeIf->data;
1243 AddressInterface *iface = adapter->interface;
1244 nodeIf = g_list_next(nodeIf);
1246 if(iface->useInterface) {
1247 AddressTypeControlItem *atci = adapter->atci;
1248 text = atci->displayName;
1250 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1251 NULL, NULL, &text, FOLDER_SPACING,
1255 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1256 gtk_cmctree_node_set_row_data_full(
1257 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1258 addressbook_free_treenode );
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1277 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1278 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1281 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1284 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1285 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1286 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1287 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1288 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1289 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1290 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1291 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1292 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1293 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1295 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1297 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1298 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1300 addrbook.window = window;
1301 addrbook.hpaned = hpaned;
1302 addrbook.vpaned = vpaned;
1303 addrbook.menubar = menubar;
1304 addrbook.ctree = ctree;
1307 addrbook.editaddress_vbox = editaddress_vbox;
1308 addrbook.clist = clist;
1309 addrbook.label = label;
1310 addrbook.entry = entry;
1311 addrbook.statusbar = statusbar;
1312 addrbook.status_cid = gtk_statusbar_get_context_id(
1313 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1315 addrbook.help_btn = help_btn;
1316 addrbook.edit_btn = edit_btn;
1317 addrbook.del_btn = del_btn;
1318 addrbook.reg_btn = reg_btn;
1319 addrbook.lup_btn = lup_btn;
1320 addrbook.to_btn = to_btn;
1321 addrbook.cc_btn = cc_btn;
1322 addrbook.bcc_btn = bcc_btn;
1324 addrbook.tree_popup = tree_popup;
1325 addrbook.list_popup = list_popup;
1326 addrbook.ui_manager = ui_manager;
1328 addrbook.listSelected = NULL;
1330 if (!geometry.min_height) {
1331 geometry.min_width = ADDRESSBOOK_WIDTH;
1332 geometry.min_height = ADDRESSBOOK_HEIGHT;
1335 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1337 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1338 prefs_common.addressbookwin_height);
1340 gtk_window_move(GTK_WINDOW(window), 48, 48);
1343 if (!prefs_common.addressbook_use_editaddress_dialog) {
1344 if (prefs_common.addressbook_vpaned_pos > 0)
1345 gtk_paned_set_position(GTK_PANED(vpaned),
1346 prefs_common.addressbook_vpaned_pos);
1348 if (prefs_common.addressbook_hpaned_pos > 0)
1349 gtk_paned_set_position(GTK_PANED(hpaned),
1350 prefs_common.addressbook_hpaned_pos);
1353 gtk_widget_show_all(window);
1357 * Close address book window and save to file(s).
1359 static gint addressbook_close( void ) {
1360 address_completion_end(addrbook.window);
1361 if (!prefs_common.addressbook_use_editaddress_dialog)
1362 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1364 addressbook_pane_save_position();
1366 gtk_widget_hide(addrbook.window);
1367 addressbook_export_to_file();
1372 * Display message in status line.
1373 * \param msg Message to display.
1375 static void addressbook_status_show( gchar *msg ) {
1376 if( addrbook.statusbar != NULL ) {
1378 GTK_STATUSBAR(addrbook.statusbar),
1379 addrbook.status_cid );
1382 GTK_STATUSBAR(addrbook.statusbar),
1383 addrbook.status_cid, msg );
1388 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1392 *addressbook_msgbuf = '\0';
1394 name = addrindex_ds_get_name( ds );
1395 retVal = addrindex_ds_get_status_code( ds );
1396 if( retVal == MGU_SUCCESS ) {
1397 g_snprintf( addressbook_msgbuf,
1398 sizeof(addressbook_msgbuf), "%s", name );
1401 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1402 g_snprintf( addressbook_msgbuf,
1403 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1406 addressbook_status_show( addressbook_msgbuf );
1409 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1411 addressbook_edit_address_cb(NULL, NULL);
1414 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1416 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1420 * Delete one or more objects from address list.
1422 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1424 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1425 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1426 AddressObject *pobj;
1427 AdapterDSource *ads = NULL;
1428 GtkCMCTreeNode *nodeList;
1431 AddressBookFile *abf = NULL;
1432 AddressDataSource *ds = NULL;
1433 AddressInterface *iface;
1434 AddrItemObject *aio;
1435 AddrSelectItem *item;
1437 gboolean refreshList = FALSE;
1439 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1440 cm_return_if_fail(pobj != NULL);
1442 /* Test whether anything selected for deletion */
1443 nodeList = addrbook.listSelected;
1445 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1446 if( aio == NULL) return;
1447 ds = addressbook_find_datasource( addrbook.treeSelected );
1448 if( ds == NULL ) return;
1450 /* Test for read only */
1451 iface = ds->interface;
1452 if( iface->readOnly ) {
1453 alertpanel( _("Delete address(es)"),
1454 _("This address data is readonly and cannot be deleted."),
1455 GTK_STOCK_CLOSE, NULL, NULL );
1459 /* Test whether Ok to proceed */
1461 if( pobj->type == ADDR_DATASOURCE ) {
1462 ads = ADAPTER_DSOURCE(pobj);
1463 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1465 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1468 else if( pobj->type == ADDR_ITEM_GROUP ) {
1471 if( ! procFlag ) return;
1472 abf = ds->rawDataSource;
1473 if( abf == NULL ) return;
1475 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1476 g_signal_handlers_block_by_func
1477 (G_OBJECT(addrbook.clist),
1478 G_CALLBACK(addressbook_list_row_unselected), NULL);
1480 /* Process deletions */
1481 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1482 GList *groups = NULL, *persons = NULL, *emails = NULL;
1483 gboolean group_delete = TRUE;
1484 /* Items inside folders */
1485 list = addrselect_get_list( _addressSelect_ );
1486 /* Confirm deletion */
1490 node = g_list_next( node );
1491 aio = ( AddrItemObject * ) item->addressItem;
1492 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1493 group_delete = FALSE;
1498 aval = alertpanel( _("Delete group"),
1499 _("Really delete the group(s)?\n"
1500 "The addresses it contains will not be lost."),
1501 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1502 if( aval != G_ALERTALTERNATE ) {
1506 aval = alertpanel( _("Delete address(es)"),
1507 _("Really delete the address(es)?"),
1508 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1509 if( aval != G_ALERTALTERNATE ) {
1514 /* first, set lists of groups and persons to remove */
1518 node = g_list_next( node );
1519 aio = ( AddrItemObject * ) item->addressItem;
1522 if( aio->type == ADDR_ITEM_GROUP ) {
1523 groups = g_list_prepend(groups, item);
1525 else if( aio->type == ADDR_ITEM_PERSON ) {
1526 persons = g_list_prepend(persons, item);
1529 /* then set list of emails to remove *if* they're not children of
1530 * persons to remove */
1534 node = g_list_next( node );
1535 aio = ( AddrItemObject * ) item->addressItem;
1538 if( aio->type == ADDR_ITEM_EMAIL ) {
1539 ItemEMail *sitem = ( ItemEMail * ) aio;
1540 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1541 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1542 emails = g_list_prepend(emails, item);
1544 /* else, the email will be removed via the parent person */
1547 /* then delete groups */
1551 node = g_list_next( node );
1552 aio = ( AddrItemObject * ) item->addressItem;
1555 if( aio->type == ADDR_ITEM_GROUP ) {
1556 ItemGroup *item = ( ItemGroup * ) aio;
1557 GtkCMCTreeNode *nd = NULL;
1558 nd = addressbook_find_group_node( addrbook.opened, item );
1559 item = addrbook_remove_group( abf, item );
1561 addritem_free_item_group( item );
1563 /* Remove group from parent node */
1564 gtk_cmctree_remove_node( ctree, nd );
1568 /* then delete persons */
1572 node = g_list_next( node );
1573 aio = ( AddrItemObject * ) item->addressItem;
1576 if( aio->type == ADDR_ITEM_PERSON ) {
1577 ItemPerson *item = ( ItemPerson * ) aio;
1578 item->status = DELETE_ENTRY;
1579 addressbook_folder_remove_one_person( clist, item );
1580 if (pobj->type == ADDR_ITEM_FOLDER)
1581 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1582 item = addrbook_remove_person( abf, item );
1584 if (ds && ds->type == ADDR_IF_LDAP) {
1585 LdapServer *server = ds->rawDataSource;
1586 ldapsvr_set_modified(server, TRUE);
1587 ldapsvr_update_book(server, item);
1591 gchar *filename = addritem_person_get_picture(item);
1592 if (filename && is_file_exist(filename))
1593 claws_unlink(filename);
1595 addritem_free_item_person( item );
1599 /* then delete emails */
1603 node = g_list_next( node );
1604 aio = ( AddrItemObject * ) item->addressItem;
1608 if( aio->type == ADDR_ITEM_EMAIL ) {
1609 ItemEMail *sitem = ( ItemEMail * ) aio;
1610 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1611 sitem = addrbook_person_remove_email( abf, person, sitem );
1613 addrcache_remove_email(abf->addressCache, sitem);
1614 addritem_free_item_email( sitem );
1616 addressbook_folder_refresh_one_person( clist, person );
1619 g_list_free( groups );
1620 g_list_free( persons );
1621 g_list_free( emails );
1622 g_list_free( list );
1623 addressbook_list_select_clear();
1625 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1626 addressbook_set_clist(
1627 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1631 addrbook_set_dirty(abf, TRUE);
1632 addressbook_export_to_file();
1633 addressbook_list_menu_setup();
1636 else if( pobj->type == ADDR_ITEM_GROUP ) {
1637 /* Items inside groups */
1638 list = addrselect_get_list( _addressSelect_ );
1642 node = g_list_next( node );
1643 aio = ( AddrItemObject * ) item->addressItem;
1644 if( aio->type == ADDR_ITEM_EMAIL ) {
1645 ItemEMail *item = ( ItemEMail * ) aio;
1646 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1647 item = addrbook_person_remove_email( abf, person, item );
1649 addritem_free_item_email( item );
1653 g_list_free( list );
1654 addressbook_list_select_clear();
1655 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1656 addressbook_set_clist(
1657 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1661 addrbook_set_dirty(abf, TRUE);
1662 addressbook_export_to_file();
1663 addressbook_list_menu_setup();
1667 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1668 gtk_cmctree_remove_node( clist, nodeList );
1670 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1671 g_signal_handlers_unblock_by_func
1672 (G_OBJECT(addrbook.clist),
1673 G_CALLBACK(addressbook_list_row_unselected), NULL);
1676 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1678 addressbook_new_address_cb( NULL, NULL );
1681 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1684 gchar *address = NULL;
1686 if( aio->type == ADDR_ITEM_EMAIL ) {
1687 ItemPerson *person = NULL;
1688 ItemEMail *email = ( ItemEMail * ) aio;
1690 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1691 if( email->address ) {
1692 if( ADDRITEM_NAME(email) ) {
1693 name = ADDRITEM_NAME(email);
1694 if( *name == '\0' ) {
1695 name = ADDRITEM_NAME(person);
1698 else if( ADDRITEM_NAME(person) ) {
1699 name = ADDRITEM_NAME(person);
1702 buf = g_strdup( email->address );
1704 address = email->address;
1707 else if( aio->type == ADDR_ITEM_PERSON ) {
1708 ItemPerson *person = ( ItemPerson * ) aio;
1709 GList *node = person->listEMail;
1711 name = ADDRITEM_NAME(person);
1713 ItemEMail *email = ( ItemEMail * ) node->data;
1714 address = email->address;
1718 if( name && name[0] != '\0' ) {
1719 if( strchr_with_skip_quote( name, '"', ',' ) )
1720 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1722 buf = g_strdup_printf( "%s <%s>", name, address );
1725 buf = g_strdup( address );
1732 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1736 AddrSelectItem *item;
1737 AddrItemObject *aio;
1740 compose = addrbook.target_compose;
1741 if( ! compose ) return;
1743 /* Nothing selected, but maybe there is something in text entry */
1744 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1746 compose_entry_append(
1747 compose, addr, (ComposeEntryType)data , PREF_NONE);
1750 /* Select from address list */
1751 list = addrselect_get_list( _addressSelect_ );
1756 node = g_list_next( node );
1757 aio = item->addressItem;
1758 if( aio->type == ADDR_ITEM_PERSON ||
1759 aio->type == ADDR_ITEM_EMAIL ) {
1760 addr = addressbook_format_address( aio );
1761 compose_entry_append(
1762 compose, addr, (ComposeEntryType) data, PREF_NONE );
1765 else if( aio->type == ADDR_ITEM_GROUP ) {
1766 ItemGroup *group = ( ItemGroup * ) aio;
1767 GList *nodeMail = group->listEMail;
1769 ItemEMail *email = nodeMail->data;
1771 addr = addressbook_format_address(
1772 ( AddrItemObject * ) email );
1773 compose_entry_append(
1774 compose, addr, (ComposeEntryType) data, PREF_NONE );
1776 nodeMail = g_list_next( nodeMail );
1781 AddressObject *obj = NULL;
1783 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1785 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1786 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1787 GList *nodeMail = itemGroup->listEMail;
1789 ItemEMail *email = nodeMail->data;
1791 addr = addressbook_format_address(
1792 ( AddrItemObject * ) email );
1793 compose_entry_append(
1794 compose, addr, (ComposeEntryType) data, PREF_NONE );
1796 nodeMail = g_list_next( nodeMail );
1800 g_list_free( list );
1803 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1804 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1805 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1806 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1808 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1809 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1810 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1811 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1813 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1814 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1815 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1816 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1817 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1820 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1821 gboolean canEdit = FALSE;
1822 gboolean canDelete = TRUE;
1823 gboolean canAdd = FALSE;
1824 gboolean canEditTr = TRUE;
1825 gboolean editAddress = FALSE;
1826 gboolean canExport = TRUE;
1827 AddressTypeControlItem *atci = NULL;
1828 AddressDataSource *ds = NULL;
1829 AddressInterface *iface = NULL;
1831 if( obj == NULL ) return;
1832 if( obj->type == ADDR_INTERFACE ) {
1833 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1834 iface = adapter->interface;
1836 if( iface->haveLibrary ) {
1837 /* Enable appropriate File / New command */
1838 atci = adapter->atci;
1839 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1842 canEditTr = canExport = FALSE;
1844 else if( obj->type == ADDR_DATASOURCE ) {
1845 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1846 ds = ads->dataSource;
1847 iface = ds->interface;
1848 if( ! iface->readOnly ) {
1849 canAdd = canEdit = editAddress = canDelete = TRUE;
1851 if( ! iface->haveLibrary ) {
1852 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1855 else if( obj->type == ADDR_ITEM_FOLDER ) {
1856 ds = addressbook_find_datasource( addrbook.treeSelected );
1858 iface = ds->interface;
1859 if( iface->readOnly ) {
1864 canAdd = editAddress = TRUE;
1868 else if( obj->type == ADDR_ITEM_GROUP ) {
1869 ds = addressbook_find_datasource( addrbook.treeSelected );
1871 iface = ds->interface;
1872 if( ! iface->readOnly ) {
1878 if( addrbook.listSelected == NULL )
1882 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1883 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1884 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1885 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1888 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1889 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1890 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1891 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1893 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1894 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1897 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1898 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1902 * Address book tree callback function that responds to selection of tree
1905 * \param ctree Tree widget.
1906 * \param node Node that was selected.
1907 * \param column Column number where selected occurred.
1908 * \param data Pointer to user data.
1910 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1911 gint column, gpointer data)
1913 AddressObject *obj = NULL;
1914 AdapterDSource *ads = NULL;
1915 AddressDataSource *ds = NULL;
1916 ItemFolder *rootFolder = NULL;
1917 AddressObjectType aot;
1919 addrbook.treeSelected = node;
1920 addrbook.listSelected = NULL;
1921 addressbook_status_show( "" );
1922 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1924 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1926 addressbook_set_clist(NULL, TRUE);
1929 addrbook.opened = node;
1931 if( obj->type == ADDR_DATASOURCE ) {
1932 /* Read from file */
1933 static gboolean tVal = TRUE;
1935 ads = ADAPTER_DSOURCE(obj);
1936 if( ads == NULL ) return;
1937 ds = ads->dataSource;
1938 if( ds == NULL ) return;
1940 if( addrindex_ds_get_modify_flag( ds ) ) {
1941 addrindex_ds_read_data( ds );
1944 if( ! addrindex_ds_get_read_flag( ds ) ) {
1945 addrindex_ds_read_data( ds );
1947 addressbook_ds_show_message( ds );
1949 if( ! addrindex_ds_get_access_flag( ds ) ) {
1950 /* Remove existing folders and groups */
1951 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1952 addressbook_tree_remove_children( ctree, node );
1953 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1955 /* Load folders into the tree */
1956 rootFolder = addrindex_ds_get_root_folder( ds );
1957 if( ds && ds->type == ADDR_IF_JPILOT ) {
1958 aot = ADDR_CATEGORY;
1960 else if( ds && ds->type == ADDR_IF_LDAP ) {
1961 aot = ADDR_LDAP_QUERY;
1964 aot = ADDR_ITEM_FOLDER;
1966 addressbook_node_add_folder( node, ds, rootFolder, aot );
1967 addrindex_ds_set_access_flag( ds, &tVal );
1968 gtk_cmctree_expand( ctree, node );
1971 addressbook_set_clist(NULL, TRUE);
1974 /* Update address list */
1975 g_signal_handlers_block_by_func
1977 G_CALLBACK(addressbook_tree_selected), NULL);
1978 addressbook_set_clist( obj, FALSE );
1979 g_signal_handlers_unblock_by_func
1981 G_CALLBACK(addressbook_tree_selected), NULL);
1982 if (!prefs_common.addressbook_use_editaddress_dialog)
1983 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1985 /* Setup main menu selections */
1986 addressbook_menubar_set_sensitive( FALSE );
1987 addressbook_menuitem_set_sensitive( obj, node );
1988 addressbook_list_select_clear();
1989 addressbook_list_menu_setup();
1994 * Setup address list popup menu items. Items are enabled or disabled as
1997 static void addressbook_list_menu_setup( void ) {
1998 GtkCMCTree *clist = NULL;
1999 AddressObject *pobj = NULL;
2000 AddressObject *obj = NULL;
2001 AdapterDSource *ads = NULL;
2002 AddressInterface *iface = NULL;
2003 AddressDataSource *ds = NULL;
2004 gboolean canEdit = FALSE;
2005 gboolean canDelete = FALSE;
2006 gboolean canCut = FALSE;
2007 gboolean canCopy = FALSE;
2008 gboolean canPaste = FALSE;
2009 gboolean canBrowse = FALSE;
2011 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2012 if( pobj == NULL ) return;
2014 clist = GTK_CMCTREE(addrbook.clist);
2015 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2016 if( obj == NULL ) canEdit = FALSE;
2018 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2019 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2021 if( pobj->type == ADDR_DATASOURCE ) {
2022 /* Parent object is a data source */
2023 ads = ADAPTER_DSOURCE(pobj);
2024 ds = ads->dataSource;
2027 iface = ds->interface;
2030 if( ! iface->readOnly ) {
2031 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2032 if (iface->type != ADDR_IF_LDAP)
2033 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2034 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2037 canDelete = canEdit;
2040 else if( pobj->type != ADDR_INTERFACE ) {
2041 /* Parent object is not an interface */
2042 ds = addressbook_find_datasource( addrbook.treeSelected );
2045 iface = ds->interface;
2048 if( ! iface->readOnly ) {
2049 /* Folder or group */
2050 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2051 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2052 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2053 if( obj ) canEdit = TRUE;
2056 if( pobj->type == ADDR_ITEM_FOLDER ) {
2057 if (iface->type != ADDR_IF_LDAP)
2058 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2059 if( obj ) canEdit = TRUE;
2061 canDelete = canEdit;
2063 if( iface->type == ADDR_IF_LDAP ) {
2064 if( obj ) canBrowse = TRUE;
2071 /* Enable cut and paste */
2072 if( ! addrclip_is_empty( _clipBoard_ ) )
2074 if( ! addrselect_test_empty( _addressSelect_ ) )
2076 /* Enable copy if something is selected */
2077 if( ! addrselect_test_empty( _addressSelect_ ) )
2081 /* Disable edit or browse if more than one row selected */
2082 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2087 /* Forbid write changes when read-only */
2088 if( iface && iface->readOnly ) {
2094 /* Now go finalize menu items */
2095 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2096 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2098 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2099 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2104 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2105 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2106 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2108 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2109 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2110 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2112 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2113 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2115 if (addrbook.target_compose) {
2116 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2117 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2118 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2121 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2125 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2126 GtkCMCTreeNode *node,
2133 * Add list of items into tree node below specified tree node.
2134 * \param treeNode Tree node.
2135 * \param ds Data source.
2136 * \param listItems List of items.
2138 static void addressbook_treenode_add_list(
2139 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2145 AddrItemObject *aio;
2149 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2152 group = ( ItemGroup * ) aio;
2153 nn = addressbook_node_add_group( treeNode, ds, group );
2155 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2158 folder = ( ItemFolder * ) aio;
2159 nn = addressbook_node_add_folder(
2160 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2162 node = g_list_next( node );
2166 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2167 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2171 * Cut from address list widget.
2173 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2174 _clipBoard_->cutFlag = TRUE;
2175 addrclip_clear( _clipBoard_ );
2176 addrclip_add( _clipBoard_, _addressSelect_ );
2177 /* addrclip_list_show( _clipBoard_, stdout ); */
2181 * Copy from address list widget.
2183 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2184 _clipBoard_->cutFlag = FALSE;
2185 addrclip_clear( _clipBoard_ );
2186 addrclip_add( _clipBoard_, _addressSelect_ );
2187 /* addrclip_list_show( _clipBoard_, stdout ); */
2191 * Paste clipboard into address list widget.
2193 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2194 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2195 AddressObject *pobj = NULL;
2196 AddressDataSource *ds = NULL;
2197 AddressBookFile *abf = NULL;
2198 ItemFolder *folder = NULL;
2199 GList *folderGroup = NULL;
2201 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2202 if( ds == NULL ) return;
2203 if( addrindex_ds_get_readonly( ds ) ) {
2204 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2208 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2210 if( pobj->type == ADDR_ITEM_FOLDER ) {
2211 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2213 else if( pobj->type == ADDR_ITEM_GROUP ) {
2214 alertpanel_error( _("Cannot paste into an address group.") );
2219 /* Get an address book */
2220 abf = addressbook_get_book_file();
2221 if( abf == NULL ) return;
2223 if( _clipBoard_->cutFlag ) {
2225 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2227 /* Remove all groups and folders in clipboard from tree node */
2228 addressbook_treenode_remove_item();
2230 /* Remove all "cut" items */
2231 addrclip_delete_item( _clipBoard_ );
2233 /* Clear clipboard - cut items??? */
2234 addrclip_clear( _clipBoard_ );
2238 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2241 /* addrclip_list_show( _clipBoard_, stdout ); */
2243 /* Update tree by inserting node for each folder or group */
2244 addressbook_treenode_add_list(
2245 addrbook.treeSelected, ds, folderGroup );
2246 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2247 g_list_free( folderGroup );
2251 /* Display items pasted */
2252 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2253 addressbook_set_clist(
2254 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2262 * Add current treenode object to clipboard. Note that widget only allows
2263 * one entry from the tree list to be selected.
2265 static void addressbook_treenode_to_clipboard( void ) {
2266 AddressObject *obj = NULL;
2267 AddressDataSource *ds = NULL;
2268 AddrSelectItem *item;
2269 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2270 GtkCMCTreeNode *node;
2272 node = addrbook.treeSelected;
2273 if( node == NULL ) return;
2274 obj = gtk_cmctree_node_get_row_data( ctree, node );
2275 if( obj == NULL ) return;
2277 ds = addressbook_find_datasource( node );
2278 if( ds == NULL ) return;
2281 if( obj->type == ADDR_ITEM_FOLDER ) {
2282 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2283 ItemFolder *folder = adapter->itemFolder;
2285 item = addrselect_create_node( obj );
2286 item->uid = g_strdup( ADDRITEM_ID(folder) );
2288 else if( obj->type == ADDR_ITEM_GROUP ) {
2289 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2290 ItemGroup *group = adapter->itemGroup;
2292 item = addrselect_create_node( obj );
2293 item->uid = g_strdup( ADDRITEM_ID(group) );
2295 else if( obj->type == ADDR_DATASOURCE ) {
2297 item = addrselect_create_node( obj );
2302 /* Clear existing list and add item into list */
2305 addressbook_list_select_clear();
2306 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2307 addrselect_list_add( _addressSelect_, item, cacheID );
2313 * Cut from tree widget.
2315 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2316 _clipBoard_->cutFlag = TRUE;
2317 addressbook_treenode_to_clipboard();
2318 addrclip_clear( _clipBoard_ );
2319 addrclip_add( _clipBoard_, _addressSelect_ );
2320 /* addrclip_list_show( _clipBoard_, stdout ); */
2324 * Copy from tree widget.
2326 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2327 _clipBoard_->cutFlag = FALSE;
2328 addressbook_treenode_to_clipboard();
2329 addrclip_clear( _clipBoard_ );
2330 addrclip_add( _clipBoard_, _addressSelect_ );
2331 /* addrclip_list_show( _clipBoard_, stdout ); */
2335 * Paste clipboard into address tree widget.
2337 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2338 addressbook_clip_paste_cb(NULL,NULL);
2342 * Clear selected entries in clipboard.
2344 static void addressbook_list_select_clear( void ) {
2345 addrselect_list_clear( _addressSelect_ );
2349 * Add specified address item to selected address list.
2350 * \param aio Address item object.
2351 * \param ds Datasource.
2353 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2356 if( ds == NULL ) return;
2357 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2358 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2363 * Remove specified address item from selected address list.
2364 * \param aio Address item object.
2366 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2367 addrselect_list_remove( _addressSelect_, aio );
2371 * Invoke EMail compose window with addresses in selected address list.
2373 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2376 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2377 listAddress = addrselect_build_list( _addressSelect_ );
2378 compose_new_with_list( NULL, listAddress );
2379 mgu_free_dlist( listAddress );
2384 static void addressbook_list_row_selected( GtkCMCTree *clist,
2385 GtkCMCTreeNode *node,
2389 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2390 AddrItemObject *aio = NULL;
2391 AddressObject *pobj = NULL;
2392 AdapterDSource *ads = NULL;
2393 AddressDataSource *ds = NULL;
2395 gtk_entry_set_text( entry, "" );
2396 addrbook.listSelected = node;
2398 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2399 if( pobj == NULL ) return;
2401 if( pobj->type == ADDR_DATASOURCE ) {
2402 ads = ADAPTER_DSOURCE(pobj);
2403 ds = ads->dataSource;
2405 else if( pobj->type != ADDR_INTERFACE ) {
2406 ds = addressbook_find_datasource( addrbook.treeSelected );
2409 aio = gtk_cmctree_node_get_row_data( clist, node );
2411 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2412 addressbook_list_select_add( aio, ds );
2415 addressbook_list_menu_setup();
2417 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2418 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2420 if (obj && obj->type != ADDR_ITEM_GROUP)
2421 addressbook_edit_address(NULL, 0, NULL, FALSE);
2425 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2426 GtkCMCTreeNode *node,
2430 AddrItemObject *aio;
2432 aio = gtk_cmctree_node_get_row_data( ctree, node );
2434 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2435 addressbook_list_select_remove( aio );
2438 if (!prefs_common.addressbook_use_editaddress_dialog)
2439 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2442 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2443 GdkEventButton *event,
2446 if( ! event ) return FALSE;
2448 addressbook_list_menu_setup();
2450 if( event->button == 3 ) {
2451 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2452 event->button, event->time );
2453 } else if (event->button == 1) {
2454 if (event->type == GDK_2BUTTON_PRESS) {
2455 if (prefs_common.add_address_by_click &&
2456 addrbook.target_compose)
2457 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2459 if (prefs_common.addressbook_use_editaddress_dialog)
2460 addressbook_edit_address_cb(NULL, NULL);
2462 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2463 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2464 if( obj && obj->type == ADDR_ITEM_GROUP )
2465 addressbook_edit_address_cb(NULL, NULL);
2473 static gboolean addressbook_list_button_released(GtkWidget *widget,
2474 GdkEventButton *event,
2480 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2481 GdkEventButton *event,
2484 GtkCMCList *clist = GTK_CMCLIST(ctree);
2486 AddressObject *obj = NULL;
2487 AdapterDSource *ads = NULL;
2488 AddressInterface *iface = NULL;
2489 AddressDataSource *ds = NULL;
2490 gboolean canEdit = FALSE;
2491 gboolean canDelete = FALSE;
2492 gboolean canCut = FALSE;
2493 gboolean canCopy = FALSE;
2494 gboolean canPaste = FALSE;
2495 gboolean canTreeCut = FALSE;
2496 gboolean canTreeCopy = FALSE;
2497 gboolean canTreePaste = FALSE;
2498 gboolean canLookup = FALSE;
2499 GtkCMCTreeNode *node = NULL;
2501 if( ! event ) return FALSE;
2502 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2504 if (event->button == 1) {
2505 if (event->type == GDK_2BUTTON_PRESS) {
2506 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2507 gtkut_clist_set_focus_row(clist, row);
2508 obj = gtk_cmclist_get_row_data( clist, row );
2513 if (obj->type == ADDR_ITEM_GROUP) {
2515 addressbook_treenode_edit_cb(NULL, NULL);
2517 /* expand pr collapse */
2518 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2519 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2525 addressbook_menubar_set_sensitive( FALSE );
2527 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2528 gtkut_clist_set_focus_row(clist, row);
2529 obj = gtk_cmclist_get_row_data( clist, row );
2532 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2536 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2538 if( ! addrclip_is_empty( _clipBoard_ ) )
2539 canTreePaste = TRUE;
2541 if (obj->type == ADDR_INTERFACE) {
2542 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2543 iface = adapter->interface;
2546 if( !iface->readOnly ) {
2547 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2548 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2550 if( iface->externalQuery )
2553 if (obj->type == ADDR_DATASOURCE) {
2554 ads = ADAPTER_DSOURCE(obj);
2555 ds = ads->dataSource;
2558 iface = ds->interface;
2561 if( !iface->readOnly ) {
2563 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2564 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2565 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2569 if( iface->externalQuery )
2572 else if (obj->type == ADDR_ITEM_FOLDER) {
2573 ds = addressbook_find_datasource( node );
2576 iface = ds->interface;
2579 if( !iface->readOnly ) {
2583 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2584 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2585 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2589 if( iface->externalQuery ) {
2590 /* Enable deletion of LDAP folder */
2595 else if (obj->type == ADDR_ITEM_GROUP) {
2596 ds = addressbook_find_datasource( node );
2599 iface = ds->interface;
2602 if( ! iface->readOnly ) {
2605 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2606 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2610 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2612 if( ! addrselect_test_empty( _addressSelect_ ) )
2614 if( ! addrclip_is_empty( _clipBoard_ ) )
2617 /* Forbid write changes when read-only */
2618 if( iface && iface->readOnly ) {
2620 canTreePaste = FALSE;
2628 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2629 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2630 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2631 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2632 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2634 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2635 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2636 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2637 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2638 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2640 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2641 addrbook.target_compose != NULL);
2643 if( event->button == 3 )
2644 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2645 event->button, event->time);
2650 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2651 GdkEventButton *event,
2654 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2658 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2660 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2661 AddressObject *obj = NULL;
2662 AddressDataSource *ds = NULL;
2663 AddressBookFile *abf = NULL;
2664 ItemFolder *parentFolder = NULL;
2665 ItemFolder *folder = NULL;
2667 if( ! addrbook.treeSelected ) return;
2668 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2669 if( obj == NULL ) return;
2670 ds = addressbook_find_datasource( addrbook.treeSelected );
2671 if( ds == NULL ) return;
2673 if( obj->type == ADDR_DATASOURCE ) {
2674 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2676 else if( obj->type == ADDR_ITEM_FOLDER ) {
2677 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2683 abf = ds->rawDataSource;
2684 if( abf == NULL ) return;
2685 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2688 nn = addressbook_node_add_folder(
2689 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2690 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2691 if( addrbook.treeSelected == addrbook.opened )
2692 addressbook_set_clist(obj, TRUE);
2696 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2698 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2699 AddressObject *obj = NULL;
2700 AddressDataSource *ds = NULL;
2701 AddressBookFile *abf = NULL;
2702 ItemFolder *parentFolder = NULL;
2703 ItemGroup *group = NULL;
2705 if( ! addrbook.treeSelected ) return;
2706 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2707 if( obj == NULL ) return;
2708 ds = addressbook_find_datasource( addrbook.treeSelected );
2709 if( ds == NULL ) return;
2711 if( obj->type == ADDR_DATASOURCE ) {
2712 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2714 else if( obj->type == ADDR_ITEM_FOLDER ) {
2715 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2721 abf = ds->rawDataSource;
2722 if( abf == NULL ) return;
2723 group = addressbook_edit_group( abf, parentFolder, NULL );
2726 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2727 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2728 if( addrbook.treeSelected == addrbook.opened )
2729 addressbook_set_clist(obj, TRUE);
2733 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2735 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2738 GdkPixbuf *pix_cl, *pix_op;
2739 gboolean is_leaf, expanded;
2741 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2743 &is_leaf, &expanded);
2744 gtk_sctree_set_node_info(ctree, node, name, spacing,
2751 * \param obj Address object to edit.
2752 * \param node Node in tree.
2753 * \return New name of data source.
2755 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2756 gchar *newName = NULL;
2757 AddressDataSource *ds = NULL;
2758 AddressInterface *iface = NULL;
2759 AdapterDSource *ads = NULL;
2761 ds = addressbook_find_datasource( node );
2762 if( ds == NULL ) return NULL;
2763 iface = ds->interface;
2764 if( ! iface->haveLibrary ) return NULL;
2766 /* Read data from data source */
2767 if( addrindex_ds_get_modify_flag( ds ) ) {
2768 addrindex_ds_read_data( ds );
2771 if( ! addrindex_ds_get_read_flag( ds ) ) {
2772 addrindex_ds_read_data( ds );
2776 ads = ADAPTER_DSOURCE(obj);
2777 if( ads->subType == ADDR_BOOK ) {
2778 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2780 else if( ads->subType == ADDR_VCARD ) {
2781 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2784 else if( ads->subType == ADDR_JPILOT ) {
2785 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2789 else if( ads->subType == ADDR_LDAP ) {
2790 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2796 newName = obj->name;
2801 * Edit an object that is in the address tree area.
2803 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2805 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2807 AddressDataSource *ds = NULL;
2808 AddressBookFile *abf = NULL;
2809 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2812 if( ! addrbook.treeSelected ) return;
2813 node = addrbook.treeSelected;
2814 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2815 obj = gtk_cmctree_node_get_row_data( ctree, node );
2816 if( obj == NULL ) return;
2817 parentNode = GTK_CMCTREE_ROW(node)->parent;
2819 ds = addressbook_find_datasource( node );
2820 if( ds == NULL ) return;
2822 if( obj->type == ADDR_DATASOURCE ) {
2823 name = addressbook_edit_datasource( obj, node );
2824 if( name == NULL ) return;
2827 abf = ds->rawDataSource;
2828 if( abf == NULL ) return;
2829 if( obj->type == ADDR_ITEM_FOLDER ) {
2830 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2831 ItemFolder *item = adapter->itemFolder;
2832 ItemFolder *parentFolder = NULL;
2833 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2834 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2835 name = ADDRITEM_NAME(item);
2837 else if( obj->type == ADDR_ITEM_GROUP ) {
2838 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2839 ItemGroup *item = adapter->itemGroup;
2840 ItemFolder *parentFolder = NULL;
2841 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2842 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2843 name = ADDRITEM_NAME(item);
2846 if( name && parentNode ) {
2847 /* Update node in tree view */
2848 addressbook_change_node_name( node, name );
2849 gtk_sctree_sort_node(ctree, parentNode);
2850 gtk_cmctree_expand( ctree, node );
2851 gtk_sctree_select( GTK_SCTREE( ctree), node );
2858 ADDRTREE_DEL_FOLDER_ONLY,
2859 ADDRTREE_DEL_FOLDER_ADDR
2863 * Delete an item from the tree widget.
2864 * \param data Data passed in.
2865 * \param action Action.
2866 * \param widget Widget issuing callback.
2868 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2870 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2871 GtkCMCTreeNode *node = NULL;
2875 AddrBookBase *adbase;
2876 AddressCache *cache;
2877 AdapterDSource *ads = NULL;
2878 AddressInterface *iface = NULL;
2879 AddressDataSource *ds = NULL;
2880 gboolean remFlag = FALSE;
2881 TreeItemDelType delType;
2883 if( ! addrbook.treeSelected ) return;
2884 node = addrbook.treeSelected;
2885 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2887 obj = gtk_cmctree_node_get_row_data( ctree, node );
2888 cm_return_if_fail(obj != NULL);
2890 if( obj->type == ADDR_DATASOURCE ) {
2891 ads = ADAPTER_DSOURCE(obj);
2892 if( ads == NULL ) return;
2893 ds = ads->dataSource;
2894 if( ds == NULL ) return;
2897 /* Must be folder or something else */
2898 ds = addressbook_find_datasource( node );
2899 if( ds == NULL ) return;
2901 /* Only allow deletion from non-readOnly */
2902 iface = ds->interface;
2903 if( iface->readOnly ) {
2904 /* Allow deletion of query results */
2905 if( ! iface->externalQuery ) return;
2909 /* Confirm deletion */
2910 delType = ADDRTREE_DEL_NONE;
2911 if( obj->type == ADDR_ITEM_FOLDER ) {
2912 if( iface->externalQuery ) {
2913 message = g_strdup_printf( _(
2914 "Do you want to delete the query " \
2915 "results and addresses in '%s' ?" ),
2917 aval = alertpanel( _("Delete"), message,
2918 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2920 if( aval == G_ALERTALTERNATE ) {
2921 delType = ADDRTREE_DEL_FOLDER_ADDR;
2925 message = g_strdup_printf
2926 ( _( "Do you want to delete '%s' ? "
2927 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2929 aval = alertpanel( _("Delete folder"), message,
2930 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2932 if( aval == G_ALERTALTERNATE ) {
2933 delType = ADDRTREE_DEL_FOLDER_ONLY;
2935 else if( aval == G_ALERTOTHER ) {
2936 delType = ADDRTREE_DEL_FOLDER_ADDR;
2940 else if( obj->type == ADDR_ITEM_GROUP ) {
2941 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2942 "The addresses it contains will not be lost."), obj->name);
2943 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2944 "+" GTK_STOCK_DELETE, NULL);
2946 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2948 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2949 "The addresses it contains will be lost."), obj->name);
2950 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2951 "+" GTK_STOCK_DELETE, NULL);
2953 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2955 if( delType == ADDRTREE_DEL_NONE ) return;
2957 /* Proceed with deletion */
2958 if( obj->type == ADDR_DATASOURCE ) {
2959 /* Remove node from tree */
2960 gtk_cmctree_remove_node( ctree, node );
2962 /* Remove data source. */
2963 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2964 addrindex_free_datasource( ds );
2969 /* Get reference to cache */
2970 adbase = ( AddrBookBase * ) ds->rawDataSource;
2971 if( adbase == NULL ) return;
2972 cache = adbase->addressCache;
2974 /* Remove query results folder */
2975 if( iface->externalQuery ) {
2976 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2977 ItemFolder *folder = adapter->itemFolder;
2979 adapter->itemFolder = NULL;
2981 g_print( "remove folder for ::%s::\n", obj->name );
2982 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2983 g_print( "-------------- remove results\n" );
2985 addrindex_remove_results( ds, folder );
2986 /* g_print( "-------------- remove node\n" ); */
2987 gtk_cmctree_remove_node( ctree, node );
2991 /* Code below is valid for regular address book deletion */
2992 if( obj->type == ADDR_ITEM_FOLDER ) {
2993 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2994 ItemFolder *item = adapter->itemFolder;
2996 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2997 /* Remove folder only */
2998 item = addrcache_remove_folder( cache, item );
3000 addritem_free_item_folder( item );
3001 addressbook_move_nodes_up( ctree, node );
3005 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3006 /* Remove folder and addresses */
3007 item = addrcache_remove_folder_delete( cache, item );
3009 addritem_free_item_folder( item );
3014 else if( obj->type == ADDR_ITEM_GROUP ) {
3015 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3016 ItemGroup *item = adapter->itemGroup;
3018 item = addrcache_remove_group( cache, item );
3020 addritem_free_item_group( item );
3027 gtk_cmctree_remove_node(ctree, node );
3031 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3033 if( person && addrbook.treeSelected == addrbook.opened ) {
3034 person->status = ADD_ENTRY;
3035 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3036 addressbook_folder_refresh_one_person(
3037 GTK_CMCTREE(addrbook.clist), person );
3039 addressbook_address_list_set_focus();
3042 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3044 if( person && addrbook.treeSelected == addrbook.opened) {
3045 person->status = ADD_ENTRY;
3046 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3047 addressbook_set_clist(
3048 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3052 addressbook_address_list_set_focus();
3056 * Label (a format string) that is used to name each folder.
3058 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3061 * Search ctree widget callback function.
3062 * \param pA Pointer to node.
3063 * \param pB Pointer to data item being sought.
3064 * \return Zero (0) if folder found.
3066 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3069 aoA = ( AddressObject * ) pA;
3070 if( aoA->type == ADDR_ITEM_FOLDER ) {
3071 ItemFolder *folder, *fld;
3073 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3074 folder = ( ItemFolder * ) pB;
3075 if( fld == folder ) return 0; /* Found folder */
3080 static ItemFolder * addressbook_setup_subf(
3081 AddressDataSource *ds, gchar *title,
3082 GtkCMCTreeNode *pNode )
3084 AddrBookBase *adbase;
3085 AddressCache *cache;
3088 GtkCMCTreeNode *nNode;
3090 AddressObjectType aoType = ADDR_NONE;
3093 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3095 if( ds && ds->type == ADDR_IF_LDAP ) {
3097 aoType = ADDR_LDAP_QUERY;
3104 ctree = GTK_CMCTREE(addrbook.ctree);
3105 /* Get reference to address cache */
3106 adbase = ( AddrBookBase * ) ds->rawDataSource;
3107 cache = adbase->addressCache;
3109 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3110 GList *cur = children;
3111 for (; cur; cur = cur->next) {
3112 ItemFolder *child = (ItemFolder *) cur->data;
3113 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3114 nNode = gtk_cmctree_find_by_row_data_custom(
3116 addressbook_treenode_find_folder_cb );
3118 addrindex_remove_results( ds, child );
3119 while( child->listPerson ) {
3120 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3121 item = addrcache_remove_person( cache, item );
3123 addritem_free_item_person( item );
3127 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3128 addrbook.treeSelected = nNode;
3135 /* Create a folder */
3136 folder = addrcache_add_new_folder( cache, NULL );
3137 name = g_strdup_printf( "%s", title );
3138 addritem_folder_set_name( folder, name );
3139 addritem_folder_set_remarks( folder, "" );
3142 /* Now let's see the folder */
3143 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3144 gtk_cmctree_expand( ctree, pNode );
3146 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3147 addrbook.treeSelected = nNode;
3153 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3154 AddressObject *pobj = NULL;
3155 AddressDataSource *ds = NULL;
3156 AddressBookFile *abf = NULL;
3157 debug_print("adding address\n");
3158 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3159 if( pobj == NULL ) {
3160 debug_print("no row data\n");
3163 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3165 debug_print("no datasource\n");
3169 abf = ds->rawDataSource;
3171 g_print("no addressbook file\n");
3175 if( pobj->type == ADDR_DATASOURCE ) {
3176 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3177 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3179 ItemFolder *folder = NULL;
3181 if (abf && abf->type == ADDR_IF_LDAP) {
3182 GtkCMCTreeNode *parentNode;
3183 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3184 if( ds == NULL ) return;
3186 /* We must have a datasource that is an external interface */
3187 if( ! ds->interface->haveLibrary ) return;
3188 if( ! ds->interface->externalQuery ) return;
3190 if( pobj->type == ADDR_ITEM_FOLDER ) {
3191 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3194 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3196 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3198 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3199 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3201 abf = ds->rawDataSource;
3204 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3205 addrbook.editaddress_vbox,
3206 addressbook_new_address_from_book_post_cb,
3209 if (ds && abf && abf->type == ADDR_IF_LDAP) {
3210 LdapServer *server = ds->rawDataSource;
3211 ldapsvr_set_modified(server, TRUE);
3212 ldapsvr_update_book(server, NULL);
3213 if (server->retVal != LDAPRC_SUCCESS) {
3214 alertpanel( _("Add address(es)"),
3215 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3216 GTK_STOCK_CLOSE, NULL, NULL );
3217 server->retVal = LDAPRC_SUCCESS;
3222 if (prefs_common.addressbook_use_editaddress_dialog)
3223 addressbook_new_address_from_book_post_cb( person );
3226 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3228 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3231 if (abf && abf->type == ADDR_IF_LDAP) {
3232 GtkCMCTreeNode *parentNode;
3233 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3234 if( ds == NULL ) return;
3236 /* We must have a datasource that is an external interface */
3237 if( ! ds->interface->haveLibrary ) return;
3238 if( ! ds->interface->externalQuery ) return;
3240 if( pobj->type == ADDR_ITEM_FOLDER ) {
3241 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3244 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3246 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3249 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3250 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3252 abf = ds->rawDataSource;
3255 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3256 addrbook.editaddress_vbox,
3257 addressbook_new_address_from_folder_post_cb,
3260 if (ds && abf && abf->type == ADDR_IF_LDAP) {
3261 LdapServer *server = ds->rawDataSource;
3262 ldapsvr_set_modified(server, TRUE);
3263 ldapsvr_update_book(server, NULL);
3264 if (server->retVal != LDAPRC_SUCCESS) {
3265 alertpanel( _("Add address(es)"),
3266 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3267 GTK_STOCK_CLOSE, NULL, NULL );
3272 if (prefs_common.addressbook_use_editaddress_dialog)
3273 addressbook_new_address_from_folder_post_cb( person );
3275 else if( pobj->type == ADDR_ITEM_GROUP ) {
3276 /* New address in group */
3277 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3278 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3279 if (addrbook.treeSelected == addrbook.opened) {
3280 /* Change node name in tree. */
3281 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3282 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3283 addressbook_set_clist(
3284 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3292 * Search for specified child group node in address index tree.
3293 * \param parent Parent node.
3294 * \param group Group to find.
3296 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3297 GtkCMCTreeNode *node = NULL;
3298 GtkCMCTreeRow *currRow;
3300 currRow = GTK_CMCTREE_ROW( parent );
3302 node = currRow->children;
3306 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3307 if( obj->type == ADDR_ITEM_GROUP ) {
3308 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3309 if( g == group ) return node;
3311 currRow = GTK_CMCTREE_ROW(node);
3312 node = currRow->sibling;
3318 static AddressBookFile *addressbook_get_book_file() {
3319 AddressBookFile *abf = NULL;
3320 AddressDataSource *ds = NULL;
3322 ds = addressbook_find_datasource( addrbook.treeSelected );
3323 if( ds == NULL ) return NULL;
3324 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3328 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3329 GtkCMCTreeNode *node;
3332 /* Remove existing folders and groups */
3333 row = GTK_CMCTREE_ROW( parent );
3335 while( (node = row->children) ) {
3336 gtk_cmctree_remove_node( ctree, node );
3341 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3342 GtkCMCTreeNode *parent, *child;
3343 GtkCMCTreeRow *currRow;
3344 currRow = GTK_CMCTREE_ROW( node );
3346 parent = currRow->parent;
3347 while( (child = currRow->children) ) {
3348 gtk_cmctree_move( ctree, child, parent, node );
3350 gtk_sctree_sort_node( ctree, parent );
3354 static void addressbook_edit_address_post_cb( ItemPerson *person )
3358 AddressBookFile *abf = addressbook_get_book_file();
3360 if (abf && abf->type == ADDR_IF_LDAP) {
3361 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3362 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3365 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3366 invalidate_address_completion();
3368 addressbook_address_list_set_focus();
3371 void addressbook_address_list_set_focus( void )
3373 if (!prefs_common.addressbook_use_editaddress_dialog) {
3374 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3375 addressbook_list_menu_setup();
3379 void addressbook_address_list_disable_some_actions(void)
3381 /* disable address copy/pasting when editing contact's detail (embedded form) */
3382 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3383 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3384 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3387 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3388 addressbook_edit_address(data, 0, NULL, TRUE);
3391 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3392 gboolean force_focus ) {
3393 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3395 AddressObject *obj = NULL, *pobj = NULL;
3396 AddressDataSource *ds = NULL;
3397 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3399 AddressBookFile *abf = NULL;
3401 if( addrbook.listSelected == NULL ) return;
3402 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3403 cm_return_if_fail(obj != NULL);
3405 ctree = GTK_CMCTREE( addrbook.ctree );
3406 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3407 node = gtk_cmctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3409 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3410 if( ds == NULL ) return;
3412 abf = addressbook_get_book_file();
3414 if( obj->type == ADDR_ITEM_EMAIL ) {
3415 ItemEMail *email = ( ItemEMail * ) obj;
3416 if( email == NULL ) return;
3417 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3418 /* Edit parent group */
3419 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3420 ItemGroup *itemGrp = adapter->itemGroup;
3421 if( abf == NULL ) return;
3422 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3423 name = ADDRITEM_NAME(itemGrp);
3424 node = addrbook.treeSelected;
3425 parentNode = GTK_CMCTREE_ROW(node)->parent;
3428 /* Edit person - email page */
3430 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3431 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3432 addressbook_edit_address_post_cb,
3433 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3436 if (abf && abf->type == ADDR_IF_LDAP) {
3437 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3438 person->status = UPDATE_ENTRY;
3441 if (prefs_common.addressbook_use_editaddress_dialog)
3442 addressbook_edit_address_post_cb( person );
3447 else if( obj->type == ADDR_ITEM_PERSON ) {
3448 /* Edit person - basic page */
3449 ItemPerson *person = ( ItemPerson * ) obj;
3450 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3451 addressbook_edit_address_post_cb,
3452 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3455 if (abf && abf->type == ADDR_IF_LDAP) {
3456 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3457 person->status = UPDATE_ENTRY;
3460 if (prefs_common.addressbook_use_editaddress_dialog)
3461 addressbook_edit_address_post_cb( person );
3465 else if( obj->type == ADDR_ITEM_GROUP ) {
3466 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3467 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3468 parentNode = addrbook.treeSelected;
3469 node = addressbook_find_group_node( parentNode, itemGrp );
3470 name = ADDRITEM_NAME(itemGrp);
3471 invalidate_address_completion();
3477 /* Update tree node with node name */
3478 if( node == NULL ) return;
3479 addressbook_change_node_name( node, name );
3480 gtk_sctree_sort_node( ctree, parentNode );
3481 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3482 addressbook_set_clist(
3483 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3488 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3490 addressbook_del_clicked(NULL, NULL);
3493 static void close_cb(GtkAction *action, gpointer data)
3495 addressbook_close();
3498 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3499 addressbook_export_to_file();
3502 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3504 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3505 if( person ) addritem_person_set_opened( person, TRUE );
3509 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3511 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3512 if( person ) addritem_person_set_opened( person, FALSE );
3516 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3518 gchar *eMailAlias = ADDRITEM_NAME(email);
3519 if( eMailAlias && *eMailAlias != '\0' ) {
3521 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3524 str = g_strdup( eMailAlias );
3530 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3531 GList *items = itemGroup->listEMail;
3532 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3533 for( ; items != NULL; items = g_list_next( items ) ) {
3534 GtkCMCTreeNode *nodeEMail = NULL;
3535 gchar *text[N_LIST_COLS];
3536 ItemEMail *email = items->data;
3540 if( ! email ) continue;
3542 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3543 str = addressbook_format_item_clist( person, email );
3545 text[COL_NAME] = addressbook_set_col_name_guard(str);
3548 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3550 text[COL_ADDRESS] = email->address;
3551 text[COL_REMARKS] = email->remarks;
3552 nodeEMail = gtk_sctree_insert_node(
3554 text, FOLDER_SPACING,
3558 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3564 gchar *addressbook_set_col_name_guard(gchar *value)
3566 gchar *ret = "<not set>";
3567 gchar *tmp = g_strdup(value);
3569 if (tmp !=NULL && *tmp != '\0')
3575 static void addressbook_folder_load_one_person(
3576 GtkCMCTree *clist, ItemPerson *person,
3577 AddressTypeControlItem *atci,
3578 AddressTypeControlItem *atciMail )
3580 GtkCMCTreeNode *nodePerson = NULL;
3581 GtkCMCTreeNode *nodeEMail = NULL;
3582 gchar *text[N_LIST_COLS];
3583 gboolean flgFirst = TRUE, haveAddr = FALSE;
3586 AddressBookFile *abf = addressbook_get_book_file();
3589 if( person == NULL ) return;
3591 text[COL_NAME] = "";
3592 node = person->listEMail;
3594 ItemEMail *email = node->data;
3595 gchar *eMailAddr = NULL;
3596 node = g_list_next( node );
3598 text[COL_ADDRESS] = email->address;
3599 text[COL_REMARKS] = email->remarks;
3600 eMailAddr = ADDRITEM_NAME(email);
3601 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3603 /* First email belongs with person */
3604 gchar *str = addressbook_format_item_clist( person, email );
3606 text[COL_NAME] = addressbook_set_col_name_guard(str);
3609 else if( abf && abf->type == ADDR_IF_LDAP &&
3610 person && person->nickName ) {
3611 if (person->nickName) {
3612 if (strcmp(person->nickName, "") != 0) {
3613 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3616 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3622 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3624 nodePerson = gtk_sctree_insert_node(
3626 text, FOLDER_SPACING,
3629 FALSE, person->isOpened );
3632 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3635 /* Subsequent email is a child node of person */
3636 text[COL_NAME] = ADDRITEM_NAME(email);
3637 nodeEMail = gtk_sctree_insert_node(
3638 clist, nodePerson, NULL,
3639 text, FOLDER_SPACING,
3641 atciMail->iconXpmOpen,
3643 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3649 /* Have name without EMail */
3650 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3651 text[COL_ADDRESS] = "";
3652 text[COL_REMARKS] = "";
3653 nodePerson = gtk_sctree_insert_node(
3655 text, FOLDER_SPACING,
3658 FALSE, person->isOpened );
3659 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3664 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3666 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3667 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3669 if( atci == NULL ) return;
3670 if( atciMail == NULL ) return;
3672 /* Load email addresses */
3673 items = addritem_folder_get_person_list( itemFolder );
3674 for( ; items != NULL; items = g_list_next( items ) ) {
3675 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3677 /* Free up the list */
3678 mgu_clear_list( items );
3679 g_list_free( items );
3682 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3683 addrbook.listSelected = NULL;
3684 gtk_cmctree_remove_node( clist, node );
3685 addressbook_menubar_set_sensitive( FALSE );
3686 addressbook_menuitem_set_sensitive(
3687 gtk_cmctree_node_get_row_data(
3688 GTK_CMCTREE(clist), addrbook.treeSelected ),
3689 addrbook.treeSelected );
3692 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3693 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3694 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3695 GtkCMCTreeNode *node;
3696 if( atci == NULL ) return;
3697 if( atciMail == NULL ) return;
3698 if( person == NULL ) return;
3699 /* unload the person */
3701 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3703 addressbook_folder_remove_node( clist, node );
3704 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3705 gtk_sctree_sort_node( clist, NULL );
3706 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3708 gtk_sctree_select( GTK_SCTREE(clist), node );
3709 if (!gtk_cmctree_node_is_visible( clist, node ) )
3710 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3714 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3715 GtkCMCTreeNode *node;
3718 if( person == NULL ) return;
3719 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3720 row = gtk_cmclist_find_row_from_data( GTK_CMCLIST(clist), person );
3722 addressbook_folder_remove_node( clist, node );
3726 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3728 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3730 /* Load any groups */
3731 if( ! atci ) return;
3732 items = addritem_folder_get_group_list( itemFolder );
3733 for( ; items != NULL; items = g_list_next( items ) ) {
3734 GtkCMCTreeNode *nodeGroup = NULL;
3735 gchar *text[N_LIST_COLS];
3736 ItemGroup *group = items->data;
3737 if( group == NULL ) continue;
3738 text[COL_NAME] = ADDRITEM_NAME(group);
3739 text[COL_ADDRESS] = "";
3740 text[COL_REMARKS] = "";
3741 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3742 text, FOLDER_SPACING,
3746 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3747 gtk_sctree_sort_node(clist, NULL);
3749 /* Free up the list */
3750 mgu_clear_list( items );
3751 g_list_free( items );
3755 * Search ctree widget callback function.
3756 * \param pA Pointer to node.
3757 * \param pB Pointer to data item being sought.
3758 * \return Zero (0) if group found.
3760 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3763 aoA = ( AddressObject * ) pA;
3764 if( aoA->type == ADDR_ITEM_GROUP ) {
3765 ItemGroup *group, *grp;
3767 grp = ADAPTER_GROUP(aoA)->itemGroup;
3768 group = ( ItemGroup * ) pB;
3769 if( grp == group ) return 0; /* Found group */
3775 * Remove folder and group nodes from tree widget for items contained ("cut")
3778 static void addressbook_treenode_remove_item( void ) {
3780 AddrSelectItem *cutItem;
3781 AddressCache *cache;
3782 AddrItemObject *aio;
3783 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3786 node = _clipBoard_->objectList;
3788 cutItem = node->data;
3789 node = g_list_next( node );
3790 cache = addrindex_get_cache(
3791 _clipBoard_->addressIndex, cutItem->cacheID );
3792 if( cache == NULL ) continue;
3793 aio = addrcache_get_object( cache, cutItem->uid );
3796 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3799 folder = ( ItemFolder * ) aio;
3800 tn = gtk_cmctree_find_by_row_data_custom(
3801 ctree, NULL, folder,
3802 addressbook_treenode_find_folder_cb );
3804 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3807 group = ( ItemGroup * ) aio;
3808 tn = gtk_cmctree_find_by_row_data_custom(
3810 addressbook_treenode_find_group_cb );
3814 /* Free up adapter and remove node. */
3815 gtk_cmctree_remove_node( ctree, tn );
3822 * Find parent datasource for specified tree node.
3823 * \param node Node to test.
3824 * \return Data source, or NULL if not found.
3826 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3827 AddressDataSource *ds = NULL;
3830 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3833 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3834 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3836 /* g_print( "ao->type = %d\n", ao->type ); */
3837 if( ao->type == ADDR_DATASOURCE ) {
3838 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3839 /* g_print( "found it\n" ); */
3840 ds = ads->dataSource;
3844 node = GTK_CMCTREE_ROW(node)->parent;
3850 * Load address list widget with children of specified object.
3851 * \param obj Parent object to be loaded.
3853 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3854 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3855 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3856 AddressDataSource *ds = NULL;
3857 AdapterDSource *ads = NULL;
3858 static AddressObject *last_obj = NULL;
3860 if (addrbook.clist == NULL) {
3863 if (obj == last_obj && !refresh)
3868 gtk_cmclist_clear(clist);
3872 if( obj->type == ADDR_INTERFACE ) {
3873 /* g_print( "set_clist: loading datasource...\n" ); */
3874 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3878 gtk_cmclist_freeze(clist);
3879 gtk_cmclist_clear(clist);
3881 if( obj->type == ADDR_DATASOURCE ) {
3882 ads = ADAPTER_DSOURCE(obj);
3883 ds = ADAPTER_DSOURCE(obj)->dataSource;
3885 /* Load root folder */
3886 ItemFolder *rootFolder = NULL;
3887 rootFolder = addrindex_ds_get_root_folder( ds );
3888 addressbook_folder_load_person(
3889 ctreelist, addrindex_ds_get_root_folder( ds ) );
3890 addressbook_folder_load_group(
3891 ctreelist, addrindex_ds_get_root_folder( ds ) );
3895 if( obj->type == ADDR_ITEM_GROUP ) {
3897 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3898 addressbook_load_group( ctreelist, itemGroup );
3900 else if( obj->type == ADDR_ITEM_FOLDER ) {
3902 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3903 addressbook_folder_load_person( ctreelist, itemFolder );
3904 addressbook_folder_load_group( ctreelist, itemFolder );
3907 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3908 clist->focus_row = -1;
3909 gtk_cmclist_thaw(clist);
3913 * Call back function to free adaptor. Call back is setup by function
3914 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3915 * called when the address book tree widget node is removed by calling
3916 * function gtk_cmctree_remove_node().
3918 * \param data Tree node's row data.
3920 static void addressbook_free_treenode( gpointer data ) {
3923 ao = ( AddressObject * ) data;
3924 if( ao == NULL ) return;
3925 if( ao->type == ADDR_INTERFACE ) {
3926 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3927 addrbookctl_free_interface( ai );
3929 else if( ao->type == ADDR_DATASOURCE ) {
3930 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3931 addrbookctl_free_datasource( ads );
3933 else if( ao->type == ADDR_ITEM_FOLDER ) {
3934 AdapterFolder *af = ADAPTER_FOLDER(ao);
3935 addrbookctl_free_folder( af );
3937 else if( ao->type == ADDR_ITEM_GROUP ) {
3938 AdapterGroup *ag = ADAPTER_GROUP(ao);
3939 addrbookctl_free_group( ag );
3944 * Create new adaptor for specified data source.
3946 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3947 AddressObjectType otype, gchar *name )
3949 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3950 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3951 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3952 adapter->dataSource = ds;
3953 adapter->subType = otype;
3957 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3958 ADDRESS_OBJECT_NAME(adapter) =
3959 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3963 * Load tree from address index with the initial data.
3965 static void addressbook_load_tree( void ) {
3966 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3967 GList *nodeIf, *nodeDS;
3968 AdapterInterface *adapter;
3969 AddressInterface *iface;
3970 AddressTypeControlItem *atci;
3971 AddressDataSource *ds;
3972 AdapterDSource *ads;
3973 GtkCMCTreeNode *node, *newNode;
3976 nodeIf = _addressInterfaceList_;
3978 adapter = nodeIf->data;
3979 node = adapter->treeNode;
3980 iface = adapter->interface;
3981 atci = adapter->atci;
3983 if( iface->useInterface ) {
3984 /* Load data sources below interface node */
3985 nodeDS = iface->listSource;
3989 name = addrindex_ds_get_name( ds );
3990 ads = addressbook_create_ds_adapter(
3991 ds, atci->objectType, name );
3992 newNode = addressbook_add_object(
3993 node, ADDRESS_OBJECT(ads) );
3994 nodeDS = g_list_next( nodeDS );
3996 gtk_cmctree_expand( ctree, node );
3999 nodeIf = g_list_next( nodeIf );
4004 * Convert the old address book to new format.
4006 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4007 gboolean retVal = FALSE;
4008 gboolean errFlag = TRUE;
4011 /* Read old address book, performing conversion */
4012 debug_print( "Reading and converting old address book...\n" );
4013 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4014 addrindex_read_data( addrIndex );
4015 if( addrIndex->retVal == MGU_NO_FILE ) {
4016 /* We do not have a file - new user */
4017 debug_print( "New user... create new books...\n" );
4018 addrindex_create_new_books( addrIndex );
4019 if( addrIndex->retVal == MGU_SUCCESS ) {
4020 /* Save index file */
4021 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4022 addrindex_save_data( addrIndex );
4023 if( addrIndex->retVal == MGU_SUCCESS ) {
4028 msg = _( "New user, could not save index file." );
4032 msg = _( "New user, could not save address book files." );
4036 /* We have an old file */
4037 if( addrIndex->wasConverted ) {
4038 /* Converted successfully - save address index */
4039 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4040 addrindex_save_data( addrIndex );
4041 if( addrIndex->retVal == MGU_SUCCESS ) {
4042 msg = _( "Old address book converted successfully." );
4047 msg = _("Old address book converted,\n"
4048 "could not save new address index file." );
4052 /* File conversion failed - just create new books */
4053 debug_print( "File conversion failed... just create new books...\n" );
4054 addrindex_create_new_books( addrIndex );
4055 if( addrIndex->retVal == MGU_SUCCESS ) {
4057 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4058 addrindex_save_data( addrIndex );
4059 if( addrIndex->retVal == MGU_SUCCESS ) {
4060 msg = _("Could not convert address book,\n"
4061 "but created empty new address book files." );
4066 msg = _("Could not convert address book,\n"
4067 "could not save new address index file." );
4071 msg = _("Could not convert address book\n"
4072 "and could not create new address book files." );
4077 debug_print( "Error\n%s\n", msg );
4078 alertpanel_full(_("Addressbook conversion error"), msg,
4079 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4080 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4083 debug_print( "Warning\n%s\n", msg );
4084 alertpanel_full(_("Addressbook conversion error"), msg,
4085 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4086 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4092 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4096 gboolean failed = FALSE;
4098 if( ( dp = opendir( origdir ) ) == NULL ) {
4102 while( ( d = readdir( dp ) ) != NULL ) {
4103 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4106 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4108 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4110 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4123 /* all copies succeeded, we can remove source files */
4124 if( ( dp = opendir( origdir ) ) == NULL ) {
4127 while( ( d = readdir( dp ) ) != NULL ) {
4128 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4131 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4133 claws_unlink(orig_file);
4143 void addressbook_read_file( void ) {
4144 AddressIndex *addrIndex = NULL;
4145 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4147 debug_print( "Reading address index...\n" );
4148 if( _addressIndex_ ) {
4149 debug_print( "address book already read!!!\n" );
4153 addrIndex = addrindex_create_index();
4154 addrindex_initialize();
4156 /* Use new address book index. */
4158 if ( !is_dir_exist(indexdir) ) {
4159 if ( make_dir(indexdir) < 0 ) {
4160 addrindex_set_file_path( addrIndex, get_rc_dir() );
4161 g_warning( "couldn't create dir %s\n", indexdir);
4163 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4164 remove_dir_recursive(indexdir);
4165 addrindex_set_file_path( addrIndex, get_rc_dir() );
4166 g_error("couldn't migrate dir %s", indexdir);
4168 addrindex_set_file_path( addrIndex, indexdir);
4172 addrindex_set_file_path( addrIndex, indexdir);
4175 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4176 addrindex_read_data( addrIndex );
4177 if( addrIndex->retVal == MGU_NO_FILE ) {
4178 /* Conversion required */
4179 debug_print( "Converting...\n" );
4180 if( addressbook_convert( addrIndex ) ) {
4181 _addressIndex_ = addrIndex;
4184 else if( addrIndex->retVal == MGU_SUCCESS ) {
4185 _addressIndex_ = addrIndex;
4188 /* Error reading address book */
4189 debug_print( "Could not read address index.\n" );
4190 addrindex_print_index( addrIndex, stdout );
4191 alertpanel_full(_("Addressbook Error"),
4192 _("Could not read address index"),
4193 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4194 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4196 debug_print( "done.\n" );
4200 * Add object into the address index tree widget.
4201 * Enter: node Parent node.
4202 * obj Object to add.
4203 * Return: Node that was added, or NULL if object not added.
4205 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4208 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4209 GtkCMCTreeNode *added;
4210 AddressObject *pobj;
4211 AddressObjectType otype;
4212 AddressTypeControlItem *atci = NULL;
4214 cm_return_val_if_fail(node != NULL, NULL);
4215 cm_return_val_if_fail(obj != NULL, NULL);
4217 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4218 cm_return_val_if_fail(pobj != NULL, NULL);
4220 /* Determine object type to be displayed */
4221 if( obj->type == ADDR_DATASOURCE ) {
4222 otype = ADAPTER_DSOURCE(obj)->subType;
4228 /* Handle any special conditions. */
4230 atci = addrbookctl_lookup( otype );
4232 if( atci->showInTree ) {
4233 /* Add object to tree */
4236 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4237 atci->iconXpm, atci->iconXpmOpen,
4238 atci->treeLeaf, atci->treeExpand );
4239 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4240 addressbook_free_treenode );
4244 gtk_sctree_sort_node(ctree, node);
4250 * Add group into the address index tree.
4251 * \param node Parent node.
4252 * \param ds Data source.
4253 * \param itemGroup Group to add.
4254 * \return Inserted node.
4256 static GtkCMCTreeNode *addressbook_node_add_group(
4257 GtkCMCTreeNode *node, AddressDataSource *ds,
4258 ItemGroup *itemGroup )
4260 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4261 GtkCMCTreeNode *newNode;
4262 AdapterGroup *adapter;
4263 AddressTypeControlItem *atci = NULL;
4266 if( ds == NULL ) return NULL;
4267 if( node == NULL || itemGroup == NULL ) return NULL;
4269 name = &itemGroup->obj.name;
4271 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4273 adapter = g_new0( AdapterGroup, 1 );
4274 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4275 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4276 adapter->itemGroup = itemGroup;
4278 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4279 atci->iconXpm, atci->iconXpm,
4280 atci->treeLeaf, atci->treeExpand );
4281 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4282 addressbook_free_treenode );
4283 gtk_sctree_sort_node( ctree, node );
4288 * Add folder into the address index tree. Only visible folders are loaded into
4289 * the address index tree. Note that the root folder is not inserted into the
4292 * \param node Parent node.
4293 * \param ds Data source.
4294 * \param itemFolder Folder to add.
4295 * \param otype Object type to display.
4296 * \return Inserted node for the folder.
4298 static GtkCMCTreeNode *addressbook_node_add_folder(
4299 GtkCMCTreeNode *node, AddressDataSource *ds,
4300 ItemFolder *itemFolder, AddressObjectType otype )
4302 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4303 GtkCMCTreeNode *newNode = NULL;
4304 AdapterFolder *adapter;
4305 AddressTypeControlItem *atci = NULL;
4306 GList *listItems = NULL;
4308 ItemFolder *rootFolder;
4310 /* Only visible folders */
4311 if( itemFolder == NULL || itemFolder->isHidden )
4316 if( node == NULL || itemFolder == NULL )
4319 /* Determine object type */
4320 atci = addrbookctl_lookup( otype );
4324 rootFolder = addrindex_ds_get_root_folder( ds );
4325 if( itemFolder == rootFolder ) {
4329 adapter = g_new0( AdapterFolder, 1 );
4330 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4331 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4332 adapter->itemFolder = itemFolder;
4334 name = ADDRITEM_NAME(itemFolder);
4335 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4336 atci->iconXpm, atci->iconXpm,
4337 atci->treeLeaf, atci->treeExpand );
4339 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4340 addressbook_free_treenode );
4344 listItems = itemFolder->listFolder;
4345 while( listItems ) {
4346 ItemFolder *item = listItems->data;
4347 addressbook_node_add_folder( newNode, ds, item, otype );
4348 listItems = g_list_next( listItems );
4350 listItems = itemFolder->listGroup;
4351 while( listItems ) {
4352 ItemGroup *item = listItems->data;
4353 addressbook_node_add_group( newNode, ds, item );
4354 listItems = g_list_next( listItems );
4356 gtk_sctree_sort_node( ctree, node );
4360 void addressbook_export_to_file( void ) {
4361 if( _addressIndex_ ) {
4362 /* Save all new address book data */
4363 debug_print( "Saving address books...\n" );
4364 addrindex_save_all_books( _addressIndex_ );
4366 debug_print( "Exporting addressbook to file...\n" );
4367 addrindex_save_data( _addressIndex_ );
4368 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4369 addrindex_print_index( _addressIndex_, stdout );
4372 /* Notify address completion of new data */
4373 invalidate_address_completion();
4377 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4379 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4380 addressbook_lup_clicked(NULL, NULL);
4385 * Comparison using cell contents (text in first column). Used for sort
4386 * address index widget.
4388 static gint addressbook_treenode_compare_func(
4389 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4391 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4392 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4393 gchar *name1 = NULL, *name2 = NULL;
4394 if( cell1 ) name1 = cell1->u.text;
4395 if( cell2 ) name2 = cell2->u.text;
4396 if( ! name1 ) return ( name2 != NULL );
4397 if( ! name2 ) return -1;
4398 return g_utf8_collate( name1, name2 );
4401 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4402 AdapterDSource *ads;
4403 AdapterInterface *adapter;
4404 GtkCMCTreeNode *newNode;
4406 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4407 if( adapter == NULL ) return;
4408 ads = addressbook_edit_book( _addressIndex_, NULL );
4410 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4412 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4413 addrbook.treeSelected = newNode;
4418 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4419 AdapterDSource *ads;
4420 AdapterInterface *adapter;
4421 GtkCMCTreeNode *newNode;
4423 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4424 if( adapter == NULL ) return;
4425 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4427 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4429 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4430 addrbook.treeSelected = newNode;
4436 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4437 AdapterDSource *ads;
4438 AdapterInterface *adapter;
4439 AddressInterface *iface;
4440 GtkCMCTreeNode *newNode;
4442 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4443 if( adapter == NULL ) return;
4444 iface = adapter->interface;
4445 if( ! iface->haveLibrary ) return;
4446 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4448 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4450 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4451 addrbook.treeSelected = newNode;
4458 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4459 AdapterDSource *ads;
4460 AdapterInterface *adapter;
4461 AddressInterface *iface;
4462 GtkCMCTreeNode *newNode;
4464 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4465 if( adapter == NULL ) return;
4466 iface = adapter->interface;
4467 if( ! iface->haveLibrary ) return;
4468 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4470 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4472 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4473 addrbook.treeSelected = newNode;
4480 * Display address search status message.
4481 * \param queryType Query type.
4482 * \param status Status/Error code.
4484 static void addressbook_search_message( gint queryType, gint sts ) {
4486 *addressbook_msgbuf = '\0';
4488 if( sts != MGU_SUCCESS ) {
4489 if( queryType == ADDRQUERY_LDAP ) {
4491 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4496 g_snprintf( addressbook_msgbuf,
4497 sizeof(addressbook_msgbuf), "%s", desc );
4498 addressbook_status_show( addressbook_msgbuf );
4501 addressbook_status_show( "" );
4506 * Refresh addressbook by forcing refresh of current selected object in
4509 static void addressbook_refresh_current( void ) {
4513 ctree = GTK_CMCTREE(addrbook.ctree);
4514 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4515 if( obj == NULL ) return;
4516 addressbook_set_clist( obj, TRUE );
4520 * Message that is displayed whilst a query is executing in a background
4523 static gchar *_tempMessage_ = N_( "Busy searching..." );
4526 * Address search idle function. This function is called during UI idle time
4527 * while a search is in progress.
4529 * \param data Idler data.
4531 static void addressbook_search_idle( gpointer data ) {
4535 queryID = GPOINTER_TO_INT( data );
4536 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4541 * Search completion callback function. This removes the query from the idle
4544 * \param sender Sender of query.
4545 * \param queryID Query ID of search request.
4546 * \param status Search status.
4547 * \param data Query data.
4549 static void addressbook_search_callback_end(
4550 gpointer sender, gint queryID, gint status, gpointer data )
4554 AddrQueryObject *aqo;
4556 /* Remove idler function */
4557 ptrQID = GINT_TO_POINTER( queryID );
4559 g_idle_remove_by_data( ptrQID );
4562 /* Refresh addressbook contents */
4563 addressbook_refresh_current();
4564 req = qrymgr_find_request( queryID );
4566 aqo = ( AddrQueryObject * ) req->queryList->data;
4567 addressbook_search_message( aqo->queryType, status );
4570 /* Stop the search */
4571 addrindex_stop_search( queryID );
4577 * \param ds Data source to search.
4578 * \param searchTerm String to lookup.
4579 * \param pNode Parent data source node.
4581 static void addressbook_perform_search(
4582 AddressDataSource *ds, gchar *searchTerm,
4583 GtkCMCTreeNode *pNode )
4585 AddrBookBase *adbase;
4586 AddressCache *cache;
4592 AddressObjectType aoType = ADDR_NONE;
4596 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4598 if( ds && ds->type == ADDR_IF_LDAP ) {
4600 aoType = ADDR_LDAP_QUERY;
4606 /* Get reference to address cache */
4607 adbase = ( AddrBookBase * ) ds->rawDataSource;
4608 cache = adbase->addressCache;
4610 /* Create a folder for the search results */
4611 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4612 folder = addressbook_setup_subf(ds, name, pNode);
4615 /* Setup the search */
4616 queryID = addrindex_setup_explicit_search(
4617 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4618 if( queryID == 0 ) return;
4620 /* Set up idler function */
4621 idleID = g_idle_add(
4622 ( GtkFunction ) addressbook_search_idle,
4623 GINT_TO_POINTER( queryID ) );
4625 /* Start search, sit back and wait for something to happen */
4626 addrindex_start_search( queryID );
4628 addressbook_status_show( _tempMessage_ );
4632 * Lookup button handler. Address search is only performed against
4633 * address interfaces for external queries.
4635 * \param button Lookup button widget.
4636 * \param data Data object.
4638 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4641 AddressDataSource *ds;
4642 AddressInterface *iface;
4644 GtkCMCTreeNode *node, *parentNode;
4646 node = addrbook.treeSelected;
4647 if( ! node ) return;
4648 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4650 ctree = GTK_CMCTREE(addrbook.ctree);
4651 obj = gtk_cmctree_node_get_row_data( ctree, node );
4652 if( obj == NULL ) return;
4654 ds = addressbook_find_datasource( node );
4655 if( ds == NULL ) return;
4657 /* We must have a datasource that is an external interface */
4658 iface = ds->interface;
4659 if( ! iface->haveLibrary ) return;
4660 if( ! iface->externalQuery ) return;
4663 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4664 g_strchomp( searchTerm );
4666 if( obj->type == ADDR_ITEM_FOLDER ) {
4667 parentNode = GTK_CMCTREE_ROW(node)->parent;
4672 addressbook_perform_search( ds, searchTerm, parentNode );
4674 gtk_widget_grab_focus( addrbook.entry );
4676 g_free( searchTerm );
4679 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4680 addressbook_close();
4685 * Browse address entry for highlighted entry.
4687 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4689 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4691 AddressDataSource *ds;
4692 AddressInterface *iface;
4696 if(addrbook.listSelected == NULL)
4699 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4703 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4707 iface = ds->interface;
4708 if(!iface || !iface->haveLibrary )
4712 if (obj->type == ADDR_ITEM_EMAIL) {
4713 email = ( ItemEMail * ) obj;
4717 person = (ItemPerson *) ADDRITEM_PARENT(email);
4719 else if (obj->type == ADDR_ITEM_PERSON) {
4720 person = (ItemPerson *) obj;
4727 if( iface && iface->type == ADDR_IF_LDAP ) {
4728 browseldap_entry(ds, person->externalID);
4733 /* **********************************************************************
4734 * Build lookup tables.
4735 * ***********************************************************************
4739 * Remap object types.
4740 * Enter: abType AddressObjectType (used in tree node).
4741 * Return: ItemObjectType (used in address cache data).
4743 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4744 ItemObjectType ioType;
4747 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4748 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4749 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4750 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4751 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4752 default: ioType = ITEMTYPE_NONE; break;
4757 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4758 atci = addrbookctl_lookup(id); \
4760 atci->iconXpm = icon; \
4761 atci->iconXpmOpen = iconopen; \
4763 g_warning("can't get atci %d\n", id); \
4768 * Build table that controls the rendering of object types.
4770 static void addrbookctl_build_icons( GtkWidget *window ) {
4771 AddressTypeControlItem *atci;
4775 g_object_unref(interfacexpm);
4777 g_object_unref(folderxpm);
4779 g_object_unref(folderopenxpm);
4781 g_object_unref(groupxpm);
4783 g_object_unref(vcardxpm);
4785 g_object_unref(bookxpm);
4787 g_object_unref(addressxpm);
4789 g_object_unref(jpilotxpm);
4791 g_object_unref(categoryxpm);
4793 g_object_unref(ldapxpm);
4795 g_object_unref(addrsearchxpm);
4796 stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacexpm );
4797 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4798 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4799 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4800 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4801 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4802 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4803 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4804 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4805 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4806 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4808 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4809 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4810 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4811 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4812 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4813 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4814 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4815 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4816 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4817 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4818 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4823 * Build table that controls the rendering of object types.
4825 static void addrbookctl_build_map( GtkWidget *window ) {
4826 AddressTypeControlItem *atci;
4828 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4829 _addressBookTypeList_ = NULL;
4832 atci = g_new0( AddressTypeControlItem, 1 );
4833 atci->objectType = ADDR_INTERFACE;
4834 atci->interfaceType = ADDR_IF_NONE;
4835 atci->showInTree = TRUE;
4836 atci->treeExpand = TRUE;
4837 atci->treeLeaf = FALSE;
4838 atci->displayName = _( "Interface" );
4839 atci->menuCommand = NULL;
4840 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4841 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4844 atci = g_new0( AddressTypeControlItem, 1 );
4845 atci->objectType = ADDR_BOOK;
4846 atci->interfaceType = ADDR_IF_BOOK;
4847 atci->showInTree = TRUE;
4848 atci->treeExpand = TRUE;
4849 atci->treeLeaf = FALSE;
4850 atci->displayName = _( "Address Book" );
4851 atci->menuCommand = "Menu/Book/NewBook";
4852 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4853 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4856 atci = g_new0( AddressTypeControlItem, 1 );
4857 atci->objectType = ADDR_ITEM_PERSON;
4858 atci->interfaceType = ADDR_IF_NONE;
4859 atci->showInTree = FALSE;
4860 atci->treeExpand = FALSE;
4861 atci->treeLeaf = FALSE;
4862 atci->displayName = _( "Person" );
4863 atci->menuCommand = NULL;
4864 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4865 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4868 atci = g_new0( AddressTypeControlItem, 1 );
4869 atci->objectType = ADDR_ITEM_EMAIL;
4870 atci->interfaceType = ADDR_IF_NONE;
4871 atci->showInTree = FALSE;
4872 atci->treeExpand = FALSE;
4873 atci->treeLeaf = TRUE;
4874 atci->displayName = _( "Email Address" );
4875 atci->menuCommand = NULL;
4876 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4877 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4880 atci = g_new0( AddressTypeControlItem, 1 );
4881 atci->objectType = ADDR_ITEM_GROUP;
4882 atci->interfaceType = ADDR_IF_BOOK;
4883 atci->showInTree = TRUE;
4884 atci->treeExpand = FALSE;
4885 atci->treeLeaf = FALSE;
4886 atci->displayName = _( "Group" );
4887 atci->menuCommand = NULL;
4888 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4889 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4892 atci = g_new0( AddressTypeControlItem, 1 );
4893 atci->objectType = ADDR_ITEM_FOLDER;
4894 atci->interfaceType = ADDR_IF_BOOK;
4895 atci->showInTree = TRUE;
4896 atci->treeExpand = FALSE;
4897 atci->treeLeaf = FALSE;
4898 atci->displayName = _( "Folder" );
4899 atci->menuCommand = NULL;
4900 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4901 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4904 atci = g_new0( AddressTypeControlItem, 1 );
4905 atci->objectType = ADDR_VCARD;
4906 atci->interfaceType = ADDR_IF_VCARD;
4907 atci->showInTree = TRUE;
4908 atci->treeExpand = TRUE;
4909 atci->treeLeaf = TRUE;
4910 atci->displayName = _( "vCard" );
4911 atci->menuCommand = "Menu/Book/NewVCard";
4912 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4913 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4916 atci = g_new0( AddressTypeControlItem, 1 );
4917 atci->objectType = ADDR_JPILOT;
4918 atci->interfaceType = ADDR_IF_JPILOT;
4919 atci->showInTree = TRUE;
4920 atci->treeExpand = TRUE;
4921 atci->treeLeaf = FALSE;
4922 atci->displayName = _( "JPilot" );
4923 atci->menuCommand = "Menu/Book/NewJPilot";
4924 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4925 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4928 atci = g_new0( AddressTypeControlItem, 1 );
4929 atci->objectType = ADDR_CATEGORY;
4930 atci->interfaceType = ADDR_IF_JPILOT;
4931 atci->showInTree = TRUE;
4932 atci->treeExpand = TRUE;
4933 atci->treeLeaf = TRUE;
4934 atci->displayName = _( "JPilot" );
4935 atci->menuCommand = NULL;
4936 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4937 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4940 atci = g_new0( AddressTypeControlItem, 1 );
4941 atci->objectType = ADDR_LDAP;
4942 atci->interfaceType = ADDR_IF_LDAP;
4943 atci->showInTree = TRUE;
4944 atci->treeExpand = TRUE;
4945 atci->treeLeaf = FALSE;
4946 atci->displayName = _( "LDAP servers" );
4947 atci->menuCommand = "Menu/Book/NewLDAPServer";
4948 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4949 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4952 atci = g_new0( AddressTypeControlItem, 1 );
4953 atci->objectType = ADDR_LDAP_QUERY;
4954 atci->interfaceType = ADDR_IF_LDAP;
4955 atci->showInTree = TRUE;
4956 atci->treeExpand = FALSE;
4957 atci->treeLeaf = TRUE;
4958 atci->displayName = _( "LDAP Query" );
4959 atci->menuCommand = NULL;
4960 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4961 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4963 addrbookctl_build_icons(window);
4966 void addressbook_reflect_prefs_pixmap_theme(void)
4968 if (addrbook.window)
4969 addrbookctl_build_icons(addrbook.window);
4973 * Search for specified object type.
4975 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4977 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4981 * Search for specified interface type.
4983 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4984 GList *node = _addressBookTypeList_;
4986 AddressTypeControlItem *atci = node->data;
4987 if( atci->interfaceType == ifType ) return atci;
4988 node = g_list_next( node );
4993 static void addrbookctl_free_address( AddressObject *obj ) {
4994 g_free( obj->name );
4995 obj->type = ADDR_NONE;
4999 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5000 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5001 adapter->interface = NULL;
5002 adapter->interfaceType = ADDR_IF_NONE;
5003 adapter->atci = NULL;
5004 adapter->enabled = FALSE;
5005 adapter->haveLibrary = FALSE;
5006 adapter->treeNode = NULL;
5010 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5011 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5012 adapter->dataSource = NULL;
5013 adapter->subType = ADDR_NONE;
5017 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5018 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5019 adapter->itemFolder = NULL;
5023 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5024 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5025 adapter->itemGroup = NULL;
5030 * Build GUI interface list.
5032 static void addrbookctl_build_iflist( void ) {
5033 AddressTypeControlItem *atci;
5034 AdapterInterface *adapter;
5037 if( _addressIndex_ == NULL ) {
5038 _addressIndex_ = addrindex_create_index();
5039 if( _clipBoard_ == NULL ) {
5040 _clipBoard_ = addrclip_create();
5042 addrclip_set_index( _clipBoard_, _addressIndex_ );
5044 _addressInterfaceList_ = NULL;
5045 list = addrindex_get_interface_list( _addressIndex_ );
5047 AddressInterface *interface = list->data;
5048 atci = addrbookctl_lookup_iface( interface->type );
5050 adapter = g_new0( AdapterInterface, 1 );
5051 adapter->interfaceType = interface->type;
5052 adapter->atci = atci;
5053 adapter->interface = interface;
5054 adapter->treeNode = NULL;
5055 adapter->enabled = TRUE;
5056 adapter->haveLibrary = interface->haveLibrary;
5057 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5058 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5059 _addressInterfaceList_ =
5060 g_list_append( _addressInterfaceList_, adapter );
5062 list = g_list_next( list );
5067 * Find GUI interface type specified interface type.
5068 * \param ifType Interface type.
5069 * \return Interface item, or NULL if not found.
5071 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5072 GList *node = _addressInterfaceList_;
5074 AdapterInterface *adapter = node->data;
5075 if( adapter->interfaceType == ifType ) return adapter;
5076 node = g_list_next( node );
5082 * Build interface list selection.
5084 static void addrbookctl_build_ifselect( void ) {
5085 GList *newList = NULL;
5090 gchar *endptr = NULL;
5092 AdapterInterface *adapter;
5094 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5097 splitStr = g_strsplit( selectStr, ",", -1 );
5098 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5100 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5101 ifType = strtol( splitStr[i], &endptr, 10 );
5104 if( strcmp( endptr, "/n" ) == 0 ) {
5108 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5109 adapter = addrbookctl_find_interface( ifType );
5111 newList = g_list_append( newList, adapter );
5118 /* g_print( "i=%d\n", i ); */
5119 g_strfreev( splitStr );
5120 g_free( selectStr );
5122 /* Replace existing list */
5123 mgu_clear_list( _addressIFaceSelection_ );
5124 g_list_free( _addressIFaceSelection_ );
5125 _addressIFaceSelection_ = newList;
5129 /* ***********************************************************************
5130 * Add sender to address book.
5131 * ***********************************************************************
5135 * This function is used by the Add sender to address book function.
5137 gboolean addressbook_add_contact(
5138 const gchar *name, const gchar *address, const gchar *remarks,
5139 GdkPixbuf *picture )
5141 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5142 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5143 debug_print( "addressbook_add_contact - added\n" );
5144 addressbook_refresh();
5149 /* ***********************************************************************
5150 * Book/folder selection.
5151 * ***********************************************************************
5155 * This function is used by the matcher dialog to select a book/folder.
5157 gchar *addressbook_folder_selection( const gchar *folderpath)
5159 AddressBookFile *book = NULL;
5160 ItemFolder *folder = NULL;
5163 cm_return_val_if_fail( folderpath != NULL, NULL);
5165 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5167 if ( folder != NULL) {
5169 gchar *oldtmp = NULL;
5170 AddrItemObject *obj = NULL;
5172 /* walk thru folder->parent to build the full folder path */
5173 /* TODO: wwp: optimize this */
5175 tmp = g_strdup(obj->uid);
5176 while ( obj->parent ) {
5178 if ( obj->name != NULL ) {
5179 oldtmp = g_strdup(tmp);
5181 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5185 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5188 path = g_strdup_printf("%s", book->fileName);
5190 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5196 /* ***********************************************************************
5197 * Book/folder checking.
5198 * ***********************************************************************
5201 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5203 FolderInfo *fi = g_new0( FolderInfo, 1 );
5205 fi->folder = folder;
5209 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5210 FolderInfo *fiParent, FolderPathMatch *match )
5216 FolderPathMatch *nextmatch = NULL;
5221 list = parentFolder->listFolder;
5223 folder = list->data;
5224 fName = g_strdup( ADDRITEM_NAME(folder) );
5226 /* match folder name, match pointer will be set to NULL if next recursive call
5227 doesn't need to match subfolder name */
5228 if ( match != NULL &&
5229 match->matched == FALSE ) {
5230 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5231 /* folder name matches, prepare next subfolder match */
5232 debug_print("matched folder name '%s'\n", fName);
5234 if ( match->folder_path[match->index] == NULL ) {
5235 /* we've matched all elements */
5236 match->matched = TRUE;
5237 match->folder = folder;
5238 debug_print("book/folder path matched!\n");
5240 /* keep on matching */
5248 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5249 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5251 list = g_list_next( list );
5256 * This function is used by to check if a matcher book/folder path corresponds to an
5257 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5258 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5259 if book AND folder are NULL this means that folderpath was empty or Any.
5260 If folderpath is a simple book name (without folder), book will not be NULL and folder
5261 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5264 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5265 AddressDataSource **book,
5266 ItemFolder **folder )
5268 AddressDataSource *ds;
5269 GList *list, *nodeDS;
5270 ItemFolder *rootFolder;
5271 AddressBookFile *abf;
5273 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5280 if ( folderpath == NULL )
5283 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5286 /* split the folder path we've received, we'll try to match this path, subpath by
5287 subpath against the book/folder structure in order */
5288 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5289 if (!folder_path_match.folder_path)
5292 list = addrindex_get_interface_list( _addressIndex_ );
5293 while ( list && !folder_path_match.matched ) {
5294 AddressInterface *interface = list->data;
5295 if ( interface && interface->type == ADDR_IF_BOOK ) {
5296 nodeDS = interface->listSource;
5297 while ( nodeDS && !folder_path_match.matched ) {
5300 /* Read address book */
5301 if( ! addrindex_ds_get_read_flag( ds ) ) {
5302 addrindex_ds_read_data( ds );
5305 /* Add node for address book */
5306 abf = ds->rawDataSource;
5308 /* match book name */
5309 if ( abf && abf->fileName &&
5310 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5312 debug_print("matched book name '%s'\n", abf->fileName);
5313 folder_path_match.book = ds;
5315 if ( folder_path_match.folder_path[1] == NULL ) {
5316 /* no folder part to match */
5318 folder_path_match.matched = TRUE;
5319 folder_path_match.folder = NULL;
5320 debug_print("book path matched!\n");
5323 /* match folder part */
5325 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5326 rootFolder = addrindex_ds_get_root_folder( ds );
5328 /* prepare for recursive call */
5329 folder_path_match.index = 1;
5330 /* this call will set folder_path_match.matched and folder_path_match.folder */
5331 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5336 nodeDS = g_list_next( nodeDS );
5339 list = g_list_next( list );
5342 g_strfreev( folder_path_match.folder_path );
5345 *book = folder_path_match.book;
5347 *folder = folder_path_match.folder;
5348 return folder_path_match.matched;
5352 /* **********************************************************************
5354 * ***********************************************************************
5360 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5361 AddressDataSource *ds = NULL;
5362 AdapterDSource *ads = NULL;
5363 AddressBookFile *abf = NULL;
5364 AdapterInterface *adapter;
5365 GtkCMCTreeNode *newNode;
5367 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5369 if( adapter->treeNode ) {
5370 abf = addressbook_imp_ldif( _addressIndex_ );
5372 ds = addrindex_index_add_datasource(
5373 _addressIndex_, ADDR_IF_BOOK, abf );
5374 ads = addressbook_create_ds_adapter(
5375 ds, ADDR_BOOK, NULL );
5376 addressbook_ads_set_name(
5377 ads, addrbook_get_name( abf ) );
5378 newNode = addressbook_add_object(
5380 ADDRESS_OBJECT(ads) );
5382 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5384 addrbook.treeSelected = newNode;
5387 /* Notify address completion */
5388 invalidate_address_completion();
5397 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5398 AddressDataSource *ds = NULL;
5399 AdapterDSource *ads = NULL;
5400 AddressBookFile *abf = NULL;
5401 AdapterInterface *adapter;
5402 GtkCMCTreeNode *newNode;
5404 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5406 if( adapter->treeNode ) {
5407 abf = addressbook_imp_mutt( _addressIndex_ );
5409 ds = addrindex_index_add_datasource(
5410 _addressIndex_, ADDR_IF_BOOK, abf );
5411 ads = addressbook_create_ds_adapter(
5412 ds, ADDR_BOOK, NULL );
5413 addressbook_ads_set_name(
5414 ads, addrbook_get_name( abf ) );
5415 newNode = addressbook_add_object(
5417 ADDRESS_OBJECT(ads) );
5419 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5421 addrbook.treeSelected = newNode;
5424 /* Notify address completion */
5425 invalidate_address_completion();
5434 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5435 AddressDataSource *ds = NULL;
5436 AdapterDSource *ads = NULL;
5437 AddressBookFile *abf = NULL;
5438 AdapterInterface *adapter;
5439 GtkCMCTreeNode *newNode;
5441 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5443 if( adapter->treeNode ) {
5444 abf = addressbook_imp_pine( _addressIndex_ );
5446 ds = addrindex_index_add_datasource(
5447 _addressIndex_, ADDR_IF_BOOK, abf );
5448 ads = addressbook_create_ds_adapter(
5449 ds, ADDR_BOOK, NULL );
5450 addressbook_ads_set_name(
5451 ads, addrbook_get_name( abf ) );
5452 newNode = addressbook_add_object(
5454 ADDRESS_OBJECT(ads) );
5456 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5458 addrbook.treeSelected = newNode;
5461 /* Notify address completion */
5462 invalidate_address_completion();
5469 * Harvest addresses.
5470 * \param folderItem Folder to import.
5471 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5472 * \param msgList List of message numbers, or NULL to process folder.
5474 void addressbook_harvest(
5475 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5477 AddressDataSource *ds = NULL;
5478 AdapterDSource *ads = NULL;
5479 AddressBookFile *abf = NULL;
5480 AdapterInterface *adapter;
5481 GtkCMCTreeNode *newNode;
5483 abf = addrgather_dlg_execute(
5484 folderItem, _addressIndex_, sourceInd, msgList );
5486 ds = addrindex_index_add_datasource(
5487 _addressIndex_, ADDR_IF_BOOK, abf );
5489 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5491 if( adapter->treeNode ) {
5492 ads = addressbook_create_ds_adapter(
5493 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5494 newNode = addressbook_add_object(
5496 ADDRESS_OBJECT(ads) );
5500 /* Notify address completion */
5501 invalidate_address_completion();
5508 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5509 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5511 AddressDataSource *ds = NULL;
5512 AddrBookBase *adbase;
5513 AddressCache *cache;
5514 GtkCMCTreeNode *node = NULL;
5516 if( ! addrbook.treeSelected ) return;
5517 node = addrbook.treeSelected;
5518 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5519 obj = gtk_cmctree_node_get_row_data( ctree, node );
5520 if( obj == NULL ) return;
5522 ds = addressbook_find_datasource( node );
5523 if( ds == NULL ) return;
5524 adbase = ( AddrBookBase * ) ds->rawDataSource;
5525 cache = adbase->addressCache;
5526 addressbook_exp_html( cache );
5532 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5533 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5535 AddressDataSource *ds = NULL;
5536 AddrBookBase *adbase;
5537 AddressCache *cache;
5538 GtkCMCTreeNode *node = NULL;
5540 if( ! addrbook.treeSelected ) return;
5541 node = addrbook.treeSelected;
5542 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5543 obj = gtk_cmctree_node_get_row_data( ctree, node );
5544 if( obj == NULL ) return;
5546 ds = addressbook_find_datasource( node );
5547 if( ds == NULL ) return;
5548 adbase = ( AddrBookBase * ) ds->rawDataSource;
5549 cache = adbase->addressCache;
5550 addressbook_exp_ldif( cache );
5553 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5555 addrduplicates_find(GTK_WINDOW(addrbook.window));
5558 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5560 addressbook_custom_attr_edit();
5563 static void addressbook_start_drag(GtkWidget *widget, gint button,
5567 GdkDragContext *context;
5568 if (addressbook_target_list == NULL)
5569 addressbook_target_list = gtk_target_list_new(
5570 addressbook_drag_types, 1);
5571 context = gtk_drag_begin(widget, addressbook_target_list,
5572 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5573 gtk_drag_set_icon_default(context);
5576 static void addressbook_drag_data_get(GtkWidget *widget,
5577 GdkDragContext *drag_context,
5578 GtkSelectionData *selection_data,
5583 AddrItemObject *aio = NULL;
5584 AddressObject *pobj = NULL;
5585 AdapterDSource *ads = NULL;
5586 AddressDataSource *ds = NULL;
5589 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5591 if( pobj == NULL ) return;
5593 if( pobj->type == ADDR_DATASOURCE ) {
5594 ads = ADAPTER_DSOURCE(pobj);
5595 ds = ads->dataSource;
5596 } else if (pobj->type == ADDR_ITEM_GROUP) {
5601 else if( pobj->type != ADDR_INTERFACE ) {
5602 ds = addressbook_find_datasource( addrbook.treeSelected );
5608 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5609 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5610 GTK_CMCTREE_NODE(cur->data));
5611 while (aio && aio->type != ADDR_ITEM_PERSON) {
5616 if (aio && aio->type == ADDR_ITEM_PERSON) {
5617 if( ds && ds->interface && ds->interface->readOnly)
5618 gtk_selection_data_set(selection_data,
5619 selection_data->target, 8,
5620 (const guchar *)"Dummy_addr_copy", 15);
5622 gtk_selection_data_set(selection_data,
5623 selection_data->target, 8,
5624 (const guchar *)"Dummy_addr_move", 15);
5628 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5629 GdkDragContext *context,
5636 GtkCMCTreeNode *node = NULL;
5637 gboolean acceptable = FALSE;
5638 gint height = addrbook.ctree->allocation.height;
5639 gint total_height = addrbook.ctree->requisition.height;
5640 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5641 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5642 gfloat vpos = pos->value;
5644 if (gtk_cmclist_get_selection_info
5645 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5647 if (y > height - 24 && height + vpos < total_height) {
5648 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5649 gtk_adjustment_changed(pos);
5651 if (y < 24 && y > 0) {
5652 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5653 gtk_adjustment_changed(pos);
5655 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5658 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5659 if( obj->type == ADDR_ITEM_FOLDER
5660 || obj->type == ADDR_ITEM_GROUP)
5663 AdapterDSource *ads = NULL;
5664 AddressDataSource *ds = NULL;
5665 ads = ADAPTER_DSOURCE(obj);
5666 if (ads == NULL ){ return FALSE;}
5667 ds = ads->dataSource;
5668 if (ds == NULL ) { return FALSE;}
5676 g_signal_handlers_block_by_func
5678 G_CALLBACK(addressbook_tree_selected), NULL);
5679 gtk_sctree_select( GTK_SCTREE(widget), node);
5680 g_signal_handlers_unblock_by_func
5682 G_CALLBACK(addressbook_tree_selected), NULL);
5683 gdk_drag_status(context,
5684 (context->actions == GDK_ACTION_COPY ?
5685 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5687 gdk_drag_status(context, 0, time);
5692 static void addressbook_drag_leave_cb(GtkWidget *widget,
5693 GdkDragContext *context,
5697 if (addrbook.treeSelected) {
5698 g_signal_handlers_block_by_func
5700 G_CALLBACK(addressbook_tree_selected), NULL);
5701 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5702 g_signal_handlers_unblock_by_func
5704 G_CALLBACK(addressbook_tree_selected), NULL);
5709 static void addressbook_drag_received_cb(GtkWidget *widget,
5710 GdkDragContext *drag_context,
5713 GtkSelectionData *data,
5719 GtkCMCTreeNode *node;
5720 GtkCMCTreeNode *lastopened = addrbook.opened;
5722 if (!strncmp(data->data, "Dummy_addr", 10)) {
5723 if (gtk_cmclist_get_selection_info
5724 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5728 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5729 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5732 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5733 if (drag_context->action == GDK_ACTION_COPY ||
5734 !strcmp(data->data, "Dummy_addr_copy"))
5735 addressbook_clip_copy_cb(NULL, NULL);
5737 addressbook_clip_cut_cb(NULL, NULL);
5738 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5739 addressbook_clip_paste_cb(NULL,NULL);
5740 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5741 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5742 gtk_drag_finish(drag_context, TRUE, TRUE, time);