2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2009 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
32 #include <sys/types.h>
36 #include "addressbook.h"
37 #include "manage_window.h"
38 #include "prefs_common.h"
39 #include "alertpanel.h"
40 #include "inputdialog.h"
42 #include "stock_pixmap.h"
44 #include "prefs_gtk.h"
50 #include "addr_compl.h"
53 #include "addressitem.h"
55 #include "addrcache.h"
57 #include "addrindex.h"
58 #include "addressadd.h"
59 #include "addrduplicates.h"
60 #include "addressbook_foldersel.h"
62 #include "editvcard.h"
63 #include "editgroup.h"
64 #include "editaddress.h"
66 #include "importldif.h"
67 #include "importmutt.h"
68 #include "importpine.h"
73 #include "editjpilot.h"
78 #include "ldapserver.h"
80 #include "ldapupdate.h"
82 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
85 #include "addrquery.h"
86 #include "addrselect.h"
88 #include "addrgather.h"
89 #include "adbookbase.h"
90 #include "exphtmldlg.h"
91 #include "expldifdlg.h"
92 #include "browseldap.h"
93 #include "addrcustomattr.h"
99 } AddressIndexColumns;
107 } AddressListColumns;
110 AddressBookFile *book;
118 AddressDataSource *book;
122 static gchar *list_titles[] = { N_("Name"),
126 #define COL_NAME_WIDTH 164
127 #define COL_ADDRESS_WIDTH 156
129 #define COL_FOLDER_WIDTH 170
130 #define ADDRESSBOOK_WIDTH 640
131 #define ADDRESSBOOK_HEIGHT 360
133 #define ADDRESSBOOK_MSGBUF_SIZE 2048
135 static GdkPixbuf *folderxpm = NULL;
136 static GdkPixbuf *folderopenxpm = NULL;
137 static GdkPixbuf *groupxpm = NULL;
138 static GdkPixbuf *interfacexpm = NULL;
139 static GdkPixbuf *bookxpm = NULL;
140 static GdkPixbuf *addressxpm = NULL;
141 static GdkPixbuf *vcardxpm = NULL;
142 static GdkPixbuf *jpilotxpm = NULL;
143 static GdkPixbuf *categoryxpm = NULL;
144 static GdkPixbuf *ldapxpm = NULL;
145 static GdkPixbuf *addrsearchxpm = NULL;
148 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
150 /* Address list selection */
151 static AddrSelectList *_addressSelect_ = NULL;
152 static AddressClipboard *_clipBoard_ = NULL;
154 /* Address index file and interfaces */
155 static AddressIndex *_addressIndex_ = NULL;
156 static GList *_addressInterfaceList_ = NULL;
157 static GList *_addressIFaceSelection_ = NULL;
158 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
160 static AddressBook_win addrbook;
162 static GHashTable *_addressBookTypeHash_ = NULL;
163 static GList *_addressBookTypeList_ = NULL;
165 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
166 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
167 static void addressbook_edit_address_post_cb( ItemPerson *person );
169 static void addressbook_create (void);
170 static gint addressbook_close (void);
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;
670 Compose *addressbook_get_target_compose(void)
672 return addrbook.target_compose;
676 * Refresh addressbook and save to file(s).
678 void addressbook_refresh( void )
680 if (addrbook.window) {
681 if (addrbook.treeSelected) {
682 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
683 addrbook.treeSelected);
684 addressbook_set_clist(
685 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
686 addrbook.treeSelected),
691 addressbook_export_to_file();
694 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
696 if (event && event->keyval == GDK_Escape)
698 else if (event && event->keyval == GDK_Delete) {
699 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
700 if ( /* address_index_has_focus || */ address_list_has_focus )
701 addressbook_del_clicked(NULL, NULL);
707 *\brief Save Gtk object size to prefs dataset
709 static void addressbook_size_allocate_cb(GtkWidget *widget,
710 GtkAllocation *allocation)
712 cm_return_if_fail(allocation != NULL);
714 prefs_common.addressbookwin_width = allocation->width;
715 prefs_common.addressbookwin_height = allocation->height;
718 static gint sort_column_number = 0;
719 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
721 static gint list_case_sort(
722 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
724 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
725 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
726 gchar *name1 = NULL, *name2 = NULL;
727 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
728 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
730 if( aio1->type == aio2->type ) {
732 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
734 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
735 if( ! name1 ) return ( name2 != NULL );
736 if( ! name2 ) return -1;
737 return g_utf8_collate( name1, name2 );
739 /* Order groups before person */
740 if( aio1->type == ITEMTYPE_GROUP ) {
741 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
742 } else if( aio2->type == ITEMTYPE_GROUP ) {
743 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
749 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
750 const GtkSortType sort_type)
753 GtkWidget *hbox, *label, *arrow;
755 sort_column_number = col;
756 sort_column_type = sort_type;
757 gtk_cmclist_set_compare_func(clist, list_case_sort);
758 gtk_cmclist_set_sort_type(clist, sort_type);
759 gtk_cmclist_set_sort_column(clist, col);
761 gtk_cmclist_freeze(clist);
762 gtk_cmclist_sort(clist);
764 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
765 hbox = gtk_hbox_new(FALSE, 4);
766 label = gtk_label_new(gettext(list_titles[pos]));
767 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
770 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
771 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
772 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
775 gtk_widget_show_all(hbox);
776 gtk_cmclist_set_column_widget(clist, pos, hbox);
779 gtk_cmclist_thaw(clist);
782 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
784 static GtkSortType sort_type = GTK_SORT_ASCENDING;
786 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
788 addressbook_sort_list(clist, COL_NAME, sort_type);
791 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
793 static GtkSortType sort_type = GTK_SORT_ASCENDING;
795 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
797 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
800 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
802 static GtkSortType sort_type = GTK_SORT_ASCENDING;
804 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
806 addressbook_sort_list(clist, COL_REMARKS, sort_type);
809 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
812 address_index_has_focus = TRUE;
816 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
819 address_index_has_focus = FALSE;
820 if (!prefs_common.addressbook_use_editaddress_dialog
821 && !address_list_has_focus)
822 addressbook_address_list_disable_some_actions();
826 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
829 address_list_has_focus = TRUE;
833 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
836 address_list_has_focus = FALSE;
837 if (!prefs_common.addressbook_use_editaddress_dialog
838 && !address_index_has_focus)
839 addressbook_address_list_disable_some_actions();
843 /* save hpane and vpane's handle position when it moves */
844 static void addressbook_pane_save_position(void)
847 prefs_common.addressbook_hpaned_pos =
848 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
850 prefs_common.addressbook_vpaned_pos =
851 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
855 * Create the address book widgets. The address book contains two CTree widgets: the
856 * address index tree on the left and the address list on the right.
858 * The address index tree displays a hierarchy of interfaces and groups. Each node in
859 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
860 * data sources and folder objects.
862 * The address list displays group, person and email objects. These items are linked
863 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
866 * In the tradition of MVC architecture, the data stores have been separated from the
867 * GUI components. The addrindex.c file provides the interface to all data stores.
869 static void addressbook_create(void)
875 GtkWidget *ctree_swin;
877 GtkWidget *editaddress_vbox;
878 GtkWidget *clist_vbox;
879 GtkWidget *clist_swin;
886 GtkWidget *statusbar;
897 GtkWidget *close_btn;
898 GtkWidget *tree_popup;
899 GtkWidget *list_popup;
901 GtkUIManager *ui_manager;
902 GtkActionGroup *action_group;
903 gchar *index_titles[N_INDEX_COLS];
907 static GdkGeometry geometry;
909 debug_print("Creating addressbook window...\n");
911 index_titles[COL_SOURCES] = _("Sources");
913 /* Address book window */
914 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
915 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
916 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
917 gtk_widget_realize(window);
919 g_signal_connect(G_OBJECT(window), "delete_event",
920 G_CALLBACK(addressbook_close), NULL);
921 g_signal_connect(G_OBJECT(window), "size_allocate",
922 G_CALLBACK(addressbook_size_allocate_cb), NULL);
923 g_signal_connect(G_OBJECT(window), "key_press_event",
924 G_CALLBACK(key_pressed), NULL);
925 MANAGE_WINDOW_SIGNALS_CONNECT(window);
927 vbox = gtk_vbox_new(FALSE, 0);
928 gtk_container_add(GTK_CONTAINER(window), vbox);
931 ui_manager = gtk_ui_manager_new();
932 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
933 G_N_ELEMENTS(addressbook_entries), NULL);
934 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
935 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
936 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
937 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
940 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
942 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_POPUP)
945 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
951 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
955 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
958 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
960 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
968 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
983 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
990 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
991 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
994 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
996 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
999 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1001 hildon_window_set_menu(HILDON_WINDOW(window), GTK_MENU(menubar));
1004 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1005 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1006 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1008 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1009 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1010 GTK_POLICY_AUTOMATIC,
1011 GTK_POLICY_AUTOMATIC);
1012 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1015 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1016 GTK_WIDGET_UNSET_FLAGS(GTK_CMCLIST(ctree)->column[0].button,
1019 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1020 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1021 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1022 if (prefs_common.enable_dotted_lines) {
1023 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_DOTTED);
1024 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1025 GTK_CMCTREE_EXPANDER_SQUARE);
1027 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1028 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1029 GTK_CMCTREE_EXPANDER_TRIANGLE);
1031 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1032 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1033 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1034 addressbook_treenode_compare_func);
1036 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1037 G_CALLBACK(addressbook_tree_selected), NULL);
1038 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1039 G_CALLBACK(addressbook_tree_button_pressed),
1041 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1042 G_CALLBACK(addressbook_tree_button_released),
1045 g_signal_connect(G_OBJECT(ctree), "select_row",
1046 G_CALLBACK(addressbook_select_row_tree), NULL);
1048 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1049 addressbook_drag_types, 1,
1050 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1051 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1052 G_CALLBACK(addressbook_drag_motion_cb),
1054 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1055 G_CALLBACK(addressbook_drag_leave_cb),
1057 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1058 G_CALLBACK(addressbook_drag_received_cb),
1060 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1061 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1062 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1063 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1065 clist_vbox = gtk_vbox_new(FALSE, 4);
1067 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1068 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1069 GTK_POLICY_AUTOMATIC,
1070 GTK_POLICY_AUTOMATIC);
1071 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1074 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1075 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1076 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_EXTENDED);
1077 if (prefs_common.enable_dotted_lines) {
1078 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_DOTTED);
1079 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1080 GTK_CMCTREE_EXPANDER_SQUARE);
1082 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1083 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1084 GTK_CMCTREE_EXPANDER_TRIANGLE);
1086 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1087 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1088 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1090 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1092 gtk_widget_set_size_request(clist, -1, 80);
1094 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1095 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1096 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1097 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1098 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1099 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1100 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1101 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1102 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1103 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1104 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1106 for (i = 0; i < N_LIST_COLS; i++)
1107 GTK_WIDGET_UNSET_FLAGS(GTK_CMCLIST(clist)->column[i].button,
1110 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1111 G_CALLBACK(addressbook_list_row_selected), NULL);
1112 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1113 G_CALLBACK(addressbook_list_row_unselected), NULL);
1114 g_signal_connect(G_OBJECT(clist), "button_press_event",
1115 G_CALLBACK(addressbook_list_button_pressed),
1117 g_signal_connect(G_OBJECT(clist), "button_release_event",
1118 G_CALLBACK(addressbook_list_button_released),
1120 g_signal_connect(G_OBJECT(clist), "tree_expand",
1121 G_CALLBACK(addressbook_person_expand_node), NULL );
1122 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1123 G_CALLBACK(addressbook_person_collapse_node), NULL );
1124 g_signal_connect(G_OBJECT(clist), "start_drag",
1125 G_CALLBACK(addressbook_start_drag), NULL);
1126 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1127 G_CALLBACK(addressbook_drag_data_get), NULL);
1128 hbox = gtk_hbox_new(FALSE, 4);
1129 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1131 label = gtk_label_new(_("Lookup name:"));
1132 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1134 entry = gtk_entry_new();
1135 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1137 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1139 g_signal_connect(G_OBJECT(entry), "key_press_event",
1140 G_CALLBACK(addressbook_entry_key_pressed),
1143 if (!prefs_common.addressbook_use_editaddress_dialog) {
1144 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1145 vpaned = gtk_vpaned_new();
1146 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1147 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1150 editaddress_vbox = NULL;
1152 hpaned = gtk_hpaned_new();
1153 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1154 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1155 if (prefs_common.addressbook_use_editaddress_dialog)
1156 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1158 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1161 hsbox = gtk_hbox_new(FALSE, 0);
1162 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1163 statusbar = gtk_statusbar_new();
1164 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1167 hbbox = gtk_hbutton_box_new();
1168 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1169 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1170 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1171 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1173 gtkut_stock_button_add_help(hbbox, &help_btn);
1175 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1176 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1177 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1178 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1179 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1180 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1181 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1182 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1183 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1186 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1187 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1188 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1190 g_signal_connect(G_OBJECT(help_btn), "clicked",
1191 G_CALLBACK(manual_open_with_anchor_cb),
1192 MANUAL_ANCHOR_ADDRBOOK);
1194 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1195 G_CALLBACK(addressbook_edit_clicked), NULL);
1196 g_signal_connect(G_OBJECT(del_btn), "clicked",
1197 G_CALLBACK(addressbook_del_clicked), NULL);
1198 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1199 G_CALLBACK(addressbook_reg_clicked), NULL);
1200 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1201 G_CALLBACK(addressbook_lup_clicked), NULL);
1203 to_btn = gtk_button_new_with_label
1204 (prefs_common_translated_header_name("To:"));
1205 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1206 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1207 cc_btn = gtk_button_new_with_label
1208 (prefs_common_translated_header_name("Cc:"));
1209 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1210 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1211 bcc_btn = gtk_button_new_with_label
1212 (prefs_common_translated_header_name("Bcc:"));
1213 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1214 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1216 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1217 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1218 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1220 g_signal_connect(G_OBJECT(to_btn), "clicked",
1221 G_CALLBACK(addressbook_to_clicked),
1222 GINT_TO_POINTER(COMPOSE_TO));
1223 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1224 G_CALLBACK(addressbook_to_clicked),
1225 GINT_TO_POINTER(COMPOSE_CC));
1226 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1227 G_CALLBACK(addressbook_to_clicked),
1228 GINT_TO_POINTER(COMPOSE_BCC));
1229 g_signal_connect(G_OBJECT(close_btn), "clicked",
1230 G_CALLBACK(addressbook_close_clicked), NULL);
1232 /* Build icons for interface */
1234 /* Build control tables */
1235 addrbookctl_build_map(window);
1236 addrbookctl_build_iflist();
1237 addrbookctl_build_ifselect();
1239 addrbook.clist = NULL;
1241 /* Add each interface into the tree as a root level folder */
1242 nodeIf = _addressInterfaceList_;
1244 AdapterInterface *adapter = nodeIf->data;
1245 AddressInterface *iface = adapter->interface;
1246 nodeIf = g_list_next(nodeIf);
1248 if(iface->useInterface) {
1249 AddressTypeControlItem *atci = adapter->atci;
1250 text = atci->displayName;
1252 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1253 NULL, NULL, &text, FOLDER_SPACING,
1257 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1258 gtk_cmctree_node_set_row_data_full(
1259 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1260 addressbook_free_treenode );
1266 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1279 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1280 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1284 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1285 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1286 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1287 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1288 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1289 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1290 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1291 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1292 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1293 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1294 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1295 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1297 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1299 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1300 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1302 addrbook.window = window;
1303 addrbook.hpaned = hpaned;
1304 addrbook.vpaned = vpaned;
1305 addrbook.menubar = menubar;
1306 addrbook.ctree = ctree;
1309 addrbook.editaddress_vbox = editaddress_vbox;
1310 addrbook.clist = clist;
1311 addrbook.label = label;
1312 addrbook.entry = entry;
1313 addrbook.statusbar = statusbar;
1314 addrbook.status_cid = gtk_statusbar_get_context_id(
1315 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1317 addrbook.help_btn = help_btn;
1318 addrbook.edit_btn = edit_btn;
1319 addrbook.del_btn = del_btn;
1320 addrbook.reg_btn = reg_btn;
1321 addrbook.lup_btn = lup_btn;
1322 addrbook.to_btn = to_btn;
1323 addrbook.cc_btn = cc_btn;
1324 addrbook.bcc_btn = bcc_btn;
1326 addrbook.tree_popup = tree_popup;
1327 addrbook.list_popup = list_popup;
1328 addrbook.ui_manager = ui_manager;
1330 addrbook.listSelected = NULL;
1332 if (!geometry.min_height) {
1333 geometry.min_width = ADDRESSBOOK_WIDTH;
1334 geometry.min_height = ADDRESSBOOK_HEIGHT;
1337 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1339 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1340 prefs_common.addressbookwin_height);
1342 gtk_window_move(GTK_WINDOW(window), 48, 48);
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_edit_clicked(GtkButton *button, gpointer data)
1413 addressbook_edit_address_cb(NULL, NULL);
1416 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1418 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1422 * Delete one or more objects from address list.
1424 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1426 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1427 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1428 AddressObject *pobj;
1429 AdapterDSource *ads = NULL;
1430 GtkCMCTreeNode *nodeList;
1433 AddressBookFile *abf = NULL;
1434 AddressDataSource *ds = NULL;
1435 AddressInterface *iface;
1436 AddrItemObject *aio;
1437 AddrSelectItem *item;
1439 gboolean refreshList = FALSE;
1441 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1442 cm_return_if_fail(pobj != NULL);
1444 /* Test whether anything selected for deletion */
1445 nodeList = addrbook.listSelected;
1447 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1448 if( aio == NULL) return;
1449 ds = addressbook_find_datasource( addrbook.treeSelected );
1450 if( ds == NULL ) return;
1452 /* Test for read only */
1453 iface = ds->interface;
1454 if( iface->readOnly ) {
1455 alertpanel( _("Delete address(es)"),
1456 _("This address data is readonly and cannot be deleted."),
1457 GTK_STOCK_CLOSE, NULL, NULL );
1461 /* Test whether Ok to proceed */
1463 if( pobj->type == ADDR_DATASOURCE ) {
1464 ads = ADAPTER_DSOURCE(pobj);
1465 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1467 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1470 else if( pobj->type == ADDR_ITEM_GROUP ) {
1473 if( ! procFlag ) return;
1474 abf = ds->rawDataSource;
1475 if( abf == NULL ) return;
1477 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1478 g_signal_handlers_block_by_func
1479 (G_OBJECT(addrbook.clist),
1480 G_CALLBACK(addressbook_list_row_unselected), NULL);
1482 /* Process deletions */
1483 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1484 GList *groups = NULL, *persons = NULL, *emails = NULL;
1485 gboolean group_delete = TRUE;
1486 /* Items inside folders */
1487 list = addrselect_get_list( _addressSelect_ );
1488 /* Confirm deletion */
1492 node = g_list_next( node );
1493 aio = ( AddrItemObject * ) item->addressItem;
1494 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1495 group_delete = FALSE;
1500 aval = alertpanel( _("Delete group"),
1501 _("Really delete the group(s)?\n"
1502 "The addresses it contains will not be lost."),
1503 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1504 if( aval != G_ALERTALTERNATE ) {
1508 aval = alertpanel( _("Delete address(es)"),
1509 _("Really delete the address(es)?"),
1510 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1511 if( aval != G_ALERTALTERNATE ) {
1516 /* first, set lists of groups and persons to remove */
1520 node = g_list_next( node );
1521 aio = ( AddrItemObject * ) item->addressItem;
1524 if( aio->type == ADDR_ITEM_GROUP ) {
1525 groups = g_list_prepend(groups, item);
1527 else if( aio->type == ADDR_ITEM_PERSON ) {
1528 persons = g_list_prepend(persons, item);
1531 /* then set list of emails to remove *if* they're not children of
1532 * persons to remove */
1536 node = g_list_next( node );
1537 aio = ( AddrItemObject * ) item->addressItem;
1540 if( aio->type == ADDR_ITEM_EMAIL ) {
1541 ItemEMail *sitem = ( ItemEMail * ) aio;
1542 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1543 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1544 emails = g_list_prepend(emails, item);
1546 /* else, the email will be removed via the parent person */
1549 /* then delete groups */
1553 node = g_list_next( node );
1554 aio = ( AddrItemObject * ) item->addressItem;
1557 if( aio->type == ADDR_ITEM_GROUP ) {
1558 ItemGroup *item = ( ItemGroup * ) aio;
1559 GtkCMCTreeNode *nd = NULL;
1560 nd = addressbook_find_group_node( addrbook.opened, item );
1561 item = addrbook_remove_group( abf, item );
1563 addritem_free_item_group( item );
1565 /* Remove group from parent node */
1566 gtk_cmctree_remove_node( ctree, nd );
1570 /* then delete persons */
1574 node = g_list_next( node );
1575 aio = ( AddrItemObject * ) item->addressItem;
1578 if( aio->type == ADDR_ITEM_PERSON ) {
1579 ItemPerson *item = ( ItemPerson * ) aio;
1580 item->status = DELETE_ENTRY;
1581 addressbook_folder_remove_one_person( clist, item );
1582 if (pobj->type == ADDR_ITEM_FOLDER)
1583 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1584 item = addrbook_remove_person( abf, item );
1586 if (ds && ds->type == ADDR_IF_LDAP) {
1587 LdapServer *server = ds->rawDataSource;
1588 ldapsvr_set_modified(server, TRUE);
1589 ldapsvr_update_book(server, item);
1593 gchar *filename = addritem_person_get_picture(item);
1594 if (filename && is_file_exist(filename))
1595 claws_unlink(filename);
1597 addritem_free_item_person( item );
1601 /* then delete emails */
1605 node = g_list_next( node );
1606 aio = ( AddrItemObject * ) item->addressItem;
1610 if( aio->type == ADDR_ITEM_EMAIL ) {
1611 ItemEMail *sitem = ( ItemEMail * ) aio;
1612 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1613 sitem = addrbook_person_remove_email( abf, person, sitem );
1615 addrcache_remove_email(abf->addressCache, sitem);
1616 addritem_free_item_email( sitem );
1618 addressbook_folder_refresh_one_person( clist, person );
1621 g_list_free( groups );
1622 g_list_free( persons );
1623 g_list_free( emails );
1624 g_list_free( list );
1625 addressbook_list_select_clear();
1627 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1628 addressbook_set_clist(
1629 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1633 addrbook_set_dirty(abf, TRUE);
1634 addressbook_export_to_file();
1635 addressbook_list_menu_setup();
1638 else if( pobj->type == ADDR_ITEM_GROUP ) {
1639 /* Items inside groups */
1640 list = addrselect_get_list( _addressSelect_ );
1644 node = g_list_next( node );
1645 aio = ( AddrItemObject * ) item->addressItem;
1646 if( aio->type == ADDR_ITEM_EMAIL ) {
1647 ItemEMail *item = ( ItemEMail * ) aio;
1648 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1649 item = addrbook_person_remove_email( abf, person, item );
1651 addritem_free_item_email( item );
1655 g_list_free( list );
1656 addressbook_list_select_clear();
1657 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1658 addressbook_set_clist(
1659 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1663 addrbook_set_dirty(abf, TRUE);
1664 addressbook_export_to_file();
1665 addressbook_list_menu_setup();
1669 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1670 gtk_cmctree_remove_node( clist, nodeList );
1672 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1673 g_signal_handlers_unblock_by_func
1674 (G_OBJECT(addrbook.clist),
1675 G_CALLBACK(addressbook_list_row_unselected), NULL);
1678 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1680 addressbook_new_address_cb( NULL, NULL );
1683 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1686 gchar *address = NULL;
1688 if( aio->type == ADDR_ITEM_EMAIL ) {
1689 ItemPerson *person = NULL;
1690 ItemEMail *email = ( ItemEMail * ) aio;
1692 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1693 if( email->address ) {
1694 if( ADDRITEM_NAME(email) ) {
1695 name = ADDRITEM_NAME(email);
1696 if( *name == '\0' ) {
1697 name = ADDRITEM_NAME(person);
1700 else if( ADDRITEM_NAME(person) ) {
1701 name = ADDRITEM_NAME(person);
1704 buf = g_strdup( email->address );
1706 address = email->address;
1709 else if( aio->type == ADDR_ITEM_PERSON ) {
1710 ItemPerson *person = ( ItemPerson * ) aio;
1711 GList *node = person->listEMail;
1713 name = ADDRITEM_NAME(person);
1715 ItemEMail *email = ( ItemEMail * ) node->data;
1716 address = email->address;
1720 if( name && name[0] != '\0' ) {
1721 if( strchr_with_skip_quote( name, '"', ',' ) )
1722 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1724 buf = g_strdup_printf( "%s <%s>", name, address );
1727 buf = g_strdup( address );
1734 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1738 AddrSelectItem *item;
1739 AddrItemObject *aio;
1742 compose = addrbook.target_compose;
1743 if( ! compose ) return;
1745 /* Nothing selected, but maybe there is something in text entry */
1746 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1748 compose_entry_append(
1749 compose, addr, (ComposeEntryType)data , PREF_NONE);
1752 /* Select from address list */
1753 list = addrselect_get_list( _addressSelect_ );
1758 node = g_list_next( node );
1759 aio = item->addressItem;
1760 if( aio->type == ADDR_ITEM_PERSON ||
1761 aio->type == ADDR_ITEM_EMAIL ) {
1762 addr = addressbook_format_address( aio );
1763 compose_entry_append(
1764 compose, addr, (ComposeEntryType) data, PREF_NONE );
1767 else if( aio->type == ADDR_ITEM_GROUP ) {
1768 ItemGroup *group = ( ItemGroup * ) aio;
1769 GList *nodeMail = group->listEMail;
1771 ItemEMail *email = nodeMail->data;
1773 addr = addressbook_format_address(
1774 ( AddrItemObject * ) email );
1775 compose_entry_append(
1776 compose, addr, (ComposeEntryType) data, PREF_NONE );
1778 nodeMail = g_list_next( nodeMail );
1783 AddressObject *obj = NULL;
1785 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1787 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1788 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1789 GList *nodeMail = itemGroup->listEMail;
1791 ItemEMail *email = nodeMail->data;
1793 addr = addressbook_format_address(
1794 ( AddrItemObject * ) email );
1795 compose_entry_append(
1796 compose, addr, (ComposeEntryType) data, PREF_NONE );
1798 nodeMail = g_list_next( nodeMail );
1802 g_list_free( list );
1805 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1806 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1807 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1808 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1810 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1811 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1812 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1813 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1815 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1816 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1817 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1818 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1819 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1822 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1823 gboolean canEdit = FALSE;
1824 gboolean canDelete = TRUE;
1825 gboolean canAdd = FALSE;
1826 gboolean canEditTr = TRUE;
1827 gboolean editAddress = FALSE;
1828 gboolean canExport = TRUE;
1829 AddressTypeControlItem *atci = NULL;
1830 AddressDataSource *ds = NULL;
1831 AddressInterface *iface = NULL;
1833 if( obj == NULL ) return;
1834 if( obj->type == ADDR_INTERFACE ) {
1835 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1836 iface = adapter->interface;
1838 if( iface->haveLibrary ) {
1839 /* Enable appropriate File / New command */
1840 atci = adapter->atci;
1841 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1844 canEditTr = canExport = FALSE;
1846 else if( obj->type == ADDR_DATASOURCE ) {
1847 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1848 ds = ads->dataSource;
1849 iface = ds->interface;
1850 if( ! iface->readOnly ) {
1851 canAdd = canEdit = editAddress = canDelete = TRUE;
1853 if( ! iface->haveLibrary ) {
1854 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1857 else if( obj->type == ADDR_ITEM_FOLDER ) {
1858 ds = addressbook_find_datasource( addrbook.treeSelected );
1860 iface = ds->interface;
1861 if( iface->readOnly ) {
1866 canAdd = editAddress = TRUE;
1870 else if( obj->type == ADDR_ITEM_GROUP ) {
1871 ds = addressbook_find_datasource( addrbook.treeSelected );
1873 iface = ds->interface;
1874 if( ! iface->readOnly ) {
1880 if( addrbook.listSelected == NULL )
1884 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1885 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1886 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1887 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1890 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1891 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1892 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1893 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1895 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1896 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1899 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1900 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1904 * Address book tree callback function that responds to selection of tree
1907 * \param ctree Tree widget.
1908 * \param node Node that was selected.
1909 * \param column Column number where selected occurred.
1910 * \param data Pointer to user data.
1912 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1913 gint column, gpointer data)
1915 AddressObject *obj = NULL;
1916 AdapterDSource *ads = NULL;
1917 AddressDataSource *ds = NULL;
1918 ItemFolder *rootFolder = NULL;
1919 AddressObjectType aot;
1921 addrbook.treeSelected = node;
1922 addrbook.listSelected = NULL;
1923 addressbook_status_show( "" );
1924 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1926 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1928 addressbook_set_clist(NULL, TRUE);
1931 addrbook.opened = node;
1933 if( obj->type == ADDR_DATASOURCE ) {
1934 /* Read from file */
1935 static gboolean tVal = TRUE;
1937 ads = ADAPTER_DSOURCE(obj);
1938 if( ads == NULL ) return;
1939 ds = ads->dataSource;
1940 if( ds == NULL ) return;
1942 if( addrindex_ds_get_modify_flag( ds ) ) {
1943 addrindex_ds_read_data( ds );
1946 if( ! addrindex_ds_get_read_flag( ds ) ) {
1947 addrindex_ds_read_data( ds );
1949 addressbook_ds_show_message( ds );
1951 if( ! addrindex_ds_get_access_flag( ds ) ) {
1952 /* Remove existing folders and groups */
1953 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1954 addressbook_tree_remove_children( ctree, node );
1955 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1957 /* Load folders into the tree */
1958 rootFolder = addrindex_ds_get_root_folder( ds );
1959 if( ds && ds->type == ADDR_IF_JPILOT ) {
1960 aot = ADDR_CATEGORY;
1962 else if( ds && ds->type == ADDR_IF_LDAP ) {
1963 aot = ADDR_LDAP_QUERY;
1966 aot = ADDR_ITEM_FOLDER;
1968 addressbook_node_add_folder( node, ds, rootFolder, aot );
1969 addrindex_ds_set_access_flag( ds, &tVal );
1970 gtk_cmctree_expand( ctree, node );
1973 addressbook_set_clist(NULL, TRUE);
1976 /* Update address list */
1977 g_signal_handlers_block_by_func
1979 G_CALLBACK(addressbook_tree_selected), NULL);
1980 addressbook_set_clist( obj, FALSE );
1981 g_signal_handlers_unblock_by_func
1983 G_CALLBACK(addressbook_tree_selected), NULL);
1984 if (!prefs_common.addressbook_use_editaddress_dialog)
1985 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1987 /* Setup main menu selections */
1988 addressbook_menubar_set_sensitive( FALSE );
1989 addressbook_menuitem_set_sensitive( obj, node );
1990 addressbook_list_select_clear();
1991 addressbook_list_menu_setup();
1996 * Setup address list popup menu items. Items are enabled or disabled as
1999 static void addressbook_list_menu_setup( void ) {
2000 GtkCMCTree *clist = NULL;
2001 AddressObject *pobj = NULL;
2002 AddressObject *obj = NULL;
2003 AdapterDSource *ads = NULL;
2004 AddressInterface *iface = NULL;
2005 AddressDataSource *ds = NULL;
2006 gboolean canEdit = FALSE;
2007 gboolean canDelete = FALSE;
2008 gboolean canCut = FALSE;
2009 gboolean canCopy = FALSE;
2010 gboolean canPaste = FALSE;
2011 gboolean canBrowse = FALSE;
2013 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2014 if( pobj == NULL ) return;
2016 clist = GTK_CMCTREE(addrbook.clist);
2017 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2018 if( obj == NULL ) canEdit = FALSE;
2020 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2021 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2023 if( pobj->type == ADDR_DATASOURCE ) {
2024 /* Parent object is a data source */
2025 ads = ADAPTER_DSOURCE(pobj);
2026 ds = ads->dataSource;
2029 iface = ds->interface;
2032 if( ! iface->readOnly ) {
2033 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2034 if (iface->type != ADDR_IF_LDAP)
2035 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2036 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2039 canDelete = canEdit;
2042 else if( pobj->type != ADDR_INTERFACE ) {
2043 /* Parent object is not an interface */
2044 ds = addressbook_find_datasource( addrbook.treeSelected );
2047 iface = ds->interface;
2050 if( ! iface->readOnly ) {
2051 /* Folder or group */
2052 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2053 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2054 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2055 if( obj ) canEdit = TRUE;
2058 if( pobj->type == ADDR_ITEM_FOLDER ) {
2059 if (iface->type != ADDR_IF_LDAP)
2060 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2061 if( obj ) canEdit = TRUE;
2063 canDelete = canEdit;
2065 if( iface->type == ADDR_IF_LDAP ) {
2066 if( obj ) canBrowse = TRUE;
2073 /* Enable cut and paste */
2074 if( ! addrclip_is_empty( _clipBoard_ ) )
2076 if( ! addrselect_test_empty( _addressSelect_ ) )
2078 /* Enable copy if something is selected */
2079 if( ! addrselect_test_empty( _addressSelect_ ) )
2083 /* Disable edit or browse if more than one row selected */
2084 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2089 /* Forbid write changes when read-only */
2090 if( iface && iface->readOnly ) {
2096 /* Now go finalize menu items */
2097 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2098 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2101 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2102 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2104 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2106 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2107 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2108 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2110 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2111 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2112 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2114 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2115 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2117 if (addrbook.target_compose) {
2118 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2119 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2120 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2123 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2127 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2128 GtkCMCTreeNode *node,
2135 * Add list of items into tree node below specified tree node.
2136 * \param treeNode Tree node.
2137 * \param ds Data source.
2138 * \param listItems List of items.
2140 static void addressbook_treenode_add_list(
2141 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2147 AddrItemObject *aio;
2151 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2154 group = ( ItemGroup * ) aio;
2155 nn = addressbook_node_add_group( treeNode, ds, group );
2157 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2160 folder = ( ItemFolder * ) aio;
2161 nn = addressbook_node_add_folder(
2162 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2164 node = g_list_next( node );
2168 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2169 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2173 * Cut from address list widget.
2175 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2176 _clipBoard_->cutFlag = TRUE;
2177 addrclip_clear( _clipBoard_ );
2178 addrclip_add( _clipBoard_, _addressSelect_ );
2179 /* addrclip_list_show( _clipBoard_, stdout ); */
2183 * Copy from address list widget.
2185 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2186 _clipBoard_->cutFlag = FALSE;
2187 addrclip_clear( _clipBoard_ );
2188 addrclip_add( _clipBoard_, _addressSelect_ );
2189 /* addrclip_list_show( _clipBoard_, stdout ); */
2193 * Paste clipboard into address list widget.
2195 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2196 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2197 AddressObject *pobj = NULL;
2198 AddressDataSource *ds = NULL;
2199 AddressBookFile *abf = NULL;
2200 ItemFolder *folder = NULL;
2201 GList *folderGroup = NULL;
2203 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2204 if( ds == NULL ) return;
2205 if( addrindex_ds_get_readonly( ds ) ) {
2206 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2210 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2212 if( pobj->type == ADDR_ITEM_FOLDER ) {
2213 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2215 else if( pobj->type == ADDR_ITEM_GROUP ) {
2216 alertpanel_error( _("Cannot paste into an address group.") );
2221 /* Get an address book */
2222 abf = addressbook_get_book_file();
2223 if( abf == NULL ) return;
2225 if( _clipBoard_->cutFlag ) {
2227 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2229 /* Remove all groups and folders in clipboard from tree node */
2230 addressbook_treenode_remove_item();
2232 /* Remove all "cut" items */
2233 addrclip_delete_item( _clipBoard_ );
2235 /* Clear clipboard - cut items??? */
2236 addrclip_clear( _clipBoard_ );
2240 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2243 /* addrclip_list_show( _clipBoard_, stdout ); */
2245 /* Update tree by inserting node for each folder or group */
2246 addressbook_treenode_add_list(
2247 addrbook.treeSelected, ds, folderGroup );
2248 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2249 g_list_free( folderGroup );
2253 /* Display items pasted */
2254 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2255 addressbook_set_clist(
2256 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2264 * Add current treenode object to clipboard. Note that widget only allows
2265 * one entry from the tree list to be selected.
2267 static void addressbook_treenode_to_clipboard( void ) {
2268 AddressObject *obj = NULL;
2269 AddressDataSource *ds = NULL;
2270 AddrSelectItem *item;
2271 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2272 GtkCMCTreeNode *node;
2274 node = addrbook.treeSelected;
2275 if( node == NULL ) return;
2276 obj = gtk_cmctree_node_get_row_data( ctree, node );
2277 if( obj == NULL ) return;
2279 ds = addressbook_find_datasource( node );
2280 if( ds == NULL ) return;
2283 if( obj->type == ADDR_ITEM_FOLDER ) {
2284 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2285 ItemFolder *folder = adapter->itemFolder;
2287 item = addrselect_create_node( obj );
2288 item->uid = g_strdup( ADDRITEM_ID(folder) );
2290 else if( obj->type == ADDR_ITEM_GROUP ) {
2291 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2292 ItemGroup *group = adapter->itemGroup;
2294 item = addrselect_create_node( obj );
2295 item->uid = g_strdup( ADDRITEM_ID(group) );
2297 else if( obj->type == ADDR_DATASOURCE ) {
2299 item = addrselect_create_node( obj );
2304 /* Clear existing list and add item into list */
2307 addressbook_list_select_clear();
2308 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2309 addrselect_list_add( _addressSelect_, item, cacheID );
2315 * Cut from tree widget.
2317 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2318 _clipBoard_->cutFlag = TRUE;
2319 addressbook_treenode_to_clipboard();
2320 addrclip_clear( _clipBoard_ );
2321 addrclip_add( _clipBoard_, _addressSelect_ );
2322 /* addrclip_list_show( _clipBoard_, stdout ); */
2326 * Copy from tree widget.
2328 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2329 _clipBoard_->cutFlag = FALSE;
2330 addressbook_treenode_to_clipboard();
2331 addrclip_clear( _clipBoard_ );
2332 addrclip_add( _clipBoard_, _addressSelect_ );
2333 /* addrclip_list_show( _clipBoard_, stdout ); */
2337 * Paste clipboard into address tree widget.
2339 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2340 addressbook_clip_paste_cb(NULL,NULL);
2344 * Clear selected entries in clipboard.
2346 static void addressbook_list_select_clear( void ) {
2347 addrselect_list_clear( _addressSelect_ );
2351 * Add specified address item to selected address list.
2352 * \param aio Address item object.
2353 * \param ds Datasource.
2355 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2358 if( ds == NULL ) return;
2359 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2360 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2365 * Remove specified address item from selected address list.
2366 * \param aio Address item object.
2368 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2369 addrselect_list_remove( _addressSelect_, aio );
2373 * Invoke EMail compose window with addresses in selected address list.
2375 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2378 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2379 listAddress = addrselect_build_list( _addressSelect_ );
2380 compose_new_with_list( NULL, listAddress );
2381 mgu_free_dlist( listAddress );
2386 static void addressbook_list_row_selected( GtkCMCTree *clist,
2387 GtkCMCTreeNode *node,
2391 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2392 AddrItemObject *aio = NULL;
2393 AddressObject *pobj = NULL;
2394 AdapterDSource *ads = NULL;
2395 AddressDataSource *ds = NULL;
2397 gtk_entry_set_text( entry, "" );
2398 addrbook.listSelected = node;
2400 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2401 if( pobj == NULL ) return;
2403 if( pobj->type == ADDR_DATASOURCE ) {
2404 ads = ADAPTER_DSOURCE(pobj);
2405 ds = ads->dataSource;
2407 else if( pobj->type != ADDR_INTERFACE ) {
2408 ds = addressbook_find_datasource( addrbook.treeSelected );
2411 aio = gtk_cmctree_node_get_row_data( clist, node );
2413 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2414 addressbook_list_select_add( aio, ds );
2417 addressbook_list_menu_setup();
2419 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2420 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2422 if (obj && obj->type != ADDR_ITEM_GROUP)
2423 addressbook_edit_address(NULL, 0, NULL, FALSE);
2427 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2428 GtkCMCTreeNode *node,
2432 AddrItemObject *aio;
2434 aio = gtk_cmctree_node_get_row_data( ctree, node );
2436 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2437 addressbook_list_select_remove( aio );
2440 if (!prefs_common.addressbook_use_editaddress_dialog)
2441 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2444 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2445 GdkEventButton *event,
2448 if( ! event ) return FALSE;
2450 addressbook_list_menu_setup();
2452 if( event->button == 3 ) {
2453 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2454 event->button, event->time );
2455 } else if (event->button == 1) {
2456 if (event->type == GDK_2BUTTON_PRESS) {
2457 if (prefs_common.add_address_by_click &&
2458 addrbook.target_compose)
2459 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2461 if (prefs_common.addressbook_use_editaddress_dialog)
2462 addressbook_edit_address_cb(NULL, NULL);
2464 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2465 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2466 if( obj && obj->type == ADDR_ITEM_GROUP )
2467 addressbook_edit_address_cb(NULL, NULL);
2475 static gboolean addressbook_list_button_released(GtkWidget *widget,
2476 GdkEventButton *event,
2482 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2483 GdkEventButton *event,
2486 GtkCMCList *clist = GTK_CMCLIST(ctree);
2488 AddressObject *obj = NULL;
2489 AdapterDSource *ads = NULL;
2490 AddressInterface *iface = NULL;
2491 AddressDataSource *ds = NULL;
2492 gboolean canEdit = FALSE;
2493 gboolean canDelete = FALSE;
2494 gboolean canCut = FALSE;
2495 gboolean canCopy = FALSE;
2496 gboolean canPaste = FALSE;
2497 gboolean canTreeCut = FALSE;
2498 gboolean canTreeCopy = FALSE;
2499 gboolean canTreePaste = FALSE;
2500 gboolean canLookup = FALSE;
2501 GtkCMCTreeNode *node = NULL;
2503 if( ! event ) return FALSE;
2504 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2506 if (event->button == 1) {
2507 if (event->type == GDK_2BUTTON_PRESS) {
2508 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2509 gtkut_clist_set_focus_row(clist, row);
2510 obj = gtk_cmclist_get_row_data( clist, row );
2515 if (obj->type == ADDR_ITEM_GROUP) {
2517 addressbook_treenode_edit_cb(NULL, NULL);
2519 /* expand pr collapse */
2520 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2521 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2527 addressbook_menubar_set_sensitive( FALSE );
2529 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2530 gtkut_clist_set_focus_row(clist, row);
2531 obj = gtk_cmclist_get_row_data( clist, row );
2534 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2538 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2540 if( ! addrclip_is_empty( _clipBoard_ ) )
2541 canTreePaste = TRUE;
2543 if (obj->type == ADDR_INTERFACE) {
2544 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2545 iface = adapter->interface;
2548 if( !iface->readOnly ) {
2549 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2550 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2552 if( iface->externalQuery )
2555 if (obj->type == ADDR_DATASOURCE) {
2556 ads = ADAPTER_DSOURCE(obj);
2557 ds = ads->dataSource;
2560 iface = ds->interface;
2563 if( !iface->readOnly ) {
2565 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2566 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2567 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2571 if( iface->externalQuery )
2574 else if (obj->type == ADDR_ITEM_FOLDER) {
2575 ds = addressbook_find_datasource( node );
2578 iface = ds->interface;
2581 if( !iface->readOnly ) {
2585 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2586 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2587 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2591 if( iface->externalQuery ) {
2592 /* Enable deletion of LDAP folder */
2597 else if (obj->type == ADDR_ITEM_GROUP) {
2598 ds = addressbook_find_datasource( node );
2601 iface = ds->interface;
2604 if( ! iface->readOnly ) {
2607 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2608 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2612 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2614 if( ! addrselect_test_empty( _addressSelect_ ) )
2616 if( ! addrclip_is_empty( _clipBoard_ ) )
2619 /* Forbid write changes when read-only */
2620 if( iface && iface->readOnly ) {
2622 canTreePaste = FALSE;
2630 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2631 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2632 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2633 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2634 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2636 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2637 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2638 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2639 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2640 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2642 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2643 addrbook.target_compose != NULL);
2645 if( event->button == 3 )
2646 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2647 event->button, event->time);
2652 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2653 GdkEventButton *event,
2656 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2660 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2662 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2663 AddressObject *obj = NULL;
2664 AddressDataSource *ds = NULL;
2665 AddressBookFile *abf = NULL;
2666 ItemFolder *parentFolder = NULL;
2667 ItemFolder *folder = NULL;
2669 if( ! addrbook.treeSelected ) return;
2670 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2671 if( obj == NULL ) return;
2672 ds = addressbook_find_datasource( addrbook.treeSelected );
2673 if( ds == NULL ) return;
2675 if( obj->type == ADDR_DATASOURCE ) {
2676 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2678 else if( obj->type == ADDR_ITEM_FOLDER ) {
2679 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2685 abf = ds->rawDataSource;
2686 if( abf == NULL ) return;
2687 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2690 nn = addressbook_node_add_folder(
2691 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2692 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2693 if( addrbook.treeSelected == addrbook.opened )
2694 addressbook_set_clist(obj, TRUE);
2698 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2700 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2701 AddressObject *obj = NULL;
2702 AddressDataSource *ds = NULL;
2703 AddressBookFile *abf = NULL;
2704 ItemFolder *parentFolder = NULL;
2705 ItemGroup *group = NULL;
2707 if( ! addrbook.treeSelected ) return;
2708 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2709 if( obj == NULL ) return;
2710 ds = addressbook_find_datasource( addrbook.treeSelected );
2711 if( ds == NULL ) return;
2713 if( obj->type == ADDR_DATASOURCE ) {
2714 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2716 else if( obj->type == ADDR_ITEM_FOLDER ) {
2717 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2723 abf = ds->rawDataSource;
2724 if( abf == NULL ) return;
2725 group = addressbook_edit_group( abf, parentFolder, NULL );
2728 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2729 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2730 if( addrbook.treeSelected == addrbook.opened )
2731 addressbook_set_clist(obj, TRUE);
2735 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2737 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2740 GdkPixbuf *pix_cl, *pix_op;
2741 gboolean is_leaf, expanded;
2743 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2745 &is_leaf, &expanded);
2746 gtk_sctree_set_node_info(ctree, node, name, spacing,
2753 * \param obj Address object to edit.
2754 * \param node Node in tree.
2755 * \return New name of data source.
2757 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2758 gchar *newName = NULL;
2759 AddressDataSource *ds = NULL;
2760 AddressInterface *iface = NULL;
2761 AdapterDSource *ads = NULL;
2763 ds = addressbook_find_datasource( node );
2764 if( ds == NULL ) return NULL;
2765 iface = ds->interface;
2766 if( ! iface->haveLibrary ) return NULL;
2768 /* Read data from data source */
2769 if( addrindex_ds_get_modify_flag( ds ) ) {
2770 addrindex_ds_read_data( ds );
2773 if( ! addrindex_ds_get_read_flag( ds ) ) {
2774 addrindex_ds_read_data( ds );
2778 ads = ADAPTER_DSOURCE(obj);
2779 if( ads->subType == ADDR_BOOK ) {
2780 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2782 else if( ads->subType == ADDR_VCARD ) {
2783 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2786 else if( ads->subType == ADDR_JPILOT ) {
2787 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2791 else if( ads->subType == ADDR_LDAP ) {
2792 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2798 newName = obj->name;
2803 * Edit an object that is in the address tree area.
2805 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2807 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2809 AddressDataSource *ds = NULL;
2810 AddressBookFile *abf = NULL;
2811 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2814 if( ! addrbook.treeSelected ) return;
2815 node = addrbook.treeSelected;
2816 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2817 obj = gtk_cmctree_node_get_row_data( ctree, node );
2818 if( obj == NULL ) return;
2819 parentNode = GTK_CMCTREE_ROW(node)->parent;
2821 ds = addressbook_find_datasource( node );
2822 if( ds == NULL ) return;
2824 if( obj->type == ADDR_DATASOURCE ) {
2825 name = addressbook_edit_datasource( obj, node );
2826 if( name == NULL ) return;
2829 abf = ds->rawDataSource;
2830 if( abf == NULL ) return;
2831 if( obj->type == ADDR_ITEM_FOLDER ) {
2832 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2833 ItemFolder *item = adapter->itemFolder;
2834 ItemFolder *parentFolder = NULL;
2835 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2836 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2837 name = ADDRITEM_NAME(item);
2839 else if( obj->type == ADDR_ITEM_GROUP ) {
2840 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2841 ItemGroup *item = adapter->itemGroup;
2842 ItemFolder *parentFolder = NULL;
2843 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2844 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2845 name = ADDRITEM_NAME(item);
2848 if( name && parentNode ) {
2849 /* Update node in tree view */
2850 addressbook_change_node_name( node, name );
2851 gtk_sctree_sort_node(ctree, parentNode);
2852 gtk_cmctree_expand( ctree, node );
2853 gtk_sctree_select( GTK_SCTREE( ctree), node );
2860 ADDRTREE_DEL_FOLDER_ONLY,
2861 ADDRTREE_DEL_FOLDER_ADDR
2865 * Delete an item from the tree widget.
2866 * \param data Data passed in.
2867 * \param action Action.
2868 * \param widget Widget issuing callback.
2870 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2872 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2873 GtkCMCTreeNode *node = NULL;
2877 AddrBookBase *adbase;
2878 AddressCache *cache;
2879 AdapterDSource *ads = NULL;
2880 AddressInterface *iface = NULL;
2881 AddressDataSource *ds = NULL;
2882 gboolean remFlag = FALSE;
2883 TreeItemDelType delType;
2885 if( ! addrbook.treeSelected ) return;
2886 node = addrbook.treeSelected;
2887 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2889 obj = gtk_cmctree_node_get_row_data( ctree, node );
2890 cm_return_if_fail(obj != NULL);
2892 if( obj->type == ADDR_DATASOURCE ) {
2893 ads = ADAPTER_DSOURCE(obj);
2894 if( ads == NULL ) return;
2895 ds = ads->dataSource;
2896 if( ds == NULL ) return;
2899 /* Must be folder or something else */
2900 ds = addressbook_find_datasource( node );
2901 if( ds == NULL ) return;
2903 /* Only allow deletion from non-readOnly */
2904 iface = ds->interface;
2905 if( iface->readOnly ) {
2906 /* Allow deletion of query results */
2907 if( ! iface->externalQuery ) return;
2911 /* Confirm deletion */
2912 delType = ADDRTREE_DEL_NONE;
2913 if( obj->type == ADDR_ITEM_FOLDER ) {
2914 if( iface->externalQuery ) {
2915 message = g_strdup_printf( _(
2916 "Do you want to delete the query " \
2917 "results and addresses in '%s' ?" ),
2919 aval = alertpanel( _("Delete"), message,
2920 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2922 if( aval == G_ALERTALTERNATE ) {
2923 delType = ADDRTREE_DEL_FOLDER_ADDR;
2927 message = g_strdup_printf
2928 ( _( "Do you want to delete '%s' ? "
2929 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2931 aval = alertpanel( _("Delete folder"), message,
2932 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2934 if( aval == G_ALERTALTERNATE ) {
2935 delType = ADDRTREE_DEL_FOLDER_ONLY;
2937 else if( aval == G_ALERTOTHER ) {
2938 delType = ADDRTREE_DEL_FOLDER_ADDR;
2942 else if( obj->type == ADDR_ITEM_GROUP ) {
2943 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2944 "The addresses it contains will not be lost."), obj->name);
2945 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2946 "+" GTK_STOCK_DELETE, NULL);
2948 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2950 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2951 "The addresses it contains will be lost."), obj->name);
2952 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2953 "+" GTK_STOCK_DELETE, NULL);
2955 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2957 if( delType == ADDRTREE_DEL_NONE ) return;
2959 /* Proceed with deletion */
2960 if( obj->type == ADDR_DATASOURCE ) {
2961 /* Remove node from tree */
2962 gtk_cmctree_remove_node( ctree, node );
2964 /* Remove data source. */
2965 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2966 addrindex_free_datasource( ds );
2971 /* Get reference to cache */
2972 adbase = ( AddrBookBase * ) ds->rawDataSource;
2973 if( adbase == NULL ) return;
2974 cache = adbase->addressCache;
2976 /* Remove query results folder */
2977 if( iface->externalQuery ) {
2978 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2979 ItemFolder *folder = adapter->itemFolder;
2981 adapter->itemFolder = NULL;
2983 g_print( "remove folder for ::%s::\n", obj->name );
2984 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2985 g_print( "-------------- remove results\n" );
2987 addrindex_remove_results( ds, folder );
2988 /* g_print( "-------------- remove node\n" ); */
2989 gtk_cmctree_remove_node( ctree, node );
2993 /* Code below is valid for regular address book deletion */
2994 if( obj->type == ADDR_ITEM_FOLDER ) {
2995 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2996 ItemFolder *item = adapter->itemFolder;
2998 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2999 /* Remove folder only */
3000 item = addrcache_remove_folder( cache, item );
3002 addritem_free_item_folder( item );
3003 addressbook_move_nodes_up( ctree, node );
3007 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3008 /* Remove folder and addresses */
3009 item = addrcache_remove_folder_delete( cache, item );
3011 addritem_free_item_folder( item );
3016 else if( obj->type == ADDR_ITEM_GROUP ) {
3017 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3018 ItemGroup *item = adapter->itemGroup;
3020 item = addrcache_remove_group( cache, item );
3022 addritem_free_item_group( item );
3029 gtk_cmctree_remove_node(ctree, node );
3033 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3035 if( person && addrbook.treeSelected == addrbook.opened ) {
3036 person->status = ADD_ENTRY;
3037 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3038 addressbook_folder_refresh_one_person(
3039 GTK_CMCTREE(addrbook.clist), person );
3041 addressbook_address_list_set_focus();
3044 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3046 if( person && addrbook.treeSelected == addrbook.opened) {
3047 person->status = ADD_ENTRY;
3048 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3049 addressbook_set_clist(
3050 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3054 addressbook_address_list_set_focus();
3058 * Label (a format string) that is used to name each folder.
3060 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3063 * Search ctree widget callback function.
3064 * \param pA Pointer to node.
3065 * \param pB Pointer to data item being sought.
3066 * \return Zero (0) if folder found.
3068 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3071 aoA = ( AddressObject * ) pA;
3072 if( aoA->type == ADDR_ITEM_FOLDER ) {
3073 ItemFolder *folder, *fld;
3075 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3076 folder = ( ItemFolder * ) pB;
3077 if( fld == folder ) return 0; /* Found folder */
3082 static ItemFolder * addressbook_setup_subf(
3083 AddressDataSource *ds, gchar *title,
3084 GtkCMCTreeNode *pNode )
3086 AddrBookBase *adbase;
3087 AddressCache *cache;
3090 GtkCMCTreeNode *nNode;
3092 AddressObjectType aoType = ADDR_NONE;
3095 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3097 if( ds && ds->type == ADDR_IF_LDAP ) {
3099 aoType = ADDR_LDAP_QUERY;
3106 ctree = GTK_CMCTREE(addrbook.ctree);
3107 /* Get reference to address cache */
3108 adbase = ( AddrBookBase * ) ds->rawDataSource;
3109 cache = adbase->addressCache;
3111 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3112 GList *cur = children;
3113 for (; cur; cur = cur->next) {
3114 ItemFolder *child = (ItemFolder *) cur->data;
3115 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3116 nNode = gtk_cmctree_find_by_row_data_custom(
3118 addressbook_treenode_find_folder_cb );
3120 addrindex_remove_results( ds, child );
3121 while( child->listPerson ) {
3122 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3123 item = addrcache_remove_person( cache, item );
3125 addritem_free_item_person( item );
3129 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3130 addrbook.treeSelected = nNode;
3137 /* Create a folder */
3138 folder = addrcache_add_new_folder( cache, NULL );
3139 name = g_strdup_printf( "%s", title );
3140 addritem_folder_set_name( folder, name );
3141 addritem_folder_set_remarks( folder, "" );
3144 /* Now let's see the folder */
3145 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3146 gtk_cmctree_expand( ctree, pNode );
3148 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3149 addrbook.treeSelected = nNode;
3155 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3156 AddressObject *pobj = NULL;
3157 AddressDataSource *ds = NULL;
3158 AddressBookFile *abf = NULL;
3159 debug_print("adding address\n");
3160 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3161 if( pobj == NULL ) {
3162 debug_print("no row data\n");
3165 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3167 debug_print("no datasource\n");
3171 abf = ds->rawDataSource;
3173 g_print("no addressbook file\n");
3177 if( pobj->type == ADDR_DATASOURCE ) {
3178 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3179 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3181 ItemFolder *folder = NULL;
3183 if (abf && abf->type == ADDR_IF_LDAP) {
3184 GtkCMCTreeNode *parentNode;
3185 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3186 if( ds == NULL ) return;
3188 /* We must have a datasource that is an external interface */
3189 if( ! ds->interface->haveLibrary ) return;
3190 if( ! ds->interface->externalQuery ) return;
3192 if( pobj->type == ADDR_ITEM_FOLDER ) {
3193 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3196 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3198 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3200 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3201 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3203 abf = ds->rawDataSource;
3206 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3207 addrbook.editaddress_vbox,
3208 addressbook_new_address_from_book_post_cb,
3211 if (ds && abf && abf->type == ADDR_IF_LDAP) {
3212 LdapServer *server = ds->rawDataSource;
3213 ldapsvr_set_modified(server, TRUE);
3214 ldapsvr_update_book(server, NULL);
3215 if (server->retVal != LDAPRC_SUCCESS) {
3216 alertpanel( _("Add address(es)"),
3217 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3218 GTK_STOCK_CLOSE, NULL, NULL );
3219 server->retVal = LDAPRC_SUCCESS;
3224 if (prefs_common.addressbook_use_editaddress_dialog)
3225 addressbook_new_address_from_book_post_cb( person );
3228 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3230 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3233 if (abf && abf->type == ADDR_IF_LDAP) {
3234 GtkCMCTreeNode *parentNode;
3235 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3236 if( ds == NULL ) return;
3238 /* We must have a datasource that is an external interface */
3239 if( ! ds->interface->haveLibrary ) return;
3240 if( ! ds->interface->externalQuery ) return;
3242 if( pobj->type == ADDR_ITEM_FOLDER ) {
3243 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3246 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3248 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3251 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3252 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3254 abf = ds->rawDataSource;
3257 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3258 addrbook.editaddress_vbox,
3259 addressbook_new_address_from_folder_post_cb,
3262 if (ds && abf && abf->type == ADDR_IF_LDAP) {
3263 LdapServer *server = ds->rawDataSource;
3264 ldapsvr_set_modified(server, TRUE);
3265 ldapsvr_update_book(server, NULL);
3266 if (server->retVal != LDAPRC_SUCCESS) {
3267 alertpanel( _("Add address(es)"),
3268 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3269 GTK_STOCK_CLOSE, NULL, NULL );
3274 if (prefs_common.addressbook_use_editaddress_dialog)
3275 addressbook_new_address_from_folder_post_cb( person );
3277 else if( pobj->type == ADDR_ITEM_GROUP ) {
3278 /* New address in group */
3279 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3280 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3281 if (addrbook.treeSelected == addrbook.opened) {
3282 /* Change node name in tree. */
3283 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3284 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3285 addressbook_set_clist(
3286 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3294 * Search for specified child group node in address index tree.
3295 * \param parent Parent node.
3296 * \param group Group to find.
3298 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3299 GtkCMCTreeNode *node = NULL;
3300 GtkCMCTreeRow *currRow;
3302 currRow = GTK_CMCTREE_ROW( parent );
3304 node = currRow->children;
3308 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3309 if( obj->type == ADDR_ITEM_GROUP ) {
3310 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3311 if( g == group ) return node;
3313 currRow = GTK_CMCTREE_ROW(node);
3314 node = currRow->sibling;
3320 static AddressBookFile *addressbook_get_book_file() {
3321 AddressBookFile *abf = NULL;
3322 AddressDataSource *ds = NULL;
3324 ds = addressbook_find_datasource( addrbook.treeSelected );
3325 if( ds == NULL ) return NULL;
3326 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3330 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3331 GtkCMCTreeNode *node;
3334 /* Remove existing folders and groups */
3335 row = GTK_CMCTREE_ROW( parent );
3337 while( (node = row->children) ) {
3338 gtk_cmctree_remove_node( ctree, node );
3343 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3344 GtkCMCTreeNode *parent, *child;
3345 GtkCMCTreeRow *currRow;
3346 currRow = GTK_CMCTREE_ROW( node );
3348 parent = currRow->parent;
3349 while( (child = currRow->children) ) {
3350 gtk_cmctree_move( ctree, child, parent, node );
3352 gtk_sctree_sort_node( ctree, parent );
3356 static void addressbook_edit_address_post_cb( ItemPerson *person )
3360 AddressBookFile *abf = addressbook_get_book_file();
3362 if (abf && abf->type == ADDR_IF_LDAP) {
3363 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3364 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3367 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3368 invalidate_address_completion();
3370 addressbook_address_list_set_focus();
3373 void addressbook_address_list_set_focus( void )
3375 if (!prefs_common.addressbook_use_editaddress_dialog) {
3376 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3377 addressbook_list_menu_setup();
3381 void addressbook_address_list_disable_some_actions(void)
3383 /* disable address copy/pasting when editing contact's detail (embedded form) */
3384 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3385 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3386 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3389 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3390 addressbook_edit_address(data, 0, NULL, TRUE);
3393 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3394 gboolean force_focus ) {
3395 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3397 AddressObject *obj = NULL, *pobj = NULL;
3398 AddressDataSource *ds = NULL;
3399 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3401 AddressBookFile *abf = NULL;
3403 if( addrbook.listSelected == NULL ) return;
3404 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3405 cm_return_if_fail(obj != NULL);
3407 ctree = GTK_CMCTREE( addrbook.ctree );
3408 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3409 node = gtk_cmctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3411 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3412 if( ds == NULL ) return;
3414 abf = addressbook_get_book_file();
3416 if( obj->type == ADDR_ITEM_EMAIL ) {
3417 ItemEMail *email = ( ItemEMail * ) obj;
3418 if( email == NULL ) return;
3419 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3420 /* Edit parent group */
3421 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3422 ItemGroup *itemGrp = adapter->itemGroup;
3423 if( abf == NULL ) return;
3424 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3425 name = ADDRITEM_NAME(itemGrp);
3426 node = addrbook.treeSelected;
3427 parentNode = GTK_CMCTREE_ROW(node)->parent;
3430 /* Edit person - email page */
3432 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3433 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3434 addressbook_edit_address_post_cb,
3435 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3438 if (abf && abf->type == ADDR_IF_LDAP) {
3439 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3440 person->status = UPDATE_ENTRY;
3443 if (prefs_common.addressbook_use_editaddress_dialog)
3444 addressbook_edit_address_post_cb( person );
3449 else if( obj->type == ADDR_ITEM_PERSON ) {
3450 /* Edit person - basic page */
3451 ItemPerson *person = ( ItemPerson * ) obj;
3452 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3453 addressbook_edit_address_post_cb,
3454 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3457 if (abf && abf->type == ADDR_IF_LDAP) {
3458 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3459 person->status = UPDATE_ENTRY;
3462 if (prefs_common.addressbook_use_editaddress_dialog)
3463 addressbook_edit_address_post_cb( person );
3467 else if( obj->type == ADDR_ITEM_GROUP ) {
3468 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3469 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3470 parentNode = addrbook.treeSelected;
3471 node = addressbook_find_group_node( parentNode, itemGrp );
3472 name = ADDRITEM_NAME(itemGrp);
3473 invalidate_address_completion();
3479 /* Update tree node with node name */
3480 if( node == NULL ) return;
3481 addressbook_change_node_name( node, name );
3482 gtk_sctree_sort_node( ctree, parentNode );
3483 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3484 addressbook_set_clist(
3485 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3490 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3492 addressbook_del_clicked(NULL, NULL);
3495 static void close_cb(GtkAction *action, gpointer data)
3497 addressbook_close();
3500 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3501 addressbook_export_to_file();
3504 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3506 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3507 if( person ) addritem_person_set_opened( person, TRUE );
3511 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3513 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3514 if( person ) addritem_person_set_opened( person, FALSE );
3518 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3520 gchar *eMailAlias = ADDRITEM_NAME(email);
3521 if( eMailAlias && *eMailAlias != '\0' ) {
3523 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3526 str = g_strdup( eMailAlias );
3532 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3533 GList *items = itemGroup->listEMail;
3534 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3535 for( ; items != NULL; items = g_list_next( items ) ) {
3536 GtkCMCTreeNode *nodeEMail = NULL;
3537 gchar *text[N_LIST_COLS];
3538 ItemEMail *email = items->data;
3542 if( ! email ) continue;
3544 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3545 str = addressbook_format_item_clist( person, email );
3547 text[COL_NAME] = addressbook_set_col_name_guard(str);
3550 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3552 text[COL_ADDRESS] = email->address;
3553 text[COL_REMARKS] = email->remarks;
3554 nodeEMail = gtk_sctree_insert_node(
3556 text, FOLDER_SPACING,
3560 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3566 gchar *addressbook_set_col_name_guard(gchar *value)
3568 gchar *ret = "<not set>";
3569 gchar *tmp = g_strdup(value);
3571 if (tmp !=NULL && *tmp != '\0')
3577 static void addressbook_folder_load_one_person(
3578 GtkCMCTree *clist, ItemPerson *person,
3579 AddressTypeControlItem *atci,
3580 AddressTypeControlItem *atciMail )
3582 GtkCMCTreeNode *nodePerson = NULL;
3583 GtkCMCTreeNode *nodeEMail = NULL;
3584 gchar *text[N_LIST_COLS];
3585 gboolean flgFirst = TRUE, haveAddr = FALSE;
3588 AddressBookFile *abf = addressbook_get_book_file();
3591 if( person == NULL ) return;
3593 text[COL_NAME] = "";
3594 node = person->listEMail;
3596 ItemEMail *email = node->data;
3597 gchar *eMailAddr = NULL;
3598 node = g_list_next( node );
3600 text[COL_ADDRESS] = email->address;
3601 text[COL_REMARKS] = email->remarks;
3602 eMailAddr = ADDRITEM_NAME(email);
3603 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3605 /* First email belongs with person */
3606 gchar *str = addressbook_format_item_clist( person, email );
3608 text[COL_NAME] = addressbook_set_col_name_guard(str);
3611 else if( abf && abf->type == ADDR_IF_LDAP &&
3612 person && person->nickName ) {
3613 if (person->nickName) {
3614 if (strcmp(person->nickName, "") != 0) {
3615 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3618 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3624 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3626 nodePerson = gtk_sctree_insert_node(
3628 text, FOLDER_SPACING,
3631 FALSE, person->isOpened );
3634 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3637 /* Subsequent email is a child node of person */
3638 text[COL_NAME] = ADDRITEM_NAME(email);
3639 nodeEMail = gtk_sctree_insert_node(
3640 clist, nodePerson, NULL,
3641 text, FOLDER_SPACING,
3643 atciMail->iconXpmOpen,
3645 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3651 /* Have name without EMail */
3652 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3653 text[COL_ADDRESS] = "";
3654 text[COL_REMARKS] = "";
3655 nodePerson = gtk_sctree_insert_node(
3657 text, FOLDER_SPACING,
3660 FALSE, person->isOpened );
3661 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3666 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3668 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3669 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3671 if( atci == NULL ) return;
3672 if( atciMail == NULL ) return;
3674 /* Load email addresses */
3675 items = addritem_folder_get_person_list( itemFolder );
3676 for( ; items != NULL; items = g_list_next( items ) ) {
3677 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3679 /* Free up the list */
3680 mgu_clear_list( items );
3681 g_list_free( items );
3684 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3685 addrbook.listSelected = NULL;
3686 gtk_cmctree_remove_node( clist, node );
3687 addressbook_menubar_set_sensitive( FALSE );
3688 addressbook_menuitem_set_sensitive(
3689 gtk_cmctree_node_get_row_data(
3690 GTK_CMCTREE(clist), addrbook.treeSelected ),
3691 addrbook.treeSelected );
3694 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3695 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3696 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3697 GtkCMCTreeNode *node;
3698 if( atci == NULL ) return;
3699 if( atciMail == NULL ) return;
3700 if( person == NULL ) return;
3701 /* unload the person */
3703 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3705 addressbook_folder_remove_node( clist, node );
3706 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3707 gtk_sctree_sort_node( clist, NULL );
3708 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3710 gtk_sctree_select( GTK_SCTREE(clist), node );
3711 if (!gtk_cmctree_node_is_visible( clist, node ) )
3712 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3716 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3717 GtkCMCTreeNode *node;
3720 if( person == NULL ) return;
3721 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3722 row = gtk_cmclist_find_row_from_data( GTK_CMCLIST(clist), person );
3724 addressbook_folder_remove_node( clist, node );
3728 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3730 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3732 /* Load any groups */
3733 if( ! atci ) return;
3734 items = addritem_folder_get_group_list( itemFolder );
3735 for( ; items != NULL; items = g_list_next( items ) ) {
3736 GtkCMCTreeNode *nodeGroup = NULL;
3737 gchar *text[N_LIST_COLS];
3738 ItemGroup *group = items->data;
3739 if( group == NULL ) continue;
3740 text[COL_NAME] = ADDRITEM_NAME(group);
3741 text[COL_ADDRESS] = "";
3742 text[COL_REMARKS] = "";
3743 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3744 text, FOLDER_SPACING,
3748 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3749 gtk_sctree_sort_node(clist, NULL);
3751 /* Free up the list */
3752 mgu_clear_list( items );
3753 g_list_free( items );
3757 * Search ctree widget callback function.
3758 * \param pA Pointer to node.
3759 * \param pB Pointer to data item being sought.
3760 * \return Zero (0) if group found.
3762 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3765 aoA = ( AddressObject * ) pA;
3766 if( aoA->type == ADDR_ITEM_GROUP ) {
3767 ItemGroup *group, *grp;
3769 grp = ADAPTER_GROUP(aoA)->itemGroup;
3770 group = ( ItemGroup * ) pB;
3771 if( grp == group ) return 0; /* Found group */
3777 * Remove folder and group nodes from tree widget for items contained ("cut")
3780 static void addressbook_treenode_remove_item( void ) {
3782 AddrSelectItem *cutItem;
3783 AddressCache *cache;
3784 AddrItemObject *aio;
3785 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3788 node = _clipBoard_->objectList;
3790 cutItem = node->data;
3791 node = g_list_next( node );
3792 cache = addrindex_get_cache(
3793 _clipBoard_->addressIndex, cutItem->cacheID );
3794 if( cache == NULL ) continue;
3795 aio = addrcache_get_object( cache, cutItem->uid );
3798 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3801 folder = ( ItemFolder * ) aio;
3802 tn = gtk_cmctree_find_by_row_data_custom(
3803 ctree, NULL, folder,
3804 addressbook_treenode_find_folder_cb );
3806 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3809 group = ( ItemGroup * ) aio;
3810 tn = gtk_cmctree_find_by_row_data_custom(
3812 addressbook_treenode_find_group_cb );
3816 /* Free up adapter and remove node. */
3817 gtk_cmctree_remove_node( ctree, tn );
3824 * Find parent datasource for specified tree node.
3825 * \param node Node to test.
3826 * \return Data source, or NULL if not found.
3828 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3829 AddressDataSource *ds = NULL;
3832 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3835 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3836 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3838 /* g_print( "ao->type = %d\n", ao->type ); */
3839 if( ao->type == ADDR_DATASOURCE ) {
3840 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3841 /* g_print( "found it\n" ); */
3842 ds = ads->dataSource;
3846 node = GTK_CMCTREE_ROW(node)->parent;
3852 * Load address list widget with children of specified object.
3853 * \param obj Parent object to be loaded.
3855 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3856 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3857 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3858 AddressDataSource *ds = NULL;
3859 AdapterDSource *ads = NULL;
3860 static AddressObject *last_obj = NULL;
3862 if (addrbook.clist == NULL) {
3865 if (obj == last_obj && !refresh)
3870 gtk_cmclist_clear(clist);
3874 if( obj->type == ADDR_INTERFACE ) {
3875 /* g_print( "set_clist: loading datasource...\n" ); */
3876 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3880 gtk_cmclist_freeze(clist);
3881 gtk_cmclist_clear(clist);
3883 if( obj->type == ADDR_DATASOURCE ) {
3884 ads = ADAPTER_DSOURCE(obj);
3885 ds = ADAPTER_DSOURCE(obj)->dataSource;
3887 /* Load root folder */
3888 ItemFolder *rootFolder = NULL;
3889 rootFolder = addrindex_ds_get_root_folder( ds );
3890 addressbook_folder_load_person(
3891 ctreelist, addrindex_ds_get_root_folder( ds ) );
3892 addressbook_folder_load_group(
3893 ctreelist, addrindex_ds_get_root_folder( ds ) );
3897 if( obj->type == ADDR_ITEM_GROUP ) {
3899 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3900 addressbook_load_group( ctreelist, itemGroup );
3902 else if( obj->type == ADDR_ITEM_FOLDER ) {
3904 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3905 addressbook_folder_load_person( ctreelist, itemFolder );
3906 addressbook_folder_load_group( ctreelist, itemFolder );
3909 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3910 clist->focus_row = -1;
3911 gtk_cmclist_thaw(clist);
3915 * Call back function to free adaptor. Call back is setup by function
3916 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3917 * called when the address book tree widget node is removed by calling
3918 * function gtk_cmctree_remove_node().
3920 * \param data Tree node's row data.
3922 static void addressbook_free_treenode( gpointer data ) {
3925 ao = ( AddressObject * ) data;
3926 if( ao == NULL ) return;
3927 if( ao->type == ADDR_INTERFACE ) {
3928 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3929 addrbookctl_free_interface( ai );
3931 else if( ao->type == ADDR_DATASOURCE ) {
3932 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3933 addrbookctl_free_datasource( ads );
3935 else if( ao->type == ADDR_ITEM_FOLDER ) {
3936 AdapterFolder *af = ADAPTER_FOLDER(ao);
3937 addrbookctl_free_folder( af );
3939 else if( ao->type == ADDR_ITEM_GROUP ) {
3940 AdapterGroup *ag = ADAPTER_GROUP(ao);
3941 addrbookctl_free_group( ag );
3946 * Create new adaptor for specified data source.
3948 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3949 AddressObjectType otype, gchar *name )
3951 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3952 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3953 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3954 adapter->dataSource = ds;
3955 adapter->subType = otype;
3959 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3960 ADDRESS_OBJECT_NAME(adapter) =
3961 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3965 * Load tree from address index with the initial data.
3967 static void addressbook_load_tree( void ) {
3968 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3969 GList *nodeIf, *nodeDS;
3970 AdapterInterface *adapter;
3971 AddressInterface *iface;
3972 AddressTypeControlItem *atci;
3973 AddressDataSource *ds;
3974 AdapterDSource *ads;
3975 GtkCMCTreeNode *node, *newNode;
3978 nodeIf = _addressInterfaceList_;
3980 adapter = nodeIf->data;
3981 node = adapter->treeNode;
3982 iface = adapter->interface;
3983 atci = adapter->atci;
3985 if( iface->useInterface ) {
3986 /* Load data sources below interface node */
3987 nodeDS = iface->listSource;
3991 name = addrindex_ds_get_name( ds );
3992 ads = addressbook_create_ds_adapter(
3993 ds, atci->objectType, name );
3994 newNode = addressbook_add_object(
3995 node, ADDRESS_OBJECT(ads) );
3996 nodeDS = g_list_next( nodeDS );
3998 gtk_cmctree_expand( ctree, node );
4001 nodeIf = g_list_next( nodeIf );
4006 * Convert the old address book to new format.
4008 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4009 gboolean retVal = FALSE;
4010 gboolean errFlag = TRUE;
4013 /* Read old address book, performing conversion */
4014 debug_print( "Reading and converting old address book...\n" );
4015 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4016 addrindex_read_data( addrIndex );
4017 if( addrIndex->retVal == MGU_NO_FILE ) {
4018 /* We do not have a file - new user */
4019 debug_print( "New user... create new books...\n" );
4020 addrindex_create_new_books( addrIndex );
4021 if( addrIndex->retVal == MGU_SUCCESS ) {
4022 /* Save index file */
4023 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4024 addrindex_save_data( addrIndex );
4025 if( addrIndex->retVal == MGU_SUCCESS ) {
4030 msg = _( "New user, could not save index file." );
4034 msg = _( "New user, could not save address book files." );
4038 /* We have an old file */
4039 if( addrIndex->wasConverted ) {
4040 /* Converted successfully - save address index */
4041 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4042 addrindex_save_data( addrIndex );
4043 if( addrIndex->retVal == MGU_SUCCESS ) {
4044 msg = _( "Old address book converted successfully." );
4049 msg = _("Old address book converted,\n"
4050 "could not save new address index file." );
4054 /* File conversion failed - just create new books */
4055 debug_print( "File conversion failed... just create new books...\n" );
4056 addrindex_create_new_books( addrIndex );
4057 if( addrIndex->retVal == MGU_SUCCESS ) {
4059 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4060 addrindex_save_data( addrIndex );
4061 if( addrIndex->retVal == MGU_SUCCESS ) {
4062 msg = _("Could not convert address book,\n"
4063 "but created empty new address book files." );
4068 msg = _("Could not convert address book,\n"
4069 "could not save new address index file." );
4073 msg = _("Could not convert address book\n"
4074 "and could not create new address book files." );
4079 debug_print( "Error\n%s\n", msg );
4080 alertpanel_full(_("Addressbook conversion error"), msg,
4081 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4082 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4085 debug_print( "Warning\n%s\n", msg );
4086 alertpanel_full(_("Addressbook conversion error"), msg,
4087 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4088 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4094 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4098 gboolean failed = FALSE;
4100 if( ( dp = opendir( origdir ) ) == NULL ) {
4104 while( ( d = readdir( dp ) ) != NULL ) {
4105 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4108 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4110 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4112 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4125 /* all copies succeeded, we can remove source files */
4126 if( ( dp = opendir( origdir ) ) == NULL ) {
4129 while( ( d = readdir( dp ) ) != NULL ) {
4130 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4133 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4135 claws_unlink(orig_file);
4145 void addressbook_read_file( void ) {
4146 AddressIndex *addrIndex = NULL;
4147 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4149 debug_print( "Reading address index...\n" );
4150 if( _addressIndex_ ) {
4151 debug_print( "address book already read!!!\n" );
4155 addrIndex = addrindex_create_index();
4156 addrindex_initialize();
4158 /* Use new address book index. */
4160 if ( !is_dir_exist(indexdir) ) {
4161 if ( make_dir(indexdir) < 0 ) {
4162 addrindex_set_file_path( addrIndex, get_rc_dir() );
4163 g_warning( "couldn't create dir %s\n", indexdir);
4165 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4166 remove_dir_recursive(indexdir);
4167 addrindex_set_file_path( addrIndex, get_rc_dir() );
4168 g_error("couldn't migrate dir %s", indexdir);
4170 addrindex_set_file_path( addrIndex, indexdir);
4174 addrindex_set_file_path( addrIndex, indexdir);
4177 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4178 addrindex_read_data( addrIndex );
4179 if( addrIndex->retVal == MGU_NO_FILE ) {
4180 /* Conversion required */
4181 debug_print( "Converting...\n" );
4182 if( addressbook_convert( addrIndex ) ) {
4183 _addressIndex_ = addrIndex;
4186 else if( addrIndex->retVal == MGU_SUCCESS ) {
4187 _addressIndex_ = addrIndex;
4190 /* Error reading address book */
4191 debug_print( "Could not read address index.\n" );
4192 addrindex_print_index( addrIndex, stdout );
4193 alertpanel_full(_("Addressbook Error"),
4194 _("Could not read address index"),
4195 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4196 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4198 debug_print( "done.\n" );
4202 * Add object into the address index tree widget.
4203 * Enter: node Parent node.
4204 * obj Object to add.
4205 * Return: Node that was added, or NULL if object not added.
4207 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4210 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4211 GtkCMCTreeNode *added;
4212 AddressObject *pobj;
4213 AddressObjectType otype;
4214 AddressTypeControlItem *atci = NULL;
4216 cm_return_val_if_fail(node != NULL, NULL);
4217 cm_return_val_if_fail(obj != NULL, NULL);
4219 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4220 cm_return_val_if_fail(pobj != NULL, NULL);
4222 /* Determine object type to be displayed */
4223 if( obj->type == ADDR_DATASOURCE ) {
4224 otype = ADAPTER_DSOURCE(obj)->subType;
4230 /* Handle any special conditions. */
4232 atci = addrbookctl_lookup( otype );
4234 if( atci->showInTree ) {
4235 /* Add object to tree */
4238 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4239 atci->iconXpm, atci->iconXpmOpen,
4240 atci->treeLeaf, atci->treeExpand );
4241 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4242 addressbook_free_treenode );
4246 gtk_sctree_sort_node(ctree, node);
4252 * Add group into the address index tree.
4253 * \param node Parent node.
4254 * \param ds Data source.
4255 * \param itemGroup Group to add.
4256 * \return Inserted node.
4258 static GtkCMCTreeNode *addressbook_node_add_group(
4259 GtkCMCTreeNode *node, AddressDataSource *ds,
4260 ItemGroup *itemGroup )
4262 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4263 GtkCMCTreeNode *newNode;
4264 AdapterGroup *adapter;
4265 AddressTypeControlItem *atci = NULL;
4268 if( ds == NULL ) return NULL;
4269 if( node == NULL || itemGroup == NULL ) return NULL;
4271 name = &itemGroup->obj.name;
4273 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4275 adapter = g_new0( AdapterGroup, 1 );
4276 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4277 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4278 adapter->itemGroup = itemGroup;
4280 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4281 atci->iconXpm, atci->iconXpm,
4282 atci->treeLeaf, atci->treeExpand );
4283 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4284 addressbook_free_treenode );
4285 gtk_sctree_sort_node( ctree, node );
4290 * Add folder into the address index tree. Only visible folders are loaded into
4291 * the address index tree. Note that the root folder is not inserted into the
4294 * \param node Parent node.
4295 * \param ds Data source.
4296 * \param itemFolder Folder to add.
4297 * \param otype Object type to display.
4298 * \return Inserted node for the folder.
4300 static GtkCMCTreeNode *addressbook_node_add_folder(
4301 GtkCMCTreeNode *node, AddressDataSource *ds,
4302 ItemFolder *itemFolder, AddressObjectType otype )
4304 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4305 GtkCMCTreeNode *newNode = NULL;
4306 AdapterFolder *adapter;
4307 AddressTypeControlItem *atci = NULL;
4308 GList *listItems = NULL;
4310 ItemFolder *rootFolder;
4312 /* Only visible folders */
4313 if( itemFolder == NULL || itemFolder->isHidden )
4318 if( node == NULL || itemFolder == NULL )
4321 /* Determine object type */
4322 atci = addrbookctl_lookup( otype );
4326 rootFolder = addrindex_ds_get_root_folder( ds );
4327 if( itemFolder == rootFolder ) {
4331 adapter = g_new0( AdapterFolder, 1 );
4332 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4333 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4334 adapter->itemFolder = itemFolder;
4336 name = ADDRITEM_NAME(itemFolder);
4337 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4338 atci->iconXpm, atci->iconXpm,
4339 atci->treeLeaf, atci->treeExpand );
4341 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4342 addressbook_free_treenode );
4346 listItems = itemFolder->listFolder;
4347 while( listItems ) {
4348 ItemFolder *item = listItems->data;
4349 addressbook_node_add_folder( newNode, ds, item, otype );
4350 listItems = g_list_next( listItems );
4352 listItems = itemFolder->listGroup;
4353 while( listItems ) {
4354 ItemGroup *item = listItems->data;
4355 addressbook_node_add_group( newNode, ds, item );
4356 listItems = g_list_next( listItems );
4358 gtk_sctree_sort_node( ctree, node );
4362 void addressbook_export_to_file( void ) {
4363 if( _addressIndex_ ) {
4364 /* Save all new address book data */
4365 debug_print( "Saving address books...\n" );
4366 addrindex_save_all_books( _addressIndex_ );
4368 debug_print( "Exporting addressbook to file...\n" );
4369 addrindex_save_data( _addressIndex_ );
4370 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4371 addrindex_print_index( _addressIndex_, stdout );
4374 /* Notify address completion of new data */
4375 invalidate_address_completion();
4379 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4381 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4382 addressbook_lup_clicked(NULL, NULL);
4387 * Comparison using cell contents (text in first column). Used for sort
4388 * address index widget.
4390 static gint addressbook_treenode_compare_func(
4391 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4393 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4394 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4395 gchar *name1 = NULL, *name2 = NULL;
4396 if( cell1 ) name1 = cell1->u.text;
4397 if( cell2 ) name2 = cell2->u.text;
4398 if( ! name1 ) return ( name2 != NULL );
4399 if( ! name2 ) return -1;
4400 return g_utf8_collate( name1, name2 );
4403 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4404 AdapterDSource *ads;
4405 AdapterInterface *adapter;
4406 GtkCMCTreeNode *newNode;
4408 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4409 if( adapter == NULL ) return;
4410 ads = addressbook_edit_book( _addressIndex_, NULL );
4412 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4414 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4415 addrbook.treeSelected = newNode;
4420 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4421 AdapterDSource *ads;
4422 AdapterInterface *adapter;
4423 GtkCMCTreeNode *newNode;
4425 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4426 if( adapter == NULL ) return;
4427 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4429 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4431 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4432 addrbook.treeSelected = newNode;
4438 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4439 AdapterDSource *ads;
4440 AdapterInterface *adapter;
4441 AddressInterface *iface;
4442 GtkCMCTreeNode *newNode;
4444 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4445 if( adapter == NULL ) return;
4446 iface = adapter->interface;
4447 if( ! iface->haveLibrary ) return;
4448 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4450 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4452 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4453 addrbook.treeSelected = newNode;
4460 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4461 AdapterDSource *ads;
4462 AdapterInterface *adapter;
4463 AddressInterface *iface;
4464 GtkCMCTreeNode *newNode;
4466 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4467 if( adapter == NULL ) return;
4468 iface = adapter->interface;
4469 if( ! iface->haveLibrary ) return;
4470 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4472 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4474 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4475 addrbook.treeSelected = newNode;
4482 * Display address search status message.
4483 * \param queryType Query type.
4484 * \param status Status/Error code.
4486 static void addressbook_search_message( gint queryType, gint sts ) {
4488 *addressbook_msgbuf = '\0';
4490 if( sts != MGU_SUCCESS ) {
4491 if( queryType == ADDRQUERY_LDAP ) {
4493 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4498 g_snprintf( addressbook_msgbuf,
4499 sizeof(addressbook_msgbuf), "%s", desc );
4500 addressbook_status_show( addressbook_msgbuf );
4503 addressbook_status_show( "" );
4508 * Refresh addressbook by forcing refresh of current selected object in
4511 static void addressbook_refresh_current( void ) {
4515 ctree = GTK_CMCTREE(addrbook.ctree);
4516 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4517 if( obj == NULL ) return;
4518 addressbook_set_clist( obj, TRUE );
4522 * Message that is displayed whilst a query is executing in a background
4525 static gchar *_tempMessage_ = N_( "Busy searching..." );
4528 * Address search idle function. This function is called during UI idle time
4529 * while a search is in progress.
4531 * \param data Idler data.
4533 static void addressbook_search_idle( gpointer data ) {
4537 queryID = GPOINTER_TO_INT( data );
4538 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4543 * Search completion callback function. This removes the query from the idle
4546 * \param sender Sender of query.
4547 * \param queryID Query ID of search request.
4548 * \param status Search status.
4549 * \param data Query data.
4551 static void addressbook_search_callback_end(
4552 gpointer sender, gint queryID, gint status, gpointer data )
4556 AddrQueryObject *aqo;
4558 /* Remove idler function */
4559 ptrQID = GINT_TO_POINTER( queryID );
4561 g_idle_remove_by_data( ptrQID );
4564 /* Refresh addressbook contents */
4565 addressbook_refresh_current();
4566 req = qrymgr_find_request( queryID );
4568 aqo = ( AddrQueryObject * ) req->queryList->data;
4569 addressbook_search_message( aqo->queryType, status );
4572 /* Stop the search */
4573 addrindex_stop_search( queryID );
4579 * \param ds Data source to search.
4580 * \param searchTerm String to lookup.
4581 * \param pNode Parent data source node.
4583 static void addressbook_perform_search(
4584 AddressDataSource *ds, gchar *searchTerm,
4585 GtkCMCTreeNode *pNode )
4587 AddrBookBase *adbase;
4588 AddressCache *cache;
4594 AddressObjectType aoType = ADDR_NONE;
4598 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4600 if( ds && ds->type == ADDR_IF_LDAP ) {
4602 aoType = ADDR_LDAP_QUERY;
4608 /* Get reference to address cache */
4609 adbase = ( AddrBookBase * ) ds->rawDataSource;
4610 cache = adbase->addressCache;
4612 /* Create a folder for the search results */
4613 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4614 folder = addressbook_setup_subf(ds, name, pNode);
4617 /* Setup the search */
4618 queryID = addrindex_setup_explicit_search(
4619 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4620 if( queryID == 0 ) return;
4622 /* Set up idler function */
4623 idleID = g_idle_add(
4624 ( GtkFunction ) addressbook_search_idle,
4625 GINT_TO_POINTER( queryID ) );
4627 /* Start search, sit back and wait for something to happen */
4628 addrindex_start_search( queryID );
4630 addressbook_status_show( _tempMessage_ );
4634 * Lookup button handler. Address search is only performed against
4635 * address interfaces for external queries.
4637 * \param button Lookup button widget.
4638 * \param data Data object.
4640 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4643 AddressDataSource *ds;
4644 AddressInterface *iface;
4646 GtkCMCTreeNode *node, *parentNode;
4648 node = addrbook.treeSelected;
4649 if( ! node ) return;
4650 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4652 ctree = GTK_CMCTREE(addrbook.ctree);
4653 obj = gtk_cmctree_node_get_row_data( ctree, node );
4654 if( obj == NULL ) return;
4656 ds = addressbook_find_datasource( node );
4657 if( ds == NULL ) return;
4659 /* We must have a datasource that is an external interface */
4660 iface = ds->interface;
4661 if( ! iface->haveLibrary ) return;
4662 if( ! iface->externalQuery ) return;
4665 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4666 g_strchomp( searchTerm );
4668 if( obj->type == ADDR_ITEM_FOLDER ) {
4669 parentNode = GTK_CMCTREE_ROW(node)->parent;
4674 addressbook_perform_search( ds, searchTerm, parentNode );
4676 gtk_widget_grab_focus( addrbook.entry );
4678 g_free( searchTerm );
4681 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4682 addressbook_close();
4687 * Browse address entry for highlighted entry.
4689 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4691 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4693 AddressDataSource *ds;
4694 AddressInterface *iface;
4698 if(addrbook.listSelected == NULL)
4701 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4705 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4709 iface = ds->interface;
4710 if(!iface || !iface->haveLibrary )
4714 if (obj->type == ADDR_ITEM_EMAIL) {
4715 email = ( ItemEMail * ) obj;
4719 person = (ItemPerson *) ADDRITEM_PARENT(email);
4721 else if (obj->type == ADDR_ITEM_PERSON) {
4722 person = (ItemPerson *) obj;
4729 if( iface && iface->type == ADDR_IF_LDAP ) {
4730 browseldap_entry(ds, person->externalID);
4735 /* **********************************************************************
4736 * Build lookup tables.
4737 * ***********************************************************************
4741 * Remap object types.
4742 * Enter: abType AddressObjectType (used in tree node).
4743 * Return: ItemObjectType (used in address cache data).
4745 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4746 ItemObjectType ioType;
4749 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4750 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4751 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4752 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4753 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4754 default: ioType = ITEMTYPE_NONE; break;
4759 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4760 atci = addrbookctl_lookup(id); \
4762 atci->iconXpm = icon; \
4763 atci->iconXpmOpen = iconopen; \
4765 g_warning("can't get atci %d\n", id); \
4770 * Build table that controls the rendering of object types.
4772 static void addrbookctl_build_icons( GtkWidget *window ) {
4773 AddressTypeControlItem *atci;
4777 g_object_unref(interfacexpm);
4779 g_object_unref(folderxpm);
4781 g_object_unref(folderopenxpm);
4783 g_object_unref(groupxpm);
4785 g_object_unref(vcardxpm);
4787 g_object_unref(bookxpm);
4789 g_object_unref(addressxpm);
4791 g_object_unref(jpilotxpm);
4793 g_object_unref(categoryxpm);
4795 g_object_unref(ldapxpm);
4797 g_object_unref(addrsearchxpm);
4798 stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacexpm );
4799 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4800 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4801 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4802 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4803 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4804 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4805 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4806 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4807 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4808 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4810 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4811 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4812 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4813 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4814 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4815 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4816 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4817 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4818 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4819 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4820 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4825 * Build table that controls the rendering of object types.
4827 static void addrbookctl_build_map( GtkWidget *window ) {
4828 AddressTypeControlItem *atci;
4830 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4831 _addressBookTypeList_ = NULL;
4834 atci = g_new0( AddressTypeControlItem, 1 );
4835 atci->objectType = ADDR_INTERFACE;
4836 atci->interfaceType = ADDR_IF_NONE;
4837 atci->showInTree = TRUE;
4838 atci->treeExpand = TRUE;
4839 atci->treeLeaf = FALSE;
4840 atci->displayName = _( "Interface" );
4841 atci->menuCommand = NULL;
4842 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4843 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4846 atci = g_new0( AddressTypeControlItem, 1 );
4847 atci->objectType = ADDR_BOOK;
4848 atci->interfaceType = ADDR_IF_BOOK;
4849 atci->showInTree = TRUE;
4850 atci->treeExpand = TRUE;
4851 atci->treeLeaf = FALSE;
4852 atci->displayName = _( "Address Book" );
4853 atci->menuCommand = "Menu/Book/NewBook";
4854 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4855 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4858 atci = g_new0( AddressTypeControlItem, 1 );
4859 atci->objectType = ADDR_ITEM_PERSON;
4860 atci->interfaceType = ADDR_IF_NONE;
4861 atci->showInTree = FALSE;
4862 atci->treeExpand = FALSE;
4863 atci->treeLeaf = FALSE;
4864 atci->displayName = _( "Person" );
4865 atci->menuCommand = NULL;
4866 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4867 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4870 atci = g_new0( AddressTypeControlItem, 1 );
4871 atci->objectType = ADDR_ITEM_EMAIL;
4872 atci->interfaceType = ADDR_IF_NONE;
4873 atci->showInTree = FALSE;
4874 atci->treeExpand = FALSE;
4875 atci->treeLeaf = TRUE;
4876 atci->displayName = _( "Email Address" );
4877 atci->menuCommand = NULL;
4878 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4879 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4882 atci = g_new0( AddressTypeControlItem, 1 );
4883 atci->objectType = ADDR_ITEM_GROUP;
4884 atci->interfaceType = ADDR_IF_BOOK;
4885 atci->showInTree = TRUE;
4886 atci->treeExpand = FALSE;
4887 atci->treeLeaf = FALSE;
4888 atci->displayName = _( "Group" );
4889 atci->menuCommand = NULL;
4890 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4891 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4894 atci = g_new0( AddressTypeControlItem, 1 );
4895 atci->objectType = ADDR_ITEM_FOLDER;
4896 atci->interfaceType = ADDR_IF_BOOK;
4897 atci->showInTree = TRUE;
4898 atci->treeExpand = FALSE;
4899 atci->treeLeaf = FALSE;
4900 atci->displayName = _( "Folder" );
4901 atci->menuCommand = NULL;
4902 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4903 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4906 atci = g_new0( AddressTypeControlItem, 1 );
4907 atci->objectType = ADDR_VCARD;
4908 atci->interfaceType = ADDR_IF_VCARD;
4909 atci->showInTree = TRUE;
4910 atci->treeExpand = TRUE;
4911 atci->treeLeaf = TRUE;
4912 atci->displayName = _( "vCard" );
4913 atci->menuCommand = "Menu/Book/NewVCard";
4914 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4915 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4918 atci = g_new0( AddressTypeControlItem, 1 );
4919 atci->objectType = ADDR_JPILOT;
4920 atci->interfaceType = ADDR_IF_JPILOT;
4921 atci->showInTree = TRUE;
4922 atci->treeExpand = TRUE;
4923 atci->treeLeaf = FALSE;
4924 atci->displayName = _( "JPilot" );
4925 atci->menuCommand = "Menu/Book/NewJPilot";
4926 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4927 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4930 atci = g_new0( AddressTypeControlItem, 1 );
4931 atci->objectType = ADDR_CATEGORY;
4932 atci->interfaceType = ADDR_IF_JPILOT;
4933 atci->showInTree = TRUE;
4934 atci->treeExpand = TRUE;
4935 atci->treeLeaf = TRUE;
4936 atci->displayName = _( "JPilot" );
4937 atci->menuCommand = NULL;
4938 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4939 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4942 atci = g_new0( AddressTypeControlItem, 1 );
4943 atci->objectType = ADDR_LDAP;
4944 atci->interfaceType = ADDR_IF_LDAP;
4945 atci->showInTree = TRUE;
4946 atci->treeExpand = TRUE;
4947 atci->treeLeaf = FALSE;
4948 atci->displayName = _( "LDAP servers" );
4949 atci->menuCommand = "Menu/Book/NewLDAPServer";
4950 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4951 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4954 atci = g_new0( AddressTypeControlItem, 1 );
4955 atci->objectType = ADDR_LDAP_QUERY;
4956 atci->interfaceType = ADDR_IF_LDAP;
4957 atci->showInTree = TRUE;
4958 atci->treeExpand = FALSE;
4959 atci->treeLeaf = TRUE;
4960 atci->displayName = _( "LDAP Query" );
4961 atci->menuCommand = NULL;
4962 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4963 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4965 addrbookctl_build_icons(window);
4968 void addressbook_reflect_prefs_pixmap_theme(void)
4970 if (addrbook.window)
4971 addrbookctl_build_icons(addrbook.window);
4975 * Search for specified object type.
4977 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4979 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4983 * Search for specified interface type.
4985 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4986 GList *node = _addressBookTypeList_;
4988 AddressTypeControlItem *atci = node->data;
4989 if( atci->interfaceType == ifType ) return atci;
4990 node = g_list_next( node );
4995 static void addrbookctl_free_address( AddressObject *obj ) {
4996 g_free( obj->name );
4997 obj->type = ADDR_NONE;
5001 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5002 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5003 adapter->interface = NULL;
5004 adapter->interfaceType = ADDR_IF_NONE;
5005 adapter->atci = NULL;
5006 adapter->enabled = FALSE;
5007 adapter->haveLibrary = FALSE;
5008 adapter->treeNode = NULL;
5012 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5013 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5014 adapter->dataSource = NULL;
5015 adapter->subType = ADDR_NONE;
5019 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5020 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5021 adapter->itemFolder = NULL;
5025 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5026 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5027 adapter->itemGroup = NULL;
5032 * Build GUI interface list.
5034 static void addrbookctl_build_iflist( void ) {
5035 AddressTypeControlItem *atci;
5036 AdapterInterface *adapter;
5039 if( _addressIndex_ == NULL ) {
5040 _addressIndex_ = addrindex_create_index();
5041 if( _clipBoard_ == NULL ) {
5042 _clipBoard_ = addrclip_create();
5044 addrclip_set_index( _clipBoard_, _addressIndex_ );
5046 _addressInterfaceList_ = NULL;
5047 list = addrindex_get_interface_list( _addressIndex_ );
5049 AddressInterface *interface = list->data;
5050 atci = addrbookctl_lookup_iface( interface->type );
5052 adapter = g_new0( AdapterInterface, 1 );
5053 adapter->interfaceType = interface->type;
5054 adapter->atci = atci;
5055 adapter->interface = interface;
5056 adapter->treeNode = NULL;
5057 adapter->enabled = TRUE;
5058 adapter->haveLibrary = interface->haveLibrary;
5059 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5060 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5061 _addressInterfaceList_ =
5062 g_list_append( _addressInterfaceList_, adapter );
5064 list = g_list_next( list );
5069 * Find GUI interface type specified interface type.
5070 * \param ifType Interface type.
5071 * \return Interface item, or NULL if not found.
5073 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5074 GList *node = _addressInterfaceList_;
5076 AdapterInterface *adapter = node->data;
5077 if( adapter->interfaceType == ifType ) return adapter;
5078 node = g_list_next( node );
5084 * Build interface list selection.
5086 static void addrbookctl_build_ifselect( void ) {
5087 GList *newList = NULL;
5092 gchar *endptr = NULL;
5094 AdapterInterface *adapter;
5096 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5099 splitStr = g_strsplit( selectStr, ",", -1 );
5100 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5102 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5103 ifType = strtol( splitStr[i], &endptr, 10 );
5106 if( strcmp( endptr, "/n" ) == 0 ) {
5110 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5111 adapter = addrbookctl_find_interface( ifType );
5113 newList = g_list_append( newList, adapter );
5120 /* g_print( "i=%d\n", i ); */
5121 g_strfreev( splitStr );
5122 g_free( selectStr );
5124 /* Replace existing list */
5125 mgu_clear_list( _addressIFaceSelection_ );
5126 g_list_free( _addressIFaceSelection_ );
5127 _addressIFaceSelection_ = newList;
5131 /* ***********************************************************************
5132 * Add sender to address book.
5133 * ***********************************************************************
5137 * This function is used by the Add sender to address book function.
5139 gboolean addressbook_add_contact(
5140 const gchar *name, const gchar *address, const gchar *remarks,
5141 GdkPixbuf *picture )
5143 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5144 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5145 debug_print( "addressbook_add_contact - added\n" );
5146 addressbook_refresh();
5151 /* ***********************************************************************
5152 * Book/folder selection.
5153 * ***********************************************************************
5157 * This function is used by the matcher dialog to select a book/folder.
5159 gchar *addressbook_folder_selection( const gchar *folderpath)
5161 AddressBookFile *book = NULL;
5162 ItemFolder *folder = NULL;
5165 cm_return_val_if_fail( folderpath != NULL, NULL);
5167 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5169 if ( folder != NULL) {
5171 gchar *oldtmp = NULL;
5172 AddrItemObject *obj = NULL;
5174 /* walk thru folder->parent to build the full folder path */
5175 /* TODO: wwp: optimize this */
5177 tmp = g_strdup(obj->uid);
5178 while ( obj->parent ) {
5180 if ( obj->name != NULL ) {
5181 oldtmp = g_strdup(tmp);
5183 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5187 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5190 path = g_strdup_printf("%s", book->fileName);
5192 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5198 /* ***********************************************************************
5199 * Book/folder checking.
5200 * ***********************************************************************
5203 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5205 FolderInfo *fi = g_new0( FolderInfo, 1 );
5207 fi->folder = folder;
5211 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5212 FolderInfo *fiParent, FolderPathMatch *match )
5218 FolderPathMatch *nextmatch = NULL;
5223 list = parentFolder->listFolder;
5225 folder = list->data;
5226 fName = g_strdup( ADDRITEM_NAME(folder) );
5228 /* match folder name, match pointer will be set to NULL if next recursive call
5229 doesn't need to match subfolder name */
5230 if ( match != NULL &&
5231 match->matched == FALSE ) {
5232 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5233 /* folder name matches, prepare next subfolder match */
5234 debug_print("matched folder name '%s'\n", fName);
5236 if ( match->folder_path[match->index] == NULL ) {
5237 /* we've matched all elements */
5238 match->matched = TRUE;
5239 match->folder = folder;
5240 debug_print("book/folder path matched!\n");
5242 /* keep on matching */
5250 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5251 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5253 list = g_list_next( list );
5258 * This function is used by to check if a matcher book/folder path corresponds to an
5259 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5260 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5261 if book AND folder are NULL this means that folderpath was empty or Any.
5262 If folderpath is a simple book name (without folder), book will not be NULL and folder
5263 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5266 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5267 AddressDataSource **book,
5268 ItemFolder **folder )
5270 AddressDataSource *ds;
5271 GList *list, *nodeDS;
5272 ItemFolder *rootFolder;
5273 AddressBookFile *abf;
5275 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5282 if ( folderpath == NULL )
5285 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5288 /* split the folder path we've received, we'll try to match this path, subpath by
5289 subpath against the book/folder structure in order */
5290 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5291 if (!folder_path_match.folder_path)
5294 list = addrindex_get_interface_list( _addressIndex_ );
5295 while ( list && !folder_path_match.matched ) {
5296 AddressInterface *interface = list->data;
5297 if ( interface && interface->type == ADDR_IF_BOOK ) {
5298 nodeDS = interface->listSource;
5299 while ( nodeDS && !folder_path_match.matched ) {
5302 /* Read address book */
5303 if( ! addrindex_ds_get_read_flag( ds ) ) {
5304 addrindex_ds_read_data( ds );
5307 /* Add node for address book */
5308 abf = ds->rawDataSource;
5310 /* match book name */
5311 if ( abf && abf->fileName &&
5312 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5314 debug_print("matched book name '%s'\n", abf->fileName);
5315 folder_path_match.book = ds;
5317 if ( folder_path_match.folder_path[1] == NULL ) {
5318 /* no folder part to match */
5320 folder_path_match.matched = TRUE;
5321 folder_path_match.folder = NULL;
5322 debug_print("book path matched!\n");
5325 /* match folder part */
5327 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5328 rootFolder = addrindex_ds_get_root_folder( ds );
5330 /* prepare for recursive call */
5331 folder_path_match.index = 1;
5332 /* this call will set folder_path_match.matched and folder_path_match.folder */
5333 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5338 nodeDS = g_list_next( nodeDS );
5341 list = g_list_next( list );
5344 g_strfreev( folder_path_match.folder_path );
5347 *book = folder_path_match.book;
5349 *folder = folder_path_match.folder;
5350 return folder_path_match.matched;
5354 /* **********************************************************************
5356 * ***********************************************************************
5362 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5363 AddressDataSource *ds = NULL;
5364 AdapterDSource *ads = NULL;
5365 AddressBookFile *abf = NULL;
5366 AdapterInterface *adapter;
5367 GtkCMCTreeNode *newNode;
5369 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5371 if( adapter->treeNode ) {
5372 abf = addressbook_imp_ldif( _addressIndex_ );
5374 ds = addrindex_index_add_datasource(
5375 _addressIndex_, ADDR_IF_BOOK, abf );
5376 ads = addressbook_create_ds_adapter(
5377 ds, ADDR_BOOK, NULL );
5378 addressbook_ads_set_name(
5379 ads, addrbook_get_name( abf ) );
5380 newNode = addressbook_add_object(
5382 ADDRESS_OBJECT(ads) );
5384 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5386 addrbook.treeSelected = newNode;
5389 /* Notify address completion */
5390 invalidate_address_completion();
5399 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5400 AddressDataSource *ds = NULL;
5401 AdapterDSource *ads = NULL;
5402 AddressBookFile *abf = NULL;
5403 AdapterInterface *adapter;
5404 GtkCMCTreeNode *newNode;
5406 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5408 if( adapter->treeNode ) {
5409 abf = addressbook_imp_mutt( _addressIndex_ );
5411 ds = addrindex_index_add_datasource(
5412 _addressIndex_, ADDR_IF_BOOK, abf );
5413 ads = addressbook_create_ds_adapter(
5414 ds, ADDR_BOOK, NULL );
5415 addressbook_ads_set_name(
5416 ads, addrbook_get_name( abf ) );
5417 newNode = addressbook_add_object(
5419 ADDRESS_OBJECT(ads) );
5421 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5423 addrbook.treeSelected = newNode;
5426 /* Notify address completion */
5427 invalidate_address_completion();
5436 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5437 AddressDataSource *ds = NULL;
5438 AdapterDSource *ads = NULL;
5439 AddressBookFile *abf = NULL;
5440 AdapterInterface *adapter;
5441 GtkCMCTreeNode *newNode;
5443 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5445 if( adapter->treeNode ) {
5446 abf = addressbook_imp_pine( _addressIndex_ );
5448 ds = addrindex_index_add_datasource(
5449 _addressIndex_, ADDR_IF_BOOK, abf );
5450 ads = addressbook_create_ds_adapter(
5451 ds, ADDR_BOOK, NULL );
5452 addressbook_ads_set_name(
5453 ads, addrbook_get_name( abf ) );
5454 newNode = addressbook_add_object(
5456 ADDRESS_OBJECT(ads) );
5458 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5460 addrbook.treeSelected = newNode;
5463 /* Notify address completion */
5464 invalidate_address_completion();
5471 * Harvest addresses.
5472 * \param folderItem Folder to import.
5473 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5474 * \param msgList List of message numbers, or NULL to process folder.
5476 void addressbook_harvest(
5477 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5479 AddressDataSource *ds = NULL;
5480 AdapterDSource *ads = NULL;
5481 AddressBookFile *abf = NULL;
5482 AdapterInterface *adapter;
5483 GtkCMCTreeNode *newNode;
5485 abf = addrgather_dlg_execute(
5486 folderItem, _addressIndex_, sourceInd, msgList );
5488 ds = addrindex_index_add_datasource(
5489 _addressIndex_, ADDR_IF_BOOK, abf );
5491 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5493 if( adapter->treeNode ) {
5494 ads = addressbook_create_ds_adapter(
5495 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5496 newNode = addressbook_add_object(
5498 ADDRESS_OBJECT(ads) );
5502 /* Notify address completion */
5503 invalidate_address_completion();
5510 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5511 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5513 AddressDataSource *ds = NULL;
5514 AddrBookBase *adbase;
5515 AddressCache *cache;
5516 GtkCMCTreeNode *node = NULL;
5518 if( ! addrbook.treeSelected ) return;
5519 node = addrbook.treeSelected;
5520 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5521 obj = gtk_cmctree_node_get_row_data( ctree, node );
5522 if( obj == NULL ) return;
5524 ds = addressbook_find_datasource( node );
5525 if( ds == NULL ) return;
5526 adbase = ( AddrBookBase * ) ds->rawDataSource;
5527 cache = adbase->addressCache;
5528 addressbook_exp_html( cache );
5534 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5535 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5537 AddressDataSource *ds = NULL;
5538 AddrBookBase *adbase;
5539 AddressCache *cache;
5540 GtkCMCTreeNode *node = NULL;
5542 if( ! addrbook.treeSelected ) return;
5543 node = addrbook.treeSelected;
5544 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5545 obj = gtk_cmctree_node_get_row_data( ctree, node );
5546 if( obj == NULL ) return;
5548 ds = addressbook_find_datasource( node );
5549 if( ds == NULL ) return;
5550 adbase = ( AddrBookBase * ) ds->rawDataSource;
5551 cache = adbase->addressCache;
5552 addressbook_exp_ldif( cache );
5555 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5557 addrduplicates_find(GTK_WINDOW(addrbook.window));
5560 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5562 addressbook_custom_attr_edit();
5565 static void addressbook_start_drag(GtkWidget *widget, gint button,
5569 GdkDragContext *context;
5570 if (addressbook_target_list == NULL)
5571 addressbook_target_list = gtk_target_list_new(
5572 addressbook_drag_types, 1);
5573 context = gtk_drag_begin(widget, addressbook_target_list,
5574 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5575 gtk_drag_set_icon_default(context);
5578 static void addressbook_drag_data_get(GtkWidget *widget,
5579 GdkDragContext *drag_context,
5580 GtkSelectionData *selection_data,
5585 AddrItemObject *aio = NULL;
5586 AddressObject *pobj = NULL;
5587 AdapterDSource *ads = NULL;
5588 AddressDataSource *ds = NULL;
5591 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5593 if( pobj == NULL ) return;
5595 if( pobj->type == ADDR_DATASOURCE ) {
5596 ads = ADAPTER_DSOURCE(pobj);
5597 ds = ads->dataSource;
5598 } else if (pobj->type == ADDR_ITEM_GROUP) {
5603 else if( pobj->type != ADDR_INTERFACE ) {
5604 ds = addressbook_find_datasource( addrbook.treeSelected );
5610 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5611 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5612 GTK_CMCTREE_NODE(cur->data));
5613 while (aio && aio->type != ADDR_ITEM_PERSON) {
5618 if (aio && aio->type == ADDR_ITEM_PERSON) {
5619 if( ds && ds->interface && ds->interface->readOnly)
5620 gtk_selection_data_set(selection_data,
5621 selection_data->target, 8,
5622 (const guchar *)"Dummy_addr_copy", 15);
5624 gtk_selection_data_set(selection_data,
5625 selection_data->target, 8,
5626 (const guchar *)"Dummy_addr_move", 15);
5630 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5631 GdkDragContext *context,
5638 GtkCMCTreeNode *node = NULL;
5639 gboolean acceptable = FALSE;
5640 gint height = addrbook.ctree->allocation.height;
5641 gint total_height = addrbook.ctree->requisition.height;
5642 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5643 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5644 gfloat vpos = pos->value;
5646 if (gtk_cmclist_get_selection_info
5647 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5649 if (y > height - 24 && height + vpos < total_height) {
5650 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5651 gtk_adjustment_changed(pos);
5653 if (y < 24 && y > 0) {
5654 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5655 gtk_adjustment_changed(pos);
5657 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5660 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5661 if( obj->type == ADDR_ITEM_FOLDER
5662 || obj->type == ADDR_ITEM_GROUP)
5665 AdapterDSource *ads = NULL;
5666 AddressDataSource *ds = NULL;
5667 ads = ADAPTER_DSOURCE(obj);
5668 if (ads == NULL ){ return FALSE;}
5669 ds = ads->dataSource;
5670 if (ds == NULL ) { return FALSE;}
5678 g_signal_handlers_block_by_func
5680 G_CALLBACK(addressbook_tree_selected), NULL);
5681 gtk_sctree_select( GTK_SCTREE(widget), node);
5682 g_signal_handlers_unblock_by_func
5684 G_CALLBACK(addressbook_tree_selected), NULL);
5685 gdk_drag_status(context,
5686 (context->actions == GDK_ACTION_COPY ?
5687 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5689 gdk_drag_status(context, 0, time);
5694 static void addressbook_drag_leave_cb(GtkWidget *widget,
5695 GdkDragContext *context,
5699 if (addrbook.treeSelected) {
5700 g_signal_handlers_block_by_func
5702 G_CALLBACK(addressbook_tree_selected), NULL);
5703 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5704 g_signal_handlers_unblock_by_func
5706 G_CALLBACK(addressbook_tree_selected), NULL);
5711 static void addressbook_drag_received_cb(GtkWidget *widget,
5712 GdkDragContext *drag_context,
5715 GtkSelectionData *data,
5721 GtkCMCTreeNode *node;
5722 GtkCMCTreeNode *lastopened = addrbook.opened;
5724 if (!strncmp(data->data, "Dummy_addr", 10)) {
5725 if (gtk_cmclist_get_selection_info
5726 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5730 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5731 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5734 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5735 if (drag_context->action == GDK_ACTION_COPY ||
5736 !strcmp(data->data, "Dummy_addr_copy"))
5737 addressbook_clip_copy_cb(NULL, NULL);
5739 addressbook_clip_cut_cb(NULL, NULL);
5740 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5741 addressbook_clip_paste_cb(NULL,NULL);
5742 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5743 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5744 gtk_drag_finish(drag_context, TRUE, TRUE, time);