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;
668 addressbook_button_set_sensitive();
671 Compose *addressbook_get_target_compose(void)
673 return addrbook.target_compose;
677 * Refresh addressbook and save to file(s).
679 void addressbook_refresh( void )
681 if (addrbook.window) {
682 if (addrbook.treeSelected) {
683 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
684 addrbook.treeSelected);
685 addressbook_set_clist(
686 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
687 addrbook.treeSelected),
692 addressbook_export_to_file();
695 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
697 if (event && event->keyval == GDK_Escape)
699 else if (event && event->keyval == GDK_Delete) {
700 /* TODO: enable deletion when focus is in ctree (needs implementation in _del_clicked() */
701 if ( /* address_index_has_focus || */ address_list_has_focus )
702 addressbook_del_clicked(NULL, NULL);
708 *\brief Save Gtk object size to prefs dataset
710 static void addressbook_size_allocate_cb(GtkWidget *widget,
711 GtkAllocation *allocation)
713 g_return_if_fail(allocation != NULL);
715 prefs_common.addressbookwin_width = allocation->width;
716 prefs_common.addressbookwin_height = allocation->height;
719 static gint sort_column_number = 0;
720 static GtkSortType sort_column_type = GTK_SORT_ASCENDING;
722 static gint list_case_sort(
723 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
725 GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1;
726 GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2;
727 gchar *name1 = NULL, *name2 = NULL;
728 AddrItemObject *aio1 = ((GtkCMCListRow *)ptr1)->data;
729 AddrItemObject *aio2 = ((GtkCMCListRow *)ptr2)->data;
731 if( aio1->type == aio2->type ) {
733 name1 = GTK_CMCELL_TEXT (row1->cell[sort_column_number])->text;
735 name2 = GTK_CMCELL_TEXT (row2->cell[sort_column_number])->text;
736 if( ! name1 ) return ( name2 != NULL );
737 if( ! name2 ) return -1;
738 return g_utf8_collate( name1, name2 );
740 /* Order groups before person */
741 if( aio1->type == ITEMTYPE_GROUP ) {
742 return (sort_column_type==GTK_SORT_ASCENDING) ? -1:+1;
743 } else if( aio2->type == ITEMTYPE_GROUP ) {
744 return (sort_column_type==GTK_SORT_ASCENDING) ? +1:-1;
750 static void addressbook_sort_list(GtkCMCList *clist, const gint col,
751 const GtkSortType sort_type)
754 GtkWidget *hbox, *label, *arrow;
756 sort_column_number = col;
757 sort_column_type = sort_type;
758 gtk_cmclist_set_compare_func(clist, list_case_sort);
759 gtk_cmclist_set_sort_type(clist, sort_type);
760 gtk_cmclist_set_sort_column(clist, col);
762 gtk_cmclist_freeze(clist);
763 gtk_cmclist_sort(clist);
765 for(pos = 0 ; pos < N_LIST_COLS ; pos++) {
766 hbox = gtk_hbox_new(FALSE, 4);
767 label = gtk_label_new(gettext(list_titles[pos]));
768 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
771 arrow = gtk_arrow_new(sort_type == GTK_SORT_ASCENDING ?
772 GTK_ARROW_DOWN : GTK_ARROW_UP, GTK_SHADOW_IN);
773 gtk_box_pack_end(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
776 gtk_widget_show_all(hbox);
777 gtk_cmclist_set_column_widget(clist, pos, hbox);
780 gtk_cmclist_thaw(clist);
783 static void addressbook_name_clicked(GtkWidget *button, GtkCMCList *clist)
785 static GtkSortType sort_type = GTK_SORT_ASCENDING;
787 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
789 addressbook_sort_list(clist, COL_NAME, sort_type);
792 static void addressbook_address_clicked(GtkWidget *button, GtkCMCList *clist)
794 static GtkSortType sort_type = GTK_SORT_ASCENDING;
796 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
798 addressbook_sort_list(clist, COL_ADDRESS, sort_type);
801 static void addressbook_remarks_clicked(GtkWidget *button, GtkCMCList *clist)
803 static GtkSortType sort_type = GTK_SORT_ASCENDING;
805 sort_type = (sort_type == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING :
807 addressbook_sort_list(clist, COL_REMARKS, sort_type);
810 static gboolean addressbook_address_index_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
813 address_index_has_focus = TRUE;
817 static gboolean addressbook_address_index_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
820 address_index_has_focus = FALSE;
821 if (!prefs_common.addressbook_use_editaddress_dialog
822 && !address_list_has_focus)
823 addressbook_address_list_disable_some_actions();
827 static gboolean addressbook_address_list_focus_evt_in(GtkWidget *widget, GdkEventFocus *event,
830 address_list_has_focus = TRUE;
834 static gboolean addressbook_address_list_focus_evt_out(GtkWidget *widget, GdkEventFocus *event,
837 address_list_has_focus = FALSE;
838 if (!prefs_common.addressbook_use_editaddress_dialog
839 && !address_index_has_focus)
840 addressbook_address_list_disable_some_actions();
844 /* save hpane and vpane's handle position when it moves */
845 static void addressbook_pane_save_position(void)
848 prefs_common.addressbook_hpaned_pos =
849 gtk_paned_get_position(GTK_PANED(addrbook.hpaned));
851 prefs_common.addressbook_vpaned_pos =
852 gtk_paned_get_position(GTK_PANED(addrbook.vpaned));
856 * Create the address book widgets. The address book contains two CTree widgets: the
857 * address index tree on the left and the address list on the right.
859 * The address index tree displays a hierarchy of interfaces and groups. Each node in
860 * this tree is linked to an address Adapter. Adapters have been created for interfaces,
861 * data sources and folder objects.
863 * The address list displays group, person and email objects. These items are linked
864 * directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data
867 * In the tradition of MVC architecture, the data stores have been separated from the
868 * GUI components. The addrindex.c file provides the interface to all data stores.
870 static void addressbook_create(void)
876 GtkWidget *ctree_swin;
878 GtkWidget *editaddress_vbox;
879 GtkWidget *clist_vbox;
880 GtkWidget *clist_swin;
887 GtkWidget *statusbar;
898 GtkWidget *close_btn;
899 GtkWidget *tree_popup;
900 GtkWidget *list_popup;
902 GtkUIManager *ui_manager;
903 GtkActionGroup *action_group;
904 gchar *index_titles[N_INDEX_COLS];
908 static GdkGeometry geometry;
910 debug_print("Creating addressbook window...\n");
912 index_titles[COL_SOURCES] = _("Sources");
914 /* Address book window */
915 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook");
916 gtk_window_set_title(GTK_WINDOW(window), _("Address book"));
917 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
918 gtk_widget_realize(window);
920 g_signal_connect(G_OBJECT(window), "delete_event",
921 G_CALLBACK(addressbook_close), NULL);
922 g_signal_connect(G_OBJECT(window), "size_allocate",
923 G_CALLBACK(addressbook_size_allocate_cb), NULL);
924 g_signal_connect(G_OBJECT(window), "key_press_event",
925 G_CALLBACK(key_pressed), NULL);
926 MANAGE_WINDOW_SIGNALS_CONNECT(window);
928 vbox = gtk_vbox_new(FALSE, 0);
929 gtk_container_add(GTK_CONTAINER(window), vbox);
932 ui_manager = gtk_ui_manager_new();
933 action_group = cm_menu_create_action_group_full(ui_manager,"Menu", addressbook_entries,
934 G_N_ELEMENTS(addressbook_entries), NULL);
935 gtk_action_group_add_actions(action_group, addressbook_tree_popup_entries,
936 G_N_ELEMENTS(addressbook_tree_popup_entries), NULL);
937 gtk_action_group_add_actions(action_group, addressbook_list_popup_entries,
938 G_N_ELEMENTS(addressbook_list_popup_entries), NULL);
941 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
943 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_POPUP)
946 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Book", "Book", GTK_UI_MANAGER_MENU)
947 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Address", "Address", GTK_UI_MANAGER_MENU)
948 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
949 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
952 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewBook", "Book/NewBook", GTK_UI_MANAGER_MENUITEM)
953 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewFolder", "Book/NewFolder", GTK_UI_MANAGER_MENUITEM)
954 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewVCard", "Book/NewVCard", GTK_UI_MANAGER_MENUITEM)
956 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewJPilot", "Book/NewJPilot", GTK_UI_MANAGER_MENUITEM)
959 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "NewLDAPServer", "Book/NewLDAPServer", GTK_UI_MANAGER_MENUITEM)
961 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator1", "Book/---", GTK_UI_MANAGER_SEPARATOR)
962 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "EditBook", "Book/EditBook", GTK_UI_MANAGER_MENUITEM)
963 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "DeleteBook", "Book/DeleteBook", GTK_UI_MANAGER_MENUITEM)
964 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Separator2", "Book/---", GTK_UI_MANAGER_SEPARATOR)
965 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Save", "Book/Save", GTK_UI_MANAGER_MENUITEM)
966 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Book", "Close", "Book/Close", GTK_UI_MANAGER_MENUITEM)
969 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "SelectAll", "Address/SelectAll", GTK_UI_MANAGER_MENUITEM)
970 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator1", "Address/---", GTK_UI_MANAGER_SEPARATOR)
971 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Cut", "Address/Cut", GTK_UI_MANAGER_MENUITEM)
972 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Copy", "Address/Copy", GTK_UI_MANAGER_MENUITEM)
973 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Paste", "Address/Paste", GTK_UI_MANAGER_MENUITEM)
974 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator2", "Address/---", GTK_UI_MANAGER_SEPARATOR)
975 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Edit", "Address/Edit", GTK_UI_MANAGER_MENUITEM)
976 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Delete", "Address/Delete", GTK_UI_MANAGER_MENUITEM)
977 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator3", "Address/---", GTK_UI_MANAGER_SEPARATOR)
978 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewAddress", "Address/NewAddress", GTK_UI_MANAGER_MENUITEM)
979 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "NewGroup", "Address/NewGroup", GTK_UI_MANAGER_MENUITEM)
980 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Separator4", "Address/---", GTK_UI_MANAGER_SEPARATOR)
981 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Address", "Mailto", "Address/Mailto", GTK_UI_MANAGER_MENUITEM)
984 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportLDIF", "Tools/ImportLDIF", GTK_UI_MANAGER_MENUITEM)
985 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportMutt", "Tools/ImportMutt", GTK_UI_MANAGER_MENUITEM)
986 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ImportPine", "Tools/ImportPine", GTK_UI_MANAGER_MENUITEM)
987 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
988 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportHTML", "Tools/ExportHTML", GTK_UI_MANAGER_MENUITEM)
989 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "ExportLDIF", "Tools/ExportLDIF", GTK_UI_MANAGER_MENUITEM)
990 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
991 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "FindDuplicates", "Tools/FindDuplicates", GTK_UI_MANAGER_MENUITEM)
992 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Tools", "EditAttrs", "Tools/EditAttrs", GTK_UI_MANAGER_MENUITEM)
995 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
997 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
1000 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
1002 hildon_window_set_menu(HILDON_WINDOW(window), GTK_MENU(menubar));
1005 vbox2 = gtk_vbox_new(FALSE, BORDER_WIDTH);
1006 gtk_container_set_border_width(GTK_CONTAINER(vbox2), BORDER_WIDTH);
1007 gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
1009 ctree_swin = gtk_scrolled_window_new(NULL, NULL);
1010 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ctree_swin),
1011 GTK_POLICY_AUTOMATIC,
1012 GTK_POLICY_AUTOMATIC);
1013 gtk_widget_set_size_request(ctree_swin, COL_FOLDER_WIDTH + 20, -1);
1016 ctree = gtk_sctree_new_with_titles(N_INDEX_COLS, 0, index_titles);
1017 GTK_WIDGET_UNSET_FLAGS(GTK_CMCLIST(ctree)->column[0].button,
1020 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1021 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1022 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1023 if (prefs_common.enable_dotted_lines) {
1024 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_DOTTED);
1025 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1026 GTK_CMCTREE_EXPANDER_SQUARE);
1028 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1029 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1030 GTK_CMCTREE_EXPANDER_TRIANGLE);
1032 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1033 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1034 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1035 addressbook_treenode_compare_func);
1037 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1038 G_CALLBACK(addressbook_tree_selected), NULL);
1039 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1040 G_CALLBACK(addressbook_tree_button_pressed),
1042 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1043 G_CALLBACK(addressbook_tree_button_released),
1046 g_signal_connect(G_OBJECT(ctree), "select_row",
1047 G_CALLBACK(addressbook_select_row_tree), NULL);
1049 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1050 addressbook_drag_types, 1,
1051 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1052 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1053 G_CALLBACK(addressbook_drag_motion_cb),
1055 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1056 G_CALLBACK(addressbook_drag_leave_cb),
1058 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1059 G_CALLBACK(addressbook_drag_received_cb),
1061 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1062 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1063 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1064 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1066 clist_vbox = gtk_vbox_new(FALSE, 4);
1068 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1069 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1070 GTK_POLICY_AUTOMATIC,
1071 GTK_POLICY_AUTOMATIC);
1072 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1075 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1076 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1077 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_EXTENDED);
1078 if (prefs_common.enable_dotted_lines) {
1079 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_DOTTED);
1080 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1081 GTK_CMCTREE_EXPANDER_SQUARE);
1083 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1084 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1085 GTK_CMCTREE_EXPANDER_TRIANGLE);
1087 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1088 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1089 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1091 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1093 gtk_widget_set_size_request(clist, -1, 80);
1095 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1096 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1097 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1098 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1099 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1100 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1101 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1102 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1103 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1104 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1105 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1107 for (i = 0; i < N_LIST_COLS; i++)
1108 GTK_WIDGET_UNSET_FLAGS(GTK_CMCLIST(clist)->column[i].button,
1111 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1112 G_CALLBACK(addressbook_list_row_selected), NULL);
1113 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1114 G_CALLBACK(addressbook_list_row_unselected), NULL);
1115 g_signal_connect(G_OBJECT(clist), "button_press_event",
1116 G_CALLBACK(addressbook_list_button_pressed),
1118 g_signal_connect(G_OBJECT(clist), "button_release_event",
1119 G_CALLBACK(addressbook_list_button_released),
1121 g_signal_connect(G_OBJECT(clist), "tree_expand",
1122 G_CALLBACK(addressbook_person_expand_node), NULL );
1123 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1124 G_CALLBACK(addressbook_person_collapse_node), NULL );
1125 g_signal_connect(G_OBJECT(clist), "start_drag",
1126 G_CALLBACK(addressbook_start_drag), NULL);
1127 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1128 G_CALLBACK(addressbook_drag_data_get), NULL);
1129 hbox = gtk_hbox_new(FALSE, 4);
1130 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1132 label = gtk_label_new(_("Lookup name:"));
1133 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1135 entry = gtk_entry_new();
1136 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1138 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1140 g_signal_connect(G_OBJECT(entry), "key_press_event",
1141 G_CALLBACK(addressbook_entry_key_pressed),
1144 if (!prefs_common.addressbook_use_editaddress_dialog) {
1145 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1146 vpaned = gtk_vpaned_new();
1147 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1148 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1151 editaddress_vbox = NULL;
1153 hpaned = gtk_hpaned_new();
1154 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1155 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1156 if (prefs_common.addressbook_use_editaddress_dialog)
1157 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1159 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1162 hsbox = gtk_hbox_new(FALSE, 0);
1163 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1164 statusbar = gtk_statusbar_new();
1165 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1168 hbbox = gtk_hbutton_box_new();
1169 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1170 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1171 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1172 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1174 gtkut_stock_button_add_help(hbbox, &help_btn);
1176 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1177 GTK_WIDGET_SET_FLAGS(edit_btn, GTK_CAN_DEFAULT);
1178 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1179 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1180 GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT);
1181 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1182 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1183 GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT);
1184 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1187 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1188 GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT);
1189 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1191 g_signal_connect(G_OBJECT(help_btn), "clicked",
1192 G_CALLBACK(manual_open_with_anchor_cb),
1193 MANUAL_ANCHOR_ADDRBOOK);
1195 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1196 G_CALLBACK(addressbook_edit_clicked), NULL);
1197 g_signal_connect(G_OBJECT(del_btn), "clicked",
1198 G_CALLBACK(addressbook_del_clicked), NULL);
1199 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1200 G_CALLBACK(addressbook_reg_clicked), NULL);
1201 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1202 G_CALLBACK(addressbook_lup_clicked), NULL);
1204 to_btn = gtk_button_new_with_label
1205 (prefs_common_translated_header_name("To:"));
1206 GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
1207 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1208 cc_btn = gtk_button_new_with_label
1209 (prefs_common_translated_header_name("Cc:"));
1210 GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
1211 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1212 bcc_btn = gtk_button_new_with_label
1213 (prefs_common_translated_header_name("Bcc:"));
1214 GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
1215 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1217 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1218 GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
1219 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1221 g_signal_connect(G_OBJECT(to_btn), "clicked",
1222 G_CALLBACK(addressbook_to_clicked),
1223 GINT_TO_POINTER(COMPOSE_TO));
1224 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1225 G_CALLBACK(addressbook_to_clicked),
1226 GINT_TO_POINTER(COMPOSE_CC));
1227 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1228 G_CALLBACK(addressbook_to_clicked),
1229 GINT_TO_POINTER(COMPOSE_BCC));
1230 g_signal_connect(G_OBJECT(close_btn), "clicked",
1231 G_CALLBACK(addressbook_close_clicked), NULL);
1233 /* Build icons for interface */
1235 /* Build control tables */
1236 addrbookctl_build_map(window);
1237 addrbookctl_build_iflist();
1238 addrbookctl_build_ifselect();
1240 addrbook.clist = NULL;
1242 /* Add each interface into the tree as a root level folder */
1243 nodeIf = _addressInterfaceList_;
1245 AdapterInterface *adapter = nodeIf->data;
1246 AddressInterface *iface = adapter->interface;
1247 nodeIf = g_list_next(nodeIf);
1249 if(iface->useInterface) {
1250 AddressTypeControlItem *atci = adapter->atci;
1251 text = atci->displayName;
1253 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1254 NULL, NULL, &text, FOLDER_SPACING,
1258 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1259 gtk_cmctree_node_set_row_data_full(
1260 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1261 addressbook_free_treenode );
1267 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1268 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1269 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1280 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1281 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1284 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1285 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1286 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1287 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1288 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1289 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1290 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1291 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1292 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1293 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1294 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1295 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1296 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1298 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1300 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1301 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1303 addrbook.window = window;
1304 addrbook.hpaned = hpaned;
1305 addrbook.vpaned = vpaned;
1306 addrbook.menubar = menubar;
1307 addrbook.ctree = ctree;
1310 addrbook.editaddress_vbox = editaddress_vbox;
1311 addrbook.clist = clist;
1312 addrbook.label = label;
1313 addrbook.entry = entry;
1314 addrbook.statusbar = statusbar;
1315 addrbook.status_cid = gtk_statusbar_get_context_id(
1316 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1318 addrbook.help_btn = help_btn;
1319 addrbook.edit_btn = edit_btn;
1320 addrbook.del_btn = del_btn;
1321 addrbook.reg_btn = reg_btn;
1322 addrbook.lup_btn = lup_btn;
1323 addrbook.to_btn = to_btn;
1324 addrbook.cc_btn = cc_btn;
1325 addrbook.bcc_btn = bcc_btn;
1327 addrbook.tree_popup = tree_popup;
1328 addrbook.list_popup = list_popup;
1329 addrbook.ui_manager = ui_manager;
1331 addrbook.listSelected = NULL;
1333 if (!geometry.min_height) {
1334 geometry.min_width = ADDRESSBOOK_WIDTH;
1335 geometry.min_height = ADDRESSBOOK_HEIGHT;
1338 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1340 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1341 prefs_common.addressbookwin_height);
1343 gtk_window_move(GTK_WINDOW(window), 48, 48);
1346 if (!prefs_common.addressbook_use_editaddress_dialog) {
1347 if (prefs_common.addressbook_vpaned_pos > 0)
1348 gtk_paned_set_position(GTK_PANED(vpaned),
1349 prefs_common.addressbook_vpaned_pos);
1351 if (prefs_common.addressbook_hpaned_pos > 0)
1352 gtk_paned_set_position(GTK_PANED(hpaned),
1353 prefs_common.addressbook_hpaned_pos);
1356 gtk_widget_show_all(window);
1360 * Close address book window and save to file(s).
1362 static gint addressbook_close( void ) {
1363 address_completion_end(addrbook.window);
1364 if (!prefs_common.addressbook_use_editaddress_dialog)
1365 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1367 addressbook_pane_save_position();
1369 gtk_widget_hide(addrbook.window);
1370 addressbook_export_to_file();
1375 * Display message in status line.
1376 * \param msg Message to display.
1378 static void addressbook_status_show( gchar *msg ) {
1379 if( addrbook.statusbar != NULL ) {
1381 GTK_STATUSBAR(addrbook.statusbar),
1382 addrbook.status_cid );
1385 GTK_STATUSBAR(addrbook.statusbar),
1386 addrbook.status_cid, msg );
1391 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1395 *addressbook_msgbuf = '\0';
1397 name = addrindex_ds_get_name( ds );
1398 retVal = addrindex_ds_get_status_code( ds );
1399 if( retVal == MGU_SUCCESS ) {
1400 g_snprintf( addressbook_msgbuf,
1401 sizeof(addressbook_msgbuf), "%s", name );
1404 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1405 g_snprintf( addressbook_msgbuf,
1406 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1409 addressbook_status_show( addressbook_msgbuf );
1412 static void addressbook_button_set_sensitive(void)
1414 gboolean to_sens = FALSE;
1415 gboolean cc_sens = FALSE;
1416 gboolean bcc_sens = FALSE;
1418 if (!addrbook.window) return;
1420 if (addrbook.target_compose) {
1426 gtk_widget_set_sensitive(addrbook.to_btn, to_sens);
1427 gtk_widget_set_sensitive(addrbook.cc_btn, cc_sens);
1428 gtk_widget_set_sensitive(addrbook.bcc_btn, bcc_sens);
1431 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1433 addressbook_edit_address_cb(NULL, NULL);
1436 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1438 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1442 * Delete one or more objects from address list.
1444 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1446 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1447 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1448 AddressObject *pobj;
1449 AdapterDSource *ads = NULL;
1450 GtkCMCTreeNode *nodeList;
1453 AddressBookFile *abf = NULL;
1454 AddressDataSource *ds = NULL;
1455 AddressInterface *iface;
1456 AddrItemObject *aio;
1457 AddrSelectItem *item;
1459 gboolean refreshList = FALSE;
1461 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1462 g_return_if_fail(pobj != NULL);
1464 /* Test whether anything selected for deletion */
1465 nodeList = addrbook.listSelected;
1467 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1468 if( aio == NULL) return;
1469 ds = addressbook_find_datasource( addrbook.treeSelected );
1470 if( ds == NULL ) return;
1472 /* Test for read only */
1473 iface = ds->interface;
1474 if( iface->readOnly ) {
1475 alertpanel( _("Delete address(es)"),
1476 _("This address data is readonly and cannot be deleted."),
1477 GTK_STOCK_CLOSE, NULL, NULL );
1481 /* Test whether Ok to proceed */
1483 if( pobj->type == ADDR_DATASOURCE ) {
1484 ads = ADAPTER_DSOURCE(pobj);
1485 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1487 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1490 else if( pobj->type == ADDR_ITEM_GROUP ) {
1493 if( ! procFlag ) return;
1494 abf = ds->rawDataSource;
1495 if( abf == NULL ) return;
1497 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1498 g_signal_handlers_block_by_func
1499 (G_OBJECT(addrbook.clist),
1500 G_CALLBACK(addressbook_list_row_unselected), NULL);
1502 /* Process deletions */
1503 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1504 GList *groups = NULL, *persons = NULL, *emails = NULL;
1505 gboolean group_delete = TRUE;
1506 /* Items inside folders */
1507 list = addrselect_get_list( _addressSelect_ );
1508 /* Confirm deletion */
1512 node = g_list_next( node );
1513 aio = ( AddrItemObject * ) item->addressItem;
1514 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1515 group_delete = FALSE;
1520 aval = alertpanel( _("Delete group"),
1521 _("Really delete the group(s)?\n"
1522 "The addresses it contains will not be lost."),
1523 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1524 if( aval != G_ALERTALTERNATE ) {
1528 aval = alertpanel( _("Delete address(es)"),
1529 _("Really delete the address(es)?"),
1530 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1531 if( aval != G_ALERTALTERNATE ) {
1536 /* first, set lists of groups and persons to remove */
1540 node = g_list_next( node );
1541 aio = ( AddrItemObject * ) item->addressItem;
1544 if( aio->type == ADDR_ITEM_GROUP ) {
1545 groups = g_list_prepend(groups, item);
1547 else if( aio->type == ADDR_ITEM_PERSON ) {
1548 persons = g_list_prepend(persons, item);
1551 /* then set list of emails to remove *if* they're not children of
1552 * persons to remove */
1556 node = g_list_next( node );
1557 aio = ( AddrItemObject * ) item->addressItem;
1560 if( aio->type == ADDR_ITEM_EMAIL ) {
1561 ItemEMail *sitem = ( ItemEMail * ) aio;
1562 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1563 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1564 emails = g_list_prepend(emails, item);
1566 /* else, the email will be removed via the parent person */
1569 /* then delete groups */
1573 node = g_list_next( node );
1574 aio = ( AddrItemObject * ) item->addressItem;
1577 if( aio->type == ADDR_ITEM_GROUP ) {
1578 ItemGroup *item = ( ItemGroup * ) aio;
1579 GtkCMCTreeNode *nd = NULL;
1580 nd = addressbook_find_group_node( addrbook.opened, item );
1581 item = addrbook_remove_group( abf, item );
1583 addritem_free_item_group( item );
1585 /* Remove group from parent node */
1586 gtk_cmctree_remove_node( ctree, nd );
1590 /* then delete persons */
1594 node = g_list_next( node );
1595 aio = ( AddrItemObject * ) item->addressItem;
1598 if( aio->type == ADDR_ITEM_PERSON ) {
1599 ItemPerson *item = ( ItemPerson * ) aio;
1600 item->status = DELETE_ENTRY;
1601 addressbook_folder_remove_one_person( clist, item );
1602 if (pobj->type == ADDR_ITEM_FOLDER)
1603 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1604 item = addrbook_remove_person( abf, item );
1606 if (ds && ds->type == ADDR_IF_LDAP) {
1607 LdapServer *server = ds->rawDataSource;
1608 ldapsvr_set_modified(server, TRUE);
1609 ldapsvr_update_book(server, item);
1613 gchar *filename = addritem_person_get_picture(item);
1614 if (filename && is_file_exist(filename))
1615 claws_unlink(filename);
1617 addritem_free_item_person( item );
1621 /* then delete emails */
1625 node = g_list_next( node );
1626 aio = ( AddrItemObject * ) item->addressItem;
1630 if( aio->type == ADDR_ITEM_EMAIL ) {
1631 ItemEMail *sitem = ( ItemEMail * ) aio;
1632 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1633 sitem = addrbook_person_remove_email( abf, person, sitem );
1635 addrcache_remove_email(abf->addressCache, sitem);
1636 addritem_free_item_email( sitem );
1638 addressbook_folder_refresh_one_person( clist, person );
1641 g_list_free( groups );
1642 g_list_free( persons );
1643 g_list_free( emails );
1644 g_list_free( list );
1645 addressbook_list_select_clear();
1647 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1648 addressbook_set_clist(
1649 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1653 addrbook_set_dirty(abf, TRUE);
1654 addressbook_export_to_file();
1655 addressbook_list_menu_setup();
1658 else if( pobj->type == ADDR_ITEM_GROUP ) {
1659 /* Items inside groups */
1660 list = addrselect_get_list( _addressSelect_ );
1664 node = g_list_next( node );
1665 aio = ( AddrItemObject * ) item->addressItem;
1666 if( aio->type == ADDR_ITEM_EMAIL ) {
1667 ItemEMail *item = ( ItemEMail * ) aio;
1668 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1669 item = addrbook_person_remove_email( abf, person, item );
1671 addritem_free_item_email( item );
1675 g_list_free( list );
1676 addressbook_list_select_clear();
1677 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1678 addressbook_set_clist(
1679 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1683 addrbook_set_dirty(abf, TRUE);
1684 addressbook_export_to_file();
1685 addressbook_list_menu_setup();
1689 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1690 gtk_cmctree_remove_node( clist, nodeList );
1692 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1693 g_signal_handlers_unblock_by_func
1694 (G_OBJECT(addrbook.clist),
1695 G_CALLBACK(addressbook_list_row_unselected), NULL);
1698 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1700 addressbook_new_address_cb( NULL, NULL );
1703 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1706 gchar *address = NULL;
1708 if( aio->type == ADDR_ITEM_EMAIL ) {
1709 ItemPerson *person = NULL;
1710 ItemEMail *email = ( ItemEMail * ) aio;
1712 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1713 if( email->address ) {
1714 if( ADDRITEM_NAME(email) ) {
1715 name = ADDRITEM_NAME(email);
1716 if( *name == '\0' ) {
1717 name = ADDRITEM_NAME(person);
1720 else if( ADDRITEM_NAME(person) ) {
1721 name = ADDRITEM_NAME(person);
1724 buf = g_strdup( email->address );
1726 address = email->address;
1729 else if( aio->type == ADDR_ITEM_PERSON ) {
1730 ItemPerson *person = ( ItemPerson * ) aio;
1731 GList *node = person->listEMail;
1733 name = ADDRITEM_NAME(person);
1735 ItemEMail *email = ( ItemEMail * ) node->data;
1736 address = email->address;
1740 if( name && name[0] != '\0' ) {
1741 if( strchr_with_skip_quote( name, '"', ',' ) )
1742 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1744 buf = g_strdup_printf( "%s <%s>", name, address );
1747 buf = g_strdup( address );
1754 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1758 AddrSelectItem *item;
1759 AddrItemObject *aio;
1762 compose = addrbook.target_compose;
1763 if( ! compose ) return;
1765 /* Nothing selected, but maybe there is something in text entry */
1766 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1768 compose_entry_append(
1769 compose, addr, (ComposeEntryType)data );
1772 /* Select from address list */
1773 list = addrselect_get_list( _addressSelect_ );
1778 node = g_list_next( node );
1779 aio = item->addressItem;
1780 if( aio->type == ADDR_ITEM_PERSON ||
1781 aio->type == ADDR_ITEM_EMAIL ) {
1782 addr = addressbook_format_address( aio );
1783 compose_entry_append(
1784 compose, addr, (ComposeEntryType) data );
1787 else if( aio->type == ADDR_ITEM_GROUP ) {
1788 ItemGroup *group = ( ItemGroup * ) aio;
1789 GList *nodeMail = group->listEMail;
1791 ItemEMail *email = nodeMail->data;
1793 addr = addressbook_format_address(
1794 ( AddrItemObject * ) email );
1795 compose_entry_append(
1796 compose, addr, (ComposeEntryType) data );
1798 nodeMail = g_list_next( nodeMail );
1803 AddressObject *obj = NULL;
1805 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1807 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1808 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1809 GList *nodeMail = itemGroup->listEMail;
1811 ItemEMail *email = nodeMail->data;
1813 addr = addressbook_format_address(
1814 ( AddrItemObject * ) email );
1815 compose_entry_append(
1816 compose, addr, (ComposeEntryType) data );
1818 nodeMail = g_list_next( nodeMail );
1822 g_list_free( list );
1825 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1826 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1827 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1828 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1830 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1831 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1832 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1833 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1835 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1836 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1837 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1838 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1839 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1842 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1843 gboolean canEdit = FALSE;
1844 gboolean canDelete = TRUE;
1845 gboolean canAdd = FALSE;
1846 gboolean canEditTr = TRUE;
1847 gboolean editAddress = FALSE;
1848 gboolean canExport = TRUE;
1849 AddressTypeControlItem *atci = NULL;
1850 AddressDataSource *ds = NULL;
1851 AddressInterface *iface = NULL;
1853 if( obj == NULL ) return;
1854 if( obj->type == ADDR_INTERFACE ) {
1855 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1856 iface = adapter->interface;
1858 if( iface->haveLibrary ) {
1859 /* Enable appropriate File / New command */
1860 atci = adapter->atci;
1861 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1864 canEditTr = canExport = FALSE;
1866 else if( obj->type == ADDR_DATASOURCE ) {
1867 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1868 ds = ads->dataSource;
1869 iface = ds->interface;
1870 if( ! iface->readOnly ) {
1871 canAdd = canEdit = editAddress = canDelete = TRUE;
1873 if( ! iface->haveLibrary ) {
1874 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1877 else if( obj->type == ADDR_ITEM_FOLDER ) {
1878 ds = addressbook_find_datasource( addrbook.treeSelected );
1880 iface = ds->interface;
1881 if( iface->readOnly ) {
1886 canAdd = editAddress = TRUE;
1890 else if( obj->type == ADDR_ITEM_GROUP ) {
1891 ds = addressbook_find_datasource( addrbook.treeSelected );
1893 iface = ds->interface;
1894 if( ! iface->readOnly ) {
1900 if( addrbook.listSelected == NULL )
1904 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1905 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1906 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1907 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1910 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1911 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1912 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1913 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1915 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1916 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1919 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1920 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1924 * Address book tree callback function that responds to selection of tree
1927 * \param ctree Tree widget.
1928 * \param node Node that was selected.
1929 * \param column Column number where selected occurred.
1930 * \param data Pointer to user data.
1932 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1933 gint column, gpointer data)
1935 AddressObject *obj = NULL;
1936 AdapterDSource *ads = NULL;
1937 AddressDataSource *ds = NULL;
1938 ItemFolder *rootFolder = NULL;
1939 AddressObjectType aot;
1941 addrbook.treeSelected = node;
1942 addrbook.listSelected = NULL;
1943 addressbook_status_show( "" );
1944 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1946 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1948 addressbook_set_clist(NULL, TRUE);
1951 addrbook.opened = node;
1953 if( obj->type == ADDR_DATASOURCE ) {
1954 /* Read from file */
1955 static gboolean tVal = TRUE;
1957 ads = ADAPTER_DSOURCE(obj);
1958 if( ads == NULL ) return;
1959 ds = ads->dataSource;
1960 if( ds == NULL ) return;
1962 if( addrindex_ds_get_modify_flag( ds ) ) {
1963 addrindex_ds_read_data( ds );
1966 if( ! addrindex_ds_get_read_flag( ds ) ) {
1967 addrindex_ds_read_data( ds );
1969 addressbook_ds_show_message( ds );
1971 if( ! addrindex_ds_get_access_flag( ds ) ) {
1972 /* Remove existing folders and groups */
1973 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1974 addressbook_tree_remove_children( ctree, node );
1975 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1977 /* Load folders into the tree */
1978 rootFolder = addrindex_ds_get_root_folder( ds );
1979 if( ds && ds->type == ADDR_IF_JPILOT ) {
1980 aot = ADDR_CATEGORY;
1982 else if( ds && ds->type == ADDR_IF_LDAP ) {
1983 aot = ADDR_LDAP_QUERY;
1986 aot = ADDR_ITEM_FOLDER;
1988 addressbook_node_add_folder( node, ds, rootFolder, aot );
1989 addrindex_ds_set_access_flag( ds, &tVal );
1990 gtk_cmctree_expand( ctree, node );
1993 addressbook_set_clist(NULL, TRUE);
1996 /* Update address list */
1997 g_signal_handlers_block_by_func
1999 G_CALLBACK(addressbook_tree_selected), NULL);
2000 addressbook_set_clist( obj, FALSE );
2001 g_signal_handlers_unblock_by_func
2003 G_CALLBACK(addressbook_tree_selected), NULL);
2004 if (!prefs_common.addressbook_use_editaddress_dialog)
2005 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2007 /* Setup main menu selections */
2008 addressbook_menubar_set_sensitive( FALSE );
2009 addressbook_menuitem_set_sensitive( obj, node );
2010 addressbook_list_select_clear();
2011 addressbook_list_menu_setup();
2016 * Setup address list popup menu items. Items are enabled or disabled as
2019 static void addressbook_list_menu_setup( void ) {
2020 GtkCMCTree *clist = NULL;
2021 AddressObject *pobj = NULL;
2022 AddressObject *obj = NULL;
2023 AdapterDSource *ads = NULL;
2024 AddressInterface *iface = NULL;
2025 AddressDataSource *ds = NULL;
2026 gboolean canEdit = FALSE;
2027 gboolean canDelete = FALSE;
2028 gboolean canCut = FALSE;
2029 gboolean canCopy = FALSE;
2030 gboolean canPaste = FALSE;
2031 gboolean canBrowse = FALSE;
2033 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2034 if( pobj == NULL ) return;
2036 clist = GTK_CMCTREE(addrbook.clist);
2037 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2038 if( obj == NULL ) canEdit = FALSE;
2040 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2041 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2043 if( pobj->type == ADDR_DATASOURCE ) {
2044 /* Parent object is a data source */
2045 ads = ADAPTER_DSOURCE(pobj);
2046 ds = ads->dataSource;
2049 iface = ds->interface;
2052 if( ! iface->readOnly ) {
2053 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2054 if (iface->type != ADDR_IF_LDAP)
2055 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2056 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2059 canDelete = canEdit;
2062 else if( pobj->type != ADDR_INTERFACE ) {
2063 /* Parent object is not an interface */
2064 ds = addressbook_find_datasource( addrbook.treeSelected );
2067 iface = ds->interface;
2070 if( ! iface->readOnly ) {
2071 /* Folder or group */
2072 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2073 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2074 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2075 if( obj ) canEdit = TRUE;
2078 if( pobj->type == ADDR_ITEM_FOLDER ) {
2079 if (iface->type != ADDR_IF_LDAP)
2080 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2081 if( obj ) canEdit = TRUE;
2083 canDelete = canEdit;
2085 if( iface->type == ADDR_IF_LDAP ) {
2086 if( obj ) canBrowse = TRUE;
2093 /* Enable cut and paste */
2094 if( ! addrclip_is_empty( _clipBoard_ ) )
2096 if( ! addrselect_test_empty( _addressSelect_ ) )
2098 /* Enable copy if something is selected */
2099 if( ! addrselect_test_empty( _addressSelect_ ) )
2103 /* Disable edit or browse if more than one row selected */
2104 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2109 /* Forbid write changes when read-only */
2110 if( iface && iface->readOnly ) {
2116 /* Now go finalize menu items */
2117 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2118 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2120 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2121 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2122 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2124 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2126 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2127 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2128 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2130 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2131 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2132 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2134 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2135 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2138 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2142 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2143 GtkCMCTreeNode *node,
2150 * Add list of items into tree node below specified tree node.
2151 * \param treeNode Tree node.
2152 * \param ds Data source.
2153 * \param listItems List of items.
2155 static void addressbook_treenode_add_list(
2156 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2162 AddrItemObject *aio;
2166 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2169 group = ( ItemGroup * ) aio;
2170 nn = addressbook_node_add_group( treeNode, ds, group );
2172 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2175 folder = ( ItemFolder * ) aio;
2176 nn = addressbook_node_add_folder(
2177 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2179 node = g_list_next( node );
2183 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2184 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2188 * Cut from address list widget.
2190 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2191 _clipBoard_->cutFlag = TRUE;
2192 addrclip_clear( _clipBoard_ );
2193 addrclip_add( _clipBoard_, _addressSelect_ );
2194 /* addrclip_list_show( _clipBoard_, stdout ); */
2198 * Copy from address list widget.
2200 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2201 _clipBoard_->cutFlag = FALSE;
2202 addrclip_clear( _clipBoard_ );
2203 addrclip_add( _clipBoard_, _addressSelect_ );
2204 /* addrclip_list_show( _clipBoard_, stdout ); */
2208 * Paste clipboard into address list widget.
2210 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2211 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2212 AddressObject *pobj = NULL;
2213 AddressDataSource *ds = NULL;
2214 AddressBookFile *abf = NULL;
2215 ItemFolder *folder = NULL;
2216 GList *folderGroup = NULL;
2218 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2219 if( ds == NULL ) return;
2220 if( addrindex_ds_get_readonly( ds ) ) {
2221 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2225 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2227 if( pobj->type == ADDR_ITEM_FOLDER ) {
2228 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2230 else if( pobj->type == ADDR_ITEM_GROUP ) {
2231 alertpanel_error( _("Cannot paste into an address group.") );
2236 /* Get an address book */
2237 abf = addressbook_get_book_file();
2238 if( abf == NULL ) return;
2240 if( _clipBoard_->cutFlag ) {
2242 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2244 /* Remove all groups and folders in clipboard from tree node */
2245 addressbook_treenode_remove_item();
2247 /* Remove all "cut" items */
2248 addrclip_delete_item( _clipBoard_ );
2250 /* Clear clipboard - cut items??? */
2251 addrclip_clear( _clipBoard_ );
2255 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2258 /* addrclip_list_show( _clipBoard_, stdout ); */
2260 /* Update tree by inserting node for each folder or group */
2261 addressbook_treenode_add_list(
2262 addrbook.treeSelected, ds, folderGroup );
2263 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2264 g_list_free( folderGroup );
2268 /* Display items pasted */
2269 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2270 addressbook_set_clist(
2271 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2279 * Add current treenode object to clipboard. Note that widget only allows
2280 * one entry from the tree list to be selected.
2282 static void addressbook_treenode_to_clipboard( void ) {
2283 AddressObject *obj = NULL;
2284 AddressDataSource *ds = NULL;
2285 AddrSelectItem *item;
2286 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2287 GtkCMCTreeNode *node;
2289 node = addrbook.treeSelected;
2290 if( node == NULL ) return;
2291 obj = gtk_cmctree_node_get_row_data( ctree, node );
2292 if( obj == NULL ) return;
2294 ds = addressbook_find_datasource( node );
2295 if( ds == NULL ) return;
2298 if( obj->type == ADDR_ITEM_FOLDER ) {
2299 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2300 ItemFolder *folder = adapter->itemFolder;
2302 item = addrselect_create_node( obj );
2303 item->uid = g_strdup( ADDRITEM_ID(folder) );
2305 else if( obj->type == ADDR_ITEM_GROUP ) {
2306 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2307 ItemGroup *group = adapter->itemGroup;
2309 item = addrselect_create_node( obj );
2310 item->uid = g_strdup( ADDRITEM_ID(group) );
2312 else if( obj->type == ADDR_DATASOURCE ) {
2314 item = addrselect_create_node( obj );
2319 /* Clear existing list and add item into list */
2322 addressbook_list_select_clear();
2323 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2324 addrselect_list_add( _addressSelect_, item, cacheID );
2330 * Cut from tree widget.
2332 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2333 _clipBoard_->cutFlag = TRUE;
2334 addressbook_treenode_to_clipboard();
2335 addrclip_clear( _clipBoard_ );
2336 addrclip_add( _clipBoard_, _addressSelect_ );
2337 /* addrclip_list_show( _clipBoard_, stdout ); */
2341 * Copy from tree widget.
2343 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2344 _clipBoard_->cutFlag = FALSE;
2345 addressbook_treenode_to_clipboard();
2346 addrclip_clear( _clipBoard_ );
2347 addrclip_add( _clipBoard_, _addressSelect_ );
2348 /* addrclip_list_show( _clipBoard_, stdout ); */
2352 * Paste clipboard into address tree widget.
2354 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2355 addressbook_clip_paste_cb(NULL,NULL);
2359 * Clear selected entries in clipboard.
2361 static void addressbook_list_select_clear( void ) {
2362 addrselect_list_clear( _addressSelect_ );
2366 * Add specified address item to selected address list.
2367 * \param aio Address item object.
2368 * \param ds Datasource.
2370 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2373 if( ds == NULL ) return;
2374 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2375 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2380 * Remove specified address item from selected address list.
2381 * \param aio Address item object.
2383 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2384 addrselect_list_remove( _addressSelect_, aio );
2388 * Invoke EMail compose window with addresses in selected address list.
2390 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2393 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2394 listAddress = addrselect_build_list( _addressSelect_ );
2395 compose_new_with_list( NULL, listAddress );
2396 mgu_free_dlist( listAddress );
2401 static void addressbook_list_row_selected( GtkCMCTree *clist,
2402 GtkCMCTreeNode *node,
2406 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2407 AddrItemObject *aio = NULL;
2408 AddressObject *pobj = NULL;
2409 AdapterDSource *ads = NULL;
2410 AddressDataSource *ds = NULL;
2412 gtk_entry_set_text( entry, "" );
2413 addrbook.listSelected = node;
2415 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2416 if( pobj == NULL ) return;
2418 if( pobj->type == ADDR_DATASOURCE ) {
2419 ads = ADAPTER_DSOURCE(pobj);
2420 ds = ads->dataSource;
2422 else if( pobj->type != ADDR_INTERFACE ) {
2423 ds = addressbook_find_datasource( addrbook.treeSelected );
2426 aio = gtk_cmctree_node_get_row_data( clist, node );
2428 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2429 addressbook_list_select_add( aio, ds );
2432 addressbook_list_menu_setup();
2434 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2435 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2437 if (obj && obj->type != ADDR_ITEM_GROUP)
2438 addressbook_edit_address(NULL, 0, NULL, FALSE);
2442 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2443 GtkCMCTreeNode *node,
2447 AddrItemObject *aio;
2449 aio = gtk_cmctree_node_get_row_data( ctree, node );
2451 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2452 addressbook_list_select_remove( aio );
2455 if (!prefs_common.addressbook_use_editaddress_dialog)
2456 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2459 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2460 GdkEventButton *event,
2463 if( ! event ) return FALSE;
2465 addressbook_list_menu_setup();
2467 if( event->button == 3 ) {
2468 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2469 event->button, event->time );
2470 } else if (event->button == 1) {
2471 if (event->type == GDK_2BUTTON_PRESS) {
2472 if (prefs_common.add_address_by_click &&
2473 addrbook.target_compose)
2474 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2476 if (prefs_common.addressbook_use_editaddress_dialog)
2477 addressbook_edit_address_cb(NULL, NULL);
2479 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2480 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2481 if( obj && obj->type == ADDR_ITEM_GROUP )
2482 addressbook_edit_address_cb(NULL, NULL);
2490 static gboolean addressbook_list_button_released(GtkWidget *widget,
2491 GdkEventButton *event,
2497 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2498 GdkEventButton *event,
2501 GtkCMCList *clist = GTK_CMCLIST(ctree);
2503 AddressObject *obj = NULL;
2504 AdapterDSource *ads = NULL;
2505 AddressInterface *iface = NULL;
2506 AddressDataSource *ds = NULL;
2507 gboolean canEdit = FALSE;
2508 gboolean canDelete = FALSE;
2509 gboolean canCut = FALSE;
2510 gboolean canCopy = FALSE;
2511 gboolean canPaste = FALSE;
2512 gboolean canTreeCut = FALSE;
2513 gboolean canTreeCopy = FALSE;
2514 gboolean canTreePaste = FALSE;
2515 gboolean canLookup = FALSE;
2516 GtkCMCTreeNode *node = NULL;
2518 if( ! event ) return FALSE;
2519 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2521 if (event->button == 1) {
2522 if (event->type == GDK_2BUTTON_PRESS) {
2523 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2524 gtkut_clist_set_focus_row(clist, row);
2525 obj = gtk_cmclist_get_row_data( clist, row );
2530 if (obj->type == ADDR_ITEM_GROUP) {
2532 addressbook_treenode_edit_cb(NULL, NULL);
2534 /* expand pr collapse */
2535 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2536 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2542 addressbook_menubar_set_sensitive( FALSE );
2544 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2545 gtkut_clist_set_focus_row(clist, row);
2546 obj = gtk_cmclist_get_row_data( clist, row );
2549 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2553 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2555 if( ! addrclip_is_empty( _clipBoard_ ) )
2556 canTreePaste = TRUE;
2558 if (obj->type == ADDR_INTERFACE) {
2559 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2560 iface = adapter->interface;
2563 if( !iface->readOnly ) {
2564 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2565 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2567 if( iface->externalQuery )
2570 if (obj->type == ADDR_DATASOURCE) {
2571 ads = ADAPTER_DSOURCE(obj);
2572 ds = ads->dataSource;
2575 iface = ds->interface;
2578 if( !iface->readOnly ) {
2580 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2581 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2582 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2586 if( iface->externalQuery )
2589 else if (obj->type == ADDR_ITEM_FOLDER) {
2590 ds = addressbook_find_datasource( node );
2593 iface = ds->interface;
2596 if( !iface->readOnly ) {
2600 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2601 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2602 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2606 if( iface->externalQuery ) {
2607 /* Enable deletion of LDAP folder */
2612 else if (obj->type == ADDR_ITEM_GROUP) {
2613 ds = addressbook_find_datasource( node );
2616 iface = ds->interface;
2619 if( ! iface->readOnly ) {
2622 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2623 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2627 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2629 if( ! addrselect_test_empty( _addressSelect_ ) )
2631 if( ! addrclip_is_empty( _clipBoard_ ) )
2634 /* Forbid write changes when read-only */
2635 if( iface && iface->readOnly ) {
2637 canTreePaste = FALSE;
2645 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2646 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2647 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2648 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2649 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2651 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2652 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2653 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2654 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2655 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2657 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2658 addrbook.target_compose != NULL);
2660 if( event->button == 3 )
2661 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2662 event->button, event->time);
2667 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2668 GdkEventButton *event,
2671 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2675 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2677 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2678 AddressObject *obj = NULL;
2679 AddressDataSource *ds = NULL;
2680 AddressBookFile *abf = NULL;
2681 ItemFolder *parentFolder = NULL;
2682 ItemFolder *folder = NULL;
2684 if( ! addrbook.treeSelected ) return;
2685 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2686 if( obj == NULL ) return;
2687 ds = addressbook_find_datasource( addrbook.treeSelected );
2688 if( ds == NULL ) return;
2690 if( obj->type == ADDR_DATASOURCE ) {
2691 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2693 else if( obj->type == ADDR_ITEM_FOLDER ) {
2694 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2700 abf = ds->rawDataSource;
2701 if( abf == NULL ) return;
2702 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2705 nn = addressbook_node_add_folder(
2706 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2707 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2708 if( addrbook.treeSelected == addrbook.opened )
2709 addressbook_set_clist(obj, TRUE);
2713 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2715 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2716 AddressObject *obj = NULL;
2717 AddressDataSource *ds = NULL;
2718 AddressBookFile *abf = NULL;
2719 ItemFolder *parentFolder = NULL;
2720 ItemGroup *group = NULL;
2722 if( ! addrbook.treeSelected ) return;
2723 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2724 if( obj == NULL ) return;
2725 ds = addressbook_find_datasource( addrbook.treeSelected );
2726 if( ds == NULL ) return;
2728 if( obj->type == ADDR_DATASOURCE ) {
2729 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2731 else if( obj->type == ADDR_ITEM_FOLDER ) {
2732 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2738 abf = ds->rawDataSource;
2739 if( abf == NULL ) return;
2740 group = addressbook_edit_group( abf, parentFolder, NULL );
2743 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2744 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2745 if( addrbook.treeSelected == addrbook.opened )
2746 addressbook_set_clist(obj, TRUE);
2750 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2752 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2755 GdkPixbuf *pix_cl, *pix_op;
2756 gboolean is_leaf, expanded;
2758 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2760 &is_leaf, &expanded);
2761 gtk_sctree_set_node_info(ctree, node, name, spacing,
2768 * \param obj Address object to edit.
2769 * \param node Node in tree.
2770 * \return New name of data source.
2772 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2773 gchar *newName = NULL;
2774 AddressDataSource *ds = NULL;
2775 AddressInterface *iface = NULL;
2776 AdapterDSource *ads = NULL;
2778 ds = addressbook_find_datasource( node );
2779 if( ds == NULL ) return NULL;
2780 iface = ds->interface;
2781 if( ! iface->haveLibrary ) return NULL;
2783 /* Read data from data source */
2784 if( addrindex_ds_get_modify_flag( ds ) ) {
2785 addrindex_ds_read_data( ds );
2788 if( ! addrindex_ds_get_read_flag( ds ) ) {
2789 addrindex_ds_read_data( ds );
2793 ads = ADAPTER_DSOURCE(obj);
2794 if( ads->subType == ADDR_BOOK ) {
2795 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2797 else if( ads->subType == ADDR_VCARD ) {
2798 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2801 else if( ads->subType == ADDR_JPILOT ) {
2802 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2806 else if( ads->subType == ADDR_LDAP ) {
2807 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2813 newName = obj->name;
2818 * Edit an object that is in the address tree area.
2820 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2822 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2824 AddressDataSource *ds = NULL;
2825 AddressBookFile *abf = NULL;
2826 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2829 if( ! addrbook.treeSelected ) return;
2830 node = addrbook.treeSelected;
2831 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2832 obj = gtk_cmctree_node_get_row_data( ctree, node );
2833 if( obj == NULL ) return;
2834 parentNode = GTK_CMCTREE_ROW(node)->parent;
2836 ds = addressbook_find_datasource( node );
2837 if( ds == NULL ) return;
2839 if( obj->type == ADDR_DATASOURCE ) {
2840 name = addressbook_edit_datasource( obj, node );
2841 if( name == NULL ) return;
2844 abf = ds->rawDataSource;
2845 if( abf == NULL ) return;
2846 if( obj->type == ADDR_ITEM_FOLDER ) {
2847 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2848 ItemFolder *item = adapter->itemFolder;
2849 ItemFolder *parentFolder = NULL;
2850 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2851 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2852 name = ADDRITEM_NAME(item);
2854 else if( obj->type == ADDR_ITEM_GROUP ) {
2855 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2856 ItemGroup *item = adapter->itemGroup;
2857 ItemFolder *parentFolder = NULL;
2858 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2859 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2860 name = ADDRITEM_NAME(item);
2863 if( name && parentNode ) {
2864 /* Update node in tree view */
2865 addressbook_change_node_name( node, name );
2866 gtk_sctree_sort_node(ctree, parentNode);
2867 gtk_cmctree_expand( ctree, node );
2868 gtk_sctree_select( GTK_SCTREE( ctree), node );
2875 ADDRTREE_DEL_FOLDER_ONLY,
2876 ADDRTREE_DEL_FOLDER_ADDR
2880 * Delete an item from the tree widget.
2881 * \param data Data passed in.
2882 * \param action Action.
2883 * \param widget Widget issuing callback.
2885 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2887 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2888 GtkCMCTreeNode *node = NULL;
2892 AddrBookBase *adbase;
2893 AddressCache *cache;
2894 AdapterDSource *ads = NULL;
2895 AddressInterface *iface = NULL;
2896 AddressDataSource *ds = NULL;
2897 gboolean remFlag = FALSE;
2898 TreeItemDelType delType;
2900 if( ! addrbook.treeSelected ) return;
2901 node = addrbook.treeSelected;
2902 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2904 obj = gtk_cmctree_node_get_row_data( ctree, node );
2905 g_return_if_fail(obj != NULL);
2907 if( obj->type == ADDR_DATASOURCE ) {
2908 ads = ADAPTER_DSOURCE(obj);
2909 if( ads == NULL ) return;
2910 ds = ads->dataSource;
2911 if( ds == NULL ) return;
2914 /* Must be folder or something else */
2915 ds = addressbook_find_datasource( node );
2916 if( ds == NULL ) return;
2918 /* Only allow deletion from non-readOnly */
2919 iface = ds->interface;
2920 if( iface->readOnly ) {
2921 /* Allow deletion of query results */
2922 if( ! iface->externalQuery ) return;
2926 /* Confirm deletion */
2927 delType = ADDRTREE_DEL_NONE;
2928 if( obj->type == ADDR_ITEM_FOLDER ) {
2929 if( iface->externalQuery ) {
2930 message = g_strdup_printf( _(
2931 "Do you want to delete the query " \
2932 "results and addresses in '%s' ?" ),
2934 aval = alertpanel( _("Delete"), message,
2935 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2937 if( aval == G_ALERTALTERNATE ) {
2938 delType = ADDRTREE_DEL_FOLDER_ADDR;
2942 message = g_strdup_printf
2943 ( _( "Do you want to delete '%s' ? "
2944 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2946 aval = alertpanel( _("Delete folder"), message,
2947 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2949 if( aval == G_ALERTALTERNATE ) {
2950 delType = ADDRTREE_DEL_FOLDER_ONLY;
2952 else if( aval == G_ALERTOTHER ) {
2953 delType = ADDRTREE_DEL_FOLDER_ADDR;
2957 else if( obj->type == ADDR_ITEM_GROUP ) {
2958 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2959 "The addresses it contains will not be lost."), obj->name);
2960 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2961 "+" GTK_STOCK_DELETE, NULL);
2963 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2965 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2966 "The addresses it contains will be lost."), obj->name);
2967 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2968 "+" GTK_STOCK_DELETE, NULL);
2970 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2972 if( delType == ADDRTREE_DEL_NONE ) return;
2974 /* Proceed with deletion */
2975 if( obj->type == ADDR_DATASOURCE ) {
2976 /* Remove node from tree */
2977 gtk_cmctree_remove_node( ctree, node );
2979 /* Remove data source. */
2980 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2981 addrindex_free_datasource( ds );
2986 /* Get reference to cache */
2987 adbase = ( AddrBookBase * ) ds->rawDataSource;
2988 if( adbase == NULL ) return;
2989 cache = adbase->addressCache;
2991 /* Remove query results folder */
2992 if( iface->externalQuery ) {
2993 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2994 ItemFolder *folder = adapter->itemFolder;
2996 adapter->itemFolder = NULL;
2998 g_print( "remove folder for ::%s::\n", obj->name );
2999 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
3000 g_print( "-------------- remove results\n" );
3002 addrindex_remove_results( ds, folder );
3003 /* g_print( "-------------- remove node\n" ); */
3004 gtk_cmctree_remove_node( ctree, node );
3008 /* Code below is valid for regular address book deletion */
3009 if( obj->type == ADDR_ITEM_FOLDER ) {
3010 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
3011 ItemFolder *item = adapter->itemFolder;
3013 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
3014 /* Remove folder only */
3015 item = addrcache_remove_folder( cache, item );
3017 addritem_free_item_folder( item );
3018 addressbook_move_nodes_up( ctree, node );
3022 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3023 /* Remove folder and addresses */
3024 item = addrcache_remove_folder_delete( cache, item );
3026 addritem_free_item_folder( item );
3031 else if( obj->type == ADDR_ITEM_GROUP ) {
3032 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3033 ItemGroup *item = adapter->itemGroup;
3035 item = addrcache_remove_group( cache, item );
3037 addritem_free_item_group( item );
3044 gtk_cmctree_remove_node(ctree, node );
3048 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3050 if( person && addrbook.treeSelected == addrbook.opened ) {
3051 person->status = ADD_ENTRY;
3052 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3053 addressbook_folder_refresh_one_person(
3054 GTK_CMCTREE(addrbook.clist), person );
3056 addressbook_address_list_set_focus();
3059 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3061 if( person && addrbook.treeSelected == addrbook.opened) {
3062 person->status = ADD_ENTRY;
3063 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3064 addressbook_set_clist(
3065 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3069 addressbook_address_list_set_focus();
3073 * Label (a format string) that is used to name each folder.
3075 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3078 * Search ctree widget callback function.
3079 * \param pA Pointer to node.
3080 * \param pB Pointer to data item being sought.
3081 * \return Zero (0) if folder found.
3083 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3086 aoA = ( AddressObject * ) pA;
3087 if( aoA->type == ADDR_ITEM_FOLDER ) {
3088 ItemFolder *folder, *fld;
3090 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3091 folder = ( ItemFolder * ) pB;
3092 if( fld == folder ) return 0; /* Found folder */
3097 static ItemFolder * addressbook_setup_subf(
3098 AddressDataSource *ds, gchar *title,
3099 GtkCMCTreeNode *pNode )
3101 AddrBookBase *adbase;
3102 AddressCache *cache;
3105 GtkCMCTreeNode *nNode;
3107 AddressObjectType aoType = ADDR_NONE;
3110 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3112 if( ds && ds->type == ADDR_IF_LDAP ) {
3114 aoType = ADDR_LDAP_QUERY;
3121 ctree = GTK_CMCTREE(addrbook.ctree);
3122 /* Get reference to address cache */
3123 adbase = ( AddrBookBase * ) ds->rawDataSource;
3124 cache = adbase->addressCache;
3126 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3127 GList *cur = children;
3128 for (; cur; cur = cur->next) {
3129 ItemFolder *child = (ItemFolder *) cur->data;
3130 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3131 nNode = gtk_cmctree_find_by_row_data_custom(
3133 addressbook_treenode_find_folder_cb );
3135 addrindex_remove_results( ds, child );
3136 while( child->listPerson ) {
3137 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3138 item = addrcache_remove_person( cache, item );
3140 addritem_free_item_person( item );
3144 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3145 addrbook.treeSelected = nNode;
3152 /* Create a folder */
3153 folder = addrcache_add_new_folder( cache, NULL );
3154 name = g_strdup_printf( "%s", title );
3155 addritem_folder_set_name( folder, name );
3156 addritem_folder_set_remarks( folder, "" );
3159 /* Now let's see the folder */
3160 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3161 gtk_cmctree_expand( ctree, pNode );
3163 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3164 addrbook.treeSelected = nNode;
3170 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3171 AddressObject *pobj = NULL;
3172 AddressDataSource *ds = NULL;
3173 AddressBookFile *abf = NULL;
3174 debug_print("adding address\n");
3175 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3176 if( pobj == NULL ) {
3177 debug_print("no row data\n");
3180 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3182 debug_print("no datasource\n");
3186 abf = ds->rawDataSource;
3188 g_print("no addressbook file\n");
3192 if( pobj->type == ADDR_DATASOURCE ) {
3193 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3194 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3196 ItemFolder *folder = NULL;
3198 if (abf && abf->type == ADDR_IF_LDAP) {
3199 GtkCMCTreeNode *parentNode;
3200 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3201 if( ds == NULL ) return;
3203 /* We must have a datasource that is an external interface */
3204 if( ! ds->interface->haveLibrary ) return;
3205 if( ! ds->interface->externalQuery ) return;
3207 if( pobj->type == ADDR_ITEM_FOLDER ) {
3208 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3211 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3213 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3215 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3216 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3218 abf = ds->rawDataSource;
3221 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3222 addrbook.editaddress_vbox,
3223 addressbook_new_address_from_book_post_cb,
3226 if (ds && abf && abf->type == ADDR_IF_LDAP) {
3227 LdapServer *server = ds->rawDataSource;
3228 ldapsvr_set_modified(server, TRUE);
3229 ldapsvr_update_book(server, NULL);
3230 if (server->retVal != LDAPRC_SUCCESS) {
3231 alertpanel( _("Add address(es)"),
3232 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3233 GTK_STOCK_CLOSE, NULL, NULL );
3234 server->retVal = LDAPRC_SUCCESS;
3239 if (prefs_common.addressbook_use_editaddress_dialog)
3240 addressbook_new_address_from_book_post_cb( person );
3243 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3245 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3248 if (abf && abf->type == ADDR_IF_LDAP) {
3249 GtkCMCTreeNode *parentNode;
3250 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3251 if( ds == NULL ) return;
3253 /* We must have a datasource that is an external interface */
3254 if( ! ds->interface->haveLibrary ) return;
3255 if( ! ds->interface->externalQuery ) return;
3257 if( pobj->type == ADDR_ITEM_FOLDER ) {
3258 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3261 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3263 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3266 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3267 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3269 abf = ds->rawDataSource;
3272 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3273 addrbook.editaddress_vbox,
3274 addressbook_new_address_from_folder_post_cb,
3277 if (ds && abf && abf->type == ADDR_IF_LDAP) {
3278 LdapServer *server = ds->rawDataSource;
3279 ldapsvr_set_modified(server, TRUE);
3280 ldapsvr_update_book(server, NULL);
3281 if (server->retVal != LDAPRC_SUCCESS) {
3282 alertpanel( _("Add address(es)"),
3283 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3284 GTK_STOCK_CLOSE, NULL, NULL );
3289 if (prefs_common.addressbook_use_editaddress_dialog)
3290 addressbook_new_address_from_folder_post_cb( person );
3292 else if( pobj->type == ADDR_ITEM_GROUP ) {
3293 /* New address in group */
3294 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3295 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3296 if (addrbook.treeSelected == addrbook.opened) {
3297 /* Change node name in tree. */
3298 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3299 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3300 addressbook_set_clist(
3301 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3309 * Search for specified child group node in address index tree.
3310 * \param parent Parent node.
3311 * \param group Group to find.
3313 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3314 GtkCMCTreeNode *node = NULL;
3315 GtkCMCTreeRow *currRow;
3317 currRow = GTK_CMCTREE_ROW( parent );
3319 node = currRow->children;
3323 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3324 if( obj->type == ADDR_ITEM_GROUP ) {
3325 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3326 if( g == group ) return node;
3328 currRow = GTK_CMCTREE_ROW(node);
3329 node = currRow->sibling;
3335 static AddressBookFile *addressbook_get_book_file() {
3336 AddressBookFile *abf = NULL;
3337 AddressDataSource *ds = NULL;
3339 ds = addressbook_find_datasource( addrbook.treeSelected );
3340 if( ds == NULL ) return NULL;
3341 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3345 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3346 GtkCMCTreeNode *node;
3349 /* Remove existing folders and groups */
3350 row = GTK_CMCTREE_ROW( parent );
3352 while( (node = row->children) ) {
3353 gtk_cmctree_remove_node( ctree, node );
3358 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3359 GtkCMCTreeNode *parent, *child;
3360 GtkCMCTreeRow *currRow;
3361 currRow = GTK_CMCTREE_ROW( node );
3363 parent = currRow->parent;
3364 while( (child = currRow->children) ) {
3365 gtk_cmctree_move( ctree, child, parent, node );
3367 gtk_sctree_sort_node( ctree, parent );
3371 static void addressbook_edit_address_post_cb( ItemPerson *person )
3375 AddressBookFile *abf = addressbook_get_book_file();
3377 if (abf && abf->type == ADDR_IF_LDAP) {
3378 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3379 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3382 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3383 invalidate_address_completion();
3385 addressbook_address_list_set_focus();
3388 void addressbook_address_list_set_focus( void )
3390 if (!prefs_common.addressbook_use_editaddress_dialog) {
3391 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3392 addressbook_list_menu_setup();
3396 void addressbook_address_list_disable_some_actions(void)
3398 /* disable address copy/pasting when editing contact's detail (embedded form) */
3399 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3400 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3401 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3404 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3405 addressbook_edit_address(data, 0, NULL, TRUE);
3408 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3409 gboolean force_focus ) {
3410 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3412 AddressObject *obj = NULL, *pobj = NULL;
3413 AddressDataSource *ds = NULL;
3414 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3416 AddressBookFile *abf = NULL;
3418 if( addrbook.listSelected == NULL ) return;
3419 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3420 g_return_if_fail(obj != NULL);
3422 ctree = GTK_CMCTREE( addrbook.ctree );
3423 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3424 node = gtk_cmctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3426 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3427 if( ds == NULL ) return;
3429 abf = addressbook_get_book_file();
3431 if( obj->type == ADDR_ITEM_EMAIL ) {
3432 ItemEMail *email = ( ItemEMail * ) obj;
3433 if( email == NULL ) return;
3434 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3435 /* Edit parent group */
3436 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3437 ItemGroup *itemGrp = adapter->itemGroup;
3438 if( abf == NULL ) return;
3439 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3440 name = ADDRITEM_NAME(itemGrp);
3441 node = addrbook.treeSelected;
3442 parentNode = GTK_CMCTREE_ROW(node)->parent;
3445 /* Edit person - email page */
3447 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3448 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3449 addressbook_edit_address_post_cb,
3450 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3453 if (abf && abf->type == ADDR_IF_LDAP) {
3454 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3455 person->status = UPDATE_ENTRY;
3458 if (prefs_common.addressbook_use_editaddress_dialog)
3459 addressbook_edit_address_post_cb( person );
3464 else if( obj->type == ADDR_ITEM_PERSON ) {
3465 /* Edit person - basic page */
3466 ItemPerson *person = ( ItemPerson * ) obj;
3467 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3468 addressbook_edit_address_post_cb,
3469 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3472 if (abf && abf->type == ADDR_IF_LDAP) {
3473 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3474 person->status = UPDATE_ENTRY;
3477 if (prefs_common.addressbook_use_editaddress_dialog)
3478 addressbook_edit_address_post_cb( person );
3482 else if( obj->type == ADDR_ITEM_GROUP ) {
3483 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3484 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3485 parentNode = addrbook.treeSelected;
3486 node = addressbook_find_group_node( parentNode, itemGrp );
3487 name = ADDRITEM_NAME(itemGrp);
3488 invalidate_address_completion();
3494 /* Update tree node with node name */
3495 if( node == NULL ) return;
3496 addressbook_change_node_name( node, name );
3497 gtk_sctree_sort_node( ctree, parentNode );
3498 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3499 addressbook_set_clist(
3500 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3505 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3507 addressbook_del_clicked(NULL, NULL);
3510 static void close_cb(GtkAction *action, gpointer data)
3512 addressbook_close();
3515 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3516 addressbook_export_to_file();
3519 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3521 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3522 if( person ) addritem_person_set_opened( person, TRUE );
3526 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3528 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3529 if( person ) addritem_person_set_opened( person, FALSE );
3533 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3535 gchar *eMailAlias = ADDRITEM_NAME(email);
3536 if( eMailAlias && *eMailAlias != '\0' ) {
3538 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3541 str = g_strdup( eMailAlias );
3547 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3548 GList *items = itemGroup->listEMail;
3549 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3550 for( ; items != NULL; items = g_list_next( items ) ) {
3551 GtkCMCTreeNode *nodeEMail = NULL;
3552 gchar *text[N_LIST_COLS];
3553 ItemEMail *email = items->data;
3557 if( ! email ) continue;
3559 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3560 str = addressbook_format_item_clist( person, email );
3562 text[COL_NAME] = addressbook_set_col_name_guard(str);
3565 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3567 text[COL_ADDRESS] = email->address;
3568 text[COL_REMARKS] = email->remarks;
3569 nodeEMail = gtk_sctree_insert_node(
3571 text, FOLDER_SPACING,
3575 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3581 gchar *addressbook_set_col_name_guard(gchar *value)
3583 gchar *ret = "<not set>";
3584 gchar *tmp = g_strdup(value);
3586 if (tmp !=NULL && *tmp != '\0')
3592 static void addressbook_folder_load_one_person(
3593 GtkCMCTree *clist, ItemPerson *person,
3594 AddressTypeControlItem *atci,
3595 AddressTypeControlItem *atciMail )
3597 GtkCMCTreeNode *nodePerson = NULL;
3598 GtkCMCTreeNode *nodeEMail = NULL;
3599 gchar *text[N_LIST_COLS];
3600 gboolean flgFirst = TRUE, haveAddr = FALSE;
3603 AddressBookFile *abf = addressbook_get_book_file();
3606 if( person == NULL ) return;
3608 text[COL_NAME] = "";
3609 node = person->listEMail;
3611 ItemEMail *email = node->data;
3612 gchar *eMailAddr = NULL;
3613 node = g_list_next( node );
3615 text[COL_ADDRESS] = email->address;
3616 text[COL_REMARKS] = email->remarks;
3617 eMailAddr = ADDRITEM_NAME(email);
3618 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3620 /* First email belongs with person */
3621 gchar *str = addressbook_format_item_clist( person, email );
3623 text[COL_NAME] = addressbook_set_col_name_guard(str);
3626 else if( abf && abf->type == ADDR_IF_LDAP &&
3627 person && person->nickName ) {
3628 if (person->nickName) {
3629 if (strcmp(person->nickName, "") != 0) {
3630 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3633 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3639 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3641 nodePerson = gtk_sctree_insert_node(
3643 text, FOLDER_SPACING,
3646 FALSE, person->isOpened );
3649 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3652 /* Subsequent email is a child node of person */
3653 text[COL_NAME] = ADDRITEM_NAME(email);
3654 nodeEMail = gtk_sctree_insert_node(
3655 clist, nodePerson, NULL,
3656 text, FOLDER_SPACING,
3658 atciMail->iconXpmOpen,
3660 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3666 /* Have name without EMail */
3667 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3668 text[COL_ADDRESS] = "";
3669 text[COL_REMARKS] = "";
3670 nodePerson = gtk_sctree_insert_node(
3672 text, FOLDER_SPACING,
3675 FALSE, person->isOpened );
3676 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3681 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3683 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3684 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3686 if( atci == NULL ) return;
3687 if( atciMail == NULL ) return;
3689 /* Load email addresses */
3690 items = addritem_folder_get_person_list( itemFolder );
3691 for( ; items != NULL; items = g_list_next( items ) ) {
3692 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3694 /* Free up the list */
3695 mgu_clear_list( items );
3696 g_list_free( items );
3699 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3700 addrbook.listSelected = NULL;
3701 gtk_cmctree_remove_node( clist, node );
3702 addressbook_menubar_set_sensitive( FALSE );
3703 addressbook_menuitem_set_sensitive(
3704 gtk_cmctree_node_get_row_data(
3705 GTK_CMCTREE(clist), addrbook.treeSelected ),
3706 addrbook.treeSelected );
3709 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3710 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3711 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3712 GtkCMCTreeNode *node;
3713 if( atci == NULL ) return;
3714 if( atciMail == NULL ) return;
3715 if( person == NULL ) return;
3716 /* unload the person */
3718 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3720 addressbook_folder_remove_node( clist, node );
3721 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3722 gtk_sctree_sort_node( clist, NULL );
3723 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3725 gtk_sctree_select( GTK_SCTREE(clist), node );
3726 if (!gtk_cmctree_node_is_visible( clist, node ) )
3727 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3731 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3732 GtkCMCTreeNode *node;
3735 if( person == NULL ) return;
3736 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3737 row = gtk_cmclist_find_row_from_data( GTK_CMCLIST(clist), person );
3739 addressbook_folder_remove_node( clist, node );
3743 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3745 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3747 /* Load any groups */
3748 if( ! atci ) return;
3749 items = addritem_folder_get_group_list( itemFolder );
3750 for( ; items != NULL; items = g_list_next( items ) ) {
3751 GtkCMCTreeNode *nodeGroup = NULL;
3752 gchar *text[N_LIST_COLS];
3753 ItemGroup *group = items->data;
3754 if( group == NULL ) continue;
3755 text[COL_NAME] = ADDRITEM_NAME(group);
3756 text[COL_ADDRESS] = "";
3757 text[COL_REMARKS] = "";
3758 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3759 text, FOLDER_SPACING,
3763 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3764 gtk_sctree_sort_node(clist, NULL);
3766 /* Free up the list */
3767 mgu_clear_list( items );
3768 g_list_free( items );
3772 * Search ctree widget callback function.
3773 * \param pA Pointer to node.
3774 * \param pB Pointer to data item being sought.
3775 * \return Zero (0) if group found.
3777 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3780 aoA = ( AddressObject * ) pA;
3781 if( aoA->type == ADDR_ITEM_GROUP ) {
3782 ItemGroup *group, *grp;
3784 grp = ADAPTER_GROUP(aoA)->itemGroup;
3785 group = ( ItemGroup * ) pB;
3786 if( grp == group ) return 0; /* Found group */
3792 * Remove folder and group nodes from tree widget for items contained ("cut")
3795 static void addressbook_treenode_remove_item( void ) {
3797 AddrSelectItem *cutItem;
3798 AddressCache *cache;
3799 AddrItemObject *aio;
3800 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3803 node = _clipBoard_->objectList;
3805 cutItem = node->data;
3806 node = g_list_next( node );
3807 cache = addrindex_get_cache(
3808 _clipBoard_->addressIndex, cutItem->cacheID );
3809 if( cache == NULL ) continue;
3810 aio = addrcache_get_object( cache, cutItem->uid );
3813 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3816 folder = ( ItemFolder * ) aio;
3817 tn = gtk_cmctree_find_by_row_data_custom(
3818 ctree, NULL, folder,
3819 addressbook_treenode_find_folder_cb );
3821 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3824 group = ( ItemGroup * ) aio;
3825 tn = gtk_cmctree_find_by_row_data_custom(
3827 addressbook_treenode_find_group_cb );
3831 /* Free up adapter and remove node. */
3832 gtk_cmctree_remove_node( ctree, tn );
3839 * Find parent datasource for specified tree node.
3840 * \param node Node to test.
3841 * \return Data source, or NULL if not found.
3843 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3844 AddressDataSource *ds = NULL;
3847 g_return_val_if_fail(addrbook.ctree != NULL, NULL);
3850 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3851 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3853 /* g_print( "ao->type = %d\n", ao->type ); */
3854 if( ao->type == ADDR_DATASOURCE ) {
3855 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3856 /* g_print( "found it\n" ); */
3857 ds = ads->dataSource;
3861 node = GTK_CMCTREE_ROW(node)->parent;
3867 * Load address list widget with children of specified object.
3868 * \param obj Parent object to be loaded.
3870 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3871 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3872 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3873 AddressDataSource *ds = NULL;
3874 AdapterDSource *ads = NULL;
3875 static AddressObject *last_obj = NULL;
3877 if (addrbook.clist == NULL) {
3880 if (obj == last_obj && !refresh)
3885 gtk_cmclist_clear(clist);
3889 if( obj->type == ADDR_INTERFACE ) {
3890 /* g_print( "set_clist: loading datasource...\n" ); */
3891 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3895 gtk_cmclist_freeze(clist);
3896 gtk_cmclist_clear(clist);
3898 if( obj->type == ADDR_DATASOURCE ) {
3899 ads = ADAPTER_DSOURCE(obj);
3900 ds = ADAPTER_DSOURCE(obj)->dataSource;
3902 /* Load root folder */
3903 ItemFolder *rootFolder = NULL;
3904 rootFolder = addrindex_ds_get_root_folder( ds );
3905 addressbook_folder_load_person(
3906 ctreelist, addrindex_ds_get_root_folder( ds ) );
3907 addressbook_folder_load_group(
3908 ctreelist, addrindex_ds_get_root_folder( ds ) );
3912 if( obj->type == ADDR_ITEM_GROUP ) {
3914 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3915 addressbook_load_group( ctreelist, itemGroup );
3917 else if( obj->type == ADDR_ITEM_FOLDER ) {
3919 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3920 addressbook_folder_load_person( ctreelist, itemFolder );
3921 addressbook_folder_load_group( ctreelist, itemFolder );
3924 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3925 clist->focus_row = -1;
3926 gtk_cmclist_thaw(clist);
3930 * Call back function to free adaptor. Call back is setup by function
3931 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3932 * called when the address book tree widget node is removed by calling
3933 * function gtk_cmctree_remove_node().
3935 * \param data Tree node's row data.
3937 static void addressbook_free_treenode( gpointer data ) {
3940 ao = ( AddressObject * ) data;
3941 if( ao == NULL ) return;
3942 if( ao->type == ADDR_INTERFACE ) {
3943 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3944 addrbookctl_free_interface( ai );
3946 else if( ao->type == ADDR_DATASOURCE ) {
3947 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3948 addrbookctl_free_datasource( ads );
3950 else if( ao->type == ADDR_ITEM_FOLDER ) {
3951 AdapterFolder *af = ADAPTER_FOLDER(ao);
3952 addrbookctl_free_folder( af );
3954 else if( ao->type == ADDR_ITEM_GROUP ) {
3955 AdapterGroup *ag = ADAPTER_GROUP(ao);
3956 addrbookctl_free_group( ag );
3961 * Create new adaptor for specified data source.
3963 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3964 AddressObjectType otype, gchar *name )
3966 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3967 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3968 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3969 adapter->dataSource = ds;
3970 adapter->subType = otype;
3974 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3975 ADDRESS_OBJECT_NAME(adapter) =
3976 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3980 * Load tree from address index with the initial data.
3982 static void addressbook_load_tree( void ) {
3983 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3984 GList *nodeIf, *nodeDS;
3985 AdapterInterface *adapter;
3986 AddressInterface *iface;
3987 AddressTypeControlItem *atci;
3988 AddressDataSource *ds;
3989 AdapterDSource *ads;
3990 GtkCMCTreeNode *node, *newNode;
3993 nodeIf = _addressInterfaceList_;
3995 adapter = nodeIf->data;
3996 node = adapter->treeNode;
3997 iface = adapter->interface;
3998 atci = adapter->atci;
4000 if( iface->useInterface ) {
4001 /* Load data sources below interface node */
4002 nodeDS = iface->listSource;
4006 name = addrindex_ds_get_name( ds );
4007 ads = addressbook_create_ds_adapter(
4008 ds, atci->objectType, name );
4009 newNode = addressbook_add_object(
4010 node, ADDRESS_OBJECT(ads) );
4011 nodeDS = g_list_next( nodeDS );
4013 gtk_cmctree_expand( ctree, node );
4016 nodeIf = g_list_next( nodeIf );
4021 * Convert the old address book to new format.
4023 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4024 gboolean retVal = FALSE;
4025 gboolean errFlag = TRUE;
4028 /* Read old address book, performing conversion */
4029 debug_print( "Reading and converting old address book...\n" );
4030 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4031 addrindex_read_data( addrIndex );
4032 if( addrIndex->retVal == MGU_NO_FILE ) {
4033 /* We do not have a file - new user */
4034 debug_print( "New user... create new books...\n" );
4035 addrindex_create_new_books( addrIndex );
4036 if( addrIndex->retVal == MGU_SUCCESS ) {
4037 /* Save index file */
4038 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4039 addrindex_save_data( addrIndex );
4040 if( addrIndex->retVal == MGU_SUCCESS ) {
4045 msg = _( "New user, could not save index file." );
4049 msg = _( "New user, could not save address book files." );
4053 /* We have an old file */
4054 if( addrIndex->wasConverted ) {
4055 /* Converted successfully - save address index */
4056 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4057 addrindex_save_data( addrIndex );
4058 if( addrIndex->retVal == MGU_SUCCESS ) {
4059 msg = _( "Old address book converted successfully." );
4064 msg = _("Old address book converted,\n"
4065 "could not save new address index file." );
4069 /* File conversion failed - just create new books */
4070 debug_print( "File conversion failed... just create new books...\n" );
4071 addrindex_create_new_books( addrIndex );
4072 if( addrIndex->retVal == MGU_SUCCESS ) {
4074 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4075 addrindex_save_data( addrIndex );
4076 if( addrIndex->retVal == MGU_SUCCESS ) {
4077 msg = _("Could not convert address book,\n"
4078 "but created empty new address book files." );
4083 msg = _("Could not convert address book,\n"
4084 "could not save new address index file." );
4088 msg = _("Could not convert address book\n"
4089 "and could not create new address book files." );
4094 debug_print( "Error\n%s\n", msg );
4095 alertpanel_full(_("Addressbook conversion error"), msg,
4096 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4097 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4100 debug_print( "Warning\n%s\n", msg );
4101 alertpanel_full(_("Addressbook conversion error"), msg,
4102 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4103 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4109 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4113 gboolean failed = FALSE;
4115 if( ( dp = opendir( origdir ) ) == NULL ) {
4119 while( ( d = readdir( dp ) ) != NULL ) {
4120 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4123 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4125 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4127 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4140 /* all copies succeeded, we can remove source files */
4141 if( ( dp = opendir( origdir ) ) == NULL ) {
4144 while( ( d = readdir( dp ) ) != NULL ) {
4145 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4148 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4150 claws_unlink(orig_file);
4160 void addressbook_read_file( void ) {
4161 AddressIndex *addrIndex = NULL;
4162 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4164 debug_print( "Reading address index...\n" );
4165 if( _addressIndex_ ) {
4166 debug_print( "address book already read!!!\n" );
4170 addrIndex = addrindex_create_index();
4171 addrindex_initialize();
4173 /* Use new address book index. */
4175 if ( !is_dir_exist(indexdir) ) {
4176 if ( make_dir(indexdir) < 0 ) {
4177 addrindex_set_file_path( addrIndex, get_rc_dir() );
4178 g_warning( "couldn't create dir %s\n", indexdir);
4180 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4181 remove_dir_recursive(indexdir);
4182 addrindex_set_file_path( addrIndex, get_rc_dir() );
4183 g_error("couldn't migrate dir %s", indexdir);
4185 addrindex_set_file_path( addrIndex, indexdir);
4189 addrindex_set_file_path( addrIndex, indexdir);
4192 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4193 addrindex_read_data( addrIndex );
4194 if( addrIndex->retVal == MGU_NO_FILE ) {
4195 /* Conversion required */
4196 debug_print( "Converting...\n" );
4197 if( addressbook_convert( addrIndex ) ) {
4198 _addressIndex_ = addrIndex;
4201 else if( addrIndex->retVal == MGU_SUCCESS ) {
4202 _addressIndex_ = addrIndex;
4205 /* Error reading address book */
4206 debug_print( "Could not read address index.\n" );
4207 addrindex_print_index( addrIndex, stdout );
4208 alertpanel_full(_("Addressbook Error"),
4209 _("Could not read address index"),
4210 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4211 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4213 debug_print( "done.\n" );
4217 * Add object into the address index tree widget.
4218 * Enter: node Parent node.
4219 * obj Object to add.
4220 * Return: Node that was added, or NULL if object not added.
4222 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4225 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4226 GtkCMCTreeNode *added;
4227 AddressObject *pobj;
4228 AddressObjectType otype;
4229 AddressTypeControlItem *atci = NULL;
4231 g_return_val_if_fail(node != NULL, NULL);
4232 g_return_val_if_fail(obj != NULL, NULL);
4234 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4235 g_return_val_if_fail(pobj != NULL, NULL);
4237 /* Determine object type to be displayed */
4238 if( obj->type == ADDR_DATASOURCE ) {
4239 otype = ADAPTER_DSOURCE(obj)->subType;
4245 /* Handle any special conditions. */
4247 atci = addrbookctl_lookup( otype );
4249 if( atci->showInTree ) {
4250 /* Add object to tree */
4253 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4254 atci->iconXpm, atci->iconXpmOpen,
4255 atci->treeLeaf, atci->treeExpand );
4256 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4257 addressbook_free_treenode );
4261 gtk_sctree_sort_node(ctree, node);
4267 * Add group into the address index tree.
4268 * \param node Parent node.
4269 * \param ds Data source.
4270 * \param itemGroup Group to add.
4271 * \return Inserted node.
4273 static GtkCMCTreeNode *addressbook_node_add_group(
4274 GtkCMCTreeNode *node, AddressDataSource *ds,
4275 ItemGroup *itemGroup )
4277 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4278 GtkCMCTreeNode *newNode;
4279 AdapterGroup *adapter;
4280 AddressTypeControlItem *atci = NULL;
4283 if( ds == NULL ) return NULL;
4284 if( node == NULL || itemGroup == NULL ) return NULL;
4286 name = &itemGroup->obj.name;
4288 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4290 adapter = g_new0( AdapterGroup, 1 );
4291 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4292 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4293 adapter->itemGroup = itemGroup;
4295 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4296 atci->iconXpm, atci->iconXpm,
4297 atci->treeLeaf, atci->treeExpand );
4298 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4299 addressbook_free_treenode );
4300 gtk_sctree_sort_node( ctree, node );
4305 * Add folder into the address index tree. Only visible folders are loaded into
4306 * the address index tree. Note that the root folder is not inserted into the
4309 * \param node Parent node.
4310 * \param ds Data source.
4311 * \param itemFolder Folder to add.
4312 * \param otype Object type to display.
4313 * \return Inserted node for the folder.
4315 static GtkCMCTreeNode *addressbook_node_add_folder(
4316 GtkCMCTreeNode *node, AddressDataSource *ds,
4317 ItemFolder *itemFolder, AddressObjectType otype )
4319 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4320 GtkCMCTreeNode *newNode = NULL;
4321 AdapterFolder *adapter;
4322 AddressTypeControlItem *atci = NULL;
4323 GList *listItems = NULL;
4325 ItemFolder *rootFolder;
4327 /* Only visible folders */
4328 if( itemFolder == NULL || itemFolder->isHidden )
4333 if( node == NULL || itemFolder == NULL )
4336 /* Determine object type */
4337 atci = addrbookctl_lookup( otype );
4341 rootFolder = addrindex_ds_get_root_folder( ds );
4342 if( itemFolder == rootFolder ) {
4346 adapter = g_new0( AdapterFolder, 1 );
4347 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4348 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4349 adapter->itemFolder = itemFolder;
4351 name = ADDRITEM_NAME(itemFolder);
4352 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4353 atci->iconXpm, atci->iconXpm,
4354 atci->treeLeaf, atci->treeExpand );
4356 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4357 addressbook_free_treenode );
4361 listItems = itemFolder->listFolder;
4362 while( listItems ) {
4363 ItemFolder *item = listItems->data;
4364 addressbook_node_add_folder( newNode, ds, item, otype );
4365 listItems = g_list_next( listItems );
4367 listItems = itemFolder->listGroup;
4368 while( listItems ) {
4369 ItemGroup *item = listItems->data;
4370 addressbook_node_add_group( newNode, ds, item );
4371 listItems = g_list_next( listItems );
4373 gtk_sctree_sort_node( ctree, node );
4377 void addressbook_export_to_file( void ) {
4378 if( _addressIndex_ ) {
4379 /* Save all new address book data */
4380 debug_print( "Saving address books...\n" );
4381 addrindex_save_all_books( _addressIndex_ );
4383 debug_print( "Exporting addressbook to file...\n" );
4384 addrindex_save_data( _addressIndex_ );
4385 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4386 addrindex_print_index( _addressIndex_, stdout );
4389 /* Notify address completion of new data */
4390 invalidate_address_completion();
4394 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4396 if (event && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
4397 addressbook_lup_clicked(NULL, NULL);
4402 * Comparison using cell contents (text in first column). Used for sort
4403 * address index widget.
4405 static gint addressbook_treenode_compare_func(
4406 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4408 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4409 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4410 gchar *name1 = NULL, *name2 = NULL;
4411 if( cell1 ) name1 = cell1->u.text;
4412 if( cell2 ) name2 = cell2->u.text;
4413 if( ! name1 ) return ( name2 != NULL );
4414 if( ! name2 ) return -1;
4415 return g_utf8_collate( name1, name2 );
4418 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4419 AdapterDSource *ads;
4420 AdapterInterface *adapter;
4421 GtkCMCTreeNode *newNode;
4423 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4424 if( adapter == NULL ) return;
4425 ads = addressbook_edit_book( _addressIndex_, NULL );
4427 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4429 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4430 addrbook.treeSelected = newNode;
4435 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4436 AdapterDSource *ads;
4437 AdapterInterface *adapter;
4438 GtkCMCTreeNode *newNode;
4440 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4441 if( adapter == NULL ) return;
4442 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4444 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4446 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4447 addrbook.treeSelected = newNode;
4453 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4454 AdapterDSource *ads;
4455 AdapterInterface *adapter;
4456 AddressInterface *iface;
4457 GtkCMCTreeNode *newNode;
4459 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4460 if( adapter == NULL ) return;
4461 iface = adapter->interface;
4462 if( ! iface->haveLibrary ) return;
4463 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4465 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4467 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4468 addrbook.treeSelected = newNode;
4475 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4476 AdapterDSource *ads;
4477 AdapterInterface *adapter;
4478 AddressInterface *iface;
4479 GtkCMCTreeNode *newNode;
4481 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4482 if( adapter == NULL ) return;
4483 iface = adapter->interface;
4484 if( ! iface->haveLibrary ) return;
4485 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4487 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4489 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4490 addrbook.treeSelected = newNode;
4497 * Display address search status message.
4498 * \param queryType Query type.
4499 * \param status Status/Error code.
4501 static void addressbook_search_message( gint queryType, gint sts ) {
4503 *addressbook_msgbuf = '\0';
4505 if( sts != MGU_SUCCESS ) {
4506 if( queryType == ADDRQUERY_LDAP ) {
4508 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4513 g_snprintf( addressbook_msgbuf,
4514 sizeof(addressbook_msgbuf), "%s", desc );
4515 addressbook_status_show( addressbook_msgbuf );
4518 addressbook_status_show( "" );
4523 * Refresh addressbook by forcing refresh of current selected object in
4526 static void addressbook_refresh_current( void ) {
4530 ctree = GTK_CMCTREE(addrbook.ctree);
4531 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4532 if( obj == NULL ) return;
4533 addressbook_set_clist( obj, TRUE );
4537 * Message that is displayed whilst a query is executing in a background
4540 static gchar *_tempMessage_ = N_( "Busy searching..." );
4543 * Address search idle function. This function is called during UI idle time
4544 * while a search is in progress.
4546 * \param data Idler data.
4548 static void addressbook_search_idle( gpointer data ) {
4552 queryID = GPOINTER_TO_INT( data );
4553 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4558 * Search completion callback function. This removes the query from the idle
4561 * \param sender Sender of query.
4562 * \param queryID Query ID of search request.
4563 * \param status Search status.
4564 * \param data Query data.
4566 static void addressbook_search_callback_end(
4567 gpointer sender, gint queryID, gint status, gpointer data )
4571 AddrQueryObject *aqo;
4573 /* Remove idler function */
4574 ptrQID = GINT_TO_POINTER( queryID );
4576 g_idle_remove_by_data( ptrQID );
4579 /* Refresh addressbook contents */
4580 addressbook_refresh_current();
4581 req = qrymgr_find_request( queryID );
4583 aqo = ( AddrQueryObject * ) req->queryList->data;
4584 addressbook_search_message( aqo->queryType, status );
4587 /* Stop the search */
4588 addrindex_stop_search( queryID );
4594 * \param ds Data source to search.
4595 * \param searchTerm String to lookup.
4596 * \param pNode Parent data source node.
4598 static void addressbook_perform_search(
4599 AddressDataSource *ds, gchar *searchTerm,
4600 GtkCMCTreeNode *pNode )
4602 AddrBookBase *adbase;
4603 AddressCache *cache;
4609 AddressObjectType aoType = ADDR_NONE;
4613 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4615 if( ds && ds->type == ADDR_IF_LDAP ) {
4617 aoType = ADDR_LDAP_QUERY;
4623 /* Get reference to address cache */
4624 adbase = ( AddrBookBase * ) ds->rawDataSource;
4625 cache = adbase->addressCache;
4627 /* Create a folder for the search results */
4628 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4629 folder = addressbook_setup_subf(ds, name, pNode);
4632 /* Setup the search */
4633 queryID = addrindex_setup_explicit_search(
4634 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4635 if( queryID == 0 ) return;
4637 /* Set up idler function */
4638 idleID = g_idle_add(
4639 ( GtkFunction ) addressbook_search_idle,
4640 GINT_TO_POINTER( queryID ) );
4642 /* Start search, sit back and wait for something to happen */
4643 addrindex_start_search( queryID );
4645 addressbook_status_show( _tempMessage_ );
4649 * Lookup button handler. Address search is only performed against
4650 * address interfaces for external queries.
4652 * \param button Lookup button widget.
4653 * \param data Data object.
4655 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4658 AddressDataSource *ds;
4659 AddressInterface *iface;
4661 GtkCMCTreeNode *node, *parentNode;
4663 node = addrbook.treeSelected;
4664 if( ! node ) return;
4665 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4667 ctree = GTK_CMCTREE(addrbook.ctree);
4668 obj = gtk_cmctree_node_get_row_data( ctree, node );
4669 if( obj == NULL ) return;
4671 ds = addressbook_find_datasource( node );
4672 if( ds == NULL ) return;
4674 /* We must have a datasource that is an external interface */
4675 iface = ds->interface;
4676 if( ! iface->haveLibrary ) return;
4677 if( ! iface->externalQuery ) return;
4680 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4681 g_strchomp( searchTerm );
4683 if( obj->type == ADDR_ITEM_FOLDER ) {
4684 parentNode = GTK_CMCTREE_ROW(node)->parent;
4689 addressbook_perform_search( ds, searchTerm, parentNode );
4691 gtk_widget_grab_focus( addrbook.entry );
4693 g_free( searchTerm );
4696 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4697 addressbook_close();
4702 * Browse address entry for highlighted entry.
4704 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4706 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4708 AddressDataSource *ds;
4709 AddressInterface *iface;
4713 if(addrbook.listSelected == NULL)
4716 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4720 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4724 iface = ds->interface;
4725 if(!iface || !iface->haveLibrary )
4729 if (obj->type == ADDR_ITEM_EMAIL) {
4730 email = ( ItemEMail * ) obj;
4734 person = (ItemPerson *) ADDRITEM_PARENT(email);
4736 else if (obj->type == ADDR_ITEM_PERSON) {
4737 person = (ItemPerson *) obj;
4744 if( iface && iface->type == ADDR_IF_LDAP ) {
4745 browseldap_entry(ds, person->externalID);
4750 /* **********************************************************************
4751 * Build lookup tables.
4752 * ***********************************************************************
4756 * Remap object types.
4757 * Enter: abType AddressObjectType (used in tree node).
4758 * Return: ItemObjectType (used in address cache data).
4760 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4761 ItemObjectType ioType;
4764 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4765 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4766 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4767 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4768 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4769 default: ioType = ITEMTYPE_NONE; break;
4774 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4775 atci = addrbookctl_lookup(id); \
4777 atci->iconXpm = icon; \
4778 atci->iconXpmOpen = iconopen; \
4780 g_warning("can't get atci %d\n", id); \
4785 * Build table that controls the rendering of object types.
4787 static void addrbookctl_build_icons( GtkWidget *window ) {
4788 AddressTypeControlItem *atci;
4791 g_object_unref(interfacexpm);
4792 g_object_unref(folderxpm);
4793 g_object_unref(folderopenxpm);
4794 g_object_unref(groupxpm);
4795 g_object_unref(vcardxpm);
4796 g_object_unref(bookxpm);
4797 g_object_unref(addressxpm);
4798 g_object_unref(jpilotxpm);
4799 g_object_unref(categoryxpm);
4800 g_object_unref(ldapxpm);
4801 g_object_unref(addrsearchxpm);
4802 stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacexpm );
4803 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4804 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4805 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4806 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4807 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4808 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4809 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4810 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4811 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4812 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4814 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4815 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4816 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4817 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4818 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4819 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4820 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4821 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4822 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4823 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4824 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4829 * Build table that controls the rendering of object types.
4831 static void addrbookctl_build_map( GtkWidget *window ) {
4832 AddressTypeControlItem *atci;
4834 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4835 _addressBookTypeList_ = NULL;
4838 atci = g_new0( AddressTypeControlItem, 1 );
4839 atci->objectType = ADDR_INTERFACE;
4840 atci->interfaceType = ADDR_IF_NONE;
4841 atci->showInTree = TRUE;
4842 atci->treeExpand = TRUE;
4843 atci->treeLeaf = FALSE;
4844 atci->displayName = _( "Interface" );
4845 atci->menuCommand = NULL;
4846 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4847 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4850 atci = g_new0( AddressTypeControlItem, 1 );
4851 atci->objectType = ADDR_BOOK;
4852 atci->interfaceType = ADDR_IF_BOOK;
4853 atci->showInTree = TRUE;
4854 atci->treeExpand = TRUE;
4855 atci->treeLeaf = FALSE;
4856 atci->displayName = _( "Address Book" );
4857 atci->menuCommand = "Menu/Book/NewBook";
4858 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4859 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4862 atci = g_new0( AddressTypeControlItem, 1 );
4863 atci->objectType = ADDR_ITEM_PERSON;
4864 atci->interfaceType = ADDR_IF_NONE;
4865 atci->showInTree = FALSE;
4866 atci->treeExpand = FALSE;
4867 atci->treeLeaf = FALSE;
4868 atci->displayName = _( "Person" );
4869 atci->menuCommand = NULL;
4870 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4871 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4874 atci = g_new0( AddressTypeControlItem, 1 );
4875 atci->objectType = ADDR_ITEM_EMAIL;
4876 atci->interfaceType = ADDR_IF_NONE;
4877 atci->showInTree = FALSE;
4878 atci->treeExpand = FALSE;
4879 atci->treeLeaf = TRUE;
4880 atci->displayName = _( "Email Address" );
4881 atci->menuCommand = NULL;
4882 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4883 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4886 atci = g_new0( AddressTypeControlItem, 1 );
4887 atci->objectType = ADDR_ITEM_GROUP;
4888 atci->interfaceType = ADDR_IF_BOOK;
4889 atci->showInTree = TRUE;
4890 atci->treeExpand = FALSE;
4891 atci->treeLeaf = FALSE;
4892 atci->displayName = _( "Group" );
4893 atci->menuCommand = NULL;
4894 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4895 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4898 atci = g_new0( AddressTypeControlItem, 1 );
4899 atci->objectType = ADDR_ITEM_FOLDER;
4900 atci->interfaceType = ADDR_IF_BOOK;
4901 atci->showInTree = TRUE;
4902 atci->treeExpand = FALSE;
4903 atci->treeLeaf = FALSE;
4904 atci->displayName = _( "Folder" );
4905 atci->menuCommand = NULL;
4906 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4907 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4910 atci = g_new0( AddressTypeControlItem, 1 );
4911 atci->objectType = ADDR_VCARD;
4912 atci->interfaceType = ADDR_IF_VCARD;
4913 atci->showInTree = TRUE;
4914 atci->treeExpand = TRUE;
4915 atci->treeLeaf = TRUE;
4916 atci->displayName = _( "vCard" );
4917 atci->menuCommand = "Menu/Book/NewVCard";
4918 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4919 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4922 atci = g_new0( AddressTypeControlItem, 1 );
4923 atci->objectType = ADDR_JPILOT;
4924 atci->interfaceType = ADDR_IF_JPILOT;
4925 atci->showInTree = TRUE;
4926 atci->treeExpand = TRUE;
4927 atci->treeLeaf = FALSE;
4928 atci->displayName = _( "JPilot" );
4929 atci->menuCommand = "Menu/Book/NewJPilot";
4930 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4931 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4934 atci = g_new0( AddressTypeControlItem, 1 );
4935 atci->objectType = ADDR_CATEGORY;
4936 atci->interfaceType = ADDR_IF_JPILOT;
4937 atci->showInTree = TRUE;
4938 atci->treeExpand = TRUE;
4939 atci->treeLeaf = TRUE;
4940 atci->displayName = _( "JPilot" );
4941 atci->menuCommand = NULL;
4942 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4943 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4946 atci = g_new0( AddressTypeControlItem, 1 );
4947 atci->objectType = ADDR_LDAP;
4948 atci->interfaceType = ADDR_IF_LDAP;
4949 atci->showInTree = TRUE;
4950 atci->treeExpand = TRUE;
4951 atci->treeLeaf = FALSE;
4952 atci->displayName = _( "LDAP servers" );
4953 atci->menuCommand = "Menu/Book/NewLDAPServer";
4954 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4955 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4958 atci = g_new0( AddressTypeControlItem, 1 );
4959 atci->objectType = ADDR_LDAP_QUERY;
4960 atci->interfaceType = ADDR_IF_LDAP;
4961 atci->showInTree = TRUE;
4962 atci->treeExpand = FALSE;
4963 atci->treeLeaf = TRUE;
4964 atci->displayName = _( "LDAP Query" );
4965 atci->menuCommand = NULL;
4966 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4967 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4969 addrbookctl_build_icons(window);
4972 void addressbook_reflect_prefs_pixmap_theme(void)
4974 if (addrbook.window)
4975 addrbookctl_build_icons(addrbook.window);
4979 * Search for specified object type.
4981 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4983 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4987 * Search for specified interface type.
4989 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4990 GList *node = _addressBookTypeList_;
4992 AddressTypeControlItem *atci = node->data;
4993 if( atci->interfaceType == ifType ) return atci;
4994 node = g_list_next( node );
4999 static void addrbookctl_free_address( AddressObject *obj ) {
5000 g_free( obj->name );
5001 obj->type = ADDR_NONE;
5005 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
5006 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5007 adapter->interface = NULL;
5008 adapter->interfaceType = ADDR_IF_NONE;
5009 adapter->atci = NULL;
5010 adapter->enabled = FALSE;
5011 adapter->haveLibrary = FALSE;
5012 adapter->treeNode = NULL;
5016 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5017 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5018 adapter->dataSource = NULL;
5019 adapter->subType = ADDR_NONE;
5023 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5024 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5025 adapter->itemFolder = NULL;
5029 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5030 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5031 adapter->itemGroup = NULL;
5036 * Build GUI interface list.
5038 static void addrbookctl_build_iflist( void ) {
5039 AddressTypeControlItem *atci;
5040 AdapterInterface *adapter;
5043 if( _addressIndex_ == NULL ) {
5044 _addressIndex_ = addrindex_create_index();
5045 if( _clipBoard_ == NULL ) {
5046 _clipBoard_ = addrclip_create();
5048 addrclip_set_index( _clipBoard_, _addressIndex_ );
5050 _addressInterfaceList_ = NULL;
5051 list = addrindex_get_interface_list( _addressIndex_ );
5053 AddressInterface *interface = list->data;
5054 atci = addrbookctl_lookup_iface( interface->type );
5056 adapter = g_new0( AdapterInterface, 1 );
5057 adapter->interfaceType = interface->type;
5058 adapter->atci = atci;
5059 adapter->interface = interface;
5060 adapter->treeNode = NULL;
5061 adapter->enabled = TRUE;
5062 adapter->haveLibrary = interface->haveLibrary;
5063 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5064 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5065 _addressInterfaceList_ =
5066 g_list_append( _addressInterfaceList_, adapter );
5068 list = g_list_next( list );
5073 * Find GUI interface type specified interface type.
5074 * \param ifType Interface type.
5075 * \return Interface item, or NULL if not found.
5077 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5078 GList *node = _addressInterfaceList_;
5080 AdapterInterface *adapter = node->data;
5081 if( adapter->interfaceType == ifType ) return adapter;
5082 node = g_list_next( node );
5088 * Build interface list selection.
5090 static void addrbookctl_build_ifselect( void ) {
5091 GList *newList = NULL;
5096 gchar *endptr = NULL;
5098 AdapterInterface *adapter;
5100 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5103 splitStr = g_strsplit( selectStr, ",", -1 );
5104 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5106 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5107 ifType = strtol( splitStr[i], &endptr, 10 );
5110 if( strcmp( endptr, "/n" ) == 0 ) {
5114 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5115 adapter = addrbookctl_find_interface( ifType );
5117 newList = g_list_append( newList, adapter );
5124 /* g_print( "i=%d\n", i ); */
5125 g_strfreev( splitStr );
5126 g_free( selectStr );
5128 /* Replace existing list */
5129 mgu_clear_list( _addressIFaceSelection_ );
5130 g_list_free( _addressIFaceSelection_ );
5131 _addressIFaceSelection_ = newList;
5135 /* ***********************************************************************
5136 * Add sender to address book.
5137 * ***********************************************************************
5141 * This function is used by the Add sender to address book function.
5143 gboolean addressbook_add_contact(
5144 const gchar *name, const gchar *address, const gchar *remarks,
5145 GdkPixbuf *picture )
5147 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5148 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5149 debug_print( "addressbook_add_contact - added\n" );
5150 addressbook_refresh();
5155 /* ***********************************************************************
5156 * Book/folder selection.
5157 * ***********************************************************************
5161 * This function is used by the matcher dialog to select a book/folder.
5163 gchar *addressbook_folder_selection( const gchar *folderpath)
5165 AddressBookFile *book = NULL;
5166 ItemFolder *folder = NULL;
5169 g_return_val_if_fail( folderpath != NULL, NULL);
5171 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5173 if ( folder != NULL) {
5175 gchar *oldtmp = NULL;
5176 AddrItemObject *obj = NULL;
5178 /* walk thru folder->parent to build the full folder path */
5179 /* TODO: wwp: optimize this */
5181 tmp = g_strdup(obj->uid);
5182 while ( obj->parent ) {
5184 if ( obj->name != NULL ) {
5185 oldtmp = g_strdup(tmp);
5187 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5191 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5194 path = g_strdup_printf("%s", book->fileName);
5196 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5202 /* ***********************************************************************
5203 * Book/folder checking.
5204 * ***********************************************************************
5207 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5209 FolderInfo *fi = g_new0( FolderInfo, 1 );
5211 fi->folder = folder;
5215 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5216 FolderInfo *fiParent, FolderPathMatch *match )
5222 FolderPathMatch *nextmatch = NULL;
5227 list = parentFolder->listFolder;
5229 folder = list->data;
5230 fName = g_strdup( ADDRITEM_NAME(folder) );
5232 /* match folder name, match pointer will be set to NULL if next recursive call
5233 doesn't need to match subfolder name */
5234 if ( match != NULL &&
5235 match->matched == FALSE ) {
5236 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5237 /* folder name matches, prepare next subfolder match */
5238 debug_print("matched folder name '%s'\n", fName);
5240 if ( match->folder_path[match->index] == NULL ) {
5241 /* we've matched all elements */
5242 match->matched = TRUE;
5243 match->folder = folder;
5244 debug_print("book/folder path matched!\n");
5246 /* keep on matching */
5254 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5255 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5257 list = g_list_next( list );
5262 * This function is used by to check if a matcher book/folder path corresponds to an
5263 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5264 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5265 if book AND folder are NULL this means that folderpath was empty or Any.
5266 If folderpath is a simple book name (without folder), book will not be NULL and folder
5267 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5270 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5271 AddressDataSource **book,
5272 ItemFolder **folder )
5274 AddressDataSource *ds;
5275 GList *list, *nodeDS;
5276 ItemFolder *rootFolder;
5277 AddressBookFile *abf;
5279 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5286 if ( folderpath == NULL )
5289 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5292 /* split the folder path we've received, we'll try to match this path, subpath by
5293 subpath against the book/folder structure in order */
5294 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5295 if (!folder_path_match.folder_path)
5298 list = addrindex_get_interface_list( _addressIndex_ );
5299 while ( list && !folder_path_match.matched ) {
5300 AddressInterface *interface = list->data;
5301 if ( interface && interface->type == ADDR_IF_BOOK ) {
5302 nodeDS = interface->listSource;
5303 while ( nodeDS && !folder_path_match.matched ) {
5306 /* Read address book */
5307 if( ! addrindex_ds_get_read_flag( ds ) ) {
5308 addrindex_ds_read_data( ds );
5311 /* Add node for address book */
5312 abf = ds->rawDataSource;
5314 /* match book name */
5315 if ( abf && abf->fileName &&
5316 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5318 debug_print("matched book name '%s'\n", abf->fileName);
5319 folder_path_match.book = ds;
5321 if ( folder_path_match.folder_path[1] == NULL ) {
5322 /* no folder part to match */
5324 folder_path_match.matched = TRUE;
5325 folder_path_match.folder = NULL;
5326 debug_print("book path matched!\n");
5329 /* match folder part */
5331 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5332 rootFolder = addrindex_ds_get_root_folder( ds );
5334 /* prepare for recursive call */
5335 folder_path_match.index = 1;
5336 /* this call will set folder_path_match.matched and folder_path_match.folder */
5337 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5342 nodeDS = g_list_next( nodeDS );
5345 list = g_list_next( list );
5348 g_strfreev( folder_path_match.folder_path );
5351 *book = folder_path_match.book;
5353 *folder = folder_path_match.folder;
5354 return folder_path_match.matched;
5358 /* **********************************************************************
5360 * ***********************************************************************
5366 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5367 AddressDataSource *ds = NULL;
5368 AdapterDSource *ads = NULL;
5369 AddressBookFile *abf = NULL;
5370 AdapterInterface *adapter;
5371 GtkCMCTreeNode *newNode;
5373 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5375 if( adapter->treeNode ) {
5376 abf = addressbook_imp_ldif( _addressIndex_ );
5378 ds = addrindex_index_add_datasource(
5379 _addressIndex_, ADDR_IF_BOOK, abf );
5380 ads = addressbook_create_ds_adapter(
5381 ds, ADDR_BOOK, NULL );
5382 addressbook_ads_set_name(
5383 ads, addrbook_get_name( abf ) );
5384 newNode = addressbook_add_object(
5386 ADDRESS_OBJECT(ads) );
5388 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5390 addrbook.treeSelected = newNode;
5393 /* Notify address completion */
5394 invalidate_address_completion();
5403 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5404 AddressDataSource *ds = NULL;
5405 AdapterDSource *ads = NULL;
5406 AddressBookFile *abf = NULL;
5407 AdapterInterface *adapter;
5408 GtkCMCTreeNode *newNode;
5410 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5412 if( adapter->treeNode ) {
5413 abf = addressbook_imp_mutt( _addressIndex_ );
5415 ds = addrindex_index_add_datasource(
5416 _addressIndex_, ADDR_IF_BOOK, abf );
5417 ads = addressbook_create_ds_adapter(
5418 ds, ADDR_BOOK, NULL );
5419 addressbook_ads_set_name(
5420 ads, addrbook_get_name( abf ) );
5421 newNode = addressbook_add_object(
5423 ADDRESS_OBJECT(ads) );
5425 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5427 addrbook.treeSelected = newNode;
5430 /* Notify address completion */
5431 invalidate_address_completion();
5440 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5441 AddressDataSource *ds = NULL;
5442 AdapterDSource *ads = NULL;
5443 AddressBookFile *abf = NULL;
5444 AdapterInterface *adapter;
5445 GtkCMCTreeNode *newNode;
5447 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5449 if( adapter->treeNode ) {
5450 abf = addressbook_imp_pine( _addressIndex_ );
5452 ds = addrindex_index_add_datasource(
5453 _addressIndex_, ADDR_IF_BOOK, abf );
5454 ads = addressbook_create_ds_adapter(
5455 ds, ADDR_BOOK, NULL );
5456 addressbook_ads_set_name(
5457 ads, addrbook_get_name( abf ) );
5458 newNode = addressbook_add_object(
5460 ADDRESS_OBJECT(ads) );
5462 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5464 addrbook.treeSelected = newNode;
5467 /* Notify address completion */
5468 invalidate_address_completion();
5475 * Harvest addresses.
5476 * \param folderItem Folder to import.
5477 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5478 * \param msgList List of message numbers, or NULL to process folder.
5480 void addressbook_harvest(
5481 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5483 AddressDataSource *ds = NULL;
5484 AdapterDSource *ads = NULL;
5485 AddressBookFile *abf = NULL;
5486 AdapterInterface *adapter;
5487 GtkCMCTreeNode *newNode;
5489 abf = addrgather_dlg_execute(
5490 folderItem, _addressIndex_, sourceInd, msgList );
5492 ds = addrindex_index_add_datasource(
5493 _addressIndex_, ADDR_IF_BOOK, abf );
5495 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5497 if( adapter->treeNode ) {
5498 ads = addressbook_create_ds_adapter(
5499 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5500 newNode = addressbook_add_object(
5502 ADDRESS_OBJECT(ads) );
5506 /* Notify address completion */
5507 invalidate_address_completion();
5514 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5515 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5517 AddressDataSource *ds = NULL;
5518 AddrBookBase *adbase;
5519 AddressCache *cache;
5520 GtkCMCTreeNode *node = NULL;
5522 if( ! addrbook.treeSelected ) return;
5523 node = addrbook.treeSelected;
5524 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5525 obj = gtk_cmctree_node_get_row_data( ctree, node );
5526 if( obj == NULL ) return;
5528 ds = addressbook_find_datasource( node );
5529 if( ds == NULL ) return;
5530 adbase = ( AddrBookBase * ) ds->rawDataSource;
5531 cache = adbase->addressCache;
5532 addressbook_exp_html( cache );
5538 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5539 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5541 AddressDataSource *ds = NULL;
5542 AddrBookBase *adbase;
5543 AddressCache *cache;
5544 GtkCMCTreeNode *node = NULL;
5546 if( ! addrbook.treeSelected ) return;
5547 node = addrbook.treeSelected;
5548 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5549 obj = gtk_cmctree_node_get_row_data( ctree, node );
5550 if( obj == NULL ) return;
5552 ds = addressbook_find_datasource( node );
5553 if( ds == NULL ) return;
5554 adbase = ( AddrBookBase * ) ds->rawDataSource;
5555 cache = adbase->addressCache;
5556 addressbook_exp_ldif( cache );
5559 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5561 addrduplicates_find(GTK_WINDOW(addrbook.window));
5564 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5566 addressbook_custom_attr_edit();
5569 static void addressbook_start_drag(GtkWidget *widget, gint button,
5573 GdkDragContext *context;
5574 if (addressbook_target_list == NULL)
5575 addressbook_target_list = gtk_target_list_new(
5576 addressbook_drag_types, 1);
5577 context = gtk_drag_begin(widget, addressbook_target_list,
5578 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5579 gtk_drag_set_icon_default(context);
5582 static void addressbook_drag_data_get(GtkWidget *widget,
5583 GdkDragContext *drag_context,
5584 GtkSelectionData *selection_data,
5589 AddrItemObject *aio = NULL;
5590 AddressObject *pobj = NULL;
5591 AdapterDSource *ads = NULL;
5592 AddressDataSource *ds = NULL;
5595 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5597 if( pobj == NULL ) return;
5599 if( pobj->type == ADDR_DATASOURCE ) {
5600 ads = ADAPTER_DSOURCE(pobj);
5601 ds = ads->dataSource;
5602 } else if (pobj->type == ADDR_ITEM_GROUP) {
5607 else if( pobj->type != ADDR_INTERFACE ) {
5608 ds = addressbook_find_datasource( addrbook.treeSelected );
5614 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5615 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5616 GTK_CMCTREE_NODE(cur->data));
5617 while (aio && aio->type != ADDR_ITEM_PERSON) {
5622 if (aio && aio->type == ADDR_ITEM_PERSON) {
5623 if( ds && ds->interface && ds->interface->readOnly)
5624 gtk_selection_data_set(selection_data,
5625 selection_data->target, 8,
5626 (const guchar *)"Dummy_addr_copy", 15);
5628 gtk_selection_data_set(selection_data,
5629 selection_data->target, 8,
5630 (const guchar *)"Dummy_addr_move", 15);
5634 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5635 GdkDragContext *context,
5642 GtkCMCTreeNode *node = NULL;
5643 gboolean acceptable = FALSE;
5644 gint height = addrbook.ctree->allocation.height;
5645 gint total_height = addrbook.ctree->requisition.height;
5646 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5647 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5648 gfloat vpos = pos->value;
5650 if (gtk_cmclist_get_selection_info
5651 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5653 if (y > height - 24 && height + vpos < total_height) {
5654 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5655 gtk_adjustment_changed(pos);
5657 if (y < 24 && y > 0) {
5658 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5659 gtk_adjustment_changed(pos);
5661 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5664 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5665 if( obj->type == ADDR_ITEM_FOLDER
5666 || obj->type == ADDR_ITEM_GROUP)
5669 AdapterDSource *ads = NULL;
5670 AddressDataSource *ds = NULL;
5671 ads = ADAPTER_DSOURCE(obj);
5672 if (ads == NULL ){ return FALSE;}
5673 ds = ads->dataSource;
5674 if (ds == NULL ) { return FALSE;}
5682 g_signal_handlers_block_by_func
5684 G_CALLBACK(addressbook_tree_selected), NULL);
5685 gtk_sctree_select( GTK_SCTREE(widget), node);
5686 g_signal_handlers_unblock_by_func
5688 G_CALLBACK(addressbook_tree_selected), NULL);
5689 gdk_drag_status(context,
5690 (context->actions == GDK_ACTION_COPY ?
5691 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5693 gdk_drag_status(context, 0, time);
5698 static void addressbook_drag_leave_cb(GtkWidget *widget,
5699 GdkDragContext *context,
5703 if (addrbook.treeSelected) {
5704 g_signal_handlers_block_by_func
5706 G_CALLBACK(addressbook_tree_selected), NULL);
5707 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5708 g_signal_handlers_unblock_by_func
5710 G_CALLBACK(addressbook_tree_selected), NULL);
5715 static void addressbook_drag_received_cb(GtkWidget *widget,
5716 GdkDragContext *drag_context,
5719 GtkSelectionData *data,
5725 GtkCMCTreeNode *node;
5726 GtkCMCTreeNode *lastopened = addrbook.opened;
5728 if (!strncmp(data->data, "Dummy_addr", 10)) {
5729 if (gtk_cmclist_get_selection_info
5730 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5734 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5735 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5738 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5739 if (drag_context->action == GDK_ACTION_COPY ||
5740 !strcmp(data->data, "Dummy_addr_copy"))
5741 addressbook_clip_copy_cb(NULL, NULL);
5743 addressbook_clip_cut_cb(NULL, NULL);
5744 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5745 addressbook_clip_paste_cb(NULL,NULL);
5746 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5747 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5748 gtk_drag_finish(drag_context, TRUE, TRUE, time);