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;
136 static GdkPixbuf *folderopenxpm;
137 static GdkPixbuf *groupxpm;
138 static GdkPixbuf *interfacexpm;
139 static GdkPixbuf *bookxpm;
140 static GdkPixbuf *addressxpm;
141 static GdkPixbuf *vcardxpm;
142 static GdkPixbuf *jpilotxpm;
143 static GdkPixbuf *categoryxpm;
144 static GdkPixbuf *ldapxpm;
145 static GdkPixbuf *addrsearchxpm;
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);
171 static void addressbook_button_set_sensitive (void);
173 static gboolean address_index_has_focus = FALSE;
174 static gboolean address_list_has_focus = FALSE;
176 /* callback functions */
177 static void addressbook_del_clicked (GtkButton *button,
179 static void addressbook_reg_clicked (GtkButton *button,
181 static void addressbook_to_clicked (GtkButton *button,
183 static void addressbook_lup_clicked (GtkButton *button,
185 static void addressbook_close_clicked (GtkButton *button,
188 static void addressbook_tree_selected (GtkCMCTree *ctree,
189 GtkCMCTreeNode *node,
192 static void addressbook_select_row_tree (GtkCMCTree *ctree,
193 GtkCMCTreeNode *node,
196 static void addressbook_list_row_selected (GtkCMCTree *clist,
197 GtkCMCTreeNode *node,
200 static void addressbook_list_row_unselected (GtkCMCTree *clist,
201 GtkCMCTreeNode *node,
204 static void addressbook_person_expand_node (GtkCMCTree *ctree,
207 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
211 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
212 GdkEventButton *event,
214 static gboolean addressbook_list_button_released(GtkWidget *widget,
215 GdkEventButton *event,
217 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
218 GdkEventButton *event,
220 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
221 GdkEventButton *event,
224 static void addressbook_new_folder_cb (GtkAction *action,
226 static void addressbook_new_group_cb (GtkAction *action,
228 static void addressbook_treenode_edit_cb (GtkAction *action,
230 static void addressbook_treenode_delete_cb (GtkAction *action,
233 static void addressbook_change_node_name (GtkCMCTreeNode *node,
236 static void addressbook_new_address_cb (GtkAction *action,
238 static void addressbook_edit_address_cb (GtkAction *action,
240 static void addressbook_delete_address_cb (GtkAction *action,
243 static void close_cb (GtkAction *action,
245 static void addressbook_file_save_cb (GtkAction *action,
248 /* Data source edit stuff */
249 static void addressbook_new_book_cb (GtkAction *action,
251 static void addressbook_new_vcard_cb (GtkAction *action,
255 static void addressbook_new_jpilot_cb (GtkAction *action,
260 static void addressbook_new_ldap_cb (GtkAction *action,
264 static void addressbook_set_clist (AddressObject *obj,
267 static void addressbook_load_tree (void);
268 void addressbook_read_file (void);
270 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
272 static void addressbook_treenode_remove_item ( void );
274 static AddressDataSource *addressbook_find_datasource
275 (GtkCMCTreeNode *node );
277 static AddressBookFile *addressbook_get_book_file(void);
279 static GtkCMCTreeNode *addressbook_node_add_folder
280 (GtkCMCTreeNode *node,
281 AddressDataSource *ds,
282 ItemFolder *itemFolder,
283 AddressObjectType otype);
284 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
285 AddressDataSource *ds,
286 ItemGroup *itemGroup);
287 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
288 GtkCMCTreeNode *parent);
289 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
290 GtkCMCTreeNode *node);
291 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
293 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
296 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
299 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
301 AddressTypeControlItem *atci,
302 AddressTypeControlItem *atciMail);
303 static void addressbook_folder_refresh_one_person(GtkCMCTree *clist,
305 static void addressbook_folder_remove_one_person(GtkCMCTree *clist,
307 static void addressbook_folder_remove_node (GtkCMCTree *clist,
308 GtkCMCTreeNode *node);
310 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
311 gboolean force_focus );
313 /* LUT's and IF stuff */
314 static void addressbook_free_treenode ( gpointer data );
315 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
316 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
318 static void addrbookctl_build_map (GtkWidget *window);
319 static void addrbookctl_build_iflist (void);
320 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
321 static void addrbookctl_build_ifselect (void);
323 static void addrbookctl_free_interface (AdapterInterface *adapter);
324 static void addrbookctl_free_datasource (AdapterDSource *adapter);
325 static void addrbookctl_free_folder (AdapterFolder *adapter);
326 static void addrbookctl_free_group (AdapterGroup *adapter);
328 static void addressbook_list_select_clear ( void );
329 static void addressbook_list_select_add ( AddrItemObject *aio,
330 AddressDataSource *ds );
331 static void addressbook_list_select_remove ( AddrItemObject *aio );
333 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
334 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
335 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
336 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
337 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
338 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
339 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
340 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
341 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
342 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
343 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
344 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
345 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
346 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
348 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
351 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
353 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
355 static void addressbook_start_drag(GtkWidget *widget, gint button,
358 static void addressbook_drag_data_get(GtkWidget *widget,
359 GdkDragContext *drag_context,
360 GtkSelectionData *selection_data,
364 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
365 GdkDragContext *context,
370 static void addressbook_drag_leave_cb(GtkWidget *widget,
371 GdkDragContext *context,
374 static void addressbook_drag_received_cb(GtkWidget *widget,
375 GdkDragContext *drag_context,
378 GtkSelectionData *data,
382 static void addressbook_list_menu_setup( void );
384 static GtkTargetEntry addressbook_drag_types[] =
386 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
389 static GtkTargetList *addressbook_target_list = NULL;
391 static void about_show_cb(GtkAction *action, gpointer data)
396 static GtkActionEntry addressbook_entries[] =
398 {"Menu", NULL, "Menu" },
400 {"Book", NULL, N_("_Book") },
401 {"Address", NULL, N_("_Edit") },
402 {"Tools", NULL, N_("_Tools") },
403 {"Help", NULL, N_("_Help") },
406 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
407 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
408 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
412 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
415 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
417 {"Book/---", NULL, "---", NULL, NULL, NULL },
419 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
420 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
421 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
422 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
423 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
426 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
427 {"Address/---", NULL, "---", NULL, NULL, NULL },
428 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
429 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
430 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
431 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
432 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
433 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
434 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
435 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
436 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
437 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
438 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
442 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
443 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
444 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
445 {"Tools/---", NULL, "---", NULL, NULL, NULL },
446 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
447 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
448 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
449 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
450 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
453 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
457 static GtkActionEntry addressbook_tree_popup_entries[] =
459 {"ABTreePopup", NULL, "ABTreePopup" },
460 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
461 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
462 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
463 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
464 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
465 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
466 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
467 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
468 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
469 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
472 static GtkActionEntry addressbook_list_popup_entries[] =
474 {"ABListPopup", NULL, "ABListPopup" },
475 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
476 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
477 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
478 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
479 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
480 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
481 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
482 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
483 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
484 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
485 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
486 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
487 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
489 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
494 * Structure of error message table.
496 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
497 struct _ErrMsgTableEntry {
502 static gchar *_errMsgUnknown_ = N_( "Unknown" );
505 * Lookup table of error messages for general errors. Note that a NULL
506 * description signifies the end of the table.
508 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
509 { MGU_SUCCESS, N_("Success") },
510 { MGU_BAD_ARGS, N_("Bad arguments") },
511 { MGU_NO_FILE, N_("File not specified") },
512 { MGU_OPEN_FILE, N_("Error opening file") },
513 { MGU_ERROR_READ, N_("Error reading file") },
514 { MGU_EOF, N_("End of file encountered") },
515 { MGU_OO_MEMORY, N_("Error allocating memory") },
516 { MGU_BAD_FORMAT, N_("Bad file format") },
517 { MGU_ERROR_WRITE, N_("Error writing to file") },
518 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
519 { MGU_NO_PATH, N_("No path specified") },
525 * Lookup table of error messages for LDAP errors.
527 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
528 { LDAPRC_SUCCESS, N_("Success") },
529 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
530 { LDAPRC_INIT, N_("Error initializing LDAP") },
531 { LDAPRC_BIND, N_("Error binding to LDAP server") },
532 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
533 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
534 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
535 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
536 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
537 { LDAPRC_TLS, N_("Error starting TLS connection") },
538 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
539 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
540 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
541 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
547 * Lookup message for specified error code.
548 * \param lut Lookup table.
549 * \param code Code to lookup.
550 * \return Description associated to code.
552 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
554 ErrMsgTableEntry entry;
557 for( i = 0; ; i++ ) {
559 if( entry.description == NULL ) break;
560 if( entry.code == code ) {
561 desc = entry.description;
566 desc = _errMsgUnknown_;
571 static gboolean lastCanLookup = FALSE;
573 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
575 if (add_and_delete) {
576 gtk_widget_show(addrbook.edit_btn);
577 gtk_widget_show(addrbook.del_btn);
578 gtk_widget_show(addrbook.reg_btn);
580 gtk_widget_hide(addrbook.edit_btn);
581 gtk_widget_hide(addrbook.del_btn);
582 gtk_widget_hide(addrbook.reg_btn);
586 gtk_widget_show(addrbook.lup_btn);
587 gtk_widget_show(addrbook.entry);
588 gtk_widget_show(addrbook.label);
590 gtk_widget_hide(addrbook.lup_btn);
591 gtk_widget_hide(addrbook.entry);
592 gtk_widget_hide(addrbook.label);
595 lastCanLookup = lookup;
598 gtk_widget_show(addrbook.to_btn);
599 gtk_widget_show(addrbook.cc_btn);
600 gtk_widget_show(addrbook.bcc_btn);
602 gtk_widget_hide(addrbook.to_btn);
603 gtk_widget_hide(addrbook.cc_btn);
604 gtk_widget_hide(addrbook.bcc_btn);
608 void addressbook_open(Compose *target)
610 /* Initialize all static members */
611 if( _clipBoard_ == NULL ) {
612 _clipBoard_ = addrclip_create();
614 if( _addressIndex_ != NULL ) {
615 addrclip_set_index( _clipBoard_, _addressIndex_ );
617 if( _addressSelect_ == NULL ) {
618 _addressSelect_ = addrselect_list_create();
620 if (!addrbook.window) {
621 addressbook_read_file();
622 addressbook_create();
623 addressbook_load_tree();
624 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
625 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
628 gtk_widget_hide(addrbook.window);
631 gtk_widget_show_all(addrbook.window);
633 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
634 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
636 if (!prefs_common.addressbook_use_editaddress_dialog)
637 addressbook_edit_person_widgetset_hide();
639 address_completion_start(addrbook.window);
641 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
642 addressbook_set_target_compose(target);
646 * Destroy addressbook.
648 void addressbook_destroy( void ) {
649 /* Free up address stuff */
650 if( _addressSelect_ != NULL ) {
651 addrselect_list_free( _addressSelect_ );
653 if( _clipBoard_ != NULL ) {
654 addrclip_free( _clipBoard_ );
656 if( _addressIndex_ != NULL ) {
657 addrindex_free_index( _addressIndex_ );
658 addrindex_teardown();
660 _addressSelect_ = NULL;
662 _addressIndex_ = NULL;
665 void addressbook_set_target_compose(Compose *target)
667 addrbook.target_compose = target;
668 addressbook_button_set_sensitive();
671 Compose *addressbook_get_target_compose(void)
673 return addrbook.target_compose;
677 * Refresh addressbook and save to file(s).
679 void addressbook_refresh( void )
681 if (addrbook.window) {
682 if (addrbook.treeSelected) {
683 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
684 addrbook.treeSelected);
685 addressbook_set_clist(
686 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
687 addrbook.treeSelected),
692 addressbook_export_to_file();
695 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
697 if (event && event->keyval == GDK_Escape)
699 else if (event && event->keyval == GDK_Delete) {
700 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
701 if ( /* address_index_has_focus || */ address_list_has_focus )
702 addressbook_del_clicked(NULL, NULL);
708 *\brief Save Gtk object size to prefs dataset
710 static void addressbook_size_allocate_cb(GtkWidget *widget,
711 GtkAllocation *allocation)
713 g_return_if_fail(allocation != NULL);
715 prefs_common.addressbookwin_width = allocation->width;
716 prefs_common.addressbookwin_height = allocation->height;
719 static gint sort_column_number = 0;
720 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
722 static gint list_case_sort(
723 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
725 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
726 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
727 gchar *name1 = NULL, *name2 = NULL;
728 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
729 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
731 if( aio1->type == aio2->type ) {
733 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
735 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
736 if( ! name1 ) return ( name2 != NULL );
737 if( ! name2 ) return -1;
738 return g_utf8_collate( name1, name2 );
740 /* Order groups before person */
741 if( aio1->type == ITEMTYPE_GROUP ) {
742 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
743 } else if( aio2->type == ITEMTYPE_GROUP ) {
744 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
750 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
751 const GtkSortType sort_type)
754 GtkWidget *hbox, *label, *arrow;
756 sort_column_number = col;
757 sort_column_type = sort_type;
758 gtk_cmclist_set_compare_func(clist, list_case_sort);
759 gtk_cmclist_set_sort_type(clist, sort_type);
760 gtk_cmclist_set_sort_column(clist, col);
762 gtk_cmclist_freeze(clist);
763 gtk_cmclist_sort(clist);
765 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
766 hbox = gtk_hbox_new(FALSE, 4);
767 label = gtk_label_new(gettext(list_titles[pos]));
768 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
771 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
772 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
773 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
776 gtk_widget_show_all(hbox);
777 gtk_cmclist_set_column_widget(clist, pos, hbox);
780 gtk_cmclist_thaw(clist);
783 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
785 static GtkSortType sort_type = GTK_SORT_ASCENDING;
787 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
789 addressbook_sort_list(clist, COL_NAME, sort_type);
792 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
794 static GtkSortType sort_type = GTK_SORT_ASCENDING;
796 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
798 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
801 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
803 static GtkSortType sort_type = GTK_SORT_ASCENDING;
805 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
807 addressbook_sort_list(clist, COL_REMARKS, sort_type);
810 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
813 address_index_has_focus = TRUE;
817 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
820 address_index_has_focus = FALSE;
821 if (!prefs_common.addressbook_use_editaddress_dialog
822 && !address_list_has_focus)
823 addressbook_address_list_disable_some_actions();
827 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
830 address_list_has_focus = TRUE;
834 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
837 address_list_has_focus = FALSE;
838 if (!prefs_common.addressbook_use_editaddress_dialog
839 && !address_index_has_focus)
840 addressbook_address_list_disable_some_actions();
844 /* save hpane and vpane's handle position when it moves */
845 static void addressbook_pane_save_position(void)
848 prefs_common.addressbook_hpaned_pos =
849 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
851 prefs_common.addressbook_vpaned_pos =
852 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
856 * Create the address book widgets. The address book contains two CTree widgets: the
857 * address index tree on the left and the address list on the right.
859 * The address index tree displays a hierarchy of interfaces and groups. Each node in
860 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
861 * data sources and folder objects.
863 * The address list displays group, person and email objects. These items are linked
864 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
867 * In the tradition of MVC architecture, the data stores have been separated from the
868 * GUI components. The addrindex.c file provides the interface to all data stores.
870 static void addressbook_create(void)
876 GtkWidget *ctree_swin;
878 GtkWidget *editaddress_vbox;
879 GtkWidget *clist_vbox;
880 GtkWidget *clist_swin;
887 GtkWidget *statusbar;
898 GtkWidget *close_btn;
899 GtkWidget *tree_popup;
900 GtkWidget *list_popup;
902 GtkUIManager *ui_manager;
903 GtkActionGroup *action_group;
904 gchar *index_titles[N_INDEX_COLS];
908 static GdkGeometry geometry;
910 debug_print("Creating addressbook window...\n");
912 index_titles[COL_SOURCES] = _("Sources");
914 /* Address book window */
915 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
916 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
917 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
918 gtk_widget_realize(window);
920 g_signal_connect(G_OBJECT(window), "delete_event",
921 G_CALLBACK(addressbook_close), NULL);
922 g_signal_connect(G_OBJECT(window), "size_allocate",
923 G_CALLBACK(addressbook_size_allocate_cb), NULL);
924 g_signal_connect(G_OBJECT(window), "key_press_event",
925 G_CALLBACK(key_pressed), NULL);
926 MANAGE_WINDOW_SIGNALS_CONNECT(window);
928 vbox = gtk_vbox_new(FALSE, 0);
929 gtk_container_add(GTK_CONTAINER(window), vbox);
932 ui_manager = gtk_ui_manager_new();
933 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
934 G_N_ELEMENTS(addressbook_entries), NULL);
935 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
936 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
937 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
938 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
941 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_POPUP)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
990 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
991 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
992 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
995 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
997 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
1000 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1002 hildon_window_set_menu(HILDON_WINDOW(window), GTK_MENU(menubar));
1005 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1006 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1007 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1009 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1010 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1011 GTK_POLICY_AUTOMATIC,
1012 GTK_POLICY_AUTOMATIC);
1013 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1016 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1017 GTK_WIDGET_UNSET_FLAGS(GTK_CMCLIST(ctree)->column[0].button,
1020 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1021 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1022 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1023 if (prefs_common.enable_dotted_lines) {
1024 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_DOTTED);
1025 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1026 GTK_CMCTREE_EXPANDER_SQUARE);
1028 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1029 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1030 GTK_CMCTREE_EXPANDER_TRIANGLE);
1032 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1033 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1034 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1035 addressbook_treenode_compare_func);
1037 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1038 G_CALLBACK(addressbook_tree_selected), NULL);
1039 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1040 G_CALLBACK(addressbook_tree_button_pressed),
1042 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1043 G_CALLBACK(addressbook_tree_button_released),
1046 g_signal_connect(G_OBJECT(ctree), "select_row",
1047 G_CALLBACK(addressbook_select_row_tree), NULL);
1049 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1050 addressbook_drag_types, 1,
1051 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1052 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1053 G_CALLBACK(addressbook_drag_motion_cb),
1055 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1056 G_CALLBACK(addressbook_drag_leave_cb),
1058 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1059 G_CALLBACK(addressbook_drag_received_cb),
1061 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1062 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1063 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1064 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1066 clist_vbox = gtk_vbox_new(FALSE, 4);
1068 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1069 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1070 GTK_POLICY_AUTOMATIC,
1071 GTK_POLICY_AUTOMATIC);
1072 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1075 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1076 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1077 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_EXTENDED);
1078 if (prefs_common.enable_dotted_lines) {
1079 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_DOTTED);
1080 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1081 GTK_CMCTREE_EXPANDER_SQUARE);
1083 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1084 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1085 GTK_CMCTREE_EXPANDER_TRIANGLE);
1087 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1088 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1089 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1091 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1093 gtk_widget_set_size_request(clist, -1, 80);
1095 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1096 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1097 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1098 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1099 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1100 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1101 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1102 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1103 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1104 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1105 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1107 for (i = 0; i < N_LIST_COLS; i++)
1108 GTK_WIDGET_UNSET_FLAGS(GTK_CMCLIST(clist)->column[i].button,
1111 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1112 G_CALLBACK(addressbook_list_row_selected), NULL);
1113 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1114 G_CALLBACK(addressbook_list_row_unselected), NULL);
1115 g_signal_connect(G_OBJECT(clist), "button_press_event",
1116 G_CALLBACK(addressbook_list_button_pressed),
1118 g_signal_connect(G_OBJECT(clist), "button_release_event",
1119 G_CALLBACK(addressbook_list_button_released),
1121 g_signal_connect(G_OBJECT(clist), "tree_expand",
1122 G_CALLBACK(addressbook_person_expand_node), NULL );
1123 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1124 G_CALLBACK(addressbook_person_collapse_node), NULL );
1125 g_signal_connect(G_OBJECT(clist), "start_drag",
1126 G_CALLBACK(addressbook_start_drag), NULL);
1127 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1128 G_CALLBACK(addressbook_drag_data_get), NULL);
1129 hbox = gtk_hbox_new(FALSE, 4);
1130 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1132 label = gtk_label_new(_("Lookup name:"));
1133 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1135 entry = gtk_entry_new();
1136 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1138 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1140 g_signal_connect(G_OBJECT(entry), "key_press_event",
1141 G_CALLBACK(addressbook_entry_key_pressed),
1144 if (!prefs_common.addressbook_use_editaddress_dialog) {
1145 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1146 vpaned = gtk_vpaned_new();
1147 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1148 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1151 editaddress_vbox = NULL;
1153 hpaned = gtk_hpaned_new();
1154 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1155 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1156 if (prefs_common.addressbook_use_editaddress_dialog)
1157 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1159 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1162 hsbox = gtk_hbox_new(FALSE, 0);
1163 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1164 statusbar = gtk_statusbar_new();
1165 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1168 hbbox = gtk_hbutton_box_new();
1169 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1170 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1171 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1172 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1174 gtkut_stock_button_add_help(hbbox, &help_btn);
1176 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1177 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1178 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1179 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1180 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1181 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1182 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1183 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1184 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1187 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1188 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1189 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1191 g_signal_connect(G_OBJECT(help_btn), "clicked",
1192 G_CALLBACK(manual_open_with_anchor_cb),
1193 MANUAL_ANCHOR_ADDRBOOK);
1195 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1196 G_CALLBACK(addressbook_edit_clicked), NULL);
1197 g_signal_connect(G_OBJECT(del_btn), "clicked",
1198 G_CALLBACK(addressbook_del_clicked), NULL);
1199 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1200 G_CALLBACK(addressbook_reg_clicked), NULL);
1201 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1202 G_CALLBACK(addressbook_lup_clicked), NULL);
1204 to_btn = gtk_button_new_with_label
1205 (prefs_common_translated_header_name("To:"));
1206 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1207 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1208 cc_btn = gtk_button_new_with_label
1209 (prefs_common_translated_header_name("Cc:"));
1210 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1211 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1212 bcc_btn = gtk_button_new_with_label
1213 (prefs_common_translated_header_name("Bcc:"));
1214 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1215 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1217 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1218 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1219 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1221 g_signal_connect(G_OBJECT(to_btn), "clicked",
1222 G_CALLBACK(addressbook_to_clicked),
1223 GINT_TO_POINTER(COMPOSE_TO));
1224 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1225 G_CALLBACK(addressbook_to_clicked),
1226 GINT_TO_POINTER(COMPOSE_CC));
1227 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1228 G_CALLBACK(addressbook_to_clicked),
1229 GINT_TO_POINTER(COMPOSE_BCC));
1230 g_signal_connect(G_OBJECT(close_btn), "clicked",
1231 G_CALLBACK(addressbook_close_clicked), NULL);
1233 /* Build icons for interface */
1234 stock_pixbuf_gdk( window, STOCK_PIXMAP_INTERFACE,
1237 /* Build control tables */
1238 addrbookctl_build_map(window);
1239 addrbookctl_build_iflist();
1240 addrbookctl_build_ifselect();
1242 addrbook.clist = NULL;
1244 /* Add each interface into the tree as a root level folder */
1245 nodeIf = _addressInterfaceList_;
1247 AdapterInterface *adapter = nodeIf->data;
1248 AddressInterface *iface = adapter->interface;
1249 nodeIf = g_list_next(nodeIf);
1251 if(iface->useInterface) {
1252 AddressTypeControlItem *atci = adapter->atci;
1253 text = atci->displayName;
1255 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1256 NULL, NULL, &text, FOLDER_SPACING,
1260 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1261 gtk_cmctree_node_set_row_data_full(
1262 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1263 addressbook_free_treenode );
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1282 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1283 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1285 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1286 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1287 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1288 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1289 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1290 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1291 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1292 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1293 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1294 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1295 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1296 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1297 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1298 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1300 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1302 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1303 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1305 addrbook.window = window;
1306 addrbook.hpaned = hpaned;
1307 addrbook.vpaned = vpaned;
1308 addrbook.menubar = menubar;
1309 addrbook.ctree = ctree;
1312 addrbook.editaddress_vbox = editaddress_vbox;
1313 addrbook.clist = clist;
1314 addrbook.label = label;
1315 addrbook.entry = entry;
1316 addrbook.statusbar = statusbar;
1317 addrbook.status_cid = gtk_statusbar_get_context_id(
1318 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1320 addrbook.help_btn = help_btn;
1321 addrbook.edit_btn = edit_btn;
1322 addrbook.del_btn = del_btn;
1323 addrbook.reg_btn = reg_btn;
1324 addrbook.lup_btn = lup_btn;
1325 addrbook.to_btn = to_btn;
1326 addrbook.cc_btn = cc_btn;
1327 addrbook.bcc_btn = bcc_btn;
1329 addrbook.tree_popup = tree_popup;
1330 addrbook.list_popup = list_popup;
1331 addrbook.ui_manager = ui_manager;
1333 addrbook.listSelected = NULL;
1335 if (!geometry.min_height) {
1336 geometry.min_width = ADDRESSBOOK_WIDTH;
1337 geometry.min_height = ADDRESSBOOK_HEIGHT;
1340 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1342 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1343 prefs_common.addressbookwin_height);
1345 if (!prefs_common.addressbook_use_editaddress_dialog) {
1346 if (prefs_common.addressbook_vpaned_pos > 0)
1347 gtk_paned_set_position(GTK_PANED(vpaned),
1348 prefs_common.addressbook_vpaned_pos);
1350 if (prefs_common.addressbook_hpaned_pos > 0)
1351 gtk_paned_set_position(GTK_PANED(hpaned),
1352 prefs_common.addressbook_hpaned_pos);
1355 gtk_widget_show_all(window);
1359 * Close address book window and save to file(s).
1361 static gint addressbook_close( void ) {
1362 address_completion_end(addrbook.window);
1363 if (!prefs_common.addressbook_use_editaddress_dialog)
1364 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1366 addressbook_pane_save_position();
1368 gtk_widget_hide(addrbook.window);
1369 addressbook_export_to_file();
1374 * Display message in status line.
1375 * \param msg Message to display.
1377 static void addressbook_status_show( gchar *msg ) {
1378 if( addrbook.statusbar != NULL ) {
1380 GTK_STATUSBAR(addrbook.statusbar),
1381 addrbook.status_cid );
1384 GTK_STATUSBAR(addrbook.statusbar),
1385 addrbook.status_cid, msg );
1390 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1394 *addressbook_msgbuf = '\0';
1396 name = addrindex_ds_get_name( ds );
1397 retVal = addrindex_ds_get_status_code( ds );
1398 if( retVal == MGU_SUCCESS ) {
1399 g_snprintf( addressbook_msgbuf,
1400 sizeof(addressbook_msgbuf), "%s", name );
1403 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1404 g_snprintf( addressbook_msgbuf,
1405 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1408 addressbook_status_show( addressbook_msgbuf );
1411 static void addressbook_button_set_sensitive(void)
1413 gboolean to_sens = FALSE;
1414 gboolean cc_sens = FALSE;
1415 gboolean bcc_sens = FALSE;
1417 if (!addrbook.window) return;
1419 if (addrbook.target_compose) {
1425 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1426 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1427 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1430 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1432 addressbook_edit_address_cb(NULL, NULL);
1435 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1437 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1441 * Delete one or more objects from address list.
1443 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1445 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1446 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1447 AddressObject *pobj;
1448 AdapterDSource *ads = NULL;
1449 GtkCMCTreeNode *nodeList;
1452 AddressBookFile *abf = NULL;
1453 AddressDataSource *ds = NULL;
1454 AddressInterface *iface;
1455 AddrItemObject *aio;
1456 AddrSelectItem *item;
1458 gboolean refreshList = FALSE;
1460 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1461 g_return_if_fail(pobj != NULL);
1463 /* Test whether anything selected for deletion */
1464 nodeList = addrbook.listSelected;
1466 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1467 if( aio == NULL) return;
1468 ds = addressbook_find_datasource( addrbook.treeSelected );
1469 if( ds == NULL ) return;
1471 /* Test for read only */
1472 iface = ds->interface;
1473 if( iface->readOnly ) {
1474 alertpanel( _("Delete address(es)"),
1475 _("This address data is readonly and cannot be deleted."),
1476 GTK_STOCK_CLOSE, NULL, NULL );
1480 /* Test whether Ok to proceed */
1482 if( pobj->type == ADDR_DATASOURCE ) {
1483 ads = ADAPTER_DSOURCE(pobj);
1484 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1486 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1489 else if( pobj->type == ADDR_ITEM_GROUP ) {
1492 if( ! procFlag ) return;
1493 abf = ds->rawDataSource;
1494 if( abf == NULL ) return;
1496 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1497 g_signal_handlers_block_by_func
1498 (G_OBJECT(addrbook.clist),
1499 G_CALLBACK(addressbook_list_row_unselected), NULL);
1501 /* Process deletions */
1502 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1503 GList *groups = NULL, *persons = NULL, *emails = NULL;
1504 gboolean group_delete = TRUE;
1505 /* Items inside folders */
1506 list = addrselect_get_list( _addressSelect_ );
1507 /* Confirm deletion */
1511 node = g_list_next( node );
1512 aio = ( AddrItemObject * ) item->addressItem;
1513 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1514 group_delete = FALSE;
1519 aval = alertpanel( _("Delete group"),
1520 _("Really delete the group(s)?\n"
1521 "The addresses it contains will not be lost."),
1522 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1523 if( aval != G_ALERTALTERNATE ) {
1527 aval = alertpanel( _("Delete address(es)"),
1528 _("Really delete the address(es)?"),
1529 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1530 if( aval != G_ALERTALTERNATE ) {
1535 /* first, set lists of groups and persons to remove */
1539 node = g_list_next( node );
1540 aio = ( AddrItemObject * ) item->addressItem;
1543 if( aio->type == ADDR_ITEM_GROUP ) {
1544 groups = g_list_prepend(groups, item);
1546 else if( aio->type == ADDR_ITEM_PERSON ) {
1547 persons = g_list_prepend(persons, item);
1550 /* then set list of emails to remove *if* they're not children of
1551 * persons to remove */
1555 node = g_list_next( node );
1556 aio = ( AddrItemObject * ) item->addressItem;
1559 if( aio->type == ADDR_ITEM_EMAIL ) {
1560 ItemEMail *sitem = ( ItemEMail * ) aio;
1561 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1562 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1563 emails = g_list_prepend(emails, item);
1565 /* else, the email will be removed via the parent person */
1568 /* then delete groups */
1572 node = g_list_next( node );
1573 aio = ( AddrItemObject * ) item->addressItem;
1576 if( aio->type == ADDR_ITEM_GROUP ) {
1577 ItemGroup *item = ( ItemGroup * ) aio;
1578 GtkCMCTreeNode *nd = NULL;
1579 nd = addressbook_find_group_node( addrbook.opened, item );
1580 item = addrbook_remove_group( abf, item );
1582 addritem_free_item_group( item );
1584 /* Remove group from parent node */
1585 gtk_cmctree_remove_node( ctree, nd );
1589 /* then delete persons */
1593 node = g_list_next( node );
1594 aio = ( AddrItemObject * ) item->addressItem;
1597 if( aio->type == ADDR_ITEM_PERSON ) {
1598 ItemPerson *item = ( ItemPerson * ) aio;
1599 item->status = DELETE_ENTRY;
1600 addressbook_folder_remove_one_person( clist, item );
1601 if (pobj->type == ADDR_ITEM_FOLDER)
1602 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1603 item = addrbook_remove_person( abf, item );
1605 if (ds && ds->type == ADDR_IF_LDAP) {
1606 LdapServer *server = ds->rawDataSource;
1607 ldapsvr_set_modified(server, TRUE);
1608 ldapsvr_update_book(server, item);
1612 gchar *filename = addritem_person_get_picture(item);
1613 if (filename && is_file_exist(filename))
1614 claws_unlink(filename);
1616 addritem_free_item_person( item );
1620 /* then delete emails */
1624 node = g_list_next( node );
1625 aio = ( AddrItemObject * ) item->addressItem;
1629 if( aio->type == ADDR_ITEM_EMAIL ) {
1630 ItemEMail *sitem = ( ItemEMail * ) aio;
1631 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1632 sitem = addrbook_person_remove_email( abf, person, sitem );
1634 addrcache_remove_email(abf->addressCache, sitem);
1635 addritem_free_item_email( sitem );
1637 addressbook_folder_refresh_one_person( clist, person );
1640 g_list_free( groups );
1641 g_list_free( persons );
1642 g_list_free( emails );
1643 g_list_free( list );
1644 addressbook_list_select_clear();
1646 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1647 addressbook_set_clist(
1648 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1652 addrbook_set_dirty(abf, TRUE);
1653 addressbook_export_to_file();
1654 addressbook_list_menu_setup();
1657 else if( pobj->type == ADDR_ITEM_GROUP ) {
1658 /* Items inside groups */
1659 list = addrselect_get_list( _addressSelect_ );
1663 node = g_list_next( node );
1664 aio = ( AddrItemObject * ) item->addressItem;
1665 if( aio->type == ADDR_ITEM_EMAIL ) {
1666 ItemEMail *item = ( ItemEMail * ) aio;
1667 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1668 item = addrbook_person_remove_email( abf, person, item );
1670 addritem_free_item_email( item );
1674 g_list_free( list );
1675 addressbook_list_select_clear();
1676 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1677 addressbook_set_clist(
1678 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1682 addrbook_set_dirty(abf, TRUE);
1683 addressbook_export_to_file();
1684 addressbook_list_menu_setup();
1688 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1689 gtk_cmctree_remove_node( clist, nodeList );
1691 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1692 g_signal_handlers_unblock_by_func
1693 (G_OBJECT(addrbook.clist),
1694 G_CALLBACK(addressbook_list_row_unselected), NULL);
1697 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1699 addressbook_new_address_cb( NULL, NULL );
1702 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1705 gchar *address = NULL;
1707 if( aio->type == ADDR_ITEM_EMAIL ) {
1708 ItemPerson *person = NULL;
1709 ItemEMail *email = ( ItemEMail * ) aio;
1711 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1712 if( email->address ) {
1713 if( ADDRITEM_NAME(email) ) {
1714 name = ADDRITEM_NAME(email);
1715 if( *name == '\0' ) {
1716 name = ADDRITEM_NAME(person);
1719 else if( ADDRITEM_NAME(person) ) {
1720 name = ADDRITEM_NAME(person);
1723 buf = g_strdup( email->address );
1725 address = email->address;
1728 else if( aio->type == ADDR_ITEM_PERSON ) {
1729 ItemPerson *person = ( ItemPerson * ) aio;
1730 GList *node = person->listEMail;
1732 name = ADDRITEM_NAME(person);
1734 ItemEMail *email = ( ItemEMail * ) node->data;
1735 address = email->address;
1739 if( name && name[0] != '\0' ) {
1740 if( strchr_with_skip_quote( name, '"', ',' ) )
1741 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1743 buf = g_strdup_printf( "%s <%s>", name, address );
1746 buf = g_strdup( address );
1753 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1757 AddrSelectItem *item;
1758 AddrItemObject *aio;
1761 compose = addrbook.target_compose;
1762 if( ! compose ) return;
1764 /* Nothing selected, but maybe there is something in text entry */
1765 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1767 compose_entry_append(
1768 compose, addr, (ComposeEntryType)data );
1771 /* Select from address list */
1772 list = addrselect_get_list( _addressSelect_ );
1777 node = g_list_next( node );
1778 aio = item->addressItem;
1779 if( aio->type == ADDR_ITEM_PERSON ||
1780 aio->type == ADDR_ITEM_EMAIL ) {
1781 addr = addressbook_format_address( aio );
1782 compose_entry_append(
1783 compose, addr, (ComposeEntryType) data );
1786 else if( aio->type == ADDR_ITEM_GROUP ) {
1787 ItemGroup *group = ( ItemGroup * ) aio;
1788 GList *nodeMail = group->listEMail;
1790 ItemEMail *email = nodeMail->data;
1792 addr = addressbook_format_address(
1793 ( AddrItemObject * ) email );
1794 compose_entry_append(
1795 compose, addr, (ComposeEntryType) data );
1797 nodeMail = g_list_next( nodeMail );
1802 AddressObject *obj = NULL;
1804 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1806 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1807 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1808 GList *nodeMail = itemGroup->listEMail;
1810 ItemEMail *email = nodeMail->data;
1812 addr = addressbook_format_address(
1813 ( AddrItemObject * ) email );
1814 compose_entry_append(
1815 compose, addr, (ComposeEntryType) data );
1817 nodeMail = g_list_next( nodeMail );
1821 g_list_free( list );
1824 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1825 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1826 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1827 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1829 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1830 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1831 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1832 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1834 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1835 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1836 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1837 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1838 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1841 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1842 gboolean canEdit = FALSE;
1843 gboolean canDelete = TRUE;
1844 gboolean canAdd = FALSE;
1845 gboolean canEditTr = TRUE;
1846 gboolean editAddress = FALSE;
1847 gboolean canExport = TRUE;
1848 AddressTypeControlItem *atci = NULL;
1849 AddressDataSource *ds = NULL;
1850 AddressInterface *iface = NULL;
1852 if( obj == NULL ) return;
1853 if( obj->type == ADDR_INTERFACE ) {
1854 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1855 iface = adapter->interface;
1857 if( iface->haveLibrary ) {
1858 /* Enable appropriate File / New command */
1859 atci = adapter->atci;
1860 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1863 canEditTr = canExport = FALSE;
1865 else if( obj->type == ADDR_DATASOURCE ) {
1866 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1867 ds = ads->dataSource;
1868 iface = ds->interface;
1869 if( ! iface->readOnly ) {
1870 canAdd = canEdit = editAddress = canDelete = TRUE;
1872 if( ! iface->haveLibrary ) {
1873 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1876 else if( obj->type == ADDR_ITEM_FOLDER ) {
1877 ds = addressbook_find_datasource( addrbook.treeSelected );
1879 iface = ds->interface;
1880 if( iface->readOnly ) {
1885 canAdd = editAddress = TRUE;
1889 else if( obj->type == ADDR_ITEM_GROUP ) {
1890 ds = addressbook_find_datasource( addrbook.treeSelected );
1892 iface = ds->interface;
1893 if( ! iface->readOnly ) {
1899 if( addrbook.listSelected == NULL )
1903 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1904 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1905 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1906 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1909 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1910 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1911 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1912 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1914 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1915 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1918 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1919 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1923 * Address book tree callback function that responds to selection of tree
1926 * \param ctree Tree widget.
1927 * \param node Node that was selected.
1928 * \param column Column number where selected occurred.
1929 * \param data Pointer to user data.
1931 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1932 gint column, gpointer data)
1934 AddressObject *obj = NULL;
1935 AdapterDSource *ads = NULL;
1936 AddressDataSource *ds = NULL;
1937 ItemFolder *rootFolder = NULL;
1938 AddressObjectType aot;
1940 addrbook.treeSelected = node;
1941 addrbook.listSelected = NULL;
1942 addressbook_status_show( "" );
1943 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1945 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1947 addressbook_set_clist(NULL, TRUE);
1950 addrbook.opened = node;
1952 if( obj->type == ADDR_DATASOURCE ) {
1953 /* Read from file */
1954 static gboolean tVal = TRUE;
1956 ads = ADAPTER_DSOURCE(obj);
1957 if( ads == NULL ) return;
1958 ds = ads->dataSource;
1959 if( ds == NULL ) return;
1961 if( addrindex_ds_get_modify_flag( ds ) ) {
1962 addrindex_ds_read_data( ds );
1965 if( ! addrindex_ds_get_read_flag( ds ) ) {
1966 addrindex_ds_read_data( ds );
1968 addressbook_ds_show_message( ds );
1970 if( ! addrindex_ds_get_access_flag( ds ) ) {
1971 /* Remove existing folders and groups */
1972 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1973 addressbook_tree_remove_children( ctree, node );
1974 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1976 /* Load folders into the tree */
1977 rootFolder = addrindex_ds_get_root_folder( ds );
1978 if( ds && ds->type == ADDR_IF_JPILOT ) {
1979 aot = ADDR_CATEGORY;
1981 else if( ds && ds->type == ADDR_IF_LDAP ) {
1982 aot = ADDR_LDAP_QUERY;
1985 aot = ADDR_ITEM_FOLDER;
1987 addressbook_node_add_folder( node, ds, rootFolder, aot );
1988 addrindex_ds_set_access_flag( ds, &tVal );
1989 gtk_cmctree_expand( ctree, node );
1992 addressbook_set_clist(NULL, TRUE);
1995 /* Update address list */
1996 g_signal_handlers_block_by_func
1998 G_CALLBACK(addressbook_tree_selected), NULL);
1999 addressbook_set_clist( obj, FALSE );
2000 g_signal_handlers_unblock_by_func
2002 G_CALLBACK(addressbook_tree_selected), NULL);
2003 if (!prefs_common.addressbook_use_editaddress_dialog)
2004 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2006 /* Setup main menu selections */
2007 addressbook_menubar_set_sensitive( FALSE );
2008 addressbook_menuitem_set_sensitive( obj, node );
2009 addressbook_list_select_clear();
2010 addressbook_list_menu_setup();
2015 * Setup address list popup menu items. Items are enabled or disabled as
2018 static void addressbook_list_menu_setup( void ) {
2019 GtkCMCTree *clist = NULL;
2020 AddressObject *pobj = NULL;
2021 AddressObject *obj = NULL;
2022 AdapterDSource *ads = NULL;
2023 AddressInterface *iface = NULL;
2024 AddressDataSource *ds = NULL;
2025 gboolean canEdit = FALSE;
2026 gboolean canDelete = FALSE;
2027 gboolean canCut = FALSE;
2028 gboolean canCopy = FALSE;
2029 gboolean canPaste = FALSE;
2030 gboolean canBrowse = FALSE;
2032 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2033 if( pobj == NULL ) return;
2035 clist = GTK_CMCTREE(addrbook.clist);
2036 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2037 if( obj == NULL ) canEdit = FALSE;
2039 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2040 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2042 if( pobj->type == ADDR_DATASOURCE ) {
2043 /* Parent object is a data source */
2044 ads = ADAPTER_DSOURCE(pobj);
2045 ds = ads->dataSource;
2048 iface = ds->interface;
2051 if( ! iface->readOnly ) {
2052 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2053 if (iface->type != ADDR_IF_LDAP)
2054 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2055 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2058 canDelete = canEdit;
2061 else if( pobj->type != ADDR_INTERFACE ) {
2062 /* Parent object is not an interface */
2063 ds = addressbook_find_datasource( addrbook.treeSelected );
2066 iface = ds->interface;
2069 if( ! iface->readOnly ) {
2070 /* Folder or group */
2071 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2072 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2073 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2074 if( obj ) canEdit = TRUE;
2077 if( pobj->type == ADDR_ITEM_FOLDER ) {
2078 if (iface->type != ADDR_IF_LDAP)
2079 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2080 if( obj ) canEdit = TRUE;
2082 canDelete = canEdit;
2084 if( iface->type == ADDR_IF_LDAP ) {
2085 if( obj ) canBrowse = TRUE;
2092 /* Enable cut and paste */
2093 if( ! addrclip_is_empty( _clipBoard_ ) )
2095 if( ! addrselect_test_empty( _addressSelect_ ) )
2097 /* Enable copy if something is selected */
2098 if( ! addrselect_test_empty( _addressSelect_ ) )
2102 /* Disable edit or browse if more than one row selected */
2103 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2108 /* Forbid write changes when read-only */
2109 if( iface && iface->readOnly ) {
2115 /* Now go finalize menu items */
2116 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2117 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2119 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2120 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2121 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2123 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2125 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2126 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2127 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2129 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2130 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2131 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2133 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2134 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2137 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2141 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2142 GtkCMCTreeNode *node,
2149 * Add list of items into tree node below specified tree node.
2150 * \param treeNode Tree node.
2151 * \param ds Data source.
2152 * \param listItems List of items.
2154 static void addressbook_treenode_add_list(
2155 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2161 AddrItemObject *aio;
2165 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2168 group = ( ItemGroup * ) aio;
2169 nn = addressbook_node_add_group( treeNode, ds, group );
2171 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2174 folder = ( ItemFolder * ) aio;
2175 nn = addressbook_node_add_folder(
2176 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2178 node = g_list_next( node );
2182 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2183 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2187 * Cut from address list widget.
2189 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2190 _clipBoard_->cutFlag = TRUE;
2191 addrclip_clear( _clipBoard_ );
2192 addrclip_add( _clipBoard_, _addressSelect_ );
2193 /* addrclip_list_show( _clipBoard_, stdout ); */
2197 * Copy from address list widget.
2199 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2200 _clipBoard_->cutFlag = FALSE;
2201 addrclip_clear( _clipBoard_ );
2202 addrclip_add( _clipBoard_, _addressSelect_ );
2203 /* addrclip_list_show( _clipBoard_, stdout ); */
2207 * Paste clipboard into address list widget.
2209 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2210 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2211 AddressObject *pobj = NULL;
2212 AddressDataSource *ds = NULL;
2213 AddressBookFile *abf = NULL;
2214 ItemFolder *folder = NULL;
2215 GList *folderGroup = NULL;
2217 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2218 if( ds == NULL ) return;
2219 if( addrindex_ds_get_readonly( ds ) ) {
2220 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2224 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2226 if( pobj->type == ADDR_ITEM_FOLDER ) {
2227 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2229 else if( pobj->type == ADDR_ITEM_GROUP ) {
2230 alertpanel_error( _("Cannot paste into an address group.") );
2235 /* Get an address book */
2236 abf = addressbook_get_book_file();
2237 if( abf == NULL ) return;
2239 if( _clipBoard_->cutFlag ) {
2241 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2243 /* Remove all groups and folders in clipboard from tree node */
2244 addressbook_treenode_remove_item();
2246 /* Remove all "cut" items */
2247 addrclip_delete_item( _clipBoard_ );
2249 /* Clear clipboard - cut items??? */
2250 addrclip_clear( _clipBoard_ );
2254 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2257 /* addrclip_list_show( _clipBoard_, stdout ); */
2259 /* Update tree by inserting node for each folder or group */
2260 addressbook_treenode_add_list(
2261 addrbook.treeSelected, ds, folderGroup );
2262 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2263 g_list_free( folderGroup );
2267 /* Display items pasted */
2268 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2269 addressbook_set_clist(
2270 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2278 * Add current treenode object to clipboard. Note that widget only allows
2279 * one entry from the tree list to be selected.
2281 static void addressbook_treenode_to_clipboard( void ) {
2282 AddressObject *obj = NULL;
2283 AddressDataSource *ds = NULL;
2284 AddrSelectItem *item;
2285 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2286 GtkCMCTreeNode *node;
2288 node = addrbook.treeSelected;
2289 if( node == NULL ) return;
2290 obj = gtk_cmctree_node_get_row_data( ctree, node );
2291 if( obj == NULL ) return;
2293 ds = addressbook_find_datasource( node );
2294 if( ds == NULL ) return;
2297 if( obj->type == ADDR_ITEM_FOLDER ) {
2298 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2299 ItemFolder *folder = adapter->itemFolder;
2301 item = addrselect_create_node( obj );
2302 item->uid = g_strdup( ADDRITEM_ID(folder) );
2304 else if( obj->type == ADDR_ITEM_GROUP ) {
2305 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2306 ItemGroup *group = adapter->itemGroup;
2308 item = addrselect_create_node( obj );
2309 item->uid = g_strdup( ADDRITEM_ID(group) );
2311 else if( obj->type == ADDR_DATASOURCE ) {
2313 item = addrselect_create_node( obj );
2318 /* Clear existing list and add item into list */
2321 addressbook_list_select_clear();
2322 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2323 addrselect_list_add( _addressSelect_, item, cacheID );
2329 * Cut from tree widget.
2331 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2332 _clipBoard_->cutFlag = TRUE;
2333 addressbook_treenode_to_clipboard();
2334 addrclip_clear( _clipBoard_ );
2335 addrclip_add( _clipBoard_, _addressSelect_ );
2336 /* addrclip_list_show( _clipBoard_, stdout ); */
2340 * Copy from tree widget.
2342 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2343 _clipBoard_->cutFlag = FALSE;
2344 addressbook_treenode_to_clipboard();
2345 addrclip_clear( _clipBoard_ );
2346 addrclip_add( _clipBoard_, _addressSelect_ );
2347 /* addrclip_list_show( _clipBoard_, stdout ); */
2351 * Paste clipboard into address tree widget.
2353 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2354 addressbook_clip_paste_cb(NULL,NULL);
2358 * Clear selected entries in clipboard.
2360 static void addressbook_list_select_clear( void ) {
2361 addrselect_list_clear( _addressSelect_ );
2365 * Add specified address item to selected address list.
2366 * \param aio Address item object.
2367 * \param ds Datasource.
2369 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2372 if( ds == NULL ) return;
2373 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2374 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2379 * Remove specified address item from selected address list.
2380 * \param aio Address item object.
2382 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2383 addrselect_list_remove( _addressSelect_, aio );
2387 * Invoke EMail compose window with addresses in selected address list.
2389 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2392 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2393 listAddress = addrselect_build_list( _addressSelect_ );
2394 compose_new_with_list( NULL, listAddress );
2395 mgu_free_dlist( listAddress );
2400 static void addressbook_list_row_selected( GtkCMCTree *clist,
2401 GtkCMCTreeNode *node,
2405 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2406 AddrItemObject *aio = NULL;
2407 AddressObject *pobj = NULL;
2408 AdapterDSource *ads = NULL;
2409 AddressDataSource *ds = NULL;
2411 gtk_entry_set_text( entry, "" );
2412 addrbook.listSelected = node;
2414 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2415 if( pobj == NULL ) return;
2417 if( pobj->type == ADDR_DATASOURCE ) {
2418 ads = ADAPTER_DSOURCE(pobj);
2419 ds = ads->dataSource;
2421 else if( pobj->type != ADDR_INTERFACE ) {
2422 ds = addressbook_find_datasource( addrbook.treeSelected );
2425 aio = gtk_cmctree_node_get_row_data( clist, node );
2427 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2428 addressbook_list_select_add( aio, ds );
2431 addressbook_list_menu_setup();
2433 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2434 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2436 if (obj && obj->type != ADDR_ITEM_GROUP)
2437 addressbook_edit_address(NULL, 0, NULL, FALSE);
2441 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2442 GtkCMCTreeNode *node,
2446 AddrItemObject *aio;
2448 aio = gtk_cmctree_node_get_row_data( ctree, node );
2450 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2451 addressbook_list_select_remove( aio );
2454 if (!prefs_common.addressbook_use_editaddress_dialog)
2455 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2458 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2459 GdkEventButton *event,
2462 if( ! event ) return FALSE;
2464 addressbook_list_menu_setup();
2466 if( event->button == 3 ) {
2467 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2468 event->button, event->time );
2469 } else if (event->button == 1) {
2470 if (event->type == GDK_2BUTTON_PRESS) {
2471 if (prefs_common.add_address_by_click &&
2472 addrbook.target_compose)
2473 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2475 if (prefs_common.addressbook_use_editaddress_dialog)
2476 addressbook_edit_address_cb(NULL, NULL);
2478 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2479 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2480 if( obj && obj->type == ADDR_ITEM_GROUP )
2481 addressbook_edit_address_cb(NULL, NULL);
2489 static gboolean addressbook_list_button_released(GtkWidget *widget,
2490 GdkEventButton *event,
2496 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2497 GdkEventButton *event,
2500 GtkCMCList *clist = GTK_CMCLIST(ctree);
2502 AddressObject *obj = NULL;
2503 AdapterDSource *ads = NULL;
2504 AddressInterface *iface = NULL;
2505 AddressDataSource *ds = NULL;
2506 gboolean canEdit = FALSE;
2507 gboolean canDelete = FALSE;
2508 gboolean canCut = FALSE;
2509 gboolean canCopy = FALSE;
2510 gboolean canPaste = FALSE;
2511 gboolean canTreeCut = FALSE;
2512 gboolean canTreeCopy = FALSE;
2513 gboolean canTreePaste = FALSE;
2514 gboolean canLookup = FALSE;
2515 GtkCMCTreeNode *node = NULL;
2517 if( ! event ) return FALSE;
2518 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2520 if (event->button == 1) {
2521 if (event->type == GDK_2BUTTON_PRESS) {
2522 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2523 gtkut_clist_set_focus_row(clist, row);
2524 obj = gtk_cmclist_get_row_data( clist, row );
2529 if (obj->type == ADDR_ITEM_GROUP) {
2531 addressbook_treenode_edit_cb(NULL, NULL);
2533 /* expand pr collapse */
2534 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2535 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2541 addressbook_menubar_set_sensitive( FALSE );
2543 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2544 gtkut_clist_set_focus_row(clist, row);
2545 obj = gtk_cmclist_get_row_data( clist, row );
2548 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2552 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2554 if( ! addrclip_is_empty( _clipBoard_ ) )
2555 canTreePaste = TRUE;
2557 if (obj->type == ADDR_INTERFACE) {
2558 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2561 iface = adapter->interface;
2564 if( !iface->readOnly ) {
2565 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2566 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2568 if( iface->externalQuery )
2571 if (obj->type == ADDR_DATASOURCE) {
2572 ads = ADAPTER_DSOURCE(obj);
2573 ds = ads->dataSource;
2576 iface = ds->interface;
2579 if( !iface->readOnly ) {
2581 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2582 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2583 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2587 if( iface->externalQuery )
2590 else if (obj->type == ADDR_ITEM_FOLDER) {
2591 ds = addressbook_find_datasource( node );
2594 iface = ds->interface;
2597 if( !iface->readOnly ) {
2601 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2602 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2603 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2607 if( iface->externalQuery ) {
2608 /* Enable deletion of LDAP folder */
2613 else if (obj->type == ADDR_ITEM_GROUP) {
2614 ds = addressbook_find_datasource( node );
2617 iface = ds->interface;
2620 if( ! iface->readOnly ) {
2623 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2624 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2628 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2630 if( ! addrselect_test_empty( _addressSelect_ ) )
2632 if( ! addrclip_is_empty( _clipBoard_ ) )
2635 /* Forbid write changes when read-only */
2636 if( iface && iface->readOnly ) {
2638 canTreePaste = FALSE;
2646 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2647 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2648 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2649 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2650 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2652 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2653 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2654 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2655 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2656 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2658 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2659 addrbook.target_compose != NULL);
2661 if( event->button == 3 )
2662 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2663 event->button, event->time);
2668 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2669 GdkEventButton *event,
2672 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2676 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2678 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2679 AddressObject *obj = NULL;
2680 AddressDataSource *ds = NULL;
2681 AddressBookFile *abf = NULL;
2682 ItemFolder *parentFolder = NULL;
2683 ItemFolder *folder = NULL;
2685 if( ! addrbook.treeSelected ) return;
2686 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2687 if( obj == NULL ) return;
2688 ds = addressbook_find_datasource( addrbook.treeSelected );
2689 if( ds == NULL ) return;
2691 if( obj->type == ADDR_DATASOURCE ) {
2692 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2694 else if( obj->type == ADDR_ITEM_FOLDER ) {
2695 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2701 abf = ds->rawDataSource;
2702 if( abf == NULL ) return;
2703 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2706 nn = addressbook_node_add_folder(
2707 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2708 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2709 if( addrbook.treeSelected == addrbook.opened )
2710 addressbook_set_clist(obj, TRUE);
2714 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2716 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2717 AddressObject *obj = NULL;
2718 AddressDataSource *ds = NULL;
2719 AddressBookFile *abf = NULL;
2720 ItemFolder *parentFolder = NULL;
2721 ItemGroup *group = NULL;
2723 if( ! addrbook.treeSelected ) return;
2724 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2725 if( obj == NULL ) return;
2726 ds = addressbook_find_datasource( addrbook.treeSelected );
2727 if( ds == NULL ) return;
2729 if( obj->type == ADDR_DATASOURCE ) {
2730 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2732 else if( obj->type == ADDR_ITEM_FOLDER ) {
2733 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2739 abf = ds->rawDataSource;
2740 if( abf == NULL ) return;
2741 group = addressbook_edit_group( abf, parentFolder, NULL );
2744 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2745 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2746 if( addrbook.treeSelected == addrbook.opened )
2747 addressbook_set_clist(obj, TRUE);
2751 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2753 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2756 GdkPixbuf *pix_cl, *pix_op;
2757 gboolean is_leaf, expanded;
2759 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2761 &is_leaf, &expanded);
2762 gtk_sctree_set_node_info(ctree, node, name, spacing,
2769 * \param obj Address object to edit.
2770 * \param node Node in tree.
2771 * \return New name of data source.
2773 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2774 gchar *newName = NULL;
2775 AddressDataSource *ds = NULL;
2776 AddressInterface *iface = NULL;
2777 AdapterDSource *ads = NULL;
2779 ds = addressbook_find_datasource( node );
2780 if( ds == NULL ) return NULL;
2781 iface = ds->interface;
2782 if( ! iface->haveLibrary ) return NULL;
2784 /* Read data from data source */
2785 if( addrindex_ds_get_modify_flag( ds ) ) {
2786 addrindex_ds_read_data( ds );
2789 if( ! addrindex_ds_get_read_flag( ds ) ) {
2790 addrindex_ds_read_data( ds );
2794 ads = ADAPTER_DSOURCE(obj);
2795 if( ads->subType == ADDR_BOOK ) {
2796 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2798 else if( ads->subType == ADDR_VCARD ) {
2799 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2802 else if( ads->subType == ADDR_JPILOT ) {
2803 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2807 else if( ads->subType == ADDR_LDAP ) {
2808 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2814 newName = obj->name;
2819 * Edit an object that is in the address tree area.
2821 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2823 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2825 AddressDataSource *ds = NULL;
2826 AddressBookFile *abf = NULL;
2827 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2830 if( ! addrbook.treeSelected ) return;
2831 node = addrbook.treeSelected;
2832 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2833 obj = gtk_cmctree_node_get_row_data( ctree, node );
2834 if( obj == NULL ) return;
2835 parentNode = GTK_CMCTREE_ROW(node)->parent;
2837 ds = addressbook_find_datasource( node );
2838 if( ds == NULL ) return;
2840 if( obj->type == ADDR_DATASOURCE ) {
2841 name = addressbook_edit_datasource( obj, node );
2842 if( name == NULL ) return;
2845 abf = ds->rawDataSource;
2846 if( abf == NULL ) return;
2847 if( obj->type == ADDR_ITEM_FOLDER ) {
2848 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2849 ItemFolder *item = adapter->itemFolder;
2850 ItemFolder *parentFolder = NULL;
2851 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2852 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2853 name = ADDRITEM_NAME(item);
2855 else if( obj->type == ADDR_ITEM_GROUP ) {
2856 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2857 ItemGroup *item = adapter->itemGroup;
2858 ItemFolder *parentFolder = NULL;
2859 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2860 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2861 name = ADDRITEM_NAME(item);
2864 if( name && parentNode ) {
2865 /* Update node in tree view */
2866 addressbook_change_node_name( node, name );
2867 gtk_sctree_sort_node(ctree, parentNode);
2868 gtk_cmctree_expand( ctree, node );
2869 gtk_sctree_select( GTK_SCTREE( ctree), node );
2876 ADDRTREE_DEL_FOLDER_ONLY,
2877 ADDRTREE_DEL_FOLDER_ADDR
2881 * Delete an item from the tree widget.
2882 * \param data Data passed in.
2883 * \param action Action.
2884 * \param widget Widget issuing callback.
2886 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2888 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2889 GtkCMCTreeNode *node = NULL;
2893 AddrBookBase *adbase;
2894 AddressCache *cache;
2895 AdapterDSource *ads = NULL;
2896 AddressInterface *iface = NULL;
2897 AddressDataSource *ds = NULL;
2898 gboolean remFlag = FALSE;
2899 TreeItemDelType delType;
2901 if( ! addrbook.treeSelected ) return;
2902 node = addrbook.treeSelected;
2903 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2905 obj = gtk_cmctree_node_get_row_data( ctree, node );
2906 g_return_if_fail(obj != NULL);
2908 if( obj->type == ADDR_DATASOURCE ) {
2909 ads = ADAPTER_DSOURCE(obj);
2910 if( ads == NULL ) return;
2911 ds = ads->dataSource;
2912 if( ds == NULL ) return;
2915 /* Must be folder or something else */
2916 ds = addressbook_find_datasource( node );
2917 if( ds == NULL ) return;
2919 /* Only allow deletion from non-readOnly */
2920 iface = ds->interface;
2921 if( iface->readOnly ) {
2922 /* Allow deletion of query results */
2923 if( ! iface->externalQuery ) return;
2927 /* Confirm deletion */
2928 delType = ADDRTREE_DEL_NONE;
2929 if( obj->type == ADDR_ITEM_FOLDER ) {
2930 if( iface->externalQuery ) {
2931 message = g_strdup_printf( _(
2932 "Do you want to delete the query " \
2933 "results and addresses in '%s' ?" ),
2935 aval = alertpanel( _("Delete"), message,
2936 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2938 if( aval == G_ALERTALTERNATE ) {
2939 delType = ADDRTREE_DEL_FOLDER_ADDR;
2943 message = g_strdup_printf
2944 ( _( "Do you want to delete '%s' ? "
2945 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2947 aval = alertpanel( _("Delete folder"), message,
2948 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2950 if( aval == G_ALERTALTERNATE ) {
2951 delType = ADDRTREE_DEL_FOLDER_ONLY;
2953 else if( aval == G_ALERTOTHER ) {
2954 delType = ADDRTREE_DEL_FOLDER_ADDR;
2958 else if( obj->type == ADDR_ITEM_GROUP ) {
2959 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2960 "The addresses it contains will not be lost."), obj->name);
2961 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2962 "+" GTK_STOCK_DELETE, NULL);
2964 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2966 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2967 "The addresses it contains will be lost."), obj->name);
2968 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2969 "+" GTK_STOCK_DELETE, NULL);
2971 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2973 if( delType == ADDRTREE_DEL_NONE ) return;
2975 /* Proceed with deletion */
2976 if( obj->type == ADDR_DATASOURCE ) {
2977 /* Remove node from tree */
2978 gtk_cmctree_remove_node( ctree, node );
2980 /* Remove data source. */
2981 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2982 addrindex_free_datasource( ds );
2987 /* Get reference to cache */
2988 adbase = ( AddrBookBase * ) ds->rawDataSource;
2989 if( adbase == NULL ) return;
2990 cache = adbase->addressCache;
2992 /* Remove query results folder */
2993 if( iface->externalQuery ) {
2994 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2995 ItemFolder *folder = adapter->itemFolder;
2997 adapter->itemFolder = NULL;
2999 g_print( "remove folder for ::%s::\n", obj->name );
3000 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3001 g_print( "-------------- remove results\n" );
3003 addrindex_remove_results( ds, folder );
3004 /* g_print( "-------------- remove node\n" ); */
3005 gtk_cmctree_remove_node( ctree, node );
3009 /* Code below is valid for regular address book deletion */
3010 if( obj->type == ADDR_ITEM_FOLDER ) {
3011 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3012 ItemFolder *item = adapter->itemFolder;
3014 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3015 /* Remove folder only */
3016 item = addrcache_remove_folder( cache, item );
3018 addritem_free_item_folder( item );
3019 addressbook_move_nodes_up( ctree, node );
3023 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3024 /* Remove folder and addresses */
3025 item = addrcache_remove_folder_delete( cache, item );
3027 addritem_free_item_folder( item );
3032 else if( obj->type == ADDR_ITEM_GROUP ) {
3033 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3034 ItemGroup *item = adapter->itemGroup;
3036 item = addrcache_remove_group( cache, item );
3038 addritem_free_item_group( item );
3045 gtk_cmctree_remove_node(ctree, node );
3049 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3051 if( person && addrbook.treeSelected == addrbook.opened ) {
3052 person->status = ADD_ENTRY;
3053 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3054 addressbook_folder_refresh_one_person(
3055 GTK_CMCTREE(addrbook.clist), person );
3057 addressbook_address_list_set_focus();
3060 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3062 if( person && addrbook.treeSelected == addrbook.opened) {
3063 person->status = ADD_ENTRY;
3064 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3065 addressbook_set_clist(
3066 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3070 addressbook_address_list_set_focus();
3074 * Label (a format string) that is used to name each folder.
3076 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3079 * Search ctree widget callback function.
3080 * \param pA Pointer to node.
3081 * \param pB Pointer to data item being sought.
3082 * \return Zero (0) if folder found.
3084 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3087 aoA = ( AddressObject * ) pA;
3088 if( aoA->type == ADDR_ITEM_FOLDER ) {
3089 ItemFolder *folder, *fld;
3091 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3092 folder = ( ItemFolder * ) pB;
3093 if( fld == folder ) return 0; /* Found folder */
3098 static ItemFolder * addressbook_setup_subf(
3099 AddressDataSource *ds, gchar *title,
3100 GtkCMCTreeNode *pNode )
3102 AddrBookBase *adbase;
3103 AddressCache *cache;
3106 GtkCMCTreeNode *nNode;
3108 AddressObjectType aoType = ADDR_NONE;
3111 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3113 if( ds && ds->type == ADDR_IF_LDAP ) {
3115 aoType = ADDR_LDAP_QUERY;
3122 ctree = GTK_CMCTREE(addrbook.ctree);
3123 /* Get reference to address cache */
3124 adbase = ( AddrBookBase * ) ds->rawDataSource;
3125 cache = adbase->addressCache;
3127 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3128 GList *cur = children;
3129 for (; cur; cur = cur->next) {
3130 ItemFolder *child = (ItemFolder *) cur->data;
3131 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3132 nNode = gtk_cmctree_find_by_row_data_custom(
3134 addressbook_treenode_find_folder_cb );
3136 addrindex_remove_results( ds, child );
3137 while( child->listPerson ) {
3138 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3139 item = addrcache_remove_person( cache, item );
3141 addritem_free_item_person( item );
3145 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3146 addrbook.treeSelected = nNode;
3153 /* Create a folder */
3154 folder = addrcache_add_new_folder( cache, NULL );
3155 name = g_strdup_printf( "%s", title );
3156 addritem_folder_set_name( folder, name );
3157 addritem_folder_set_remarks( folder, "" );
3160 /* Now let's see the folder */
3161 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3162 gtk_cmctree_expand( ctree, pNode );
3164 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3165 addrbook.treeSelected = nNode;
3171 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3172 AddressObject *pobj = NULL;
3173 AddressDataSource *ds = NULL;
3174 AddressBookFile *abf = NULL;
3175 debug_print("adding address\n");
3176 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3177 if( pobj == NULL ) {
3178 debug_print("no row data\n");
3181 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3183 debug_print("no datasource\n");
3187 abf = ds->rawDataSource;
3189 g_print("no addressbook file\n");
3193 if( pobj->type == ADDR_DATASOURCE ) {
3194 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3195 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3197 ItemFolder *folder = NULL;
3199 if (abf && abf->type == ADDR_IF_LDAP) {
3200 GtkCMCTreeNode *parentNode;
3201 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3202 if( ds == NULL ) return;
3204 /* We must have a datasource that is an external interface */
3205 if( ! ds->interface->haveLibrary ) return;
3206 if( ! ds->interface->externalQuery ) return;
3208 if( pobj->type == ADDR_ITEM_FOLDER ) {
3209 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3212 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3214 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3216 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3217 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3218 abf = ds->rawDataSource;
3221 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3222 addrbook.editaddress_vbox,
3223 addressbook_new_address_from_book_post_cb,
3226 if (abf && abf->type == ADDR_IF_LDAP) {
3227 LdapServer *server = ds->rawDataSource;
3228 ldapsvr_set_modified(server, TRUE);
3229 ldapsvr_update_book(server, NULL);
3230 if (server->retVal != LDAPRC_SUCCESS) {
3231 alertpanel( _("Add address(es)"),
3232 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3233 GTK_STOCK_CLOSE, NULL, NULL );
3234 server->retVal = LDAPRC_SUCCESS;
3239 if (prefs_common.addressbook_use_editaddress_dialog)
3240 addressbook_new_address_from_book_post_cb( person );
3243 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3245 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3248 if (abf && abf->type == ADDR_IF_LDAP) {
3249 GtkCMCTreeNode *parentNode;
3250 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3251 if( ds == NULL ) return;
3253 /* We must have a datasource that is an external interface */
3254 if( ! ds->interface->haveLibrary ) return;
3255 if( ! ds->interface->externalQuery ) return;
3257 if( pobj->type == ADDR_ITEM_FOLDER ) {
3258 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3261 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3263 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3266 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3267 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3268 abf = ds->rawDataSource;
3271 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3272 addrbook.editaddress_vbox,
3273 addressbook_new_address_from_folder_post_cb,
3276 if (abf && abf->type == ADDR_IF_LDAP) {
3277 LdapServer *server = ds->rawDataSource;
3278 ldapsvr_set_modified(server, TRUE);
3279 ldapsvr_update_book(server, NULL);
3280 if (server->retVal != LDAPRC_SUCCESS) {
3281 alertpanel( _("Add address(es)"),
3282 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3283 GTK_STOCK_CLOSE, NULL, NULL );
3288 if (prefs_common.addressbook_use_editaddress_dialog)
3289 addressbook_new_address_from_folder_post_cb( person );
3291 else if( pobj->type == ADDR_ITEM_GROUP ) {
3292 /* New address in group */
3293 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3294 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3295 if (addrbook.treeSelected == addrbook.opened) {
3296 /* Change node name in tree. */
3297 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3298 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3299 addressbook_set_clist(
3300 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3308 * Search for specified child group node in address index tree.
3309 * \param parent Parent node.
3310 * \param group Group to find.
3312 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3313 GtkCMCTreeNode *node = NULL;
3314 GtkCMCTreeRow *currRow;
3316 currRow = GTK_CMCTREE_ROW( parent );
3318 node = currRow->children;
3322 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3323 if( obj->type == ADDR_ITEM_GROUP ) {
3324 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3325 if( g == group ) return node;
3327 currRow = GTK_CMCTREE_ROW(node);
3328 node = currRow->sibling;
3334 static AddressBookFile *addressbook_get_book_file() {
3335 AddressBookFile *abf = NULL;
3336 AddressDataSource *ds = NULL;
3338 ds = addressbook_find_datasource( addrbook.treeSelected );
3339 if( ds == NULL ) return NULL;
3340 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3344 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3345 GtkCMCTreeNode *node;
3348 /* Remove existing folders and groups */
3349 row = GTK_CMCTREE_ROW( parent );
3351 while( (node = row->children) ) {
3352 gtk_cmctree_remove_node( ctree, node );
3357 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3358 GtkCMCTreeNode *parent, *child;
3359 GtkCMCTreeRow *currRow;
3360 currRow = GTK_CMCTREE_ROW( node );
3362 parent = currRow->parent;
3363 while( (child = currRow->children) ) {
3364 gtk_cmctree_move( ctree, child, parent, node );
3366 gtk_sctree_sort_node( ctree, parent );
3370 static void addressbook_edit_address_post_cb( ItemPerson *person )
3374 AddressBookFile *abf = addressbook_get_book_file();
3376 if (abf && abf->type == ADDR_IF_LDAP) {
3377 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3378 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3381 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3382 invalidate_address_completion();
3384 addressbook_address_list_set_focus();
3387 void addressbook_address_list_set_focus( void )
3389 if (!prefs_common.addressbook_use_editaddress_dialog) {
3390 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3391 addressbook_list_menu_setup();
3395 void addressbook_address_list_disable_some_actions(void)
3397 /* disable address copy/pasting when editing contact's detail (embedded form) */
3398 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3399 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3400 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3403 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3404 addressbook_edit_address(data, 0, NULL, TRUE);
3407 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3408 gboolean force_focus ) {
3409 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3411 AddressObject *obj = NULL, *pobj = NULL;
3412 AddressDataSource *ds = NULL;
3413 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3415 AddressBookFile *abf = NULL;
3417 if( addrbook.listSelected == NULL ) return;
3418 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3419 g_return_if_fail(obj != NULL);
3421 ctree = GTK_CMCTREE( addrbook.ctree );
3422 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3423 node = gtk_cmctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3425 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3426 if( ds == NULL ) return;
3428 abf = addressbook_get_book_file();
3430 if( obj->type == ADDR_ITEM_EMAIL ) {
3431 ItemEMail *email = ( ItemEMail * ) obj;
3432 if( email == NULL ) return;
3433 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3434 /* Edit parent group */
3435 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3436 ItemGroup *itemGrp = adapter->itemGroup;
3437 if( abf == NULL ) return;
3438 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3439 name = ADDRITEM_NAME(itemGrp);
3440 node = addrbook.treeSelected;
3441 parentNode = GTK_CMCTREE_ROW(node)->parent;
3444 /* Edit person - email page */
3446 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3447 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3448 addressbook_edit_address_post_cb,
3449 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3452 if (abf && abf->type == ADDR_IF_LDAP) {
3453 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3454 person->status = UPDATE_ENTRY;
3457 if (prefs_common.addressbook_use_editaddress_dialog)
3458 addressbook_edit_address_post_cb( person );
3463 else if( obj->type == ADDR_ITEM_PERSON ) {
3464 /* Edit person - basic page */
3465 ItemPerson *person = ( ItemPerson * ) obj;
3466 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3467 addressbook_edit_address_post_cb,
3468 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3471 if (abf && abf->type == ADDR_IF_LDAP) {
3472 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3473 person->status = UPDATE_ENTRY;
3476 if (prefs_common.addressbook_use_editaddress_dialog)
3477 addressbook_edit_address_post_cb( person );
3481 else if( obj->type == ADDR_ITEM_GROUP ) {
3482 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3483 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3484 parentNode = addrbook.treeSelected;
3485 node = addressbook_find_group_node( parentNode, itemGrp );
3486 name = ADDRITEM_NAME(itemGrp);
3487 invalidate_address_completion();
3493 /* Update tree node with node name */
3494 if( node == NULL ) return;
3495 addressbook_change_node_name( node, name );
3496 gtk_sctree_sort_node( ctree, parentNode );
3497 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3498 addressbook_set_clist(
3499 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3504 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3506 addressbook_del_clicked(NULL, NULL);
3509 static void close_cb(GtkAction *action, gpointer data)
3511 addressbook_close();
3514 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3515 addressbook_export_to_file();
3518 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3520 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3521 if( person ) addritem_person_set_opened( person, TRUE );
3525 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3527 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3528 if( person ) addritem_person_set_opened( person, FALSE );
3532 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3534 gchar *eMailAlias = ADDRITEM_NAME(email);
3535 if( eMailAlias && *eMailAlias != '\0' ) {
3537 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3540 str = g_strdup( eMailAlias );
3546 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3547 GList *items = itemGroup->listEMail;
3548 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3549 for( ; items != NULL; items = g_list_next( items ) ) {
3550 GtkCMCTreeNode *nodeEMail = NULL;
3551 gchar *text[N_LIST_COLS];
3552 ItemEMail *email = items->data;
3556 if( ! email ) continue;
3558 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3559 str = addressbook_format_item_clist( person, email );
3561 text[COL_NAME] = addressbook_set_col_name_guard(str);
3564 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3566 text[COL_ADDRESS] = email->address;
3567 text[COL_REMARKS] = email->remarks;
3568 nodeEMail = gtk_sctree_insert_node(
3570 text, FOLDER_SPACING,
3574 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3580 gchar *addressbook_set_col_name_guard(gchar *value)
3582 gchar *ret = "<not set>";
3583 gchar *tmp = g_strdup(value);
3585 if (tmp !=NULL && *tmp != '\0')
3591 static void addressbook_folder_load_one_person(
3592 GtkCMCTree *clist, ItemPerson *person,
3593 AddressTypeControlItem *atci,
3594 AddressTypeControlItem *atciMail )
3596 GtkCMCTreeNode *nodePerson = NULL;
3597 GtkCMCTreeNode *nodeEMail = NULL;
3598 gchar *text[N_LIST_COLS];
3599 gboolean flgFirst = TRUE, haveAddr = FALSE;
3602 AddressBookFile *abf = addressbook_get_book_file();
3605 if( person == NULL ) return;
3607 text[COL_NAME] = "";
3608 node = person->listEMail;
3610 ItemEMail *email = node->data;
3611 gchar *eMailAddr = NULL;
3612 node = g_list_next( node );
3614 text[COL_ADDRESS] = email->address;
3615 text[COL_REMARKS] = email->remarks;
3616 eMailAddr = ADDRITEM_NAME(email);
3617 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3619 /* First email belongs with person */
3620 gchar *str = addressbook_format_item_clist( person, email );
3622 text[COL_NAME] = addressbook_set_col_name_guard(str);
3625 else if( abf && abf->type == ADDR_IF_LDAP &&
3626 person && person->nickName ) {
3627 if (person->nickName) {
3628 if (strcmp(person->nickName, "") != 0) {
3629 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3632 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3638 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3640 nodePerson = gtk_sctree_insert_node(
3642 text, FOLDER_SPACING,
3645 FALSE, person->isOpened );
3648 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3651 /* Subsequent email is a child node of person */
3652 text[COL_NAME] = ADDRITEM_NAME(email);
3653 nodeEMail = gtk_sctree_insert_node(
3654 clist, nodePerson, NULL,
3655 text, FOLDER_SPACING,
3657 atciMail->iconXpmOpen,
3659 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3665 /* Have name without EMail */
3666 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3667 text[COL_ADDRESS] = "";
3668 text[COL_REMARKS] = "";
3669 nodePerson = gtk_sctree_insert_node(
3671 text, FOLDER_SPACING,
3674 FALSE, person->isOpened );
3675 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3680 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3682 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3683 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3685 if( atci == NULL ) return;
3686 if( atciMail == NULL ) return;
3688 /* Load email addresses */
3689 items = addritem_folder_get_person_list( itemFolder );
3690 for( ; items != NULL; items = g_list_next( items ) ) {
3691 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3693 /* Free up the list */
3694 mgu_clear_list( items );
3695 g_list_free( items );
3698 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3699 addrbook.listSelected = NULL;
3700 gtk_cmctree_remove_node( clist, node );
3701 addressbook_menubar_set_sensitive( FALSE );
3702 addressbook_menuitem_set_sensitive(
3703 gtk_cmctree_node_get_row_data(
3704 GTK_CMCTREE(clist), addrbook.treeSelected ),
3705 addrbook.treeSelected );
3708 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3709 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3710 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3711 GtkCMCTreeNode *node;
3712 if( atci == NULL ) return;
3713 if( atciMail == NULL ) return;
3714 if( person == NULL ) return;
3715 /* unload the person */
3717 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3719 addressbook_folder_remove_node( clist, node );
3720 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3721 gtk_sctree_sort_node( clist, NULL );
3722 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3724 gtk_sctree_select( GTK_SCTREE(clist), node );
3725 if (!gtk_cmctree_node_is_visible( clist, node ) )
3726 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3730 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3731 GtkCMCTreeNode *node;
3734 if( person == NULL ) return;
3735 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3736 row = gtk_cmclist_find_row_from_data( GTK_CMCLIST(clist), person );
3738 addressbook_folder_remove_node( clist, node );
3742 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3744 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3746 /* Load any groups */
3747 if( ! atci ) return;
3748 items = addritem_folder_get_group_list( itemFolder );
3749 for( ; items != NULL; items = g_list_next( items ) ) {
3750 GtkCMCTreeNode *nodeGroup = NULL;
3751 gchar *text[N_LIST_COLS];
3752 ItemGroup *group = items->data;
3753 if( group == NULL ) continue;
3754 text[COL_NAME] = ADDRITEM_NAME(group);
3755 text[COL_ADDRESS] = "";
3756 text[COL_REMARKS] = "";
3757 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3758 text, FOLDER_SPACING,
3762 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3763 gtk_sctree_sort_node(clist, NULL);
3765 /* Free up the list */
3766 mgu_clear_list( items );
3767 g_list_free( items );
3771 * Search ctree widget callback function.
3772 * \param pA Pointer to node.
3773 * \param pB Pointer to data item being sought.
3774 * \return Zero (0) if group found.
3776 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3779 aoA = ( AddressObject * ) pA;
3780 if( aoA->type == ADDR_ITEM_GROUP ) {
3781 ItemGroup *group, *grp;
3783 grp = ADAPTER_GROUP(aoA)->itemGroup;
3784 group = ( ItemGroup * ) pB;
3785 if( grp == group ) return 0; /* Found group */
3791 * Remove folder and group nodes from tree widget for items contained ("cut")
3794 static void addressbook_treenode_remove_item( void ) {
3796 AddrSelectItem *cutItem;
3797 AddressCache *cache;
3798 AddrItemObject *aio;
3799 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3802 node = _clipBoard_->objectList;
3804 cutItem = node->data;
3805 node = g_list_next( node );
3806 cache = addrindex_get_cache(
3807 _clipBoard_->addressIndex, cutItem->cacheID );
3808 if( cache == NULL ) continue;
3809 aio = addrcache_get_object( cache, cutItem->uid );
3812 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3815 folder = ( ItemFolder * ) aio;
3816 tn = gtk_cmctree_find_by_row_data_custom(
3817 ctree, NULL, folder,
3818 addressbook_treenode_find_folder_cb );
3820 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3823 group = ( ItemGroup * ) aio;
3824 tn = gtk_cmctree_find_by_row_data_custom(
3826 addressbook_treenode_find_group_cb );
3830 /* Free up adapter and remove node. */
3831 gtk_cmctree_remove_node( ctree, tn );
3838 * Find parent datasource for specified tree node.
3839 * \param node Node to test.
3840 * \return Data source, or NULL if not found.
3842 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3843 AddressDataSource *ds = NULL;
3846 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3849 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3850 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3852 /* g_print( "ao->type = %d\n", ao->type ); */
3853 if( ao->type == ADDR_DATASOURCE ) {
3854 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3855 /* g_print( "found it\n" ); */
3856 ds = ads->dataSource;
3860 node = GTK_CMCTREE_ROW(node)->parent;
3866 * Load address list widget with children of specified object.
3867 * \param obj Parent object to be loaded.
3869 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3870 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3871 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3872 AddressDataSource *ds = NULL;
3873 AdapterDSource *ads = NULL;
3874 static AddressObject *last_obj = NULL;
3876 if (addrbook.clist == NULL) {
3879 if (obj == last_obj && !refresh)
3884 gtk_cmclist_clear(clist);
3888 if( obj->type == ADDR_INTERFACE ) {
3889 /* g_print( "set_clist: loading datasource...\n" ); */
3890 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3894 gtk_cmclist_freeze(clist);
3895 gtk_cmclist_clear(clist);
3897 if( obj->type == ADDR_DATASOURCE ) {
3898 ads = ADAPTER_DSOURCE(obj);
3899 ds = ADAPTER_DSOURCE(obj)->dataSource;
3901 /* Load root folder */
3902 ItemFolder *rootFolder = NULL;
3903 rootFolder = addrindex_ds_get_root_folder( ds );
3904 addressbook_folder_load_person(
3905 ctreelist, addrindex_ds_get_root_folder( ds ) );
3906 addressbook_folder_load_group(
3907 ctreelist, addrindex_ds_get_root_folder( ds ) );
3911 if( obj->type == ADDR_ITEM_GROUP ) {
3913 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3914 addressbook_load_group( ctreelist, itemGroup );
3916 else if( obj->type == ADDR_ITEM_FOLDER ) {
3918 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3919 addressbook_folder_load_person( ctreelist, itemFolder );
3920 addressbook_folder_load_group( ctreelist, itemFolder );
3923 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3924 clist->focus_row = -1;
3925 gtk_cmclist_thaw(clist);
3929 * Call back function to free adaptor. Call back is setup by function
3930 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3931 * called when the address book tree widget node is removed by calling
3932 * function gtk_cmctree_remove_node().
3934 * \param data Tree node's row data.
3936 static void addressbook_free_treenode( gpointer data ) {
3939 ao = ( AddressObject * ) data;
3940 if( ao == NULL ) return;
3941 if( ao->type == ADDR_INTERFACE ) {
3942 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3943 addrbookctl_free_interface( ai );
3945 else if( ao->type == ADDR_DATASOURCE ) {
3946 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3947 addrbookctl_free_datasource( ads );
3949 else if( ao->type == ADDR_ITEM_FOLDER ) {
3950 AdapterFolder *af = ADAPTER_FOLDER(ao);
3951 addrbookctl_free_folder( af );
3953 else if( ao->type == ADDR_ITEM_GROUP ) {
3954 AdapterGroup *ag = ADAPTER_GROUP(ao);
3955 addrbookctl_free_group( ag );
3960 * Create new adaptor for specified data source.
3962 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3963 AddressObjectType otype, gchar *name )
3965 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3966 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3967 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3968 adapter->dataSource = ds;
3969 adapter->subType = otype;
3973 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3974 ADDRESS_OBJECT_NAME(adapter) =
3975 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3979 * Load tree from address index with the initial data.
3981 static void addressbook_load_tree( void ) {
3982 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3983 GList *nodeIf, *nodeDS;
3984 AdapterInterface *adapter;
3985 AddressInterface *iface;
3986 AddressTypeControlItem *atci;
3987 AddressDataSource *ds;
3988 AdapterDSource *ads;
3989 GtkCMCTreeNode *node, *newNode;
3992 nodeIf = _addressInterfaceList_;
3994 adapter = nodeIf->data;
3995 node = adapter->treeNode;
3996 iface = adapter->interface;
3997 atci = adapter->atci;
3999 if( iface->useInterface ) {
4000 /* Load data sources below interface node */
4001 nodeDS = iface->listSource;
4005 name = addrindex_ds_get_name( ds );
4006 ads = addressbook_create_ds_adapter(
4007 ds, atci->objectType, name );
4008 newNode = addressbook_add_object(
4009 node, ADDRESS_OBJECT(ads) );
4010 nodeDS = g_list_next( nodeDS );
4012 gtk_cmctree_expand( ctree, node );
4015 nodeIf = g_list_next( nodeIf );
4020 * Convert the old address book to new format.
4022 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4023 gboolean retVal = FALSE;
4024 gboolean errFlag = TRUE;
4027 /* Read old address book, performing conversion */
4028 debug_print( "Reading and converting old address book...\n" );
4029 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4030 addrindex_read_data( addrIndex );
4031 if( addrIndex->retVal == MGU_NO_FILE ) {
4032 /* We do not have a file - new user */
4033 debug_print( "New user... create new books...\n" );
4034 addrindex_create_new_books( addrIndex );
4035 if( addrIndex->retVal == MGU_SUCCESS ) {
4036 /* Save index file */
4037 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4038 addrindex_save_data( addrIndex );
4039 if( addrIndex->retVal == MGU_SUCCESS ) {
4044 msg = _( "New user, could not save index file." );
4048 msg = _( "New user, could not save address book files." );
4052 /* We have an old file */
4053 if( addrIndex->wasConverted ) {
4054 /* Converted successfully - save address index */
4055 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4056 addrindex_save_data( addrIndex );
4057 if( addrIndex->retVal == MGU_SUCCESS ) {
4058 msg = _( "Old address book converted successfully." );
4063 msg = _("Old address book converted,\n"
4064 "could not save new address index file." );
4068 /* File conversion failed - just create new books */
4069 debug_print( "File conversion failed... just create new books...\n" );
4070 addrindex_create_new_books( addrIndex );
4071 if( addrIndex->retVal == MGU_SUCCESS ) {
4073 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4074 addrindex_save_data( addrIndex );
4075 if( addrIndex->retVal == MGU_SUCCESS ) {
4076 msg = _("Could not convert address book,\n"
4077 "but created empty new address book files." );
4082 msg = _("Could not convert address book,\n"
4083 "could not save new address index file." );
4087 msg = _("Could not convert address book\n"
4088 "and could not create new address book files." );
4093 debug_print( "Error\n%s\n", msg );
4094 alertpanel_full(_("Addressbook conversion error"), msg,
4095 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4096 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4099 debug_print( "Warning\n%s\n", msg );
4100 alertpanel_full(_("Addressbook conversion error"), msg,
4101 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4102 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4108 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4112 gboolean failed = FALSE;
4114 if( ( dp = opendir( origdir ) ) == NULL ) {
4118 while( ( d = readdir( dp ) ) != NULL ) {
4119 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4122 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4124 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4126 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4139 /* all copies succeeded, we can remove source files */
4140 if( ( dp = opendir( origdir ) ) == NULL ) {
4143 while( ( d = readdir( dp ) ) != NULL ) {
4144 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4147 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4149 claws_unlink(orig_file);
4159 void addressbook_read_file( void ) {
4160 AddressIndex *addrIndex = NULL;
4161 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4163 debug_print( "Reading address index...\n" );
4164 if( _addressIndex_ ) {
4165 debug_print( "address book already read!!!\n" );
4169 addrIndex = addrindex_create_index();
4170 addrindex_initialize();
4172 /* Use new address book index. */
4174 if ( !is_dir_exist(indexdir) ) {
4175 if ( make_dir(indexdir) < 0 ) {
4176 addrindex_set_file_path( addrIndex, get_rc_dir() );
4177 g_warning( "couldn't create dir %s\n", indexdir);
4179 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4180 remove_dir_recursive(indexdir);
4181 addrindex_set_file_path( addrIndex, get_rc_dir() );
4182 g_error("couldn't migrate dir %s", indexdir);
4184 addrindex_set_file_path( addrIndex, indexdir);
4188 addrindex_set_file_path( addrIndex, indexdir);
4191 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4192 addrindex_read_data( addrIndex );
4193 if( addrIndex->retVal == MGU_NO_FILE ) {
4194 /* Conversion required */
4195 debug_print( "Converting...\n" );
4196 if( addressbook_convert( addrIndex ) ) {
4197 _addressIndex_ = addrIndex;
4200 else if( addrIndex->retVal == MGU_SUCCESS ) {
4201 _addressIndex_ = addrIndex;
4204 /* Error reading address book */
4205 debug_print( "Could not read address index.\n" );
4206 addrindex_print_index( addrIndex, stdout );
4207 alertpanel_full(_("Addressbook Error"),
4208 _("Could not read address index"),
4209 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4210 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4212 debug_print( "done.\n" );
4216 * Add object into the address index tree widget.
4217 * Enter: node Parent node.
4218 * obj Object to add.
4219 * Return: Node that was added, or NULL if object not added.
4221 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4224 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4225 GtkCMCTreeNode *added;
4226 AddressObject *pobj;
4227 AddressObjectType otype;
4228 AddressTypeControlItem *atci = NULL;
4230 g_return_val_if_fail(node != NULL, NULL);
4231 g_return_val_if_fail(obj != NULL, NULL);
4233 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4234 g_return_val_if_fail(pobj != NULL, NULL);
4236 /* Determine object type to be displayed */
4237 if( obj->type == ADDR_DATASOURCE ) {
4238 otype = ADAPTER_DSOURCE(obj)->subType;
4244 /* Handle any special conditions. */
4246 atci = addrbookctl_lookup( otype );
4248 if( atci->showInTree ) {
4249 /* Add object to tree */
4252 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4253 atci->iconXpm, atci->iconXpmOpen,
4254 atci->treeLeaf, atci->treeExpand );
4255 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4256 addressbook_free_treenode );
4260 gtk_sctree_sort_node(ctree, node);
4266 * Add group into the address index tree.
4267 * \param node Parent node.
4268 * \param ds Data source.
4269 * \param itemGroup Group to add.
4270 * \return Inserted node.
4272 static GtkCMCTreeNode *addressbook_node_add_group(
4273 GtkCMCTreeNode *node, AddressDataSource *ds,
4274 ItemGroup *itemGroup )
4276 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4277 GtkCMCTreeNode *newNode;
4278 AdapterGroup *adapter;
4279 AddressTypeControlItem *atci = NULL;
4282 if( ds == NULL ) return NULL;
4283 if( node == NULL || itemGroup == NULL ) return NULL;
4285 name = &itemGroup->obj.name;
4287 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4289 adapter = g_new0( AdapterGroup, 1 );
4290 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4291 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4292 adapter->itemGroup = itemGroup;
4294 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4295 atci->iconXpm, atci->iconXpm,
4296 atci->treeLeaf, atci->treeExpand );
4297 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4298 addressbook_free_treenode );
4299 gtk_sctree_sort_node( ctree, node );
4304 * Add folder into the address index tree. Only visible folders are loaded into
4305 * the address index tree. Note that the root folder is not inserted into the
4308 * \param node Parent node.
4309 * \param ds Data source.
4310 * \param itemFolder Folder to add.
4311 * \param otype Object type to display.
4312 * \return Inserted node for the folder.
4314 static GtkCMCTreeNode *addressbook_node_add_folder(
4315 GtkCMCTreeNode *node, AddressDataSource *ds,
4316 ItemFolder *itemFolder, AddressObjectType otype )
4318 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4319 GtkCMCTreeNode *newNode = NULL;
4320 AdapterFolder *adapter;
4321 AddressTypeControlItem *atci = NULL;
4322 GList *listItems = NULL;
4324 ItemFolder *rootFolder;
4326 /* Only visible folders */
4327 if( itemFolder->isHidden ) return NULL;
4329 if( ds == NULL ) return NULL;
4330 if( node == NULL || itemFolder == NULL ) return NULL;
4332 /* Determine object type */
4333 atci = addrbookctl_lookup( otype );
4334 if( atci == NULL ) return NULL;
4336 rootFolder = addrindex_ds_get_root_folder( ds );
4337 if( itemFolder == rootFolder ) {
4341 adapter = g_new0( AdapterFolder, 1 );
4342 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4343 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4344 adapter->itemFolder = itemFolder;
4346 name = ADDRITEM_NAME(itemFolder);
4347 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4348 atci->iconXpm, atci->iconXpm,
4349 atci->treeLeaf, atci->treeExpand );
4351 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4352 addressbook_free_treenode );
4356 listItems = itemFolder->listFolder;
4357 while( listItems ) {
4358 ItemFolder *item = listItems->data;
4359 addressbook_node_add_folder( newNode, ds, item, otype );
4360 listItems = g_list_next( listItems );
4362 listItems = itemFolder->listGroup;
4363 while( listItems ) {
4364 ItemGroup *item = listItems->data;
4365 addressbook_node_add_group( newNode, ds, item );
4366 listItems = g_list_next( listItems );
4368 gtk_sctree_sort_node( ctree, node );
4372 void addressbook_export_to_file( void ) {
4373 if( _addressIndex_ ) {
4374 /* Save all new address book data */
4375 debug_print( "Saving address books...\n" );
4376 addrindex_save_all_books( _addressIndex_ );
4378 debug_print( "Exporting addressbook to file...\n" );
4379 addrindex_save_data( _addressIndex_ );
4380 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4381 addrindex_print_index( _addressIndex_, stdout );
4384 /* Notify address completion of new data */
4385 invalidate_address_completion();
4389 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4391 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4392 addressbook_lup_clicked(NULL, NULL);
4397 * Comparison using cell contents (text in first column). Used for sort
4398 * address index widget.
4400 static gint addressbook_treenode_compare_func(
4401 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4403 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4404 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4405 gchar *name1 = NULL, *name2 = NULL;
4406 if( cell1 ) name1 = cell1->u.text;
4407 if( cell2 ) name2 = cell2->u.text;
4408 if( ! name1 ) return ( name2 != NULL );
4409 if( ! name2 ) return -1;
4410 return g_utf8_collate( name1, name2 );
4413 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4414 AdapterDSource *ads;
4415 AdapterInterface *adapter;
4416 GtkCMCTreeNode *newNode;
4418 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4419 if( adapter == NULL ) return;
4420 ads = addressbook_edit_book( _addressIndex_, NULL );
4422 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4424 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4425 addrbook.treeSelected = newNode;
4430 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4431 AdapterDSource *ads;
4432 AdapterInterface *adapter;
4433 GtkCMCTreeNode *newNode;
4435 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4436 if( adapter == NULL ) return;
4437 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4439 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4441 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4442 addrbook.treeSelected = newNode;
4448 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4449 AdapterDSource *ads;
4450 AdapterInterface *adapter;
4451 AddressInterface *iface;
4452 GtkCMCTreeNode *newNode;
4454 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4455 if( adapter == NULL ) return;
4456 iface = adapter->interface;
4457 if( ! iface->haveLibrary ) return;
4458 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4460 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4462 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4463 addrbook.treeSelected = newNode;
4470 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4471 AdapterDSource *ads;
4472 AdapterInterface *adapter;
4473 AddressInterface *iface;
4474 GtkCMCTreeNode *newNode;
4476 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4477 if( adapter == NULL ) return;
4478 iface = adapter->interface;
4479 if( ! iface->haveLibrary ) return;
4480 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4482 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4484 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4485 addrbook.treeSelected = newNode;
4492 * Display address search status message.
4493 * \param queryType Query type.
4494 * \param status Status/Error code.
4496 static void addressbook_search_message( gint queryType, gint sts ) {
4498 *addressbook_msgbuf = '\0';
4500 if( sts != MGU_SUCCESS ) {
4501 if( queryType == ADDRQUERY_LDAP ) {
4503 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4508 g_snprintf( addressbook_msgbuf,
4509 sizeof(addressbook_msgbuf), "%s", desc );
4510 addressbook_status_show( addressbook_msgbuf );
4513 addressbook_status_show( "" );
4518 * Refresh addressbook by forcing refresh of current selected object in
4521 static void addressbook_refresh_current( void ) {
4525 ctree = GTK_CMCTREE(addrbook.ctree);
4526 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4527 if( obj == NULL ) return;
4528 addressbook_set_clist( obj, TRUE );
4532 * Message that is displayed whilst a query is executing in a background
4535 static gchar *_tempMessage_ = N_( "Busy searching..." );
4538 * Address search idle function. This function is called during UI idle time
4539 * while a search is in progress.
4541 * \param data Idler data.
4543 static void addressbook_search_idle( gpointer data ) {
4547 queryID = GPOINTER_TO_INT( data );
4548 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4553 * Search completion callback function. This removes the query from the idle
4556 * \param sender Sender of query.
4557 * \param queryID Query ID of search request.
4558 * \param status Search status.
4559 * \param data Query data.
4561 static void addressbook_search_callback_end(
4562 gpointer sender, gint queryID, gint status, gpointer data )
4566 AddrQueryObject *aqo;
4568 /* Remove idler function */
4569 ptrQID = GINT_TO_POINTER( queryID );
4571 g_idle_remove_by_data( ptrQID );
4574 /* Refresh addressbook contents */
4575 addressbook_refresh_current();
4576 req = qrymgr_find_request( queryID );
4578 aqo = ( AddrQueryObject * ) req->queryList->data;
4579 addressbook_search_message( aqo->queryType, status );
4582 /* Stop the search */
4583 addrindex_stop_search( queryID );
4589 * \param ds Data source to search.
4590 * \param searchTerm String to lookup.
4591 * \param pNode Parent data source node.
4593 static void addressbook_perform_search(
4594 AddressDataSource *ds, gchar *searchTerm,
4595 GtkCMCTreeNode *pNode )
4597 AddrBookBase *adbase;
4598 AddressCache *cache;
4604 AddressObjectType aoType = ADDR_NONE;
4608 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4610 if( ds && ds->type == ADDR_IF_LDAP ) {
4612 aoType = ADDR_LDAP_QUERY;
4618 /* Get reference to address cache */
4619 adbase = ( AddrBookBase * ) ds->rawDataSource;
4620 cache = adbase->addressCache;
4622 /* Create a folder for the search results */
4623 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4624 folder = addressbook_setup_subf(ds, name, pNode);
4627 /* Setup the search */
4628 queryID = addrindex_setup_explicit_search(
4629 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4630 if( queryID == 0 ) return;
4632 /* Set up idler function */
4633 idleID = g_idle_add(
4634 ( GtkFunction ) addressbook_search_idle,
4635 GINT_TO_POINTER( queryID ) );
4637 /* Start search, sit back and wait for something to happen */
4638 addrindex_start_search( queryID );
4640 addressbook_status_show( _tempMessage_ );
4644 * Lookup button handler. Address search is only performed against
4645 * address interfaces for external queries.
4647 * \param button Lookup button widget.
4648 * \param data Data object.
4650 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4653 AddressDataSource *ds;
4654 AddressInterface *iface;
4656 GtkCMCTreeNode *node, *parentNode;
4658 node = addrbook.treeSelected;
4659 if( ! node ) return;
4660 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4662 ctree = GTK_CMCTREE(addrbook.ctree);
4663 obj = gtk_cmctree_node_get_row_data( ctree, node );
4664 if( obj == NULL ) return;
4666 ds = addressbook_find_datasource( node );
4667 if( ds == NULL ) return;
4669 /* We must have a datasource that is an external interface */
4670 iface = ds->interface;
4671 if( ! iface->haveLibrary ) return;
4672 if( ! iface->externalQuery ) return;
4675 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4676 g_strchomp( searchTerm );
4678 if( obj->type == ADDR_ITEM_FOLDER ) {
4679 parentNode = GTK_CMCTREE_ROW(node)->parent;
4684 addressbook_perform_search( ds, searchTerm, parentNode );
4686 gtk_widget_grab_focus( addrbook.entry );
4688 g_free( searchTerm );
4691 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4692 addressbook_close();
4697 * Browse address entry for highlighted entry.
4699 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4701 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4703 AddressDataSource *ds;
4704 AddressInterface *iface;
4708 if(addrbook.listSelected == NULL)
4711 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4715 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4719 iface = ds->interface;
4720 if(! iface->haveLibrary )
4724 if (obj->type == ADDR_ITEM_EMAIL) {
4725 email = ( ItemEMail * ) obj;
4729 person = (ItemPerson *) ADDRITEM_PARENT(email);
4731 else if (obj->type == ADDR_ITEM_PERSON) {
4732 person = (ItemPerson *) obj;
4739 if( iface && iface->type == ADDR_IF_LDAP ) {
4740 browseldap_entry(ds, person->externalID);
4745 /* **********************************************************************
4746 * Build lookup tables.
4747 * ***********************************************************************
4751 * Remap object types.
4752 * Enter: abType AddressObjectType (used in tree node).
4753 * Return: ItemObjectType (used in address cache data).
4755 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4756 ItemObjectType ioType;
4759 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4760 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4761 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4762 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4763 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4764 default: ioType = ITEMTYPE_NONE; break;
4770 * Build table that controls the rendering of object types.
4772 static void addrbookctl_build_map( GtkWidget *window ) {
4773 AddressTypeControlItem *atci;
4776 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4777 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4778 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4779 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4780 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4781 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4782 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4783 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4784 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4785 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4787 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4788 _addressBookTypeList_ = NULL;
4791 atci = g_new0( AddressTypeControlItem, 1 );
4792 atci->objectType = ADDR_INTERFACE;
4793 atci->interfaceType = ADDR_IF_NONE;
4794 atci->showInTree = TRUE;
4795 atci->treeExpand = TRUE;
4796 atci->treeLeaf = FALSE;
4797 atci->displayName = _( "Interface" );
4798 atci->iconXpm = folderxpm;
4799 atci->iconXpmOpen = folderopenxpm;
4800 atci->menuCommand = NULL;
4801 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4802 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4805 atci = g_new0( AddressTypeControlItem, 1 );
4806 atci->objectType = ADDR_BOOK;
4807 atci->interfaceType = ADDR_IF_BOOK;
4808 atci->showInTree = TRUE;
4809 atci->treeExpand = TRUE;
4810 atci->treeLeaf = FALSE;
4811 atci->displayName = _( "Address Book" );
4812 atci->iconXpm = bookxpm;
4813 atci->iconXpmOpen = bookxpm;
4814 atci->menuCommand = "Menu/Book/NewBook";
4815 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4816 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4819 atci = g_new0( AddressTypeControlItem, 1 );
4820 atci->objectType = ADDR_ITEM_PERSON;
4821 atci->interfaceType = ADDR_IF_NONE;
4822 atci->showInTree = FALSE;
4823 atci->treeExpand = FALSE;
4824 atci->treeLeaf = FALSE;
4825 atci->displayName = _( "Person" );
4826 atci->iconXpm = NULL;
4827 atci->iconXpmOpen = NULL;
4828 atci->menuCommand = NULL;
4829 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4830 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4833 atci = g_new0( AddressTypeControlItem, 1 );
4834 atci->objectType = ADDR_ITEM_EMAIL;
4835 atci->interfaceType = ADDR_IF_NONE;
4836 atci->showInTree = FALSE;
4837 atci->treeExpand = FALSE;
4838 atci->treeLeaf = TRUE;
4839 atci->displayName = _( "Email Address" );
4840 atci->iconXpm = addressxpm;
4841 atci->iconXpmOpen = addressxpm;
4842 atci->menuCommand = NULL;
4843 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4844 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4847 atci = g_new0( AddressTypeControlItem, 1 );
4848 atci->objectType = ADDR_ITEM_GROUP;
4849 atci->interfaceType = ADDR_IF_BOOK;
4850 atci->showInTree = TRUE;
4851 atci->treeExpand = FALSE;
4852 atci->treeLeaf = FALSE;
4853 atci->displayName = _( "Group" );
4854 atci->iconXpm = groupxpm;
4855 atci->iconXpmOpen = groupxpm;
4856 atci->menuCommand = NULL;
4857 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4858 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4861 atci = g_new0( AddressTypeControlItem, 1 );
4862 atci->objectType = ADDR_ITEM_FOLDER;
4863 atci->interfaceType = ADDR_IF_BOOK;
4864 atci->showInTree = TRUE;
4865 atci->treeExpand = FALSE;
4866 atci->treeLeaf = FALSE;
4867 atci->displayName = _( "Folder" );
4868 atci->iconXpm = folderxpm;
4869 atci->iconXpmOpen = folderopenxpm;
4870 atci->menuCommand = NULL;
4871 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4872 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4875 atci = g_new0( AddressTypeControlItem, 1 );
4876 atci->objectType = ADDR_VCARD;
4877 atci->interfaceType = ADDR_IF_VCARD;
4878 atci->showInTree = TRUE;
4879 atci->treeExpand = TRUE;
4880 atci->treeLeaf = TRUE;
4881 atci->displayName = _( "vCard" );
4882 atci->iconXpm = vcardxpm;
4883 atci->iconXpmOpen = vcardxpm;
4884 atci->menuCommand = "Menu/Book/NewVCard";
4885 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4886 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4889 atci = g_new0( AddressTypeControlItem, 1 );
4890 atci->objectType = ADDR_JPILOT;
4891 atci->interfaceType = ADDR_IF_JPILOT;
4892 atci->showInTree = TRUE;
4893 atci->treeExpand = TRUE;
4894 atci->treeLeaf = FALSE;
4895 atci->displayName = _( "JPilot" );
4896 atci->iconXpm = jpilotxpm;
4897 atci->iconXpmOpen = jpilotxpm;
4898 atci->menuCommand = "Menu/Book/NewJPilot";
4899 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4900 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4903 atci = g_new0( AddressTypeControlItem, 1 );
4904 atci->objectType = ADDR_CATEGORY;
4905 atci->interfaceType = ADDR_IF_JPILOT;
4906 atci->showInTree = TRUE;
4907 atci->treeExpand = TRUE;
4908 atci->treeLeaf = TRUE;
4909 atci->displayName = _( "JPilot" );
4910 atci->iconXpm = categoryxpm;
4911 atci->iconXpmOpen = categoryxpm;
4912 atci->menuCommand = NULL;
4913 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4914 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4917 atci = g_new0( AddressTypeControlItem, 1 );
4918 atci->objectType = ADDR_LDAP;
4919 atci->interfaceType = ADDR_IF_LDAP;
4920 atci->showInTree = TRUE;
4921 atci->treeExpand = TRUE;
4922 atci->treeLeaf = FALSE;
4923 atci->displayName = _( "LDAP servers" );
4924 atci->iconXpm = ldapxpm;
4925 atci->iconXpmOpen = ldapxpm;
4926 atci->menuCommand = "Menu/Book/NewLDAPServer";
4927 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4928 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4931 atci = g_new0( AddressTypeControlItem, 1 );
4932 atci->objectType = ADDR_LDAP_QUERY;
4933 atci->interfaceType = ADDR_IF_LDAP;
4934 atci->showInTree = TRUE;
4935 atci->treeExpand = FALSE;
4936 atci->treeLeaf = TRUE;
4937 atci->displayName = _( "LDAP Query" );
4938 atci->iconXpm = addrsearchxpm;
4939 atci->iconXpmOpen = addrsearchxpm;
4940 atci->menuCommand = NULL;
4941 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4942 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4947 * Search for specified object type.
4949 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4951 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4955 * Search for specified interface type.
4957 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4958 GList *node = _addressBookTypeList_;
4960 AddressTypeControlItem *atci = node->data;
4961 if( atci->interfaceType == ifType ) return atci;
4962 node = g_list_next( node );
4967 static void addrbookctl_free_address( AddressObject *obj ) {
4968 g_free( obj->name );
4969 obj->type = ADDR_NONE;
4973 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4974 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4975 adapter->interface = NULL;
4976 adapter->interfaceType = ADDR_IF_NONE;
4977 adapter->atci = NULL;
4978 adapter->enabled = FALSE;
4979 adapter->haveLibrary = FALSE;
4980 adapter->treeNode = NULL;
4984 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
4985 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4986 adapter->dataSource = NULL;
4987 adapter->subType = ADDR_NONE;
4991 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
4992 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4993 adapter->itemFolder = NULL;
4997 static void addrbookctl_free_group( AdapterGroup *adapter ) {
4998 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4999 adapter->itemGroup = NULL;
5004 * Build GUI interface list.
5006 static void addrbookctl_build_iflist( void ) {
5007 AddressTypeControlItem *atci;
5008 AdapterInterface *adapter;
5011 if( _addressIndex_ == NULL ) {
5012 _addressIndex_ = addrindex_create_index();
5013 if( _clipBoard_ == NULL ) {
5014 _clipBoard_ = addrclip_create();
5016 addrclip_set_index( _clipBoard_, _addressIndex_ );
5018 _addressInterfaceList_ = NULL;
5019 list = addrindex_get_interface_list( _addressIndex_ );
5021 AddressInterface *interface = list->data;
5022 atci = addrbookctl_lookup_iface( interface->type );
5024 adapter = g_new0( AdapterInterface, 1 );
5025 adapter->interfaceType = interface->type;
5026 adapter->atci = atci;
5027 adapter->interface = interface;
5028 adapter->treeNode = NULL;
5029 adapter->enabled = TRUE;
5030 adapter->haveLibrary = interface->haveLibrary;
5031 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5032 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5033 _addressInterfaceList_ =
5034 g_list_append( _addressInterfaceList_, adapter );
5036 list = g_list_next( list );
5041 * Find GUI interface type specified interface type.
5042 * \param ifType Interface type.
5043 * \return Interface item, or NULL if not found.
5045 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5046 GList *node = _addressInterfaceList_;
5048 AdapterInterface *adapter = node->data;
5049 if( adapter->interfaceType == ifType ) return adapter;
5050 node = g_list_next( node );
5056 * Build interface list selection.
5058 static void addrbookctl_build_ifselect( void ) {
5059 GList *newList = NULL;
5064 gchar *endptr = NULL;
5066 AdapterInterface *adapter;
5068 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5071 splitStr = g_strsplit( selectStr, ",", -1 );
5072 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5074 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5075 ifType = strtol( splitStr[i], &endptr, 10 );
5078 if( strcmp( endptr, "/n" ) == 0 ) {
5082 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5083 adapter = addrbookctl_find_interface( ifType );
5085 newList = g_list_append( newList, adapter );
5092 /* g_print( "i=%d\n", i ); */
5093 g_strfreev( splitStr );
5094 g_free( selectStr );
5096 /* Replace existing list */
5097 mgu_clear_list( _addressIFaceSelection_ );
5098 g_list_free( _addressIFaceSelection_ );
5099 _addressIFaceSelection_ = newList;
5103 /* ***********************************************************************
5104 * Add sender to address book.
5105 * ***********************************************************************
5109 * This function is used by the Add sender to address book function.
5111 gboolean addressbook_add_contact(
5112 const gchar *name, const gchar *address, const gchar *remarks,
5113 GdkPixbuf *picture )
5115 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5116 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5117 debug_print( "addressbook_add_contact - added\n" );
5118 addressbook_refresh();
5123 /* ***********************************************************************
5124 * Book/folder selection.
5125 * ***********************************************************************
5129 * This function is used by the matcher dialog to select a book/folder.
5131 gchar *addressbook_folder_selection( const gchar *folderpath)
5133 AddressBookFile *book = NULL;
5134 ItemFolder *folder = NULL;
5137 g_return_val_if_fail( folderpath != NULL, NULL);
5139 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5141 if ( folder != NULL) {
5143 gchar *oldtmp = NULL;
5144 AddrItemObject *obj = NULL;
5146 /* walk thru folder->parent to build the full folder path */
5147 /* TODO: wwp: optimize this */
5149 tmp = g_strdup(obj->uid);
5150 while ( obj->parent ) {
5152 if ( obj->name != NULL ) {
5153 oldtmp = g_strdup(tmp);
5155 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5159 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5162 path = g_strdup_printf("%s", book->fileName);
5164 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5170 /* ***********************************************************************
5171 * Book/folder checking.
5172 * ***********************************************************************
5175 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5177 FolderInfo *fi = g_new0( FolderInfo, 1 );
5179 fi->folder = folder;
5183 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5184 FolderInfo *fiParent, FolderPathMatch *match )
5190 FolderPathMatch *nextmatch = NULL;
5195 list = parentFolder->listFolder;
5197 folder = list->data;
5198 fName = g_strdup( ADDRITEM_NAME(folder) );
5200 /* match folder name, match pointer will be set to NULL if next recursive call
5201 doesn't need to match subfolder name */
5202 if ( match != NULL &&
5203 match->matched == FALSE ) {
5204 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5205 /* folder name matches, prepare next subfolder match */
5206 debug_print("matched folder name '%s'\n", fName);
5208 if ( match->folder_path[match->index] == NULL ) {
5209 /* we've matched all elements */
5210 match->matched = TRUE;
5211 match->folder = folder;
5212 debug_print("book/folder path matched!\n");
5214 /* keep on matching */
5222 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5223 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5225 list = g_list_next( list );
5230 * This function is used by to check if a matcher book/folder path corresponds to an
5231 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5232 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5233 if book AND folder are NULL this means that folderpath was empty or Any.
5234 If folderpath is a simple book name (without folder), book will not be NULL and folder
5235 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5238 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5239 AddressDataSource **book,
5240 ItemFolder **folder )
5242 AddressDataSource *ds;
5243 GList *list, *nodeDS;
5244 ItemFolder *rootFolder;
5245 AddressBookFile *abf;
5247 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5254 if ( folderpath == NULL )
5257 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5260 /* split the folder path we've received, we'll try to match this path, subpath by
5261 subpath against the book/folder structure in order */
5262 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5263 if (!folder_path_match.folder_path)
5266 list = addrindex_get_interface_list( _addressIndex_ );
5267 while ( list && !folder_path_match.matched ) {
5268 AddressInterface *interface = list->data;
5269 if ( interface && interface->type == ADDR_IF_BOOK ) {
5270 nodeDS = interface->listSource;
5271 while ( nodeDS && !folder_path_match.matched ) {
5274 /* Read address book */
5275 if( ! addrindex_ds_get_read_flag( ds ) ) {
5276 addrindex_ds_read_data( ds );
5279 /* Add node for address book */
5280 abf = ds->rawDataSource;
5282 /* match book name */
5283 if ( abf && abf->fileName &&
5284 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5286 debug_print("matched book name '%s'\n", abf->fileName);
5287 folder_path_match.book = ds;
5289 if ( folder_path_match.folder_path[1] == NULL ) {
5290 /* no folder part to match */
5292 folder_path_match.matched = TRUE;
5293 folder_path_match.folder = NULL;
5294 debug_print("book path matched!\n");
5297 /* match folder part */
5299 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5300 rootFolder = addrindex_ds_get_root_folder( ds );
5302 /* prepare for recursive call */
5303 folder_path_match.index = 1;
5304 /* this call will set folder_path_match.matched and folder_path_match.folder */
5305 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5310 nodeDS = g_list_next( nodeDS );
5313 list = g_list_next( list );
5316 g_strfreev( folder_path_match.folder_path );
5319 *book = folder_path_match.book;
5321 *folder = folder_path_match.folder;
5322 return folder_path_match.matched;
5326 /* **********************************************************************
5328 * ***********************************************************************
5334 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5335 AddressDataSource *ds = NULL;
5336 AdapterDSource *ads = NULL;
5337 AddressBookFile *abf = NULL;
5338 AdapterInterface *adapter;
5339 GtkCMCTreeNode *newNode;
5341 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5343 if( adapter->treeNode ) {
5344 abf = addressbook_imp_ldif( _addressIndex_ );
5346 ds = addrindex_index_add_datasource(
5347 _addressIndex_, ADDR_IF_BOOK, abf );
5348 ads = addressbook_create_ds_adapter(
5349 ds, ADDR_BOOK, NULL );
5350 addressbook_ads_set_name(
5351 ads, addrbook_get_name( abf ) );
5352 newNode = addressbook_add_object(
5354 ADDRESS_OBJECT(ads) );
5356 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5358 addrbook.treeSelected = newNode;
5361 /* Notify address completion */
5362 invalidate_address_completion();
5371 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5372 AddressDataSource *ds = NULL;
5373 AdapterDSource *ads = NULL;
5374 AddressBookFile *abf = NULL;
5375 AdapterInterface *adapter;
5376 GtkCMCTreeNode *newNode;
5378 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5380 if( adapter->treeNode ) {
5381 abf = addressbook_imp_mutt( _addressIndex_ );
5383 ds = addrindex_index_add_datasource(
5384 _addressIndex_, ADDR_IF_BOOK, abf );
5385 ads = addressbook_create_ds_adapter(
5386 ds, ADDR_BOOK, NULL );
5387 addressbook_ads_set_name(
5388 ads, addrbook_get_name( abf ) );
5389 newNode = addressbook_add_object(
5391 ADDRESS_OBJECT(ads) );
5393 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5395 addrbook.treeSelected = newNode;
5398 /* Notify address completion */
5399 invalidate_address_completion();
5408 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5409 AddressDataSource *ds = NULL;
5410 AdapterDSource *ads = NULL;
5411 AddressBookFile *abf = NULL;
5412 AdapterInterface *adapter;
5413 GtkCMCTreeNode *newNode;
5415 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5417 if( adapter->treeNode ) {
5418 abf = addressbook_imp_pine( _addressIndex_ );
5420 ds = addrindex_index_add_datasource(
5421 _addressIndex_, ADDR_IF_BOOK, abf );
5422 ads = addressbook_create_ds_adapter(
5423 ds, ADDR_BOOK, NULL );
5424 addressbook_ads_set_name(
5425 ads, addrbook_get_name( abf ) );
5426 newNode = addressbook_add_object(
5428 ADDRESS_OBJECT(ads) );
5430 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5432 addrbook.treeSelected = newNode;
5435 /* Notify address completion */
5436 invalidate_address_completion();
5443 * Harvest addresses.
5444 * \param folderItem Folder to import.
5445 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5446 * \param msgList List of message numbers, or NULL to process folder.
5448 void addressbook_harvest(
5449 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5451 AddressDataSource *ds = NULL;
5452 AdapterDSource *ads = NULL;
5453 AddressBookFile *abf = NULL;
5454 AdapterInterface *adapter;
5455 GtkCMCTreeNode *newNode;
5457 abf = addrgather_dlg_execute(
5458 folderItem, _addressIndex_, sourceInd, msgList );
5460 ds = addrindex_index_add_datasource(
5461 _addressIndex_, ADDR_IF_BOOK, abf );
5463 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5465 if( adapter->treeNode ) {
5466 ads = addressbook_create_ds_adapter(
5467 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5468 newNode = addressbook_add_object(
5470 ADDRESS_OBJECT(ads) );
5474 /* Notify address completion */
5475 invalidate_address_completion();
5482 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5483 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5485 AddressDataSource *ds = NULL;
5486 AddrBookBase *adbase;
5487 AddressCache *cache;
5488 GtkCMCTreeNode *node = NULL;
5490 if( ! addrbook.treeSelected ) return;
5491 node = addrbook.treeSelected;
5492 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5493 obj = gtk_cmctree_node_get_row_data( ctree, node );
5494 if( obj == NULL ) return;
5496 ds = addressbook_find_datasource( node );
5497 if( ds == NULL ) return;
5498 adbase = ( AddrBookBase * ) ds->rawDataSource;
5499 cache = adbase->addressCache;
5500 addressbook_exp_html( cache );
5506 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5507 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5509 AddressDataSource *ds = NULL;
5510 AddrBookBase *adbase;
5511 AddressCache *cache;
5512 GtkCMCTreeNode *node = NULL;
5514 if( ! addrbook.treeSelected ) return;
5515 node = addrbook.treeSelected;
5516 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5517 obj = gtk_cmctree_node_get_row_data( ctree, node );
5518 if( obj == NULL ) return;
5520 ds = addressbook_find_datasource( node );
5521 if( ds == NULL ) return;
5522 adbase = ( AddrBookBase * ) ds->rawDataSource;
5523 cache = adbase->addressCache;
5524 addressbook_exp_ldif( cache );
5527 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5529 addrduplicates_find(GTK_WINDOW(addrbook.window));
5532 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5534 addressbook_custom_attr_edit();
5537 static void addressbook_start_drag(GtkWidget *widget, gint button,
5541 GdkDragContext *context;
5542 if (addressbook_target_list == NULL)
5543 addressbook_target_list = gtk_target_list_new(
5544 addressbook_drag_types, 1);
5545 context = gtk_drag_begin(widget, addressbook_target_list,
5546 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5547 gtk_drag_set_icon_default(context);
5550 static void addressbook_drag_data_get(GtkWidget *widget,
5551 GdkDragContext *drag_context,
5552 GtkSelectionData *selection_data,
5557 AddrItemObject *aio = NULL;
5558 AddressObject *pobj = NULL;
5559 AdapterDSource *ads = NULL;
5560 AddressDataSource *ds = NULL;
5563 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5565 if( pobj == NULL ) return;
5567 if( pobj->type == ADDR_DATASOURCE ) {
5568 ads = ADAPTER_DSOURCE(pobj);
5569 ds = ads->dataSource;
5570 } else if (pobj->type == ADDR_ITEM_GROUP) {
5575 else if( pobj->type != ADDR_INTERFACE ) {
5576 ds = addressbook_find_datasource( addrbook.treeSelected );
5582 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5583 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5584 GTK_CMCTREE_NODE(cur->data));
5585 while (aio && aio->type != ADDR_ITEM_PERSON) {
5590 if (aio && aio->type == ADDR_ITEM_PERSON) {
5591 if( ds && ds->interface && ds->interface->readOnly)
5592 gtk_selection_data_set(selection_data,
5593 selection_data->target, 8,
5594 (const guchar *)"Dummy_addr_copy", 15);
5596 gtk_selection_data_set(selection_data,
5597 selection_data->target, 8,
5598 (const guchar *)"Dummy_addr_move", 15);
5602 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5603 GdkDragContext *context,
5610 GtkCMCTreeNode *node = NULL;
5611 gboolean acceptable = FALSE;
5612 gint height = addrbook.ctree->allocation.height;
5613 gint total_height = addrbook.ctree->requisition.height;
5614 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5615 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5616 gfloat vpos = pos->value;
5618 if (gtk_cmclist_get_selection_info
5619 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5621 if (y > height - 24 && height + vpos < total_height) {
5622 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5623 gtk_adjustment_changed(pos);
5625 if (y < 24 && y > 0) {
5626 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5627 gtk_adjustment_changed(pos);
5629 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5632 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5633 if( obj->type == ADDR_ITEM_FOLDER
5634 || obj->type == ADDR_ITEM_GROUP)
5637 AdapterDSource *ads = NULL;
5638 AddressDataSource *ds = NULL;
5639 ads = ADAPTER_DSOURCE(obj);
5640 if (ads == NULL ){ return FALSE;}
5641 ds = ads->dataSource;
5642 if (ds == NULL ) { return FALSE;}
5650 g_signal_handlers_block_by_func
5652 G_CALLBACK(addressbook_tree_selected), NULL);
5653 gtk_sctree_select( GTK_SCTREE(widget), node);
5654 g_signal_handlers_unblock_by_func
5656 G_CALLBACK(addressbook_tree_selected), NULL);
5657 gdk_drag_status(context,
5658 (context->actions == GDK_ACTION_COPY ?
5659 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5661 gdk_drag_status(context, 0, time);
5666 static void addressbook_drag_leave_cb(GtkWidget *widget,
5667 GdkDragContext *context,
5671 if (addrbook.treeSelected) {
5672 g_signal_handlers_block_by_func
5674 G_CALLBACK(addressbook_tree_selected), NULL);
5675 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5676 g_signal_handlers_unblock_by_func
5678 G_CALLBACK(addressbook_tree_selected), NULL);
5683 static void addressbook_drag_received_cb(GtkWidget *widget,
5684 GdkDragContext *drag_context,
5687 GtkSelectionData *data,
5693 GtkCMCTreeNode *node;
5694 GtkCMCTreeNode *lastopened = addrbook.opened;
5696 if (!strncmp(data->data, "Dummy_addr", 10)) {
5697 if (gtk_cmclist_get_selection_info
5698 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5702 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5703 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5706 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5707 if (drag_context->action == GDK_ACTION_COPY ||
5708 !strcmp(data->data, "Dummy_addr_copy"))
5709 addressbook_clip_copy_cb(NULL, NULL);
5711 addressbook_clip_cut_cb(NULL, NULL);
5712 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5713 addressbook_clip_paste_cb(NULL,NULL);
5714 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5715 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5716 gtk_drag_finish(drag_context, TRUE, TRUE, time);