2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2011 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"
101 } AddressIndexColumns;
109 } AddressListColumns;
112 AddressBookFile *book;
120 AddressDataSource *book;
124 static gchar *list_titles[] = { N_("Name"),
128 #define COL_NAME_WIDTH 164
129 #define COL_ADDRESS_WIDTH 156
131 #define COL_FOLDER_WIDTH 170
132 #define ADDRESSBOOK_WIDTH 640
133 #define ADDRESSBOOK_HEIGHT 360
135 #define ADDRESSBOOK_MSGBUF_SIZE 2048
137 static GdkPixbuf *folderxpm = NULL;
138 static GdkPixbuf *folderopenxpm = NULL;
139 static GdkPixbuf *groupxpm = NULL;
140 static GdkPixbuf *interfacexpm = NULL;
141 static GdkPixbuf *bookxpm = NULL;
142 static GdkPixbuf *addressxpm = NULL;
143 static GdkPixbuf *vcardxpm = NULL;
144 static GdkPixbuf *jpilotxpm = NULL;
145 static GdkPixbuf *categoryxpm = NULL;
146 static GdkPixbuf *ldapxpm = NULL;
147 static GdkPixbuf *addrsearchxpm = NULL;
150 static gchar addressbook_msgbuf[ ADDRESSBOOK_MSGBUF_SIZE ];
152 /* Address list selection */
153 static AddrSelectList *_addressSelect_ = NULL;
154 static AddressClipboard *_clipBoard_ = NULL;
156 /* Address index file and interfaces */
157 static AddressIndex *_addressIndex_ = NULL;
158 static GList *_addressInterfaceList_ = NULL;
159 static GList *_addressIFaceSelection_ = NULL;
160 #define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n"
162 static AddressBook_win addrbook;
164 static GHashTable *_addressBookTypeHash_ = NULL;
165 static GList *_addressBookTypeList_ = NULL;
167 static void addressbook_new_address_from_book_post_cb( ItemPerson *person );
168 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person );
169 static void addressbook_edit_address_post_cb( ItemPerson *person );
171 static void addressbook_create (void);
172 static gint addressbook_close (void);
174 static gboolean address_index_has_focus = FALSE;
175 static gboolean address_list_has_focus = FALSE;
177 /* callback functions */
178 static void addressbook_del_clicked (GtkButton *button,
180 static void addressbook_reg_clicked (GtkButton *button,
182 static void addressbook_to_clicked (GtkButton *button,
184 static void addressbook_lup_clicked (GtkButton *button,
186 static void addressbook_close_clicked (GtkButton *button,
189 static void addressbook_tree_selected (GtkCMCTree *ctree,
190 GtkCMCTreeNode *node,
193 static void addressbook_select_row_tree (GtkCMCTree *ctree,
194 GtkCMCTreeNode *node,
197 static void addressbook_list_row_selected (GtkCMCTree *clist,
198 GtkCMCTreeNode *node,
201 static void addressbook_list_row_unselected (GtkCMCTree *clist,
202 GtkCMCTreeNode *node,
205 static void addressbook_person_expand_node (GtkCMCTree *ctree,
208 static void addressbook_person_collapse_node (GtkCMCTree *ctree,
212 static gboolean addressbook_list_button_pressed (GtkWidget *widget,
213 GdkEventButton *event,
215 static gboolean addressbook_list_button_released(GtkWidget *widget,
216 GdkEventButton *event,
218 static gboolean addressbook_tree_button_pressed (GtkWidget *ctree,
219 GdkEventButton *event,
221 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
222 GdkEventButton *event,
225 static void addressbook_new_folder_cb (GtkAction *action,
227 static void addressbook_new_group_cb (GtkAction *action,
229 static void addressbook_treenode_edit_cb (GtkAction *action,
231 static void addressbook_treenode_delete_cb (GtkAction *action,
234 static void addressbook_change_node_name (GtkCMCTreeNode *node,
237 static void addressbook_new_address_cb (GtkAction *action,
239 static void addressbook_edit_address_cb (GtkAction *action,
241 static void addressbook_delete_address_cb (GtkAction *action,
244 static void close_cb (GtkAction *action,
246 static void addressbook_file_save_cb (GtkAction *action,
249 /* Data source edit stuff */
250 static void addressbook_new_book_cb (GtkAction *action,
252 static void addressbook_new_vcard_cb (GtkAction *action,
256 static void addressbook_new_jpilot_cb (GtkAction *action,
261 static void addressbook_new_ldap_cb (GtkAction *action,
265 static void addressbook_set_clist (AddressObject *obj,
268 static void addressbook_load_tree (void);
269 void addressbook_read_file (void);
271 static GtkCMCTreeNode *addressbook_add_object (GtkCMCTreeNode *node,
273 static void addressbook_treenode_remove_item ( void );
275 static AddressDataSource *addressbook_find_datasource
276 (GtkCMCTreeNode *node );
278 static AddressBookFile *addressbook_get_book_file(void);
280 static GtkCMCTreeNode *addressbook_node_add_folder
281 (GtkCMCTreeNode *node,
282 AddressDataSource *ds,
283 ItemFolder *itemFolder,
284 AddressObjectType otype);
285 static GtkCMCTreeNode *addressbook_node_add_group (GtkCMCTreeNode *node,
286 AddressDataSource *ds,
287 ItemGroup *itemGroup);
288 static void addressbook_tree_remove_children (GtkCMCTree *ctree,
289 GtkCMCTreeNode *parent);
290 static void addressbook_move_nodes_up (GtkCMCTree *ctree,
291 GtkCMCTreeNode *node);
292 static GtkCMCTreeNode *addressbook_find_group_node (GtkCMCTreeNode *parent,
294 static gboolean addressbook_entry_key_pressed (GtkWidget *widget,
297 static gint addressbook_treenode_compare_func (GtkCMCList *clist,
300 static void addressbook_folder_load_one_person (GtkCMCTree *clist,
302 AddressTypeControlItem *atci,
303 AddressTypeControlItem *atciMail);
304 static void addressbook_folder_refresh_one_person(GtkCMCTree *clist,
306 static void addressbook_folder_remove_one_person(GtkCMCTree *clist,
308 static void addressbook_folder_remove_node (GtkCMCTree *clist,
309 GtkCMCTreeNode *node);
311 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
312 gboolean force_focus );
314 /* LUT's and IF stuff */
315 static void addressbook_free_treenode ( gpointer data );
316 static AddressTypeControlItem *addrbookctl_lookup (gint ot);
317 static AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType);
319 static void addrbookctl_build_map (GtkWidget *window);
320 static void addrbookctl_build_iflist (void);
321 static AdapterInterface *addrbookctl_find_interface (AddressIfType ifType);
322 static void addrbookctl_build_ifselect (void);
324 static void addrbookctl_free_interface (AdapterInterface *adapter);
325 static void addrbookctl_free_datasource (AdapterDSource *adapter);
326 static void addrbookctl_free_folder (AdapterFolder *adapter);
327 static void addrbookctl_free_group (AdapterGroup *adapter);
329 static void addressbook_list_select_clear ( void );
330 static void addressbook_list_select_add ( AddrItemObject *aio,
331 AddressDataSource *ds );
332 static void addressbook_list_select_remove ( AddrItemObject *aio );
334 static void addressbook_import_ldif_cb ( GtkAction *action, gpointer data );
335 static void addressbook_find_duplicates_cb ( GtkAction *action, gpointer data );
336 static void addressbook_edit_custom_attr_cb ( GtkAction *action, gpointer data );
337 static void addressbook_import_mutt_cb ( GtkAction *action, gpointer data );
338 static void addressbook_import_pine_cb ( GtkAction *action, gpointer data );
339 static void addressbook_export_html_cb ( GtkAction *action, gpointer data );
340 static void addressbook_export_ldif_cb ( GtkAction *action, gpointer data );
341 static void addressbook_select_all_cb ( GtkAction *action, gpointer data );
342 static void addressbook_clip_cut_cb ( GtkAction *action, gpointer data );
343 static void addressbook_clip_copy_cb ( GtkAction *action, gpointer data );
344 static void addressbook_clip_paste_cb ( GtkAction *action, gpointer data );
345 static void addressbook_treenode_cut_cb ( GtkAction *action, gpointer data );
346 static void addressbook_treenode_copy_cb ( GtkAction *action, gpointer data );
347 static void addressbook_treenode_paste_cb ( GtkAction *action, gpointer data );
349 static void addressbook_mail_to_cb ( GtkAction *action, gpointer data );
352 static void addressbook_browse_entry_cb ( GtkAction *action, gpointer data );
354 static void addressbook_edit_clicked(GtkButton *button, gpointer data);
356 static void addressbook_start_drag(GtkWidget *widget, gint button,
359 static void addressbook_drag_data_get(GtkWidget *widget,
360 GdkDragContext *drag_context,
361 GtkSelectionData *selection_data,
365 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
366 GdkDragContext *context,
371 static void addressbook_drag_leave_cb(GtkWidget *widget,
372 GdkDragContext *context,
375 static void addressbook_drag_received_cb(GtkWidget *widget,
376 GdkDragContext *drag_context,
379 GtkSelectionData *data,
383 static void addressbook_list_menu_setup( void );
385 static GtkTargetEntry addressbook_drag_types[] =
387 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY}
390 static GtkTargetList *addressbook_target_list = NULL;
392 static void about_show_cb(GtkAction *action, gpointer data)
397 static GtkActionEntry addressbook_entries[] =
399 {"Menu", NULL, "Menu" },
401 {"Book", NULL, N_("_Book") },
402 {"Address", NULL, N_("_Edit") },
403 {"Tools", NULL, N_("_Tools") },
404 {"Help", NULL, N_("_Help") },
407 {"Book/NewBook", NULL, N_("New _Book"), "<control>B", NULL, G_CALLBACK(addressbook_new_book_cb) },
408 {"Book/NewFolder", NULL, N_("New _Folder"), "<control>R", NULL, G_CALLBACK(addressbook_new_folder_cb) },
409 {"Book/NewVCard", NULL, N_("New _vCard"), "<control><shift>D", NULL, G_CALLBACK(addressbook_new_vcard_cb) },
413 {"Book/NewJPilot", NULL, N_("New _JPilot"), "<control>J", NULL, G_CALLBACK(addressbook_new_jpilot_cb) },
416 {"Book/NewLDAPServer", NULL, N_("New LDAP _Server"), "<control><shift>S", NULL, G_CALLBACK(addressbook_new_ldap_cb) },
418 {"Book/---", NULL, "---", NULL, NULL, NULL },
420 {"Book/EditBook", NULL, N_("_Edit book"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
421 {"Book/DeleteBook", NULL, N_("_Delete book"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
422 /* {"Book/---", NULL, "---", NULL, NULL, NULL }, */
423 {"Book/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(addressbook_file_save_cb) },
424 {"Book/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
427 {"Address/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(addressbook_select_all_cb) },
428 {"Address/---", NULL, "---", NULL, NULL, NULL },
429 {"Address/Cut", NULL, N_("C_ut"), "<control>X", NULL, G_CALLBACK(addressbook_clip_cut_cb) },
430 {"Address/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(addressbook_clip_copy_cb) },
431 {"Address/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(addressbook_clip_paste_cb) },
432 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
433 {"Address/Edit", NULL, N_("_Edit"), "<control>Return", NULL, G_CALLBACK(addressbook_edit_address_cb) },
434 {"Address/Delete", NULL, N_("_Delete"), "<control>D", NULL, G_CALLBACK(addressbook_delete_address_cb) },
435 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
436 {"Address/NewAddress", NULL, N_("New _Address"), "<control>N", NULL, G_CALLBACK(addressbook_new_address_cb) },
437 {"Address/NewGroup", NULL, N_("New _Group"), "<control>G", NULL, G_CALLBACK(addressbook_new_group_cb) },
438 /* {"Address/---", NULL, "---", NULL, NULL, NULL }, */
439 {"Address/Mailto", NULL, N_("_Mail To"), "<control>M", NULL, G_CALLBACK(addressbook_mail_to_cb) },
443 {"Tools/ImportLDIF", NULL, N_("Import _LDIF file..."), NULL, NULL, G_CALLBACK(addressbook_import_ldif_cb) },
444 {"Tools/ImportMutt", NULL, N_("Import M_utt file..."), NULL, NULL, G_CALLBACK(addressbook_import_mutt_cb) },
445 {"Tools/ImportPine", NULL, N_("Import _Pine file..."), NULL, NULL, G_CALLBACK(addressbook_import_pine_cb) },
446 {"Tools/---", NULL, "---", NULL, NULL, NULL },
447 {"Tools/ExportHTML", NULL, N_("Export _HTML..."), NULL, NULL, G_CALLBACK(addressbook_export_html_cb) },
448 {"Tools/ExportLDIF", NULL, N_("Export LDI_F..."), NULL, NULL, G_CALLBACK(addressbook_export_ldif_cb) },
449 /* {"Tools/---", NULL, "---", NULL, NULL, NULL },*/
450 {"Tools/FindDuplicates", NULL, N_("Find duplicates..."), NULL, NULL, G_CALLBACK(addressbook_find_duplicates_cb) },
451 {"Tools/EditAttrs", NULL, N_("Edit custom attributes..."), NULL, NULL, G_CALLBACK(addressbook_edit_custom_attr_cb) },
454 {"Help/About", NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_show_cb) },
458 static GtkActionEntry addressbook_tree_popup_entries[] =
460 {"ABTreePopup", NULL, "ABTreePopup" },
461 {"ABTreePopup/EditBook", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_treenode_edit_cb) },
462 {"ABTreePopup/DeleteBook", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_treenode_delete_cb) },
463 {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL },
464 {"ABTreePopup/NewBook", NULL, N_("New _Book"), NULL, NULL, G_CALLBACK(addressbook_new_book_cb) },
465 {"ABTreePopup/NewFolder", NULL, N_("New _Folder"), NULL, NULL, G_CALLBACK(addressbook_new_folder_cb) },
466 {"ABTreePopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
467 /* {"ABTreePopup/---", NULL, "---", NULL, NULL, NULL }, */
468 {"ABTreePopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_treenode_cut_cb) },
469 {"ABTreePopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_treenode_copy_cb) },
470 {"ABTreePopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_treenode_paste_cb) },
473 static GtkActionEntry addressbook_list_popup_entries[] =
475 {"ABListPopup", NULL, "ABListPopup" },
476 {"ABListPopup/SelectAll", NULL, N_("_Select all"), NULL, NULL, G_CALLBACK(addressbook_select_all_cb) },
477 {"ABListPopup/---", NULL, "---", NULL, NULL, NULL },
478 {"ABListPopup/Edit", NULL, N_("_Edit"), NULL, NULL, G_CALLBACK(addressbook_edit_address_cb) },
479 {"ABListPopup/Delete", NULL, N_("_Delete"), NULL, NULL, G_CALLBACK(addressbook_delete_address_cb) },
480 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
481 {"ABListPopup/NewAddress", NULL, N_("New _Address"), NULL, NULL, G_CALLBACK(addressbook_new_address_cb) },
482 {"ABListPopup/NewGroup", NULL, N_("New _Group"), NULL, NULL, G_CALLBACK(addressbook_new_group_cb) },
483 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
484 {"ABListPopup/Cut", NULL, N_("C_ut"), NULL, NULL, G_CALLBACK(addressbook_clip_cut_cb) },
485 {"ABListPopup/Copy", NULL, N_("_Copy"), NULL, NULL, G_CALLBACK(addressbook_clip_copy_cb) },
486 {"ABListPopup/Paste", NULL, N_("_Paste"), NULL, NULL, G_CALLBACK(addressbook_clip_paste_cb) },
487 /* {"ABListPopup/---", NULL, "---", NULL, NULL, NULL }, */
488 {"ABListPopup/Mailto", NULL, N_("_Mail To"), NULL, NULL, G_CALLBACK(addressbook_mail_to_cb) },
490 {"ABListPopup/BrowseEntry", NULL, N_("_Browse Entry"), NULL, NULL, G_CALLBACK(addressbook_browse_entry_cb) },
495 * Structure of error message table.
497 typedef struct _ErrMsgTableEntry ErrMsgTableEntry;
498 struct _ErrMsgTableEntry {
503 static gchar *_errMsgUnknown_ = N_( "Unknown" );
506 * Lookup table of error messages for general errors. Note that a NULL
507 * description signifies the end of the table.
509 static ErrMsgTableEntry _lutErrorsGeneral_[] = {
510 { MGU_SUCCESS, N_("Success") },
511 { MGU_BAD_ARGS, N_("Bad arguments") },
512 { MGU_NO_FILE, N_("File not specified") },
513 { MGU_OPEN_FILE, N_("Error opening file") },
514 { MGU_ERROR_READ, N_("Error reading file") },
515 { MGU_EOF, N_("End of file encountered") },
516 { MGU_OO_MEMORY, N_("Error allocating memory") },
517 { MGU_BAD_FORMAT, N_("Bad file format") },
518 { MGU_ERROR_WRITE, N_("Error writing to file") },
519 { MGU_OPEN_DIRECTORY, N_("Error opening directory") },
520 { MGU_NO_PATH, N_("No path specified") },
526 * Lookup table of error messages for LDAP errors.
528 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
529 { LDAPRC_SUCCESS, N_("Success") },
530 { LDAPRC_CONNECT, N_("Error connecting to LDAP server") },
531 { LDAPRC_INIT, N_("Error initializing LDAP") },
532 { LDAPRC_BIND, N_("Error binding to LDAP server") },
533 { LDAPRC_SEARCH, N_("Error searching LDAP database") },
534 { LDAPRC_TIMEOUT, N_("Timeout performing LDAP operation") },
535 { LDAPRC_CRITERIA, N_("Error in LDAP search criteria") },
536 { LDAPRC_NOENTRIES, N_("No LDAP entries found for search criteria") },
537 { LDAPRC_STOP_FLAG, N_("LDAP search terminated on request") },
538 { LDAPRC_TLS, N_("Error starting TLS connection") },
539 { LDAPRC_NODN, N_("Distinguished Name (dn) is missing") },
540 { LDAPRC_NAMING_VIOLATION, N_("Missing required information") },
541 { LDAPRC_ALREADY_EXIST, N_("Another contact exists with that key") },
542 { LDAPRC_STRONG_AUTH, N_("Strong(er) authentication required") },
548 * Lookup message for specified error code.
549 * \param lut Lookup table.
550 * \param code Code to lookup.
551 * \return Description associated to code.
553 static gchar *addressbook_err2string( ErrMsgTableEntry lut[], gint code ) {
555 ErrMsgTableEntry entry;
558 for( i = 0; ; i++ ) {
560 if( entry.description == NULL ) break;
561 if( entry.code == code ) {
562 desc = entry.description;
567 desc = _errMsgUnknown_;
572 static gboolean lastCanLookup = FALSE;
574 static void addressbook_show_buttons(gboolean add_and_delete, gboolean lookup, gboolean mail_ops)
576 if (add_and_delete) {
577 gtk_widget_show(addrbook.edit_btn);
578 gtk_widget_show(addrbook.del_btn);
579 gtk_widget_show(addrbook.reg_btn);
581 gtk_widget_hide(addrbook.edit_btn);
582 gtk_widget_hide(addrbook.del_btn);
583 gtk_widget_hide(addrbook.reg_btn);
587 gtk_widget_show(addrbook.lup_btn);
588 gtk_widget_show(addrbook.entry);
589 gtk_widget_show(addrbook.label);
591 gtk_widget_hide(addrbook.lup_btn);
592 gtk_widget_hide(addrbook.entry);
593 gtk_widget_hide(addrbook.label);
596 lastCanLookup = lookup;
599 gtk_widget_show(addrbook.to_btn);
600 gtk_widget_show(addrbook.cc_btn);
601 gtk_widget_show(addrbook.bcc_btn);
603 gtk_widget_hide(addrbook.to_btn);
604 gtk_widget_hide(addrbook.cc_btn);
605 gtk_widget_hide(addrbook.bcc_btn);
609 void addressbook_open(Compose *target)
611 /* Initialize all static members */
612 if( _clipBoard_ == NULL ) {
613 _clipBoard_ = addrclip_create();
615 if( _addressIndex_ != NULL ) {
616 addrclip_set_index( _clipBoard_, _addressIndex_ );
618 if( _addressSelect_ == NULL ) {
619 _addressSelect_ = addrselect_list_create();
621 if (!addrbook.window) {
622 addressbook_read_file();
623 addressbook_create();
624 addressbook_load_tree();
625 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
626 GTK_CMCTREE_NODE(GTK_CMCLIST(addrbook.ctree)->row_list));
629 gtk_widget_hide(addrbook.window);
632 gtk_widget_show_all(addrbook.window);
634 maemo_window_full_screen_if_needed(GTK_WINDOW(addrbook.window));
635 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(addrbook.window));
637 if (!prefs_common.addressbook_use_editaddress_dialog)
638 addressbook_edit_person_widgetset_hide();
640 address_completion_start(addrbook.window);
642 addressbook_show_buttons(target == NULL, lastCanLookup, target != NULL);
643 addressbook_set_target_compose(target);
647 * Destroy addressbook.
649 void addressbook_destroy( void ) {
650 /* Free up address stuff */
651 if( _addressSelect_ != NULL ) {
652 addrselect_list_free( _addressSelect_ );
654 if( _clipBoard_ != NULL ) {
655 addrclip_free( _clipBoard_ );
657 if( _addressIndex_ != NULL ) {
658 addrindex_free_index( _addressIndex_ );
659 addrindex_teardown();
661 _addressSelect_ = NULL;
663 _addressIndex_ = NULL;
666 void addressbook_set_target_compose(Compose *target)
668 addrbook.target_compose = target;
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_KEY_Escape)
699 else if (event && event->keyval == GDK_KEY_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 cm_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 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree)->column[0].button, FALSE);
1019 gtk_container_add(GTK_CONTAINER(ctree_swin), ctree);
1020 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
1021 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), 0, COL_FOLDER_WIDTH);
1022 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
1023 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
1024 GTK_CMCTREE_EXPANDER_TRIANGLE);
1025 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1026 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
1027 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree),
1028 addressbook_treenode_compare_func);
1030 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
1031 G_CALLBACK(addressbook_tree_selected), NULL);
1032 g_signal_connect(G_OBJECT(ctree), "button_press_event",
1033 G_CALLBACK(addressbook_tree_button_pressed),
1035 g_signal_connect(G_OBJECT(ctree), "button_release_event",
1036 G_CALLBACK(addressbook_tree_button_released),
1039 g_signal_connect(G_OBJECT(ctree), "select_row",
1040 G_CALLBACK(addressbook_select_row_tree), NULL);
1042 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
1043 addressbook_drag_types, 1,
1044 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
1045 g_signal_connect(G_OBJECT(ctree), "drag_motion",
1046 G_CALLBACK(addressbook_drag_motion_cb),
1048 g_signal_connect(G_OBJECT(ctree), "drag_leave",
1049 G_CALLBACK(addressbook_drag_leave_cb),
1051 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
1052 G_CALLBACK(addressbook_drag_received_cb),
1054 g_signal_connect(G_OBJECT(ctree), "focus_in_event",
1055 G_CALLBACK(addressbook_address_index_focus_evt_in), NULL);
1056 g_signal_connect(G_OBJECT(ctree), "focus_out_event",
1057 G_CALLBACK(addressbook_address_index_focus_evt_out), NULL);
1059 clist_vbox = gtk_vbox_new(FALSE, 4);
1061 clist_swin = gtk_scrolled_window_new(NULL, NULL);
1062 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1063 GTK_POLICY_AUTOMATIC,
1064 GTK_POLICY_AUTOMATIC);
1065 gtk_box_pack_start(GTK_BOX(clist_vbox), clist_swin, TRUE, TRUE, 0);
1068 clist = gtk_sctree_new_with_titles(N_LIST_COLS, 0, list_titles);
1069 gtk_container_add(GTK_CONTAINER(clist_swin), clist);
1070 gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_EXTENDED);
1071 gtk_cmctree_set_line_style(GTK_CMCTREE(clist), GTK_CMCTREE_LINES_NONE);
1072 gtk_cmctree_set_expander_style(GTK_CMCTREE(clist),
1073 GTK_CMCTREE_EXPANDER_TRIANGLE);
1074 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
1075 gtk_cmctree_set_indent(GTK_CMCTREE(clist), CTREE_INDENT);
1076 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_NAME,
1078 gtk_cmclist_set_column_width(GTK_CMCLIST(clist), COL_ADDRESS,
1080 gtk_widget_set_size_request(clist, -1, 80);
1082 addressbook_sort_list(GTK_CMCLIST(clist), COL_NAME, GTK_SORT_ASCENDING);
1083 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button),
1084 "clicked", G_CALLBACK(addressbook_name_clicked), clist);
1085 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_ADDRESS].button),
1086 "clicked", G_CALLBACK(addressbook_address_clicked), clist);
1087 g_signal_connect(G_OBJECT(GTK_CMCLIST(clist)->column[COL_REMARKS].button),
1088 "clicked", G_CALLBACK(addressbook_remarks_clicked), clist);
1089 g_signal_connect(G_OBJECT(clist), "focus_in_event",
1090 G_CALLBACK(addressbook_address_list_focus_evt_in), NULL);
1091 g_signal_connect(G_OBJECT(clist), "focus_out_event",
1092 G_CALLBACK(addressbook_address_list_focus_evt_out), NULL);
1094 for (i = 0; i < N_LIST_COLS; i++)
1095 gtkut_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button,
1098 g_signal_connect(G_OBJECT(clist), "tree_select_row",
1099 G_CALLBACK(addressbook_list_row_selected), NULL);
1100 g_signal_connect(G_OBJECT(clist), "tree_unselect_row",
1101 G_CALLBACK(addressbook_list_row_unselected), NULL);
1102 g_signal_connect(G_OBJECT(clist), "button_press_event",
1103 G_CALLBACK(addressbook_list_button_pressed),
1105 g_signal_connect(G_OBJECT(clist), "button_release_event",
1106 G_CALLBACK(addressbook_list_button_released),
1108 g_signal_connect(G_OBJECT(clist), "tree_expand",
1109 G_CALLBACK(addressbook_person_expand_node), NULL );
1110 g_signal_connect(G_OBJECT(clist), "tree_collapse",
1111 G_CALLBACK(addressbook_person_collapse_node), NULL );
1112 g_signal_connect(G_OBJECT(clist), "start_drag",
1113 G_CALLBACK(addressbook_start_drag), NULL);
1114 g_signal_connect(G_OBJECT(clist), "drag_data_get",
1115 G_CALLBACK(addressbook_drag_data_get), NULL);
1116 hbox = gtk_hbox_new(FALSE, 4);
1117 gtk_box_pack_start(GTK_BOX(clist_vbox), hbox, FALSE, FALSE, 0);
1119 label = gtk_label_new(_("Lookup name:"));
1120 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1122 entry = gtk_entry_new();
1123 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1125 address_completion_register_entry(GTK_ENTRY(entry), FALSE);
1127 g_signal_connect(G_OBJECT(entry), "key_press_event",
1128 G_CALLBACK(addressbook_entry_key_pressed),
1131 if (!prefs_common.addressbook_use_editaddress_dialog) {
1132 editaddress_vbox = gtk_vbox_new(FALSE, 4);
1133 vpaned = gtk_vpaned_new();
1134 gtk_paned_pack1(GTK_PANED(vpaned), clist_vbox, FALSE, FALSE);
1135 gtk_paned_pack2(GTK_PANED(vpaned), editaddress_vbox, TRUE, FALSE);
1138 editaddress_vbox = NULL;
1140 hpaned = gtk_hpaned_new();
1141 gtk_box_pack_start(GTK_BOX(vbox2), hpaned, TRUE, TRUE, 0);
1142 gtk_paned_pack1(GTK_PANED(hpaned), ctree_swin, FALSE, FALSE);
1143 if (prefs_common.addressbook_use_editaddress_dialog)
1144 gtk_paned_pack2(GTK_PANED(hpaned), clist_vbox, TRUE, FALSE);
1146 gtk_paned_pack2(GTK_PANED(hpaned), vpaned, TRUE, FALSE);
1149 hsbox = gtk_hbox_new(FALSE, 0);
1150 gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
1151 statusbar = gtk_statusbar_new();
1152 gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
1155 hbbox = gtk_hbutton_box_new();
1156 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
1157 gtk_box_set_spacing(GTK_BOX(hbbox), 2);
1158 gtk_container_set_border_width(GTK_CONTAINER(hbbox), 4);
1159 gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0);
1161 gtkut_stock_button_add_help(hbbox, &help_btn);
1163 edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
1164 gtkut_widget_set_can_default(edit_btn, TRUE);
1165 gtk_box_pack_start(GTK_BOX(hbbox), edit_btn, TRUE, TRUE, 0);
1166 del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1167 gtkut_widget_set_can_default(del_btn, TRUE);
1168 gtk_box_pack_start(GTK_BOX(hbbox), del_btn, TRUE, TRUE, 0);
1169 reg_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
1170 gtkut_widget_set_can_default(reg_btn, TRUE);
1171 gtk_box_pack_start(GTK_BOX(hbbox), reg_btn, TRUE, TRUE, 0);
1174 lup_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
1175 gtkut_widget_set_can_default(lup_btn, TRUE);
1176 gtk_box_pack_start(GTK_BOX(hbox), lup_btn, TRUE, TRUE, 0);
1178 g_signal_connect(G_OBJECT(help_btn), "clicked",
1179 G_CALLBACK(manual_open_with_anchor_cb),
1180 MANUAL_ANCHOR_ADDRBOOK);
1182 g_signal_connect(G_OBJECT(edit_btn), "clicked",
1183 G_CALLBACK(addressbook_edit_clicked), NULL);
1184 g_signal_connect(G_OBJECT(del_btn), "clicked",
1185 G_CALLBACK(addressbook_del_clicked), NULL);
1186 g_signal_connect(G_OBJECT(reg_btn), "clicked",
1187 G_CALLBACK(addressbook_reg_clicked), NULL);
1188 g_signal_connect(G_OBJECT(lup_btn), "clicked",
1189 G_CALLBACK(addressbook_lup_clicked), NULL);
1191 to_btn = gtk_button_new_with_label
1192 (prefs_common_translated_header_name("To:"));
1193 gtkut_widget_set_can_default(to_btn, TRUE);
1194 gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
1195 cc_btn = gtk_button_new_with_label
1196 (prefs_common_translated_header_name("Cc:"));
1197 gtkut_widget_set_can_default(cc_btn, TRUE);
1198 gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
1199 bcc_btn = gtk_button_new_with_label
1200 (prefs_common_translated_header_name("Bcc:"));
1201 gtkut_widget_set_can_default(bcc_btn, TRUE);
1202 gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
1204 close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1205 gtkut_widget_set_can_default(close_btn, TRUE);
1206 gtk_box_pack_start(GTK_BOX(hbbox), close_btn, TRUE, TRUE, 0);
1208 g_signal_connect(G_OBJECT(to_btn), "clicked",
1209 G_CALLBACK(addressbook_to_clicked),
1210 GINT_TO_POINTER(COMPOSE_TO));
1211 g_signal_connect(G_OBJECT(cc_btn), "clicked",
1212 G_CALLBACK(addressbook_to_clicked),
1213 GINT_TO_POINTER(COMPOSE_CC));
1214 g_signal_connect(G_OBJECT(bcc_btn), "clicked",
1215 G_CALLBACK(addressbook_to_clicked),
1216 GINT_TO_POINTER(COMPOSE_BCC));
1217 g_signal_connect(G_OBJECT(close_btn), "clicked",
1218 G_CALLBACK(addressbook_close_clicked), NULL);
1220 /* Build icons for interface */
1222 /* Build control tables */
1223 addrbookctl_build_map(window);
1224 addrbookctl_build_iflist();
1225 addrbookctl_build_ifselect();
1227 addrbook.clist = NULL;
1229 /* Add each interface into the tree as a root level folder */
1230 nodeIf = _addressInterfaceList_;
1232 AdapterInterface *adapter = nodeIf->data;
1233 AddressInterface *iface = adapter->interface;
1234 nodeIf = g_list_next(nodeIf);
1236 if(iface->useInterface) {
1237 AddressTypeControlItem *atci = adapter->atci;
1238 text = atci->displayName;
1240 gtk_sctree_insert_node( GTK_CMCTREE(ctree),
1241 NULL, NULL, &text, FOLDER_SPACING,
1245 cm_menu_set_sensitive_full(ui_manager, atci->menuCommand, adapter->haveLibrary );
1246 gtk_cmctree_node_set_row_data_full(
1247 GTK_CMCTREE(ctree), adapter->treeNode, adapter,
1248 addressbook_free_treenode );
1254 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popups", NULL, GTK_UI_MANAGER_MENUBAR);
1255 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABTreePopup", "ABTreePopup", GTK_UI_MANAGER_MENU)
1256 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "EditBook", "ABTreePopup/EditBook", GTK_UI_MANAGER_MENUITEM)
1257 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "DeleteBook", "ABTreePopup/DeleteBook", GTK_UI_MANAGER_MENUITEM)
1258 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator1", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1259 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewBook", "ABTreePopup/NewBook", GTK_UI_MANAGER_MENUITEM)
1260 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewFolder", "ABTreePopup/NewFolder", GTK_UI_MANAGER_MENUITEM)
1261 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "NewGroup", "ABTreePopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1262 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Separator2", "ABTreePopup/---", GTK_UI_MANAGER_SEPARATOR)
1263 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Cut", "ABTreePopup/Cut", GTK_UI_MANAGER_MENUITEM)
1264 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Copy", "ABTreePopup/Copy", GTK_UI_MANAGER_MENUITEM)
1265 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABTreePopup", "Paste", "ABTreePopup/Paste", GTK_UI_MANAGER_MENUITEM)
1267 tree_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1268 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABTreePopup")));
1270 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups", "ABListPopup", "ABListPopup", GTK_UI_MANAGER_MENU)
1271 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "SelectAll", "ABListPopup/SelectAll", GTK_UI_MANAGER_MENUITEM)
1272 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator1", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1273 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Edit", "ABListPopup/Edit", GTK_UI_MANAGER_MENUITEM)
1274 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Delete", "ABListPopup/Delete", GTK_UI_MANAGER_MENUITEM)
1275 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator2", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1276 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewAddress", "ABListPopup/NewAddress", GTK_UI_MANAGER_MENUITEM)
1277 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "NewGroup", "ABListPopup/NewGroup", GTK_UI_MANAGER_MENUITEM)
1278 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator3", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1279 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Cut", "ABListPopup/Cut", GTK_UI_MANAGER_MENUITEM)
1280 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Copy", "ABListPopup/Copy", GTK_UI_MANAGER_MENUITEM)
1281 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Paste", "ABListPopup/Paste", GTK_UI_MANAGER_MENUITEM)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Separator4", "ABListPopup/---", GTK_UI_MANAGER_SEPARATOR)
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "Mailto", "ABListPopup/Mailto", GTK_UI_MANAGER_MENUITEM)
1285 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popups/ABListPopup", "BrowseEntry", "ABListPopup/BrowseEntry", GTK_UI_MANAGER_MENUITEM)
1287 list_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1288 gtk_ui_manager_get_widget(ui_manager, "/Popups/ABListPopup")));
1290 addrbook.window = window;
1291 addrbook.hpaned = hpaned;
1292 addrbook.vpaned = vpaned;
1293 addrbook.menubar = menubar;
1294 addrbook.ctree = ctree;
1297 addrbook.editaddress_vbox = editaddress_vbox;
1298 addrbook.clist = clist;
1299 addrbook.label = label;
1300 addrbook.entry = entry;
1301 addrbook.statusbar = statusbar;
1302 addrbook.status_cid = gtk_statusbar_get_context_id(
1303 GTK_STATUSBAR(statusbar), "Addressbook Window" );
1305 addrbook.help_btn = help_btn;
1306 addrbook.edit_btn = edit_btn;
1307 addrbook.del_btn = del_btn;
1308 addrbook.reg_btn = reg_btn;
1309 addrbook.lup_btn = lup_btn;
1310 addrbook.to_btn = to_btn;
1311 addrbook.cc_btn = cc_btn;
1312 addrbook.bcc_btn = bcc_btn;
1314 addrbook.tree_popup = tree_popup;
1315 addrbook.list_popup = list_popup;
1316 addrbook.ui_manager = ui_manager;
1318 addrbook.listSelected = NULL;
1320 if (!geometry.min_height) {
1321 geometry.min_width = ADDRESSBOOK_WIDTH;
1322 geometry.min_height = ADDRESSBOOK_HEIGHT;
1325 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
1327 gtk_widget_set_size_request(window, prefs_common.addressbookwin_width,
1328 prefs_common.addressbookwin_height);
1330 gtk_window_move(GTK_WINDOW(window), 48, 48);
1333 if (!prefs_common.addressbook_use_editaddress_dialog) {
1334 if (prefs_common.addressbook_vpaned_pos > 0)
1335 gtk_paned_set_position(GTK_PANED(vpaned),
1336 prefs_common.addressbook_vpaned_pos);
1338 if (prefs_common.addressbook_hpaned_pos > 0)
1339 gtk_paned_set_position(GTK_PANED(hpaned),
1340 prefs_common.addressbook_hpaned_pos);
1343 gtk_widget_show_all(window);
1347 * Close address book window and save to file(s).
1349 static gint addressbook_close( void ) {
1350 address_completion_end(addrbook.window);
1351 if (!prefs_common.addressbook_use_editaddress_dialog)
1352 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1354 addressbook_pane_save_position();
1356 gtk_widget_hide(addrbook.window);
1357 addressbook_export_to_file();
1362 * Display message in status line.
1363 * \param msg Message to display.
1365 static void addressbook_status_show( gchar *msg ) {
1366 if( addrbook.statusbar != NULL ) {
1368 GTK_STATUSBAR(addrbook.statusbar),
1369 addrbook.status_cid );
1372 GTK_STATUSBAR(addrbook.statusbar),
1373 addrbook.status_cid, msg );
1378 static void addressbook_ds_show_message( AddressDataSource *ds ) {
1382 *addressbook_msgbuf = '\0';
1384 name = addrindex_ds_get_name( ds );
1385 retVal = addrindex_ds_get_status_code( ds );
1386 if( retVal == MGU_SUCCESS ) {
1387 g_snprintf( addressbook_msgbuf,
1388 sizeof(addressbook_msgbuf), "%s", name );
1391 desc = addressbook_err2string( _lutErrorsGeneral_, retVal );
1392 g_snprintf( addressbook_msgbuf,
1393 sizeof(addressbook_msgbuf), "%s: %s", name, desc );
1396 addressbook_status_show( addressbook_msgbuf );
1399 static void addressbook_edit_clicked(GtkButton *button, gpointer data)
1401 addressbook_edit_address_cb(NULL, NULL);
1404 static gboolean find_person(AddrSelectItem *item_a, ItemPerson *person)
1406 return ((ItemPerson *)item_a->addressItem == person)?0:-1;
1410 * Delete one or more objects from address list.
1412 static void addressbook_del_clicked(GtkButton *button, gpointer data)
1414 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
1415 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
1416 AddressObject *pobj;
1417 AdapterDSource *ads = NULL;
1418 GtkCMCTreeNode *nodeList;
1421 AddressBookFile *abf = NULL;
1422 AddressDataSource *ds = NULL;
1423 AddressInterface *iface;
1424 AddrItemObject *aio;
1425 AddrSelectItem *item;
1427 gboolean refreshList = FALSE;
1429 pobj = gtk_cmctree_node_get_row_data(ctree, addrbook.opened );
1430 cm_return_if_fail(pobj != NULL);
1432 /* Test whether anything selected for deletion */
1433 nodeList = addrbook.listSelected;
1435 aio = gtk_cmctree_node_get_row_data( clist, nodeList );
1436 if( aio == NULL) return;
1437 ds = addressbook_find_datasource( addrbook.treeSelected );
1438 if( ds == NULL ) return;
1440 /* Test for read only */
1441 iface = ds->interface;
1442 if( iface->readOnly ) {
1443 alertpanel( _("Delete address(es)"),
1444 _("This address data is readonly and cannot be deleted."),
1445 GTK_STOCK_CLOSE, NULL, NULL );
1449 /* Test whether Ok to proceed */
1451 if( pobj->type == ADDR_DATASOURCE ) {
1452 ads = ADAPTER_DSOURCE(pobj);
1453 if( ads->subType == ADDR_BOOK ) procFlag = TRUE;
1455 else if( pobj->type == ADDR_ITEM_FOLDER ) {
1458 else if( pobj->type == ADDR_ITEM_GROUP ) {
1461 if( ! procFlag ) return;
1462 abf = ds->rawDataSource;
1463 if( abf == NULL ) return;
1465 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
1466 g_signal_handlers_block_by_func
1467 (G_OBJECT(addrbook.clist),
1468 G_CALLBACK(addressbook_list_row_unselected), NULL);
1470 /* Process deletions */
1471 if( pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER ) {
1472 GList *groups = NULL, *persons = NULL, *emails = NULL;
1473 gboolean group_delete = TRUE;
1474 /* Items inside folders */
1475 list = addrselect_get_list( _addressSelect_ );
1476 /* Confirm deletion */
1480 node = g_list_next( node );
1481 aio = ( AddrItemObject * ) item->addressItem;
1482 if( aio->type == ADDR_ITEM_PERSON || aio->type == ADDR_ITEM_EMAIL ) {
1483 group_delete = FALSE;
1488 aval = alertpanel( _("Delete group"),
1489 _("Really delete the group(s)?\n"
1490 "The addresses it contains will not be lost."),
1491 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1492 if( aval != G_ALERTALTERNATE ) {
1496 aval = alertpanel( _("Delete address(es)"),
1497 _("Really delete the address(es)?"),
1498 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
1499 if( aval != G_ALERTALTERNATE ) {
1504 /* first, set lists of groups and persons to remove */
1508 node = g_list_next( node );
1509 aio = ( AddrItemObject * ) item->addressItem;
1512 if( aio->type == ADDR_ITEM_GROUP ) {
1513 groups = g_list_prepend(groups, item);
1515 else if( aio->type == ADDR_ITEM_PERSON ) {
1516 persons = g_list_prepend(persons, item);
1519 /* then set list of emails to remove *if* they're not children of
1520 * persons to remove */
1524 node = g_list_next( node );
1525 aio = ( AddrItemObject * ) item->addressItem;
1528 if( aio->type == ADDR_ITEM_EMAIL ) {
1529 ItemEMail *sitem = ( ItemEMail * ) aio;
1530 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1531 if (!g_list_find_custom(persons, person, (GCompareFunc)(find_person))) {
1532 emails = g_list_prepend(emails, item);
1534 /* else, the email will be removed via the parent person */
1537 /* then delete groups */
1541 node = g_list_next( node );
1542 aio = ( AddrItemObject * ) item->addressItem;
1545 if( aio->type == ADDR_ITEM_GROUP ) {
1546 ItemGroup *item = ( ItemGroup * ) aio;
1547 GtkCMCTreeNode *nd = NULL;
1548 nd = addressbook_find_group_node( addrbook.opened, item );
1549 item = addrbook_remove_group( abf, item );
1551 addritem_free_item_group( item );
1553 /* Remove group from parent node */
1554 gtk_cmctree_remove_node( ctree, nd );
1558 /* then delete persons */
1562 node = g_list_next( node );
1563 aio = ( AddrItemObject * ) item->addressItem;
1566 if( aio->type == ADDR_ITEM_PERSON ) {
1567 ItemPerson *item = ( ItemPerson * ) aio;
1568 item->status = DELETE_ENTRY;
1569 addressbook_folder_remove_one_person( clist, item );
1570 if (pobj->type == ADDR_ITEM_FOLDER)
1571 addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
1572 item = addrbook_remove_person( abf, item );
1574 if (ds && ds->type == ADDR_IF_LDAP) {
1575 LdapServer *server = ds->rawDataSource;
1576 ldapsvr_set_modified(server, TRUE);
1577 ldapsvr_update_book(server, item);
1581 gchar *filename = addritem_person_get_picture(item);
1582 if (filename && is_file_exist(filename))
1583 claws_unlink(filename);
1585 addritem_free_item_person( item );
1589 /* then delete emails */
1593 node = g_list_next( node );
1594 aio = ( AddrItemObject * ) item->addressItem;
1598 if( aio->type == ADDR_ITEM_EMAIL ) {
1599 ItemEMail *sitem = ( ItemEMail * ) aio;
1600 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(sitem);
1601 sitem = addrbook_person_remove_email( abf, person, sitem );
1603 addrcache_remove_email(abf->addressCache, sitem);
1604 addritem_free_item_email( sitem );
1606 addressbook_folder_refresh_one_person( clist, person );
1609 g_list_free( groups );
1610 g_list_free( persons );
1611 g_list_free( emails );
1612 g_list_free( list );
1613 addressbook_list_select_clear();
1615 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1616 addressbook_set_clist(
1617 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1621 addrbook_set_dirty(abf, TRUE);
1622 addressbook_export_to_file();
1623 addressbook_list_menu_setup();
1626 else if( pobj->type == ADDR_ITEM_GROUP ) {
1627 /* Items inside groups */
1628 list = addrselect_get_list( _addressSelect_ );
1632 node = g_list_next( node );
1633 aio = ( AddrItemObject * ) item->addressItem;
1634 if( aio->type == ADDR_ITEM_EMAIL ) {
1635 ItemEMail *item = ( ItemEMail * ) aio;
1636 ItemPerson *person = ( ItemPerson * ) ADDRITEM_PARENT(item);
1637 item = addrbook_person_remove_email( abf, person, item );
1639 addritem_free_item_email( item );
1643 g_list_free( list );
1644 addressbook_list_select_clear();
1645 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened);
1646 addressbook_set_clist(
1647 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
1651 addrbook_set_dirty(abf, TRUE);
1652 addressbook_export_to_file();
1653 addressbook_list_menu_setup();
1657 gtk_cmctree_node_set_row_data( clist, nodeList, NULL );
1658 gtk_cmctree_remove_node( clist, nodeList );
1660 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
1661 g_signal_handlers_unblock_by_func
1662 (G_OBJECT(addrbook.clist),
1663 G_CALLBACK(addressbook_list_row_unselected), NULL);
1666 static void addressbook_reg_clicked(GtkButton *button, gpointer data)
1668 addressbook_new_address_cb( NULL, NULL );
1671 static gchar *addressbook_format_address( AddrItemObject * aio ) {
1674 gchar *address = NULL;
1676 if( aio->type == ADDR_ITEM_EMAIL ) {
1677 ItemPerson *person = NULL;
1678 ItemEMail *email = ( ItemEMail * ) aio;
1680 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
1681 if( email->address ) {
1682 if( ADDRITEM_NAME(email) ) {
1683 name = ADDRITEM_NAME(email);
1684 if( *name == '\0' ) {
1685 name = ADDRITEM_NAME(person);
1688 else if( ADDRITEM_NAME(person) ) {
1689 name = ADDRITEM_NAME(person);
1692 buf = g_strdup( email->address );
1694 address = email->address;
1697 else if( aio->type == ADDR_ITEM_PERSON ) {
1698 ItemPerson *person = ( ItemPerson * ) aio;
1699 GList *node = person->listEMail;
1701 name = ADDRITEM_NAME(person);
1703 ItemEMail *email = ( ItemEMail * ) node->data;
1704 address = email->address;
1708 if( name && name[0] != '\0' ) {
1709 if( strchr_with_skip_quote( name, '"', ',' ) )
1710 buf = g_strdup_printf( "\"%s\" <%s>", name, address );
1712 buf = g_strdup_printf( "%s <%s>", name, address );
1715 buf = g_strdup( address );
1722 static void addressbook_to_clicked(GtkButton *button, gpointer data)
1726 AddrSelectItem *item;
1727 AddrItemObject *aio;
1730 compose = addrbook.target_compose;
1731 if( ! compose ) return;
1733 /* Nothing selected, but maybe there is something in text entry */
1734 addr = (char *)gtk_entry_get_text( GTK_ENTRY( addrbook.entry) );
1736 compose_entry_append(
1737 compose, addr, (ComposeEntryType)data , PREF_NONE);
1740 /* Select from address list */
1741 list = addrselect_get_list( _addressSelect_ );
1746 node = g_list_next( node );
1747 aio = item->addressItem;
1748 if( aio->type == ADDR_ITEM_PERSON ||
1749 aio->type == ADDR_ITEM_EMAIL ) {
1750 addr = addressbook_format_address( aio );
1751 compose_entry_append(
1752 compose, addr, (ComposeEntryType) data, PREF_NONE );
1755 else if( aio->type == ADDR_ITEM_GROUP ) {
1756 ItemGroup *group = ( ItemGroup * ) aio;
1757 GList *nodeMail = group->listEMail;
1759 ItemEMail *email = nodeMail->data;
1761 addr = addressbook_format_address(
1762 ( AddrItemObject * ) email );
1763 compose_entry_append(
1764 compose, addr, (ComposeEntryType) data, PREF_NONE );
1766 nodeMail = g_list_next( nodeMail );
1771 AddressObject *obj = NULL;
1773 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
1775 if( obj && obj->type == ADDR_ITEM_GROUP ) {
1776 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
1777 GList *nodeMail = itemGroup->listEMail;
1779 ItemEMail *email = nodeMail->data;
1781 addr = addressbook_format_address(
1782 ( AddrItemObject * ) email );
1783 compose_entry_append(
1784 compose, addr, (ComposeEntryType) data, PREF_NONE );
1786 nodeMail = g_list_next( nodeMail );
1790 g_list_free( list );
1793 static void addressbook_menubar_set_sensitive( gboolean sensitive ) {
1794 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", sensitive );
1795 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", sensitive );
1796 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", sensitive );
1798 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/SelectAll", TRUE );
1799 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", sensitive );
1800 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", sensitive );
1801 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", sensitive );
1803 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", sensitive );
1804 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", sensitive );
1805 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", sensitive );
1806 gtk_widget_set_sensitive( addrbook.edit_btn, sensitive );
1807 gtk_widget_set_sensitive( addrbook.del_btn, sensitive );
1810 static void addressbook_menuitem_set_sensitive( AddressObject *obj, GtkCMCTreeNode *node ) {
1811 gboolean canEdit = FALSE;
1812 gboolean canDelete = TRUE;
1813 gboolean canAdd = FALSE;
1814 gboolean canEditTr = TRUE;
1815 gboolean editAddress = FALSE;
1816 gboolean canExport = TRUE;
1817 AddressTypeControlItem *atci = NULL;
1818 AddressDataSource *ds = NULL;
1819 AddressInterface *iface = NULL;
1821 if( obj == NULL ) return;
1822 if( obj->type == ADDR_INTERFACE ) {
1823 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
1824 iface = adapter->interface;
1826 if( iface->haveLibrary ) {
1827 /* Enable appropriate File / New command */
1828 atci = adapter->atci;
1829 cm_menu_set_sensitive_full(addrbook.ui_manager, atci->menuCommand, TRUE );
1832 canEditTr = canExport = FALSE;
1834 else if( obj->type == ADDR_DATASOURCE ) {
1835 AdapterDSource *ads = ADAPTER_DSOURCE(obj);
1836 ds = ads->dataSource;
1837 iface = ds->interface;
1838 if( ! iface->readOnly ) {
1839 canAdd = canEdit = editAddress = canDelete = TRUE;
1841 if( ! iface->haveLibrary ) {
1842 canAdd = canEdit = editAddress = canExport = canDelete = FALSE;
1845 else if( obj->type == ADDR_ITEM_FOLDER ) {
1846 ds = addressbook_find_datasource( addrbook.treeSelected );
1848 iface = ds->interface;
1849 if( iface->readOnly ) {
1854 canAdd = editAddress = TRUE;
1858 else if( obj->type == ADDR_ITEM_GROUP ) {
1859 ds = addressbook_find_datasource( addrbook.treeSelected );
1861 iface = ds->interface;
1862 if( ! iface->readOnly ) {
1868 if( addrbook.listSelected == NULL )
1872 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewAddress", editAddress );
1873 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/NewGroup", canAdd );
1874 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/NewFolder", canAdd );
1875 gtk_widget_set_sensitive( addrbook.reg_btn, editAddress );
1878 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
1879 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
1880 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
1881 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
1883 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEditTr );
1884 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEditTr );
1887 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportHTML", canExport );
1888 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Tools/ExportLDIF", canExport );
1892 * Address book tree callback function that responds to selection of tree
1895 * \param ctree Tree widget.
1896 * \param node Node that was selected.
1897 * \param column Column number where selected occurred.
1898 * \param data Pointer to user data.
1900 static void addressbook_tree_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1901 gint column, gpointer data)
1903 AddressObject *obj = NULL;
1904 AdapterDSource *ads = NULL;
1905 AddressDataSource *ds = NULL;
1906 ItemFolder *rootFolder = NULL;
1907 AddressObjectType aot;
1909 addrbook.treeSelected = node;
1910 addrbook.listSelected = NULL;
1911 addressbook_status_show( "" );
1912 if( addrbook.entry != NULL ) gtk_entry_set_text(GTK_ENTRY(addrbook.entry), "");
1914 if( node ) obj = gtk_cmctree_node_get_row_data( ctree, node );
1916 addressbook_set_clist(NULL, TRUE);
1919 addrbook.opened = node;
1921 if( obj->type == ADDR_DATASOURCE ) {
1922 /* Read from file */
1923 static gboolean tVal = TRUE;
1925 ads = ADAPTER_DSOURCE(obj);
1926 if( ads == NULL ) return;
1927 ds = ads->dataSource;
1928 if( ds == NULL ) return;
1930 if( addrindex_ds_get_modify_flag( ds ) ) {
1931 addrindex_ds_read_data( ds );
1934 if( ! addrindex_ds_get_read_flag( ds ) ) {
1935 addrindex_ds_read_data( ds );
1937 addressbook_ds_show_message( ds );
1939 if( ! addrindex_ds_get_access_flag( ds ) ) {
1940 /* Remove existing folders and groups */
1941 gtk_cmclist_freeze( GTK_CMCLIST(ctree) );
1942 addressbook_tree_remove_children( ctree, node );
1943 gtk_cmclist_thaw( GTK_CMCLIST(ctree) );
1945 /* Load folders into the tree */
1946 rootFolder = addrindex_ds_get_root_folder( ds );
1947 if( ds && ds->type == ADDR_IF_JPILOT ) {
1948 aot = ADDR_CATEGORY;
1950 else if( ds && ds->type == ADDR_IF_LDAP ) {
1951 aot = ADDR_LDAP_QUERY;
1954 aot = ADDR_ITEM_FOLDER;
1956 addressbook_node_add_folder( node, ds, rootFolder, aot );
1957 addrindex_ds_set_access_flag( ds, &tVal );
1958 gtk_cmctree_expand( ctree, node );
1961 addressbook_set_clist(NULL, TRUE);
1964 /* Update address list */
1965 g_signal_handlers_block_by_func
1967 G_CALLBACK(addressbook_tree_selected), NULL);
1968 addressbook_set_clist( obj, FALSE );
1969 g_signal_handlers_unblock_by_func
1971 G_CALLBACK(addressbook_tree_selected), NULL);
1972 if (!prefs_common.addressbook_use_editaddress_dialog)
1973 addressbook_edit_person_invalidate(NULL, NULL, NULL);
1975 /* Setup main menu selections */
1976 addressbook_menubar_set_sensitive( FALSE );
1977 addressbook_menuitem_set_sensitive( obj, node );
1978 addressbook_list_select_clear();
1979 addressbook_list_menu_setup();
1984 * Setup address list popup menu items. Items are enabled or disabled as
1987 static void addressbook_list_menu_setup( void ) {
1988 GtkCMCTree *clist = NULL;
1989 AddressObject *pobj = NULL;
1990 AddressObject *obj = NULL;
1991 AdapterDSource *ads = NULL;
1992 AddressInterface *iface = NULL;
1993 AddressDataSource *ds = NULL;
1994 gboolean canEdit = FALSE;
1995 gboolean canDelete = FALSE;
1996 gboolean canCut = FALSE;
1997 gboolean canCopy = FALSE;
1998 gboolean canPaste = FALSE;
1999 gboolean canBrowse = FALSE;
2001 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2002 if( pobj == NULL ) return;
2004 clist = GTK_CMCTREE(addrbook.clist);
2005 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2006 if( obj == NULL ) canEdit = FALSE;
2008 menu_set_insensitive_all( GTK_MENU_SHELL(addrbook.list_popup) );
2009 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/SelectAll", TRUE );
2011 if( pobj->type == ADDR_DATASOURCE ) {
2012 /* Parent object is a data source */
2013 ads = ADAPTER_DSOURCE(pobj);
2014 ds = ads->dataSource;
2017 iface = ds->interface;
2020 if( ! iface->readOnly ) {
2021 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2022 if (iface->type != ADDR_IF_LDAP)
2023 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2024 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2027 canDelete = canEdit;
2030 else if( pobj->type != ADDR_INTERFACE ) {
2031 /* Parent object is not an interface */
2032 ds = addressbook_find_datasource( addrbook.treeSelected );
2035 iface = ds->interface;
2038 if( ! iface->readOnly ) {
2039 /* Folder or group */
2040 if( pobj->type == ADDR_ITEM_FOLDER || pobj->type == ADDR_ITEM_GROUP ) {
2041 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2042 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2043 if( obj ) canEdit = TRUE;
2046 if( pobj->type == ADDR_ITEM_FOLDER ) {
2047 if (iface->type != ADDR_IF_LDAP)
2048 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewGroup", TRUE );
2049 if( obj ) canEdit = TRUE;
2051 canDelete = canEdit;
2053 if( iface->type == ADDR_IF_LDAP ) {
2054 if( obj ) canBrowse = TRUE;
2061 /* Enable cut and paste */
2062 if( ! addrclip_is_empty( _clipBoard_ ) )
2064 if( ! addrselect_test_empty( _addressSelect_ ) )
2066 /* Enable copy if something is selected */
2067 if( ! addrselect_test_empty( _addressSelect_ ) )
2071 /* Disable edit or browse if more than one row selected */
2072 if( GTK_CMCLIST(clist)->selection && GTK_CMCLIST(clist)->selection->next ) {
2077 /* Forbid write changes when read-only */
2078 if( iface && iface->readOnly ) {
2084 /* Now go finalize menu items */
2085 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Edit", canEdit );
2086 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Delete", canDelete );
2088 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Cut", canCut );
2089 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Copy", canCopy );
2090 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Paste", canPaste );
2092 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/Mailto", canCopy );
2094 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2095 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2096 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2098 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Edit", canEdit );
2099 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Delete", canDelete );
2100 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Mailto", canCopy );
2102 gtk_widget_set_sensitive( addrbook.edit_btn, canEdit );
2103 gtk_widget_set_sensitive( addrbook.del_btn, canDelete );
2105 if (addrbook.target_compose) {
2106 gtk_widget_set_sensitive(addrbook.to_btn, obj ? TRUE : FALSE);
2107 gtk_widget_set_sensitive(addrbook.cc_btn, obj ? TRUE : FALSE);
2108 gtk_widget_set_sensitive(addrbook.bcc_btn, obj ? TRUE : FALSE);
2111 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/BrowseEntry", canBrowse );
2115 static void addressbook_select_row_tree (GtkCMCTree *ctree,
2116 GtkCMCTreeNode *node,
2123 * Add list of items into tree node below specified tree node.
2124 * \param treeNode Tree node.
2125 * \param ds Data source.
2126 * \param listItems List of items.
2128 static void addressbook_treenode_add_list(
2129 GtkCMCTreeNode *treeNode, AddressDataSource *ds, GList *listItems )
2135 AddrItemObject *aio;
2139 if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_GROUP ) {
2142 group = ( ItemGroup * ) aio;
2143 nn = addressbook_node_add_group( treeNode, ds, group );
2145 else if( ADDRESS_OBJECT_TYPE(aio) == ITEMTYPE_FOLDER ) {
2148 folder = ( ItemFolder * ) aio;
2149 nn = addressbook_node_add_folder(
2150 treeNode, ds, folder, ADDR_ITEM_FOLDER );
2152 node = g_list_next( node );
2156 static void addressbook_select_all_cb( GtkAction *action, gpointer data ) {
2157 gtk_cmclist_select_all(GTK_CMCLIST(addrbook.clist));
2161 * Cut from address list widget.
2163 static void addressbook_clip_cut_cb( GtkAction *action, gpointer data ) {
2164 _clipBoard_->cutFlag = TRUE;
2165 addrclip_clear( _clipBoard_ );
2166 addrclip_add( _clipBoard_, _addressSelect_ );
2167 /* addrclip_list_show( _clipBoard_, stdout ); */
2171 * Copy from address list widget.
2173 static void addressbook_clip_copy_cb(GtkAction *action, gpointer data) {
2174 _clipBoard_->cutFlag = FALSE;
2175 addrclip_clear( _clipBoard_ );
2176 addrclip_add( _clipBoard_, _addressSelect_ );
2177 /* addrclip_list_show( _clipBoard_, stdout ); */
2181 * Paste clipboard into address list widget.
2183 static void addressbook_clip_paste_cb( GtkAction *action, gpointer data ) {
2184 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2185 AddressObject *pobj = NULL;
2186 AddressDataSource *ds = NULL;
2187 AddressBookFile *abf = NULL;
2188 ItemFolder *folder = NULL;
2189 GList *folderGroup = NULL;
2191 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
2192 if( ds == NULL ) return;
2193 if( addrindex_ds_get_readonly( ds ) ) {
2194 alertpanel_error( _("Cannot paste. Target address book is readonly.") );
2198 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2200 if( pobj->type == ADDR_ITEM_FOLDER ) {
2201 folder = ADAPTER_FOLDER(pobj)->itemFolder;
2203 else if( pobj->type == ADDR_ITEM_GROUP ) {
2204 alertpanel_error( _("Cannot paste into an address group.") );
2209 /* Get an address book */
2210 abf = addressbook_get_book_file();
2211 if( abf == NULL ) return;
2213 if( _clipBoard_->cutFlag ) {
2215 folderGroup = addrclip_paste_cut( _clipBoard_, abf, folder );
2217 /* Remove all groups and folders in clipboard from tree node */
2218 addressbook_treenode_remove_item();
2220 /* Remove all "cut" items */
2221 addrclip_delete_item( _clipBoard_ );
2223 /* Clear clipboard - cut items??? */
2224 addrclip_clear( _clipBoard_ );
2228 folderGroup = addrclip_paste_copy( _clipBoard_, abf, folder );
2231 /* addrclip_list_show( _clipBoard_, stdout ); */
2233 /* Update tree by inserting node for each folder or group */
2234 addressbook_treenode_add_list(
2235 addrbook.treeSelected, ds, folderGroup );
2236 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2237 g_list_free( folderGroup );
2241 /* Display items pasted */
2242 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
2243 addressbook_set_clist(
2244 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
2252 * Add current treenode object to clipboard. Note that widget only allows
2253 * one entry from the tree list to be selected.
2255 static void addressbook_treenode_to_clipboard( void ) {
2256 AddressObject *obj = NULL;
2257 AddressDataSource *ds = NULL;
2258 AddrSelectItem *item;
2259 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
2260 GtkCMCTreeNode *node;
2262 node = addrbook.treeSelected;
2263 if( node == NULL ) return;
2264 obj = gtk_cmctree_node_get_row_data( ctree, node );
2265 if( obj == NULL ) return;
2267 ds = addressbook_find_datasource( node );
2268 if( ds == NULL ) return;
2271 if( obj->type == ADDR_ITEM_FOLDER ) {
2272 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2273 ItemFolder *folder = adapter->itemFolder;
2275 item = addrselect_create_node( obj );
2276 item->uid = g_strdup( ADDRITEM_ID(folder) );
2278 else if( obj->type == ADDR_ITEM_GROUP ) {
2279 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2280 ItemGroup *group = adapter->itemGroup;
2282 item = addrselect_create_node( obj );
2283 item->uid = g_strdup( ADDRITEM_ID(group) );
2285 else if( obj->type == ADDR_DATASOURCE ) {
2287 item = addrselect_create_node( obj );
2292 /* Clear existing list and add item into list */
2295 addressbook_list_select_clear();
2296 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2297 addrselect_list_add( _addressSelect_, item, cacheID );
2303 * Cut from tree widget.
2305 static void addressbook_treenode_cut_cb( GtkAction *action, gpointer data ) {
2306 _clipBoard_->cutFlag = TRUE;
2307 addressbook_treenode_to_clipboard();
2308 addrclip_clear( _clipBoard_ );
2309 addrclip_add( _clipBoard_, _addressSelect_ );
2310 /* addrclip_list_show( _clipBoard_, stdout ); */
2314 * Copy from tree widget.
2316 static void addressbook_treenode_copy_cb( GtkAction *action, gpointer data ) {
2317 _clipBoard_->cutFlag = FALSE;
2318 addressbook_treenode_to_clipboard();
2319 addrclip_clear( _clipBoard_ );
2320 addrclip_add( _clipBoard_, _addressSelect_ );
2321 /* addrclip_list_show( _clipBoard_, stdout ); */
2325 * Paste clipboard into address tree widget.
2327 static void addressbook_treenode_paste_cb( GtkAction *action, gpointer data ) {
2328 addressbook_clip_paste_cb(NULL,NULL);
2332 * Clear selected entries in clipboard.
2334 static void addressbook_list_select_clear( void ) {
2335 addrselect_list_clear( _addressSelect_ );
2339 * Add specified address item to selected address list.
2340 * \param aio Address item object.
2341 * \param ds Datasource.
2343 static void addressbook_list_select_add( AddrItemObject *aio, AddressDataSource *ds ) {
2346 if( ds == NULL ) return;
2347 cacheID = addrindex_get_cache_id( _addressIndex_, ds );
2348 addrselect_list_add_obj( _addressSelect_, aio, cacheID );
2353 * Remove specified address item from selected address list.
2354 * \param aio Address item object.
2356 static void addressbook_list_select_remove( AddrItemObject *aio ) {
2357 addrselect_list_remove( _addressSelect_, aio );
2361 * Invoke EMail compose window with addresses in selected address list.
2363 static void addressbook_mail_to_cb( GtkAction *action, gpointer data ) {
2366 if( ! addrselect_test_empty( _addressSelect_ ) ) {
2367 listAddress = addrselect_build_list( _addressSelect_ );
2368 compose_new_with_list( NULL, listAddress );
2369 mgu_free_dlist( listAddress );
2374 static void addressbook_list_row_selected( GtkCMCTree *clist,
2375 GtkCMCTreeNode *node,
2379 GtkEntry *entry = GTK_ENTRY(addrbook.entry);
2380 AddrItemObject *aio = NULL;
2381 AddressObject *pobj = NULL;
2382 AdapterDSource *ads = NULL;
2383 AddressDataSource *ds = NULL;
2385 gtk_entry_set_text( entry, "" );
2386 addrbook.listSelected = node;
2388 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
2389 if( pobj == NULL ) return;
2391 if( pobj->type == ADDR_DATASOURCE ) {
2392 ads = ADAPTER_DSOURCE(pobj);
2393 ds = ads->dataSource;
2395 else if( pobj->type != ADDR_INTERFACE ) {
2396 ds = addressbook_find_datasource( addrbook.treeSelected );
2399 aio = gtk_cmctree_node_get_row_data( clist, node );
2401 /* g_print( "list select: %d : '%s'\n", aio->type, aio->name ); */
2402 addressbook_list_select_add( aio, ds );
2405 addressbook_list_menu_setup();
2407 if (!addrbook.target_compose && !prefs_common.addressbook_use_editaddress_dialog) {
2408 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2410 if (obj && obj->type != ADDR_ITEM_GROUP)
2411 addressbook_edit_address(NULL, 0, NULL, FALSE);
2415 static void addressbook_list_row_unselected( GtkCMCTree *ctree,
2416 GtkCMCTreeNode *node,
2420 AddrItemObject *aio;
2422 aio = gtk_cmctree_node_get_row_data( ctree, node );
2424 /* g_print( "list unselect: %d : '%s'\n", aio->type, aio->name ); */
2425 addressbook_list_select_remove( aio );
2428 if (!prefs_common.addressbook_use_editaddress_dialog)
2429 addressbook_edit_person_invalidate(NULL, NULL, NULL);
2432 static gboolean addressbook_list_button_pressed(GtkWidget *widget,
2433 GdkEventButton *event,
2436 if( ! event ) return FALSE;
2438 addressbook_list_menu_setup();
2440 if( event->button == 3 ) {
2441 gtk_menu_popup( GTK_MENU(addrbook.list_popup), NULL, NULL, NULL, NULL,
2442 event->button, event->time );
2443 } else if (event->button == 1) {
2444 if (event->type == GDK_2BUTTON_PRESS) {
2445 if (prefs_common.add_address_by_click &&
2446 addrbook.target_compose)
2447 addressbook_to_clicked(NULL, GINT_TO_POINTER(COMPOSE_TO));
2449 if (prefs_common.addressbook_use_editaddress_dialog)
2450 addressbook_edit_address_cb(NULL, NULL);
2452 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
2453 AddressObject *obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
2454 if( obj && obj->type == ADDR_ITEM_GROUP )
2455 addressbook_edit_address_cb(NULL, NULL);
2463 static gboolean addressbook_list_button_released(GtkWidget *widget,
2464 GdkEventButton *event,
2470 static gboolean addressbook_tree_button_pressed(GtkWidget *ctree,
2471 GdkEventButton *event,
2474 GtkCMCList *clist = GTK_CMCLIST(ctree);
2476 AddressObject *obj = NULL;
2477 AdapterDSource *ads = NULL;
2478 AddressInterface *iface = NULL;
2479 AddressDataSource *ds = NULL;
2480 gboolean canEdit = FALSE;
2481 gboolean canDelete = FALSE;
2482 gboolean canCut = FALSE;
2483 gboolean canCopy = FALSE;
2484 gboolean canPaste = FALSE;
2485 gboolean canTreeCut = FALSE;
2486 gboolean canTreeCopy = FALSE;
2487 gboolean canTreePaste = FALSE;
2488 gboolean canLookup = FALSE;
2489 GtkCMCTreeNode *node = NULL;
2491 if( ! event ) return FALSE;
2492 /* if( ! event || event->type != GDK_BUTTON_PRESS) return FALSE;*/
2494 if (event->button == 1) {
2495 if (event->type == GDK_2BUTTON_PRESS) {
2496 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2497 gtkut_clist_set_focus_row(clist, row);
2498 obj = gtk_cmclist_get_row_data( clist, row );
2503 if (obj->type == ADDR_ITEM_GROUP) {
2505 addressbook_treenode_edit_cb(NULL, NULL);
2507 /* expand pr collapse */
2508 node = gtk_cmctree_node_nth(GTK_CMCTREE(ctree), row);
2509 gtk_cmctree_toggle_expansion(GTK_CMCTREE(ctree), node);
2515 addressbook_menubar_set_sensitive( FALSE );
2517 if( gtk_cmclist_get_selection_info( clist, event->x, event->y, &row, &column ) ) {
2518 gtkut_clist_set_focus_row(clist, row);
2519 obj = gtk_cmclist_get_row_data( clist, row );
2522 menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup));
2526 node = gtk_cmctree_node_nth(GTK_CMCTREE(clist), row);
2528 if( ! addrclip_is_empty( _clipBoard_ ) )
2529 canTreePaste = TRUE;
2531 if (obj->type == ADDR_INTERFACE) {
2532 AdapterInterface *adapter = ADAPTER_INTERFACE(obj);
2533 iface = adapter->interface;
2536 if( !iface->readOnly ) {
2537 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewBook", TRUE );
2538 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2540 if( iface->externalQuery )
2543 if (obj->type == ADDR_DATASOURCE) {
2544 ads = ADAPTER_DSOURCE(obj);
2545 ds = ads->dataSource;
2548 iface = ds->interface;
2551 if( !iface->readOnly ) {
2553 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2554 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2555 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2559 if( iface->externalQuery )
2562 else if (obj->type == ADDR_ITEM_FOLDER) {
2563 ds = addressbook_find_datasource( node );
2566 iface = ds->interface;
2569 if( !iface->readOnly ) {
2573 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewFolder", TRUE );
2574 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/NewGroup", TRUE );
2575 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2579 if( iface->externalQuery ) {
2580 /* Enable deletion of LDAP folder */
2585 else if (obj->type == ADDR_ITEM_GROUP) {
2586 ds = addressbook_find_datasource( node );
2589 iface = ds->interface;
2592 if( ! iface->readOnly ) {
2595 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABListPopup/NewAddress", TRUE );
2596 gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
2600 if( canEdit && !addrselect_test_empty( _addressSelect_ ) )
2602 if( ! addrselect_test_empty( _addressSelect_ ) )
2604 if( ! addrclip_is_empty( _clipBoard_ ) )
2607 /* Forbid write changes when read-only */
2608 if( iface && iface->readOnly ) {
2610 canTreePaste = FALSE;
2618 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/EditBook", canEdit );
2619 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/DeleteBook", canDelete );
2620 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Cut", canTreeCut );
2621 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Copy", canTreeCopy );
2622 cm_menu_set_sensitive_full( addrbook.ui_manager, "Popups/ABTreePopup/Paste", canTreePaste );
2624 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/EditBook", canEdit );
2625 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Book/DeleteBook", canEdit );
2626 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", canCut );
2627 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", canCopy );
2628 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", canPaste );
2630 addressbook_show_buttons(addrbook.target_compose == NULL, canLookup,
2631 addrbook.target_compose != NULL);
2633 if( event->button == 3 )
2634 gtk_menu_popup(GTK_MENU(addrbook.tree_popup), NULL, NULL, NULL, NULL,
2635 event->button, event->time);
2640 static gboolean addressbook_tree_button_released(GtkWidget *ctree,
2641 GdkEventButton *event,
2644 gtkut_ctree_set_focus_row(GTK_CMCTREE(addrbook.ctree), addrbook.opened);
2648 static void addressbook_new_folder_cb(GtkAction *action, gpointer data)
2650 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2651 AddressObject *obj = NULL;
2652 AddressDataSource *ds = NULL;
2653 AddressBookFile *abf = NULL;
2654 ItemFolder *parentFolder = NULL;
2655 ItemFolder *folder = NULL;
2657 if( ! addrbook.treeSelected ) return;
2658 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
2659 if( obj == NULL ) return;
2660 ds = addressbook_find_datasource( addrbook.treeSelected );
2661 if( ds == NULL ) return;
2663 if( obj->type == ADDR_DATASOURCE ) {
2664 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2666 else if( obj->type == ADDR_ITEM_FOLDER ) {
2667 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2673 abf = ds->rawDataSource;
2674 if( abf == NULL ) return;
2675 folder = addressbook_edit_folder( abf, parentFolder, NULL );
2678 nn = addressbook_node_add_folder(
2679 addrbook.treeSelected, ds, folder, ADDR_ITEM_FOLDER );
2680 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2681 if( addrbook.treeSelected == addrbook.opened )
2682 addressbook_set_clist(obj, TRUE);
2686 static void addressbook_new_group_cb(GtkAction *action, gpointer data)
2688 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2689 AddressObject *obj = NULL;
2690 AddressDataSource *ds = NULL;
2691 AddressBookFile *abf = NULL;
2692 ItemFolder *parentFolder = NULL;
2693 ItemGroup *group = NULL;
2695 if( ! addrbook.treeSelected ) return;
2696 obj = gtk_cmctree_node_get_row_data(ctree, addrbook.treeSelected);
2697 if( obj == NULL ) return;
2698 ds = addressbook_find_datasource( addrbook.treeSelected );
2699 if( ds == NULL ) return;
2701 if( obj->type == ADDR_DATASOURCE ) {
2702 if( ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK ) return;
2704 else if( obj->type == ADDR_ITEM_FOLDER ) {
2705 parentFolder = ADAPTER_FOLDER(obj)->itemFolder;
2711 abf = ds->rawDataSource;
2712 if( abf == NULL ) return;
2713 group = addressbook_edit_group( abf, parentFolder, NULL );
2716 nn = addressbook_node_add_group( addrbook.treeSelected, ds, group );
2717 gtk_cmctree_expand( ctree, addrbook.treeSelected );
2718 if( addrbook.treeSelected == addrbook.opened )
2719 addressbook_set_clist(obj, TRUE);
2723 static void addressbook_change_node_name(GtkCMCTreeNode *node, const gchar *name)
2725 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2728 GdkPixbuf *pix_cl, *pix_op;
2729 gboolean is_leaf, expanded;
2731 gtk_cmctree_get_node_info(ctree, node, text, &spacing,
2733 &is_leaf, &expanded);
2734 gtk_cmctree_set_node_info(ctree, node, name, spacing,
2741 * \param obj Address object to edit.
2742 * \param node Node in tree.
2743 * \return New name of data source.
2745 static gchar *addressbook_edit_datasource( AddressObject *obj, GtkCMCTreeNode *node ) {
2746 gchar *newName = NULL;
2747 AddressDataSource *ds = NULL;
2748 AddressInterface *iface = NULL;
2749 AdapterDSource *ads = NULL;
2751 ds = addressbook_find_datasource( node );
2752 if( ds == NULL ) return NULL;
2753 iface = ds->interface;
2754 if( ! iface->haveLibrary ) return NULL;
2756 /* Read data from data source */
2757 if( addrindex_ds_get_modify_flag( ds ) ) {
2758 addrindex_ds_read_data( ds );
2761 if( ! addrindex_ds_get_read_flag( ds ) ) {
2762 addrindex_ds_read_data( ds );
2766 ads = ADAPTER_DSOURCE(obj);
2767 if( ads->subType == ADDR_BOOK ) {
2768 if( addressbook_edit_book( _addressIndex_, ads ) == NULL ) return NULL;
2770 else if( ads->subType == ADDR_VCARD ) {
2771 if( addressbook_edit_vcard( _addressIndex_, ads ) == NULL ) return NULL;
2774 else if( ads->subType == ADDR_JPILOT ) {
2775 if( addressbook_edit_jpilot( _addressIndex_, ads ) == NULL ) return NULL;
2779 else if( ads->subType == ADDR_LDAP ) {
2780 if( addressbook_edit_ldap( _addressIndex_, ads ) == NULL ) return NULL;
2786 newName = obj->name;
2791 * Edit an object that is in the address tree area.
2793 static void addressbook_treenode_edit_cb(GtkAction *action, gpointer data)
2795 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2797 AddressDataSource *ds = NULL;
2798 AddressBookFile *abf = NULL;
2799 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
2802 if( ! addrbook.treeSelected ) return;
2803 node = addrbook.treeSelected;
2804 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2805 obj = gtk_cmctree_node_get_row_data( ctree, node );
2806 if( obj == NULL ) return;
2807 parentNode = GTK_CMCTREE_ROW(node)->parent;
2809 ds = addressbook_find_datasource( node );
2810 if( ds == NULL ) return;
2812 if( obj->type == ADDR_DATASOURCE ) {
2813 name = addressbook_edit_datasource( obj, node );
2814 if( name == NULL ) return;
2817 abf = ds->rawDataSource;
2818 if( abf == NULL ) return;
2819 if( obj->type == ADDR_ITEM_FOLDER ) {
2820 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2821 ItemFolder *item = adapter->itemFolder;
2822 ItemFolder *parentFolder = NULL;
2823 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2824 if( addressbook_edit_folder( abf, parentFolder, item ) == NULL ) return;
2825 name = ADDRITEM_NAME(item);
2827 else if( obj->type == ADDR_ITEM_GROUP ) {
2828 AdapterGroup *adapter = ADAPTER_GROUP(obj);
2829 ItemGroup *item = adapter->itemGroup;
2830 ItemFolder *parentFolder = NULL;
2831 parentFolder = ( ItemFolder * ) ADDRITEM_PARENT(item);
2832 if( addressbook_edit_group( abf, parentFolder, item ) == NULL ) return;
2833 name = ADDRITEM_NAME(item);
2836 if( name && parentNode ) {
2837 /* Update node in tree view */
2838 addressbook_change_node_name( node, name );
2839 gtk_sctree_sort_node(ctree, parentNode);
2840 gtk_cmctree_expand( ctree, node );
2841 gtk_sctree_select( GTK_SCTREE( ctree), node );
2848 ADDRTREE_DEL_FOLDER_ONLY,
2849 ADDRTREE_DEL_FOLDER_ADDR
2853 * Delete an item from the tree widget.
2854 * \param data Data passed in.
2855 * \param action Action.
2856 * \param widget Widget issuing callback.
2858 static void addressbook_treenode_delete_cb(GtkAction *action, gpointer data)
2860 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
2861 GtkCMCTreeNode *node = NULL;
2865 AddrBookBase *adbase;
2866 AddressCache *cache;
2867 AdapterDSource *ads = NULL;
2868 AddressInterface *iface = NULL;
2869 AddressDataSource *ds = NULL;
2870 gboolean remFlag = FALSE;
2871 TreeItemDelType delType;
2873 if( ! addrbook.treeSelected ) return;
2874 node = addrbook.treeSelected;
2875 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
2877 obj = gtk_cmctree_node_get_row_data( ctree, node );
2878 cm_return_if_fail(obj != NULL);
2880 if( obj->type == ADDR_DATASOURCE ) {
2881 ads = ADAPTER_DSOURCE(obj);
2882 if( ads == NULL ) return;
2883 ds = ads->dataSource;
2884 if( ds == NULL ) return;
2887 /* Must be folder or something else */
2888 ds = addressbook_find_datasource( node );
2889 if( ds == NULL ) return;
2891 /* Only allow deletion from non-readOnly */
2892 iface = ds->interface;
2893 if( iface->readOnly ) {
2894 /* Allow deletion of query results */
2895 if( ! iface->externalQuery ) return;
2899 /* Confirm deletion */
2900 delType = ADDRTREE_DEL_NONE;
2901 if( obj->type == ADDR_ITEM_FOLDER ) {
2902 if( iface->externalQuery ) {
2903 message = g_strdup_printf( _(
2904 "Do you want to delete the query " \
2905 "results and addresses in '%s' ?" ),
2907 aval = alertpanel( _("Delete"), message,
2908 GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL );
2910 if( aval == G_ALERTALTERNATE ) {
2911 delType = ADDRTREE_DEL_FOLDER_ADDR;
2915 message = g_strdup_printf
2916 ( _( "Do you want to delete '%s' ? "
2917 "If you delete the folder only, the addresses it contains will be moved into the parent folder." ),
2919 aval = alertpanel( _("Delete folder"), message,
2920 GTK_STOCK_CANCEL, _("+Delete _folder only"), _("Delete folder and _addresses"));
2922 if( aval == G_ALERTALTERNATE ) {
2923 delType = ADDRTREE_DEL_FOLDER_ONLY;
2925 else if( aval == G_ALERTOTHER ) {
2926 delType = ADDRTREE_DEL_FOLDER_ADDR;
2930 else if( obj->type == ADDR_ITEM_GROUP ) {
2931 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2932 "The addresses it contains will not be lost."), obj->name);
2933 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2934 "+" GTK_STOCK_DELETE, NULL);
2936 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_FOLDER_ONLY;
2938 message = g_strdup_printf(_("Do you want to delete '%s'?\n"
2939 "The addresses it contains will be lost."), obj->name);
2940 aval = alertpanel(_("Delete"), message, GTK_STOCK_CANCEL,
2941 "+" GTK_STOCK_DELETE, NULL);
2943 if( aval == G_ALERTALTERNATE ) delType = ADDRTREE_DEL_DATA;
2945 if( delType == ADDRTREE_DEL_NONE ) return;
2947 /* Proceed with deletion */
2948 if( obj->type == ADDR_DATASOURCE ) {
2949 /* Remove node from tree */
2950 gtk_cmctree_remove_node( ctree, node );
2952 if (delType == ADDRTREE_DEL_DATA &&
2953 ds->interface && ds->interface->type == ADDR_IF_BOOK)
2954 addrbook_delete_book_file((AddressBookFile *) ds->rawDataSource);
2956 /* Remove data source. */
2957 if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) {
2958 addrindex_free_datasource( ds );
2963 /* Get reference to cache */
2964 adbase = ( AddrBookBase * ) ds->rawDataSource;
2965 if( adbase == NULL ) return;
2966 cache = adbase->addressCache;
2968 /* Remove query results folder */
2969 if( iface->externalQuery ) {
2970 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2971 ItemFolder *folder = adapter->itemFolder;
2973 adapter->itemFolder = NULL;
2975 g_print( "remove folder for ::%s::\n", obj->name );
2976 g_print( " folder name ::%s::\n", ADDRITEM_NAME(folder) );
2977 g_print( "-------------- remove results\n" );
2979 addrindex_remove_results( ds, folder );
2980 /* g_print( "-------------- remove node\n" ); */
2981 gtk_cmctree_remove_node( ctree, node );
2985 /* Code below is valid for regular address book deletion */
2986 if( obj->type == ADDR_ITEM_FOLDER ) {
2987 AdapterFolder *adapter = ADAPTER_FOLDER(obj);
2988 ItemFolder *item = adapter->itemFolder;
2990 if( delType == ADDRTREE_DEL_FOLDER_ONLY ) {
2991 /* Remove folder only */
2992 item = addrcache_remove_folder( cache, item );
2994 addritem_free_item_folder( item );
2995 addressbook_move_nodes_up( ctree, node );
2999 else if( delType == ADDRTREE_DEL_FOLDER_ADDR ) {
3000 /* Remove folder and addresses */
3001 item = addrcache_remove_folder_delete( cache, item );
3003 addritem_free_item_folder( item );
3008 else if( obj->type == ADDR_ITEM_GROUP ) {
3009 AdapterGroup *adapter = ADAPTER_GROUP(obj);
3010 ItemGroup *item = adapter->itemGroup;
3012 item = addrcache_remove_group( cache, item );
3014 addritem_free_item_group( item );
3021 gtk_cmctree_remove_node(ctree, node );
3025 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
3027 if( person && addrbook.treeSelected == addrbook.opened ) {
3028 person->status = ADD_ENTRY;
3029 gtk_cmclist_unselect_all( GTK_CMCLIST(addrbook.clist) );
3030 addressbook_folder_refresh_one_person(
3031 GTK_CMCTREE(addrbook.clist), person );
3033 addressbook_address_list_set_focus();
3036 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
3038 if( person && addrbook.treeSelected == addrbook.opened) {
3039 person->status = ADD_ENTRY;
3040 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3041 addressbook_set_clist(
3042 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3046 addressbook_address_list_set_focus();
3050 * Label (a format string) that is used to name each folder.
3052 static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
3055 * Search ctree widget callback function.
3056 * \param pA Pointer to node.
3057 * \param pB Pointer to data item being sought.
3058 * \return Zero (0) if folder found.
3060 static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
3063 aoA = ( AddressObject * ) pA;
3064 if( aoA->type == ADDR_ITEM_FOLDER ) {
3065 ItemFolder *folder, *fld;
3067 fld = ADAPTER_FOLDER(aoA)->itemFolder;
3068 folder = ( ItemFolder * ) pB;
3069 if( fld == folder ) return 0; /* Found folder */
3074 static ItemFolder * addressbook_setup_subf(
3075 AddressDataSource *ds, gchar *title,
3076 GtkCMCTreeNode *pNode )
3078 AddrBookBase *adbase;
3079 AddressCache *cache;
3082 GtkCMCTreeNode *nNode;
3084 AddressObjectType aoType = ADDR_NONE;
3087 if( *title == '\0' || strlen( title ) < 1 ) return NULL;
3089 if( ds && ds->type == ADDR_IF_LDAP ) {
3091 aoType = ADDR_LDAP_QUERY;
3098 ctree = GTK_CMCTREE(addrbook.ctree);
3099 /* Get reference to address cache */
3100 adbase = ( AddrBookBase * ) ds->rawDataSource;
3101 cache = adbase->addressCache;
3103 if ((children = addrcache_get_list_folder(cache)) != NULL) {
3104 GList *cur = children;
3105 for (; cur; cur = cur->next) {
3106 ItemFolder *child = (ItemFolder *) cur->data;
3107 if (!strcmp2(ADDRITEM_NAME(child), title)) {
3108 nNode = gtk_cmctree_find_by_row_data_custom(
3110 addressbook_treenode_find_folder_cb );
3112 addrindex_remove_results( ds, child );
3113 while( child->listPerson ) {
3114 ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
3115 item = addrcache_remove_person( cache, item );
3117 addritem_free_item_person( item );
3121 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3122 addrbook.treeSelected = nNode;
3129 /* Create a folder */
3130 folder = addrcache_add_new_folder( cache, NULL );
3131 name = g_strdup_printf( "%s", title );
3132 addritem_folder_set_name( folder, name );
3133 addritem_folder_set_remarks( folder, "" );
3136 /* Now let's see the folder */
3137 nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
3138 gtk_cmctree_expand( ctree, pNode );
3140 gtk_sctree_select( GTK_SCTREE(ctree), nNode );
3141 addrbook.treeSelected = nNode;
3147 static void addressbook_new_address_cb( GtkAction *action, gpointer data ) {
3148 AddressObject *pobj = NULL;
3149 AddressDataSource *ds = NULL;
3150 AddressBookFile *abf = NULL;
3151 debug_print("adding address\n");
3152 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3153 if( pobj == NULL ) {
3154 debug_print("no row data\n");
3157 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3159 debug_print("no datasource\n");
3163 abf = ds->rawDataSource;
3165 g_print("no addressbook file\n");
3169 if( pobj->type == ADDR_DATASOURCE ) {
3170 if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
3171 ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
3173 ItemFolder *folder = NULL;
3175 if (abf && abf->type == ADDR_IF_LDAP) {
3176 GtkCMCTreeNode *parentNode;
3177 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3178 if( ds == NULL ) return;
3180 /* We must have a datasource that is an external interface */
3181 if( ! ds->interface->haveLibrary ) return;
3182 if( ! ds->interface->externalQuery ) return;
3184 if( pobj->type == ADDR_ITEM_FOLDER ) {
3185 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3188 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3190 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3192 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3193 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3195 abf = ds->rawDataSource;
3198 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3199 addrbook.editaddress_vbox,
3200 addressbook_new_address_from_book_post_cb,
3203 if (ds && abf && abf->type == ADDR_IF_LDAP) {
3204 LdapServer *server = ds->rawDataSource;
3205 ldapsvr_set_modified(server, TRUE);
3206 ldapsvr_update_book(server, NULL);
3207 if (server->retVal != LDAPRC_SUCCESS) {
3208 alertpanel( _("Add address(es)"),
3209 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3210 GTK_STOCK_CLOSE, NULL, NULL );
3211 server->retVal = LDAPRC_SUCCESS;
3216 if (prefs_common.addressbook_use_editaddress_dialog)
3217 addressbook_new_address_from_book_post_cb( person );
3220 else if( pobj->type == ADDR_ITEM_FOLDER ) {
3222 ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
3225 if (abf && abf->type == ADDR_IF_LDAP) {
3226 GtkCMCTreeNode *parentNode;
3227 ds = addressbook_find_datasource( GTK_CMCTREE_NODE( addrbook.treeSelected ) );
3228 if( ds == NULL ) return;
3230 /* We must have a datasource that is an external interface */
3231 if( ! ds->interface->haveLibrary ) return;
3232 if( ! ds->interface->externalQuery ) return;
3234 if( pobj->type == ADDR_ITEM_FOLDER ) {
3235 parentNode = GTK_CMCTREE_ROW(GTK_CMCTREE_NODE( addrbook.treeSelected ) )->parent;
3238 parentNode = GTK_CMCTREE_NODE( addrbook.treeSelected );
3240 folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
3243 pobj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected);
3244 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3246 abf = ds->rawDataSource;
3249 person = addressbook_edit_person( abf, folder, NULL, FALSE,
3250 addrbook.editaddress_vbox,
3251 addressbook_new_address_from_folder_post_cb,
3254 if (ds && abf && abf->type == ADDR_IF_LDAP) {
3255 LdapServer *server = ds->rawDataSource;
3256 ldapsvr_set_modified(server, TRUE);
3257 ldapsvr_update_book(server, NULL);
3258 if (server->retVal != LDAPRC_SUCCESS) {
3259 alertpanel( _("Add address(es)"),
3260 addressbook_err2string(_lutErrorsLDAP_, server->retVal),
3261 GTK_STOCK_CLOSE, NULL, NULL );
3266 if (prefs_common.addressbook_use_editaddress_dialog)
3267 addressbook_new_address_from_folder_post_cb( person );
3269 else if( pobj->type == ADDR_ITEM_GROUP ) {
3270 /* New address in group */
3271 ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup;
3272 if( addressbook_edit_group( abf, NULL, group ) == NULL ) return;
3273 if (addrbook.treeSelected == addrbook.opened) {
3274 /* Change node name in tree. */
3275 addressbook_change_node_name( addrbook.treeSelected, ADDRITEM_NAME(group) );
3276 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
3277 addressbook_set_clist(
3278 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3286 * Search for specified child group node in address index tree.
3287 * \param parent Parent node.
3288 * \param group Group to find.
3290 static GtkCMCTreeNode *addressbook_find_group_node( GtkCMCTreeNode *parent, ItemGroup *group ) {
3291 GtkCMCTreeNode *node = NULL;
3292 GtkCMCTreeRow *currRow;
3294 currRow = GTK_CMCTREE_ROW( parent );
3296 node = currRow->children;
3300 obj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3301 if( obj->type == ADDR_ITEM_GROUP ) {
3302 ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup;
3303 if( g == group ) return node;
3305 currRow = GTK_CMCTREE_ROW(node);
3306 node = currRow->sibling;
3312 static AddressBookFile *addressbook_get_book_file() {
3313 AddressBookFile *abf = NULL;
3314 AddressDataSource *ds = NULL;
3316 ds = addressbook_find_datasource( addrbook.treeSelected );
3317 if( ds == NULL ) return NULL;
3318 if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
3322 static void addressbook_tree_remove_children( GtkCMCTree *ctree, GtkCMCTreeNode *parent ) {
3323 GtkCMCTreeNode *node;
3326 /* Remove existing folders and groups */
3327 row = GTK_CMCTREE_ROW( parent );
3329 while( (node = row->children) ) {
3330 gtk_cmctree_remove_node( ctree, node );
3335 static void addressbook_move_nodes_up( GtkCMCTree *ctree, GtkCMCTreeNode *node ) {
3336 GtkCMCTreeNode *parent, *child;
3337 GtkCMCTreeRow *currRow;
3338 currRow = GTK_CMCTREE_ROW( node );
3340 parent = currRow->parent;
3341 while( (child = currRow->children) ) {
3342 gtk_cmctree_move( ctree, child, parent, node );
3344 gtk_sctree_sort_node( ctree, parent );
3348 static void addressbook_edit_address_post_cb( ItemPerson *person )
3352 AddressBookFile *abf = addressbook_get_book_file();
3354 if (abf && abf->type == ADDR_IF_LDAP) {
3355 if (strcmp2(person->nickName, ADDRITEM_NAME(person)))
3356 addritem_person_set_nick_name( person, ADDRITEM_NAME(person));
3359 addressbook_folder_refresh_one_person( GTK_CMCTREE(addrbook.clist), person );
3360 invalidate_address_completion();
3362 addressbook_address_list_set_focus();
3365 void addressbook_address_list_set_focus( void )
3367 if (!prefs_common.addressbook_use_editaddress_dialog) {
3368 gtk_window_set_focus(GTK_WINDOW(addrbook.window), addrbook.clist);
3369 addressbook_list_menu_setup();
3373 void addressbook_address_list_disable_some_actions(void)
3375 /* disable address copy/pasting when editing contact's detail (embedded form) */
3376 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Cut", FALSE );
3377 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Copy", FALSE );
3378 cm_menu_set_sensitive_full( addrbook.ui_manager, "Menu/Address/Paste", FALSE );
3381 static void addressbook_edit_address_cb( GtkAction *action, gpointer data ) {
3382 addressbook_edit_address(data, 0, NULL, TRUE);
3385 static void addressbook_edit_address( gpointer data, guint action, GtkWidget *widget,
3386 gboolean force_focus ) {
3387 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
3389 AddressObject *obj = NULL, *pobj = NULL;
3390 AddressDataSource *ds = NULL;
3391 GtkCMCTreeNode *node = NULL, *parentNode = NULL;
3393 AddressBookFile *abf = NULL;
3395 if( addrbook.listSelected == NULL ) return;
3396 obj = gtk_cmctree_node_get_row_data( clist, addrbook.listSelected );
3397 cm_return_if_fail(obj != NULL);
3399 ctree = GTK_CMCTREE( addrbook.ctree );
3400 pobj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
3401 node = gtk_cmctree_find_by_row_data( ctree, addrbook.treeSelected, obj );
3403 ds = addressbook_find_datasource( GTK_CMCTREE_NODE(addrbook.treeSelected) );
3404 if( ds == NULL ) return;
3406 abf = addressbook_get_book_file();
3408 if( obj->type == ADDR_ITEM_EMAIL ) {
3409 ItemEMail *email = ( ItemEMail * ) obj;
3410 if( email == NULL ) return;
3411 if( pobj && pobj->type == ADDR_ITEM_GROUP ) {
3412 /* Edit parent group */
3413 AdapterGroup *adapter = ADAPTER_GROUP(pobj);
3414 ItemGroup *itemGrp = adapter->itemGroup;
3415 if( abf == NULL ) return;
3416 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3417 name = ADDRITEM_NAME(itemGrp);
3418 node = addrbook.treeSelected;
3419 parentNode = GTK_CMCTREE_ROW(node)->parent;
3422 /* Edit person - email page */
3424 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3425 if ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
3426 addressbook_edit_address_post_cb,
3427 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3430 if (abf && abf->type == ADDR_IF_LDAP) {
3431 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3432 person->status = UPDATE_ENTRY;
3435 if (prefs_common.addressbook_use_editaddress_dialog)
3436 addressbook_edit_address_post_cb( person );
3441 else if( obj->type == ADDR_ITEM_PERSON ) {
3442 /* Edit person - basic page */
3443 ItemPerson *person = ( ItemPerson * ) obj;
3444 if( addressbook_edit_person( abf, NULL, person, FALSE, addrbook.editaddress_vbox,
3445 addressbook_edit_address_post_cb,
3446 (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
3449 if (abf && abf->type == ADDR_IF_LDAP) {
3450 ldapsvr_set_modified( (LdapServer *) abf, TRUE );
3451 person->status = UPDATE_ENTRY;
3454 if (prefs_common.addressbook_use_editaddress_dialog)
3455 addressbook_edit_address_post_cb( person );
3459 else if( obj->type == ADDR_ITEM_GROUP ) {
3460 ItemGroup *itemGrp = ( ItemGroup * ) obj;
3461 if( addressbook_edit_group( abf, NULL, itemGrp ) == NULL ) return;
3462 parentNode = addrbook.treeSelected;
3463 node = addressbook_find_group_node( parentNode, itemGrp );
3464 name = ADDRITEM_NAME(itemGrp);
3465 invalidate_address_completion();
3471 /* Update tree node with node name */
3472 if( node == NULL ) return;
3473 addressbook_change_node_name( node, name );
3474 gtk_sctree_sort_node( ctree, parentNode );
3475 gtk_sctree_select( GTK_SCTREE(ctree), addrbook.opened );
3476 addressbook_set_clist(
3477 gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree),
3482 static void addressbook_delete_address_cb(GtkAction *action, gpointer data)
3484 addressbook_del_clicked(NULL, NULL);
3487 static void close_cb(GtkAction *action, gpointer data)
3489 addressbook_close();
3492 static void addressbook_file_save_cb( GtkAction *action, gpointer data ) {
3493 addressbook_export_to_file();
3496 static void addressbook_person_expand_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3498 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3499 if( person ) addritem_person_set_opened( person, TRUE );
3503 static void addressbook_person_collapse_node( GtkCMCTree *ctree, GList *node, gpointer *data ) {
3505 ItemPerson *person = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(node) );
3506 if( person ) addritem_person_set_opened( person, FALSE );
3510 static gchar *addressbook_format_item_clist( ItemPerson *person, ItemEMail *email ) {
3512 gchar *eMailAlias = ADDRITEM_NAME(email);
3513 if( eMailAlias && *eMailAlias != '\0' ) {
3515 str = g_strdup_printf( "%s - %s", ADDRITEM_NAME(person), eMailAlias );
3518 str = g_strdup( eMailAlias );
3524 static void addressbook_load_group( GtkCMCTree *clist, ItemGroup *itemGroup ) {
3525 GList *items = itemGroup->listEMail;
3526 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3527 for( ; items != NULL; items = g_list_next( items ) ) {
3528 GtkCMCTreeNode *nodeEMail = NULL;
3529 gchar *text[N_LIST_COLS];
3530 ItemEMail *email = items->data;
3534 if( ! email ) continue;
3536 person = ( ItemPerson * ) ADDRITEM_PARENT(email);
3537 str = addressbook_format_item_clist( person, email );
3539 text[COL_NAME] = addressbook_set_col_name_guard(str);
3542 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3544 text[COL_ADDRESS] = email->address;
3545 text[COL_REMARKS] = email->remarks;
3546 nodeEMail = gtk_sctree_insert_node(
3548 text, FOLDER_SPACING,
3552 gtk_cmctree_node_set_row_data( clist, nodeEMail, email );
3558 gchar *addressbook_set_col_name_guard(gchar *value)
3560 gchar *ret = "<not set>";
3561 gchar *tmp = g_strdup(value);
3563 if (tmp !=NULL && *tmp != '\0')
3569 static void addressbook_folder_load_one_person(
3570 GtkCMCTree *clist, ItemPerson *person,
3571 AddressTypeControlItem *atci,
3572 AddressTypeControlItem *atciMail )
3574 GtkCMCTreeNode *nodePerson = NULL;
3575 GtkCMCTreeNode *nodeEMail = NULL;
3576 gchar *text[N_LIST_COLS];
3577 gboolean flgFirst = TRUE, haveAddr = FALSE;
3580 AddressBookFile *abf = addressbook_get_book_file();
3583 if( person == NULL ) return;
3585 text[COL_NAME] = "";
3586 node = person->listEMail;
3588 ItemEMail *email = node->data;
3589 gchar *eMailAddr = NULL;
3590 node = g_list_next( node );
3592 text[COL_ADDRESS] = email->address;
3593 text[COL_REMARKS] = email->remarks;
3594 eMailAddr = ADDRITEM_NAME(email);
3595 if( eMailAddr && *eMailAddr == '\0' ) eMailAddr = NULL;
3597 /* First email belongs with person */
3598 gchar *str = addressbook_format_item_clist( person, email );
3600 text[COL_NAME] = addressbook_set_col_name_guard(str);
3603 else if( abf && abf->type == ADDR_IF_LDAP &&
3604 person && person->nickName ) {
3605 if (person->nickName) {
3606 if (strcmp(person->nickName, "") != 0) {
3607 text[COL_NAME] = addressbook_set_col_name_guard(person->nickName);
3610 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3616 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3618 nodePerson = gtk_sctree_insert_node(
3620 text, FOLDER_SPACING,
3623 FALSE, person->isOpened );
3626 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3629 /* Subsequent email is a child node of person */
3630 text[COL_NAME] = ADDRITEM_NAME(email);
3631 nodeEMail = gtk_sctree_insert_node(
3632 clist, nodePerson, NULL,
3633 text, FOLDER_SPACING,
3635 atciMail->iconXpmOpen,
3637 gtk_cmctree_node_set_row_data(clist, nodeEMail, email );
3643 /* Have name without EMail */
3644 text[COL_NAME] = addressbook_set_col_name_guard(ADDRITEM_NAME(person));
3645 text[COL_ADDRESS] = "";
3646 text[COL_REMARKS] = "";
3647 nodePerson = gtk_sctree_insert_node(
3649 text, FOLDER_SPACING,
3652 FALSE, person->isOpened );
3653 gtk_cmctree_node_set_row_data(clist, nodePerson, person );
3658 static void addressbook_folder_load_person( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3660 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3661 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3663 if( atci == NULL ) return;
3664 if( atciMail == NULL ) return;
3666 /* Load email addresses */
3667 items = addritem_folder_get_person_list( itemFolder );
3668 for( ; items != NULL; items = g_list_next( items ) ) {
3669 addressbook_folder_load_one_person( clist, items->data, atci, atciMail );
3671 /* Free up the list */
3672 mgu_clear_list( items );
3673 g_list_free( items );
3676 static void addressbook_folder_remove_node( GtkCMCTree *clist, GtkCMCTreeNode *node ) {
3677 addrbook.listSelected = NULL;
3678 gtk_cmctree_remove_node( clist, node );
3679 addressbook_menubar_set_sensitive( FALSE );
3680 addressbook_menuitem_set_sensitive(
3681 gtk_cmctree_node_get_row_data(
3682 GTK_CMCTREE(clist), addrbook.treeSelected ),
3683 addrbook.treeSelected );
3686 static void addressbook_folder_refresh_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3687 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_PERSON );
3688 AddressTypeControlItem *atciMail = addrbookctl_lookup( ADDR_ITEM_EMAIL );
3689 GtkCMCTreeNode *node;
3690 if( atci == NULL ) return;
3691 if( atciMail == NULL ) return;
3692 if( person == NULL ) return;
3693 /* unload the person */
3695 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3697 addressbook_folder_remove_node( clist, node );
3698 addressbook_folder_load_one_person( clist, person, atci, atciMail );
3699 gtk_sctree_sort_node( clist, NULL );
3700 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3702 gtk_sctree_select( GTK_SCTREE(clist), node );
3703 if (!gtk_cmctree_node_is_visible( clist, node ) )
3704 gtk_cmctree_node_moveto( clist, node, 0, 0, 0 );
3708 static void addressbook_folder_remove_one_person( GtkCMCTree *clist, ItemPerson *person ) {
3709 GtkCMCTreeNode *node;
3712 if( person == NULL ) return;
3713 node = gtk_cmctree_find_by_row_data( clist, NULL, person );
3714 row = gtk_cmclist_find_row_from_data( GTK_CMCLIST(clist), person );
3716 addressbook_folder_remove_node( clist, node );
3720 static void addressbook_folder_load_group( GtkCMCTree *clist, ItemFolder *itemFolder ) {
3722 AddressTypeControlItem *atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
3724 /* Load any groups */
3725 if( ! atci ) return;
3726 items = addritem_folder_get_group_list( itemFolder );
3727 for( ; items != NULL; items = g_list_next( items ) ) {
3728 GtkCMCTreeNode *nodeGroup = NULL;
3729 gchar *text[N_LIST_COLS];
3730 ItemGroup *group = items->data;
3731 if( group == NULL ) continue;
3732 text[COL_NAME] = ADDRITEM_NAME(group);
3733 text[COL_ADDRESS] = "";
3734 text[COL_REMARKS] = "";
3735 nodeGroup = gtk_sctree_insert_node(clist, NULL, NULL,
3736 text, FOLDER_SPACING,
3740 gtk_cmctree_node_set_row_data(clist, nodeGroup, group );
3741 gtk_sctree_sort_node(clist, NULL);
3743 /* Free up the list */
3744 mgu_clear_list( items );
3745 g_list_free( items );
3749 * Search ctree widget callback function.
3750 * \param pA Pointer to node.
3751 * \param pB Pointer to data item being sought.
3752 * \return Zero (0) if group found.
3754 static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer pB ) {
3757 aoA = ( AddressObject * ) pA;
3758 if( aoA->type == ADDR_ITEM_GROUP ) {
3759 ItemGroup *group, *grp;
3761 grp = ADAPTER_GROUP(aoA)->itemGroup;
3762 group = ( ItemGroup * ) pB;
3763 if( grp == group ) return 0; /* Found group */
3769 * Remove folder and group nodes from tree widget for items contained ("cut")
3772 static void addressbook_treenode_remove_item( void ) {
3774 AddrSelectItem *cutItem;
3775 AddressCache *cache;
3776 AddrItemObject *aio;
3777 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3780 node = _clipBoard_->objectList;
3782 cutItem = node->data;
3783 node = g_list_next( node );
3784 cache = addrindex_get_cache(
3785 _clipBoard_->addressIndex, cutItem->cacheID );
3786 if( cache == NULL ) continue;
3787 aio = addrcache_get_object( cache, cutItem->uid );
3790 if( ADDRITEM_TYPE(aio) == ITEMTYPE_FOLDER ) {
3793 folder = ( ItemFolder * ) aio;
3794 tn = gtk_cmctree_find_by_row_data_custom(
3795 ctree, NULL, folder,
3796 addressbook_treenode_find_folder_cb );
3798 else if( ADDRITEM_TYPE(aio) == ITEMTYPE_GROUP ) {
3801 group = ( ItemGroup * ) aio;
3802 tn = gtk_cmctree_find_by_row_data_custom(
3804 addressbook_treenode_find_group_cb );
3808 /* Free up adapter and remove node. */
3809 gtk_cmctree_remove_node( ctree, tn );
3816 * Find parent datasource for specified tree node.
3817 * \param node Node to test.
3818 * \return Data source, or NULL if not found.
3820 static AddressDataSource *addressbook_find_datasource( GtkCMCTreeNode *node ) {
3821 AddressDataSource *ds = NULL;
3824 cm_return_val_if_fail(addrbook.ctree != NULL, NULL);
3827 if( GTK_CMCTREE_ROW(node)->level < 2 ) return NULL;
3828 ao = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), node );
3830 /* g_print( "ao->type = %d\n", ao->type ); */
3831 if( ao->type == ADDR_DATASOURCE ) {
3832 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3833 /* g_print( "found it\n" ); */
3834 ds = ads->dataSource;
3838 node = GTK_CMCTREE_ROW(node)->parent;
3844 * Load address list widget with children of specified object.
3845 * \param obj Parent object to be loaded.
3847 static void addressbook_set_clist( AddressObject *obj, gboolean refresh ) {
3848 GtkCMCTree *ctreelist = GTK_CMCTREE(addrbook.clist);
3849 GtkCMCList *clist = GTK_CMCLIST(addrbook.clist);
3850 AddressDataSource *ds = NULL;
3851 AdapterDSource *ads = NULL;
3852 static AddressObject *last_obj = NULL;
3854 if (addrbook.clist == NULL) {
3857 if (obj == last_obj && !refresh)
3862 gtk_cmclist_clear(clist);
3866 if( obj->type == ADDR_INTERFACE ) {
3867 /* g_print( "set_clist: loading datasource...\n" ); */
3868 /* addressbook_node_load_datasource( GTK_CMCTREE(clist), obj ); */
3872 gtk_cmclist_freeze(clist);
3873 gtk_cmclist_clear(clist);
3875 if( obj->type == ADDR_DATASOURCE ) {
3876 ads = ADAPTER_DSOURCE(obj);
3877 ds = ADAPTER_DSOURCE(obj)->dataSource;
3879 /* Load root folder */
3880 ItemFolder *rootFolder = NULL;
3881 rootFolder = addrindex_ds_get_root_folder( ds );
3882 addressbook_folder_load_person(
3883 ctreelist, addrindex_ds_get_root_folder( ds ) );
3884 addressbook_folder_load_group(
3885 ctreelist, addrindex_ds_get_root_folder( ds ) );
3889 if( obj->type == ADDR_ITEM_GROUP ) {
3891 ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup;
3892 addressbook_load_group( ctreelist, itemGroup );
3894 else if( obj->type == ADDR_ITEM_FOLDER ) {
3896 ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder;
3897 addressbook_folder_load_person( ctreelist, itemFolder );
3898 addressbook_folder_load_group( ctreelist, itemFolder );
3901 gtk_sctree_sort_recursive(GTK_CMCTREE(clist), NULL);
3902 clist->focus_row = -1;
3903 gtk_cmclist_thaw(clist);
3907 * Call back function to free adaptor. Call back is setup by function
3908 * gtk_cmctree_node_set_row_data_full() when node is populated. This function is
3909 * called when the address book tree widget node is removed by calling
3910 * function gtk_cmctree_remove_node().
3912 * \param data Tree node's row data.
3914 static void addressbook_free_treenode( gpointer data ) {
3917 ao = ( AddressObject * ) data;
3918 if( ao == NULL ) return;
3919 if( ao->type == ADDR_INTERFACE ) {
3920 AdapterInterface *ai = ADAPTER_INTERFACE(ao);
3921 addrbookctl_free_interface( ai );
3923 else if( ao->type == ADDR_DATASOURCE ) {
3924 AdapterDSource *ads = ADAPTER_DSOURCE(ao);
3925 addrbookctl_free_datasource( ads );
3927 else if( ao->type == ADDR_ITEM_FOLDER ) {
3928 AdapterFolder *af = ADAPTER_FOLDER(ao);
3929 addrbookctl_free_folder( af );
3931 else if( ao->type == ADDR_ITEM_GROUP ) {
3932 AdapterGroup *ag = ADAPTER_GROUP(ao);
3933 addrbookctl_free_group( ag );
3938 * Create new adaptor for specified data source.
3940 AdapterDSource *addressbook_create_ds_adapter( AddressDataSource *ds,
3941 AddressObjectType otype, gchar *name )
3943 AdapterDSource *adapter = g_new0( AdapterDSource, 1 );
3944 ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE;
3945 ADDRESS_OBJECT_NAME(adapter) = g_strdup( name );
3946 adapter->dataSource = ds;
3947 adapter->subType = otype;
3951 void addressbook_ads_set_name( AdapterDSource *adapter, gchar *value ) {
3952 ADDRESS_OBJECT_NAME(adapter) =
3953 mgu_replace_string( ADDRESS_OBJECT_NAME(adapter), value );
3957 * Load tree from address index with the initial data.
3959 static void addressbook_load_tree( void ) {
3960 GtkCMCTree *ctree = GTK_CMCTREE( addrbook.ctree );
3961 GList *nodeIf, *nodeDS;
3962 AdapterInterface *adapter;
3963 AddressInterface *iface;
3964 AddressTypeControlItem *atci;
3965 AddressDataSource *ds;
3966 AdapterDSource *ads;
3967 GtkCMCTreeNode *node, *newNode;
3970 nodeIf = _addressInterfaceList_;
3972 adapter = nodeIf->data;
3973 node = adapter->treeNode;
3974 iface = adapter->interface;
3975 atci = adapter->atci;
3977 if( iface->useInterface ) {
3978 /* Load data sources below interface node */
3979 nodeDS = iface->listSource;
3983 name = addrindex_ds_get_name( ds );
3984 ads = addressbook_create_ds_adapter(
3985 ds, atci->objectType, name );
3986 newNode = addressbook_add_object(
3987 node, ADDRESS_OBJECT(ads) );
3988 nodeDS = g_list_next( nodeDS );
3990 gtk_cmctree_expand( ctree, node );
3993 nodeIf = g_list_next( nodeIf );
3998 * Convert the old address book to new format.
4000 static gboolean addressbook_convert( AddressIndex *addrIndex ) {
4001 gboolean retVal = FALSE;
4002 gboolean errFlag = TRUE;
4005 /* Read old address book, performing conversion */
4006 debug_print( "Reading and converting old address book...\n" );
4007 addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE );
4008 addrindex_read_data( addrIndex );
4009 if( addrIndex->retVal == MGU_NO_FILE ) {
4010 /* We do not have a file - new user */
4011 debug_print( "New user... create new books...\n" );
4012 addrindex_create_new_books( addrIndex );
4013 if( addrIndex->retVal == MGU_SUCCESS ) {
4014 /* Save index file */
4015 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4016 addrindex_save_data( addrIndex );
4017 if( addrIndex->retVal == MGU_SUCCESS ) {
4022 msg = _( "New user, could not save index file." );
4026 msg = _( "New user, could not save address book files." );
4030 /* We have an old file */
4031 if( addrIndex->wasConverted ) {
4032 /* Converted successfully - save address index */
4033 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4034 addrindex_save_data( addrIndex );
4035 if( addrIndex->retVal == MGU_SUCCESS ) {
4036 msg = _( "Old address book converted successfully." );
4041 msg = _("Old address book converted,\n"
4042 "could not save new address index file." );
4046 /* File conversion failed - just create new books */
4047 debug_print( "File conversion failed... just create new books...\n" );
4048 addrindex_create_new_books( addrIndex );
4049 if( addrIndex->retVal == MGU_SUCCESS ) {
4051 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4052 addrindex_save_data( addrIndex );
4053 if( addrIndex->retVal == MGU_SUCCESS ) {
4054 msg = _("Could not convert address book,\n"
4055 "but created empty new address book files." );
4060 msg = _("Could not convert address book,\n"
4061 "could not save new address index file." );
4065 msg = _("Could not convert address book\n"
4066 "and could not create new address book files." );
4071 debug_print( "Error\n%s\n", msg );
4072 alertpanel_full(_("Addressbook conversion error"), msg,
4073 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4074 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4077 debug_print( "Warning\n%s\n", msg );
4078 alertpanel_full(_("Addressbook conversion error"), msg,
4079 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4080 NULL, ALERT_WARNING, G_ALERTDEFAULT);
4086 static gboolean migrate_addrbook(const gchar *origdir, const gchar *destdir)
4090 gboolean failed = FALSE;
4092 if( ( dp = opendir( origdir ) ) == NULL ) {
4096 while( ( d = readdir( dp ) ) != NULL ) {
4097 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4100 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4102 gchar *dest_file = g_strconcat(destdir, G_DIR_SEPARATOR_S,
4104 if (copy_file(orig_file, dest_file, FALSE) < 0) {
4117 /* all copies succeeded, we can remove source files */
4118 if( ( dp = opendir( origdir ) ) == NULL ) {
4121 while( ( d = readdir( dp ) ) != NULL ) {
4122 if (strncmp(d->d_name, "addrbook-", strlen("addrbook-")))
4125 gchar *orig_file = g_strconcat(origdir, G_DIR_SEPARATOR_S,
4127 claws_unlink(orig_file);
4137 void addressbook_read_file( void ) {
4138 AddressIndex *addrIndex = NULL;
4139 gchar *indexdir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, NULL);
4141 debug_print( "Reading address index...\n" );
4142 if( _addressIndex_ ) {
4143 debug_print( "address book already read!!!\n" );
4147 addrIndex = addrindex_create_index();
4148 addrindex_initialize();
4150 /* Use new address book index. */
4152 if ( !is_dir_exist(indexdir) ) {
4153 if ( make_dir(indexdir) < 0 ) {
4154 addrindex_set_file_path( addrIndex, get_rc_dir() );
4155 g_warning( "couldn't create dir %s\n", indexdir);
4157 if (!migrate_addrbook(get_rc_dir(), indexdir)) {
4158 remove_dir_recursive(indexdir);
4159 addrindex_set_file_path( addrIndex, get_rc_dir() );
4160 g_error("couldn't migrate dir %s", indexdir);
4162 addrindex_set_file_path( addrIndex, indexdir);
4166 addrindex_set_file_path( addrIndex, indexdir);
4169 addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE );
4170 addrindex_read_data( addrIndex );
4171 if( addrIndex->retVal == MGU_NO_FILE ) {
4172 /* Conversion required */
4173 debug_print( "Converting...\n" );
4174 if( addressbook_convert( addrIndex ) ) {
4175 _addressIndex_ = addrIndex;
4178 else if( addrIndex->retVal == MGU_SUCCESS ) {
4179 _addressIndex_ = addrIndex;
4182 /* Error reading address book */
4183 debug_print( "Could not read address index.\n" );
4184 addrindex_print_index( addrIndex, stdout );
4185 alertpanel_full(_("Addressbook Error"),
4186 _("Could not read address index"),
4187 GTK_STOCK_CLOSE, NULL, NULL, FALSE,
4188 NULL, ALERT_ERROR, G_ALERTDEFAULT);
4190 debug_print( "done.\n" );
4194 * Add object into the address index tree widget.
4195 * Enter: node Parent node.
4196 * obj Object to add.
4197 * Return: Node that was added, or NULL if object not added.
4199 static GtkCMCTreeNode *addressbook_add_object(GtkCMCTreeNode *node,
4202 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4203 GtkCMCTreeNode *added;
4204 AddressObject *pobj;
4205 AddressObjectType otype;
4206 AddressTypeControlItem *atci = NULL;
4208 cm_return_val_if_fail(node != NULL, NULL);
4209 cm_return_val_if_fail(obj != NULL, NULL);
4211 pobj = gtk_cmctree_node_get_row_data(ctree, node);
4212 cm_return_val_if_fail(pobj != NULL, NULL);
4214 /* Determine object type to be displayed */
4215 if( obj->type == ADDR_DATASOURCE ) {
4216 otype = ADAPTER_DSOURCE(obj)->subType;
4222 /* Handle any special conditions. */
4224 atci = addrbookctl_lookup( otype );
4226 if( atci->showInTree ) {
4227 /* Add object to tree */
4230 added = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4231 atci->iconXpm, atci->iconXpmOpen,
4232 atci->treeLeaf, atci->treeExpand );
4233 gtk_cmctree_node_set_row_data_full( ctree, added, obj,
4234 addressbook_free_treenode );
4238 gtk_sctree_sort_node(ctree, node);
4244 * Add group into the address index tree.
4245 * \param node Parent node.
4246 * \param ds Data source.
4247 * \param itemGroup Group to add.
4248 * \return Inserted node.
4250 static GtkCMCTreeNode *addressbook_node_add_group(
4251 GtkCMCTreeNode *node, AddressDataSource *ds,
4252 ItemGroup *itemGroup )
4254 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4255 GtkCMCTreeNode *newNode;
4256 AdapterGroup *adapter;
4257 AddressTypeControlItem *atci = NULL;
4260 if( ds == NULL ) return NULL;
4261 if( node == NULL || itemGroup == NULL ) return NULL;
4263 name = &itemGroup->obj.name;
4265 atci = addrbookctl_lookup( ADDR_ITEM_GROUP );
4267 adapter = g_new0( AdapterGroup, 1 );
4268 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP;
4269 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemGroup) );
4270 adapter->itemGroup = itemGroup;
4272 newNode = gtk_sctree_insert_node( ctree, node, NULL, name, FOLDER_SPACING,
4273 atci->iconXpm, atci->iconXpm,
4274 atci->treeLeaf, atci->treeExpand );
4275 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4276 addressbook_free_treenode );
4277 gtk_sctree_sort_node( ctree, node );
4282 * Add folder into the address index tree. Only visible folders are loaded into
4283 * the address index tree. Note that the root folder is not inserted into the
4286 * \param node Parent node.
4287 * \param ds Data source.
4288 * \param itemFolder Folder to add.
4289 * \param otype Object type to display.
4290 * \return Inserted node for the folder.
4292 static GtkCMCTreeNode *addressbook_node_add_folder(
4293 GtkCMCTreeNode *node, AddressDataSource *ds,
4294 ItemFolder *itemFolder, AddressObjectType otype )
4296 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
4297 GtkCMCTreeNode *newNode = NULL;
4298 AdapterFolder *adapter;
4299 AddressTypeControlItem *atci = NULL;
4300 GList *listItems = NULL;
4302 ItemFolder *rootFolder;
4304 /* Only visible folders */
4305 if( itemFolder == NULL || itemFolder->isHidden )
4310 if( node == NULL || itemFolder == NULL )
4313 /* Determine object type */
4314 atci = addrbookctl_lookup( otype );
4318 rootFolder = addrindex_ds_get_root_folder( ds );
4319 if( itemFolder == rootFolder ) {
4323 adapter = g_new0( AdapterFolder, 1 );
4324 ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER;
4325 ADDRESS_OBJECT_NAME(adapter) = g_strdup( ADDRITEM_NAME(itemFolder) );
4326 adapter->itemFolder = itemFolder;
4328 name = ADDRITEM_NAME(itemFolder);
4329 newNode = gtk_sctree_insert_node( ctree, node, NULL, &name, FOLDER_SPACING,
4330 atci->iconXpm, atci->iconXpm,
4331 atci->treeLeaf, atci->treeExpand );
4333 gtk_cmctree_node_set_row_data_full( ctree, newNode, adapter,
4334 addressbook_free_treenode );
4338 listItems = itemFolder->listFolder;
4339 while( listItems ) {
4340 ItemFolder *item = listItems->data;
4341 addressbook_node_add_folder( newNode, ds, item, otype );
4342 listItems = g_list_next( listItems );
4344 listItems = itemFolder->listGroup;
4345 while( listItems ) {
4346 ItemGroup *item = listItems->data;
4347 addressbook_node_add_group( newNode, ds, item );
4348 listItems = g_list_next( listItems );
4350 gtk_sctree_sort_node( ctree, node );
4354 void addressbook_export_to_file( void ) {
4355 if( _addressIndex_ ) {
4356 /* Save all new address book data */
4357 debug_print( "Saving address books...\n" );
4358 addrindex_save_all_books( _addressIndex_ );
4360 debug_print( "Exporting addressbook to file...\n" );
4361 addrindex_save_data( _addressIndex_ );
4362 if( _addressIndex_->retVal != MGU_SUCCESS ) {
4363 addrindex_print_index( _addressIndex_, stdout );
4366 /* Notify address completion of new data */
4367 invalidate_address_completion();
4371 static gboolean addressbook_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
4373 if (event && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter))
4374 addressbook_lup_clicked(NULL, NULL);
4379 * Comparison using cell contents (text in first column). Used for sort
4380 * address index widget.
4382 static gint addressbook_treenode_compare_func(
4383 GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
4385 GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
4386 GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
4387 gchar *name1 = NULL, *name2 = NULL;
4388 if( cell1 ) name1 = cell1->u.text;
4389 if( cell2 ) name2 = cell2->u.text;
4390 if( ! name1 ) return ( name2 != NULL );
4391 if( ! name2 ) return -1;
4392 return g_utf8_collate( name1, name2 );
4395 static void addressbook_new_book_cb( GtkAction *action, gpointer data ) {
4396 AdapterDSource *ads;
4397 AdapterInterface *adapter;
4398 GtkCMCTreeNode *newNode;
4400 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
4401 if( adapter == NULL ) return;
4402 ads = addressbook_edit_book( _addressIndex_, NULL );
4404 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4406 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4407 addrbook.treeSelected = newNode;
4412 static void addressbook_new_vcard_cb( GtkAction *action, gpointer data ) {
4413 AdapterDSource *ads;
4414 AdapterInterface *adapter;
4415 GtkCMCTreeNode *newNode;
4417 adapter = addrbookctl_find_interface( ADDR_IF_VCARD );
4418 if( adapter == NULL ) return;
4419 ads = addressbook_edit_vcard( _addressIndex_, NULL );
4421 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4423 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4424 addrbook.treeSelected = newNode;
4430 static void addressbook_new_jpilot_cb( GtkAction *action, gpointer data ) {
4431 AdapterDSource *ads;
4432 AdapterInterface *adapter;
4433 AddressInterface *iface;
4434 GtkCMCTreeNode *newNode;
4436 adapter = addrbookctl_find_interface( ADDR_IF_JPILOT );
4437 if( adapter == NULL ) return;
4438 iface = adapter->interface;
4439 if( ! iface->haveLibrary ) return;
4440 ads = addressbook_edit_jpilot( _addressIndex_, NULL );
4442 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4444 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4445 addrbook.treeSelected = newNode;
4452 static void addressbook_new_ldap_cb( GtkAction *action, gpointer data ) {
4453 AdapterDSource *ads;
4454 AdapterInterface *adapter;
4455 AddressInterface *iface;
4456 GtkCMCTreeNode *newNode;
4458 adapter = addrbookctl_find_interface( ADDR_IF_LDAP );
4459 if( adapter == NULL ) return;
4460 iface = adapter->interface;
4461 if( ! iface->haveLibrary ) return;
4462 ads = addressbook_edit_ldap( _addressIndex_, NULL );
4464 newNode = addressbook_add_object( adapter->treeNode, ADDRESS_OBJECT(ads) );
4466 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), newNode );
4467 addrbook.treeSelected = newNode;
4474 * Display address search status message.
4475 * \param queryType Query type.
4476 * \param status Status/Error code.
4478 static void addressbook_search_message( gint queryType, gint sts ) {
4480 *addressbook_msgbuf = '\0';
4482 if( sts != MGU_SUCCESS ) {
4483 if( queryType == ADDRQUERY_LDAP ) {
4485 desc = addressbook_err2string( _lutErrorsLDAP_, sts );
4490 g_snprintf( addressbook_msgbuf,
4491 sizeof(addressbook_msgbuf), "%s", desc );
4492 addressbook_status_show( addressbook_msgbuf );
4495 addressbook_status_show( "" );
4500 * Refresh addressbook by forcing refresh of current selected object in
4503 static void addressbook_refresh_current( void ) {
4507 ctree = GTK_CMCTREE(addrbook.ctree);
4508 obj = gtk_cmctree_node_get_row_data( ctree, addrbook.treeSelected );
4509 if( obj == NULL ) return;
4510 addressbook_set_clist( obj, TRUE );
4514 * Message that is displayed whilst a query is executing in a background
4517 static gchar *_tempMessage_ = N_( "Busy searching..." );
4520 * Address search idle function. This function is called during UI idle time
4521 * while a search is in progress.
4523 * \param data Idler data.
4525 static void addressbook_search_idle( gpointer data ) {
4529 queryID = GPOINTER_TO_INT( data );
4530 g_print( "addressbook_ldap_idle... queryID=%d\n", queryID );
4535 * Search completion callback function. This removes the query from the idle
4538 * \param sender Sender of query.
4539 * \param queryID Query ID of search request.
4540 * \param status Search status.
4541 * \param data Query data.
4543 static void addressbook_search_callback_end(
4544 gpointer sender, gint queryID, gint status, gpointer data )
4548 AddrQueryObject *aqo;
4550 /* Remove idler function */
4551 ptrQID = GINT_TO_POINTER( queryID );
4553 g_idle_remove_by_data( ptrQID );
4556 /* Refresh addressbook contents */
4557 addressbook_refresh_current();
4558 req = qrymgr_find_request( queryID );
4560 aqo = ( AddrQueryObject * ) req->queryList->data;
4561 addressbook_search_message( aqo->queryType, status );
4564 /* Stop the search */
4565 addrindex_stop_search( queryID );
4571 * \param ds Data source to search.
4572 * \param searchTerm String to lookup.
4573 * \param pNode Parent data source node.
4575 static void addressbook_perform_search(
4576 AddressDataSource *ds, gchar *searchTerm,
4577 GtkCMCTreeNode *pNode )
4579 AddrBookBase *adbase;
4580 AddressCache *cache;
4586 AddressObjectType aoType = ADDR_NONE;
4590 if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
4592 if( ds && ds->type == ADDR_IF_LDAP ) {
4594 aoType = ADDR_LDAP_QUERY;
4600 /* Get reference to address cache */
4601 adbase = ( AddrBookBase * ) ds->rawDataSource;
4602 cache = adbase->addressCache;
4604 /* Create a folder for the search results */
4605 name = g_strdup_printf( _queryFolderLabel_, searchTerm );
4606 folder = addressbook_setup_subf(ds, name, pNode);
4609 /* Setup the search */
4610 queryID = addrindex_setup_explicit_search(
4611 ds, searchTerm, folder, addressbook_search_callback_end, NULL );
4612 if( queryID == 0 ) return;
4614 /* Set up idler function */
4615 idleID = g_idle_add(
4616 (GSourceFunc) addressbook_search_idle,
4617 GINT_TO_POINTER( queryID ) );
4619 /* Start search, sit back and wait for something to happen */
4620 addrindex_start_search( queryID );
4622 addressbook_status_show( _tempMessage_ );
4626 * Lookup button handler. Address search is only performed against
4627 * address interfaces for external queries.
4629 * \param button Lookup button widget.
4630 * \param data Data object.
4632 static void addressbook_lup_clicked( GtkButton *button, gpointer data ) {
4635 AddressDataSource *ds;
4636 AddressInterface *iface;
4638 GtkCMCTreeNode *node, *parentNode;
4640 node = addrbook.treeSelected;
4641 if( ! node ) return;
4642 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
4644 ctree = GTK_CMCTREE(addrbook.ctree);
4645 obj = gtk_cmctree_node_get_row_data( ctree, node );
4646 if( obj == NULL ) return;
4648 ds = addressbook_find_datasource( node );
4649 if( ds == NULL ) return;
4651 /* We must have a datasource that is an external interface */
4652 iface = ds->interface;
4653 if( ! iface->haveLibrary ) return;
4654 if( ! iface->externalQuery ) return;
4657 gtk_editable_get_chars( GTK_EDITABLE(addrbook.entry), 0, -1 );
4658 g_strchomp( searchTerm );
4660 if( obj->type == ADDR_ITEM_FOLDER ) {
4661 parentNode = GTK_CMCTREE_ROW(node)->parent;
4666 addressbook_perform_search( ds, searchTerm, parentNode );
4668 gtk_widget_grab_focus( addrbook.entry );
4670 g_free( searchTerm );
4673 static void addressbook_close_clicked( GtkButton *button, gpointer data ) {
4674 addressbook_close();
4679 * Browse address entry for highlighted entry.
4681 static void addressbook_browse_entry_cb( GtkAction *action, gpointer data)
4683 GtkCMCTree *clist = GTK_CMCTREE(addrbook.clist);
4685 AddressDataSource *ds;
4686 AddressInterface *iface;
4690 if(addrbook.listSelected == NULL)
4693 obj = gtk_cmctree_node_get_row_data(clist, addrbook.listSelected);
4697 ds = addressbook_find_datasource(GTK_CMCTREE_NODE(addrbook.treeSelected));
4701 iface = ds->interface;
4702 if(!iface || !iface->haveLibrary )
4706 if (obj->type == ADDR_ITEM_EMAIL) {
4707 email = ( ItemEMail * ) obj;
4711 person = (ItemPerson *) ADDRITEM_PARENT(email);
4713 else if (obj->type == ADDR_ITEM_PERSON) {
4714 person = (ItemPerson *) obj;
4721 if( iface && iface->type == ADDR_IF_LDAP ) {
4722 browseldap_entry(ds, person->externalID);
4727 /* **********************************************************************
4728 * Build lookup tables.
4729 * ***********************************************************************
4733 * Remap object types.
4734 * Enter: abType AddressObjectType (used in tree node).
4735 * Return: ItemObjectType (used in address cache data).
4737 ItemObjectType addressbook_type2item( AddressObjectType abType ) {
4738 ItemObjectType ioType;
4741 case ADDR_ITEM_PERSON: ioType = ITEMTYPE_PERSON; break;
4742 case ADDR_ITEM_EMAIL: ioType = ITEMTYPE_EMAIL; break;
4743 case ADDR_ITEM_FOLDER: ioType = ITEMTYPE_FOLDER; break;
4744 case ADDR_ITEM_GROUP: ioType = ITEMTYPE_GROUP; break;
4745 case ADDR_DATASOURCE: ioType = ITEMTYPE_DATASOURCE; break;
4746 default: ioType = ITEMTYPE_NONE; break;
4751 #define UPDATE_ICON_ATCI(id,icon,iconopen) { \
4752 atci = addrbookctl_lookup(id); \
4754 atci->iconXpm = icon; \
4755 atci->iconXpmOpen = iconopen; \
4757 g_warning("can't get atci %d\n", id); \
4762 * Build table that controls the rendering of object types.
4764 static void addrbookctl_build_icons( GtkWidget *window ) {
4765 AddressTypeControlItem *atci;
4769 g_object_unref(interfacexpm);
4771 g_object_unref(folderxpm);
4773 g_object_unref(folderopenxpm);
4775 g_object_unref(groupxpm);
4777 g_object_unref(vcardxpm);
4779 g_object_unref(bookxpm);
4781 g_object_unref(addressxpm);
4783 g_object_unref(jpilotxpm);
4785 g_object_unref(categoryxpm);
4787 g_object_unref(ldapxpm);
4789 g_object_unref(addrsearchxpm);
4790 stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacexpm );
4791 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
4792 stock_pixbuf_gdk(window, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
4793 stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &groupxpm);
4794 stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardxpm);
4795 stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookxpm);
4796 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addressxpm);
4797 stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotxpm);
4798 stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categoryxpm);
4799 stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldapxpm);
4800 stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS_SEARCH, &addrsearchxpm);
4802 UPDATE_ICON_ATCI(ADDR_INTERFACE,folderxpm,folderopenxpm);
4803 UPDATE_ICON_ATCI(ADDR_BOOK,bookxpm,bookxpm);
4804 UPDATE_ICON_ATCI(ADDR_ITEM_PERSON,NULL,NULL);
4805 UPDATE_ICON_ATCI(ADDR_ITEM_EMAIL,addressxpm,addressxpm);
4806 UPDATE_ICON_ATCI(ADDR_ITEM_GROUP,groupxpm,groupxpm);
4807 UPDATE_ICON_ATCI(ADDR_ITEM_FOLDER,folderxpm,folderopenxpm);
4808 UPDATE_ICON_ATCI(ADDR_VCARD,vcardxpm,vcardxpm);
4809 UPDATE_ICON_ATCI(ADDR_JPILOT,jpilotxpm,jpilotxpm);
4810 UPDATE_ICON_ATCI(ADDR_CATEGORY,categoryxpm,categoryxpm);
4811 UPDATE_ICON_ATCI(ADDR_LDAP,ldapxpm,ldapxpm);
4812 UPDATE_ICON_ATCI(ADDR_LDAP_QUERY,addrsearchxpm,addrsearchxpm);
4817 * Build table that controls the rendering of object types.
4819 static void addrbookctl_build_map( GtkWidget *window ) {
4820 AddressTypeControlItem *atci;
4822 _addressBookTypeHash_ = g_hash_table_new( g_int_hash, g_int_equal );
4823 _addressBookTypeList_ = NULL;
4826 atci = g_new0( AddressTypeControlItem, 1 );
4827 atci->objectType = ADDR_INTERFACE;
4828 atci->interfaceType = ADDR_IF_NONE;
4829 atci->showInTree = TRUE;
4830 atci->treeExpand = TRUE;
4831 atci->treeLeaf = FALSE;
4832 atci->displayName = _( "Interface" );
4833 atci->menuCommand = NULL;
4834 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4835 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4838 atci = g_new0( AddressTypeControlItem, 1 );
4839 atci->objectType = ADDR_BOOK;
4840 atci->interfaceType = ADDR_IF_BOOK;
4841 atci->showInTree = TRUE;
4842 atci->treeExpand = TRUE;
4843 atci->treeLeaf = FALSE;
4844 atci->displayName = _( "Address Book" );
4845 atci->menuCommand = "Menu/Book/NewBook";
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_ITEM_PERSON;
4852 atci->interfaceType = ADDR_IF_NONE;
4853 atci->showInTree = FALSE;
4854 atci->treeExpand = FALSE;
4855 atci->treeLeaf = FALSE;
4856 atci->displayName = _( "Person" );
4857 atci->menuCommand = NULL;
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_EMAIL;
4864 atci->interfaceType = ADDR_IF_NONE;
4865 atci->showInTree = FALSE;
4866 atci->treeExpand = FALSE;
4867 atci->treeLeaf = TRUE;
4868 atci->displayName = _( "Email Address" );
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_GROUP;
4876 atci->interfaceType = ADDR_IF_BOOK;
4877 atci->showInTree = TRUE;
4878 atci->treeExpand = FALSE;
4879 atci->treeLeaf = FALSE;
4880 atci->displayName = _( "Group" );
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_FOLDER;
4888 atci->interfaceType = ADDR_IF_BOOK;
4889 atci->showInTree = TRUE;
4890 atci->treeExpand = FALSE;
4891 atci->treeLeaf = FALSE;
4892 atci->displayName = _( "Folder" );
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_VCARD;
4900 atci->interfaceType = ADDR_IF_VCARD;
4901 atci->showInTree = TRUE;
4902 atci->treeExpand = TRUE;
4903 atci->treeLeaf = TRUE;
4904 atci->displayName = _( "vCard" );
4905 atci->menuCommand = "Menu/Book/NewVCard";
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_JPILOT;
4912 atci->interfaceType = ADDR_IF_JPILOT;
4913 atci->showInTree = TRUE;
4914 atci->treeExpand = TRUE;
4915 atci->treeLeaf = FALSE;
4916 atci->displayName = _( "JPilot" );
4917 atci->menuCommand = "Menu/Book/NewJPilot";
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_CATEGORY;
4924 atci->interfaceType = ADDR_IF_JPILOT;
4925 atci->showInTree = TRUE;
4926 atci->treeExpand = TRUE;
4927 atci->treeLeaf = TRUE;
4928 atci->displayName = _( "JPilot" );
4929 atci->menuCommand = NULL;
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_LDAP;
4936 atci->interfaceType = ADDR_IF_LDAP;
4937 atci->showInTree = TRUE;
4938 atci->treeExpand = TRUE;
4939 atci->treeLeaf = FALSE;
4940 atci->displayName = _( "LDAP servers" );
4941 atci->menuCommand = "Menu/Book/NewLDAPServer";
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_QUERY;
4948 atci->interfaceType = ADDR_IF_LDAP;
4949 atci->showInTree = TRUE;
4950 atci->treeExpand = FALSE;
4951 atci->treeLeaf = TRUE;
4952 atci->displayName = _( "LDAP Query" );
4953 atci->menuCommand = NULL;
4954 g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci );
4955 _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci );
4957 addrbookctl_build_icons(window);
4960 void addressbook_reflect_prefs_pixmap_theme(void)
4962 if (addrbook.window)
4963 addrbookctl_build_icons(addrbook.window);
4967 * Search for specified object type.
4969 static AddressTypeControlItem *addrbookctl_lookup( gint ot ) {
4971 return ( AddressTypeControlItem * ) g_hash_table_lookup( _addressBookTypeHash_, &objType );
4975 * Search for specified interface type.
4977 static AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) {
4978 GList *node = _addressBookTypeList_;
4980 AddressTypeControlItem *atci = node->data;
4981 if( atci->interfaceType == ifType ) return atci;
4982 node = g_list_next( node );
4987 static void addrbookctl_free_address( AddressObject *obj ) {
4988 g_free( obj->name );
4989 obj->type = ADDR_NONE;
4993 static void addrbookctl_free_interface( AdapterInterface *adapter ) {
4994 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
4995 adapter->interface = NULL;
4996 adapter->interfaceType = ADDR_IF_NONE;
4997 adapter->atci = NULL;
4998 adapter->enabled = FALSE;
4999 adapter->haveLibrary = FALSE;
5000 adapter->treeNode = NULL;
5004 static void addrbookctl_free_datasource( AdapterDSource *adapter ) {
5005 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5006 adapter->dataSource = NULL;
5007 adapter->subType = ADDR_NONE;
5011 static void addrbookctl_free_folder( AdapterFolder *adapter ) {
5012 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5013 adapter->itemFolder = NULL;
5017 static void addrbookctl_free_group( AdapterGroup *adapter ) {
5018 addrbookctl_free_address( ADDRESS_OBJECT(adapter) );
5019 adapter->itemGroup = NULL;
5024 * Build GUI interface list.
5026 static void addrbookctl_build_iflist( void ) {
5027 AddressTypeControlItem *atci;
5028 AdapterInterface *adapter;
5031 if( _addressIndex_ == NULL ) {
5032 _addressIndex_ = addrindex_create_index();
5033 if( _clipBoard_ == NULL ) {
5034 _clipBoard_ = addrclip_create();
5036 addrclip_set_index( _clipBoard_, _addressIndex_ );
5038 _addressInterfaceList_ = NULL;
5039 list = addrindex_get_interface_list( _addressIndex_ );
5041 AddressInterface *interface = list->data;
5042 atci = addrbookctl_lookup_iface( interface->type );
5044 adapter = g_new0( AdapterInterface, 1 );
5045 adapter->interfaceType = interface->type;
5046 adapter->atci = atci;
5047 adapter->interface = interface;
5048 adapter->treeNode = NULL;
5049 adapter->enabled = TRUE;
5050 adapter->haveLibrary = interface->haveLibrary;
5051 ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE;
5052 ADDRESS_OBJECT_NAME(adapter) = g_strdup( atci->displayName );
5053 _addressInterfaceList_ =
5054 g_list_append( _addressInterfaceList_, adapter );
5056 list = g_list_next( list );
5061 * Find GUI interface type specified interface type.
5062 * \param ifType Interface type.
5063 * \return Interface item, or NULL if not found.
5065 static AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) {
5066 GList *node = _addressInterfaceList_;
5068 AdapterInterface *adapter = node->data;
5069 if( adapter->interfaceType == ifType ) return adapter;
5070 node = g_list_next( node );
5076 * Build interface list selection.
5078 static void addrbookctl_build_ifselect( void ) {
5079 GList *newList = NULL;
5084 gchar *endptr = NULL;
5086 AdapterInterface *adapter;
5088 selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION );
5091 splitStr = g_strsplit( selectStr, ",", -1 );
5092 for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) {
5094 /* g_print( "%d : %s\n", i, splitStr[i] ); */
5095 ifType = strtol( splitStr[i], &endptr, 10 );
5098 if( strcmp( endptr, "/n" ) == 0 ) {
5102 /* g_print( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */
5103 adapter = addrbookctl_find_interface( ifType );
5105 newList = g_list_append( newList, adapter );
5112 /* g_print( "i=%d\n", i ); */
5113 g_strfreev( splitStr );
5114 g_free( selectStr );
5116 /* Replace existing list */
5117 mgu_clear_list( _addressIFaceSelection_ );
5118 g_list_free( _addressIFaceSelection_ );
5119 _addressIFaceSelection_ = newList;
5123 /* ***********************************************************************
5124 * Add sender to address book.
5125 * ***********************************************************************
5129 * This function is used by the Add sender to address book function.
5131 gboolean addressbook_add_contact(
5132 const gchar *name, const gchar *address, const gchar *remarks,
5133 GdkPixbuf *picture )
5135 debug_print( "addressbook_add_contact: name/address: %s - %s\n", name, address );
5136 if( addressadd_selection( _addressIndex_, name, address, remarks, picture ) ) {
5137 debug_print( "addressbook_add_contact - added\n" );
5138 addressbook_refresh();
5143 /* ***********************************************************************
5144 * Book/folder selection.
5145 * ***********************************************************************
5149 * This function is used by the matcher dialog to select a book/folder.
5151 gchar *addressbook_folder_selection( const gchar *folderpath)
5153 AddressBookFile *book = NULL;
5154 ItemFolder *folder = NULL;
5157 cm_return_val_if_fail( folderpath != NULL, NULL);
5159 if ( addressbook_foldersel_selection( _addressIndex_, &book, &folder, folderpath )
5161 if ( folder != NULL) {
5163 gchar *oldtmp = NULL;
5164 AddrItemObject *obj = NULL;
5166 /* walk thru folder->parent to build the full folder path */
5167 /* TODO: wwp: optimize this */
5169 tmp = g_strdup(obj->uid);
5170 while ( obj->parent ) {
5172 if ( obj->name != NULL ) {
5173 oldtmp = g_strdup(tmp);
5175 tmp = g_strdup_printf("%s/%s", obj->uid, oldtmp);
5179 path = g_strdup_printf("%s/%s", book->fileName, tmp);
5182 path = g_strdup_printf("%s", book->fileName);
5184 debug_print( "addressbook_foldersel: %s\n", path?path:"(null)");
5190 /* ***********************************************************************
5191 * Book/folder checking.
5192 * ***********************************************************************
5195 static FolderInfo *addressbook_peek_subfolder_exists_create_folderinfo( AddressBookFile *abf, ItemFolder *folder )
5197 FolderInfo *fi = g_new0( FolderInfo, 1 );
5199 fi->folder = folder;
5203 static void addressbook_peek_subfolder_exists_load_folder( ItemFolder *parentFolder,
5204 FolderInfo *fiParent, FolderPathMatch *match )
5210 FolderPathMatch *nextmatch = NULL;
5215 list = parentFolder->listFolder;
5217 folder = list->data;
5218 fName = g_strdup( ADDRITEM_NAME(folder) );
5220 /* match folder name, match pointer will be set to NULL if next recursive call
5221 doesn't need to match subfolder name */
5222 if ( match != NULL &&
5223 match->matched == FALSE ) {
5224 if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
5225 /* folder name matches, prepare next subfolder match */
5226 debug_print("matched folder name '%s'\n", fName);
5228 if ( match->folder_path[match->index] == NULL ) {
5229 /* we've matched all elements */
5230 match->matched = TRUE;
5231 match->folder = folder;
5232 debug_print("book/folder path matched!\n");
5234 /* keep on matching */
5242 fi = addressbook_peek_subfolder_exists_create_folderinfo( fiParent->book, folder );
5243 addressbook_peek_subfolder_exists_load_folder( folder, fi, nextmatch );
5245 list = g_list_next( list );
5250 * This function is used by to check if a matcher book/folder path corresponds to an
5251 existing addressbook book/folder ("" or "Any" are considered as valid, NULL invalid).
5252 Caution: returned book and folder pointers can be NULL even when returning TRUE:
5253 if book AND folder are NULL this means that folderpath was empty or Any.
5254 If folderpath is a simple book name (without folder), book will not be NULL and folder
5255 will be NULL. It's not expected to return book as NULL and folder as non NULL.
5258 gboolean addressbook_peek_folder_exists( gchar *folderpath,
5259 AddressDataSource **book,
5260 ItemFolder **folder )
5262 AddressDataSource *ds;
5263 GList *list, *nodeDS;
5264 ItemFolder *rootFolder;
5265 AddressBookFile *abf;
5267 FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL, NULL };
5274 if ( folderpath == NULL )
5277 if ( strcasecmp(folderpath, "Any") == 0 || *folderpath == '\0' )
5280 /* split the folder path we've received, we'll try to match this path, subpath by
5281 subpath against the book/folder structure in order */
5282 folder_path_match.folder_path = g_strsplit( folderpath, "/", 256 );
5283 if (!folder_path_match.folder_path)
5286 list = addrindex_get_interface_list( _addressIndex_ );
5287 while ( list && !folder_path_match.matched ) {
5288 AddressInterface *interface = list->data;
5289 if ( interface && interface->type == ADDR_IF_BOOK ) {
5290 nodeDS = interface->listSource;
5291 while ( nodeDS && !folder_path_match.matched ) {
5294 /* Read address book */
5295 if( ! addrindex_ds_get_read_flag( ds ) ) {
5296 addrindex_ds_read_data( ds );
5299 /* Add node for address book */
5300 abf = ds->rawDataSource;
5302 /* match book name */
5303 if ( abf && abf->fileName &&
5304 strcmp(folder_path_match.folder_path[0], abf->fileName) == 0 ) {
5306 debug_print("matched book name '%s'\n", abf->fileName);
5307 folder_path_match.book = ds;
5309 if ( folder_path_match.folder_path[1] == NULL ) {
5310 /* no folder part to match */
5312 folder_path_match.matched = TRUE;
5313 folder_path_match.folder = NULL;
5314 debug_print("book path matched!\n");
5317 /* match folder part */
5319 fi = addressbook_peek_subfolder_exists_create_folderinfo( abf, NULL );
5320 rootFolder = addrindex_ds_get_root_folder( ds );
5322 /* prepare for recursive call */
5323 folder_path_match.index = 1;
5324 /* this call will set folder_path_match.matched and folder_path_match.folder */
5325 addressbook_peek_subfolder_exists_load_folder( rootFolder, fi, &folder_path_match );
5330 nodeDS = g_list_next( nodeDS );
5333 list = g_list_next( list );
5336 g_strfreev( folder_path_match.folder_path );
5339 *book = folder_path_match.book;
5341 *folder = folder_path_match.folder;
5342 return folder_path_match.matched;
5346 /* **********************************************************************
5348 * ***********************************************************************
5354 static void addressbook_import_ldif_cb( GtkAction *action, gpointer data ) {
5355 AddressDataSource *ds = NULL;
5356 AdapterDSource *ads = NULL;
5357 AddressBookFile *abf = NULL;
5358 AdapterInterface *adapter;
5359 GtkCMCTreeNode *newNode;
5361 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5363 if( adapter->treeNode ) {
5364 abf = addressbook_imp_ldif( _addressIndex_ );
5366 ds = addrindex_index_add_datasource(
5367 _addressIndex_, ADDR_IF_BOOK, abf );
5368 ads = addressbook_create_ds_adapter(
5369 ds, ADDR_BOOK, NULL );
5370 addressbook_ads_set_name(
5371 ads, addrbook_get_name( abf ) );
5372 newNode = addressbook_add_object(
5374 ADDRESS_OBJECT(ads) );
5376 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5378 addrbook.treeSelected = newNode;
5381 /* Notify address completion */
5382 invalidate_address_completion();
5391 static void addressbook_import_mutt_cb( GtkAction *action, gpointer data ) {
5392 AddressDataSource *ds = NULL;
5393 AdapterDSource *ads = NULL;
5394 AddressBookFile *abf = NULL;
5395 AdapterInterface *adapter;
5396 GtkCMCTreeNode *newNode;
5398 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5400 if( adapter->treeNode ) {
5401 abf = addressbook_imp_mutt( _addressIndex_ );
5403 ds = addrindex_index_add_datasource(
5404 _addressIndex_, ADDR_IF_BOOK, abf );
5405 ads = addressbook_create_ds_adapter(
5406 ds, ADDR_BOOK, NULL );
5407 addressbook_ads_set_name(
5408 ads, addrbook_get_name( abf ) );
5409 newNode = addressbook_add_object(
5411 ADDRESS_OBJECT(ads) );
5413 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5415 addrbook.treeSelected = newNode;
5418 /* Notify address completion */
5419 invalidate_address_completion();
5428 static void addressbook_import_pine_cb( GtkAction *action, gpointer data ) {
5429 AddressDataSource *ds = NULL;
5430 AdapterDSource *ads = NULL;
5431 AddressBookFile *abf = NULL;
5432 AdapterInterface *adapter;
5433 GtkCMCTreeNode *newNode;
5435 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5437 if( adapter->treeNode ) {
5438 abf = addressbook_imp_pine( _addressIndex_ );
5440 ds = addrindex_index_add_datasource(
5441 _addressIndex_, ADDR_IF_BOOK, abf );
5442 ads = addressbook_create_ds_adapter(
5443 ds, ADDR_BOOK, NULL );
5444 addressbook_ads_set_name(
5445 ads, addrbook_get_name( abf ) );
5446 newNode = addressbook_add_object(
5448 ADDRESS_OBJECT(ads) );
5450 gtk_sctree_select( GTK_SCTREE(addrbook.ctree),
5452 addrbook.treeSelected = newNode;
5455 /* Notify address completion */
5456 invalidate_address_completion();
5463 * Harvest addresses.
5464 * \param folderItem Folder to import.
5465 * \param sourceInd Source indicator: FALSE - Folder, TRUE - Messages.
5466 * \param msgList List of message numbers, or NULL to process folder.
5468 void addressbook_harvest(
5469 FolderItem *folderItem, gboolean sourceInd, GList *msgList )
5471 AddressDataSource *ds = NULL;
5472 AdapterDSource *ads = NULL;
5473 AddressBookFile *abf = NULL;
5474 AdapterInterface *adapter;
5475 GtkCMCTreeNode *newNode;
5477 abf = addrgather_dlg_execute(
5478 folderItem, _addressIndex_, sourceInd, msgList );
5480 ds = addrindex_index_add_datasource(
5481 _addressIndex_, ADDR_IF_BOOK, abf );
5483 adapter = addrbookctl_find_interface( ADDR_IF_BOOK );
5485 if( adapter->treeNode ) {
5486 ads = addressbook_create_ds_adapter(
5487 ds, ADDR_BOOK, addrbook_get_name( abf ) );
5488 newNode = addressbook_add_object(
5490 ADDRESS_OBJECT(ads) );
5494 /* Notify address completion */
5495 invalidate_address_completion();
5502 static void addressbook_export_html_cb( GtkAction *action, gpointer data ) {
5503 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5505 AddressDataSource *ds = NULL;
5506 AddrBookBase *adbase;
5507 AddressCache *cache;
5508 GtkCMCTreeNode *node = NULL;
5510 if( ! addrbook.treeSelected ) return;
5511 node = addrbook.treeSelected;
5512 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5513 obj = gtk_cmctree_node_get_row_data( ctree, node );
5514 if( obj == NULL ) return;
5516 ds = addressbook_find_datasource( node );
5517 if( ds == NULL ) return;
5518 adbase = ( AddrBookBase * ) ds->rawDataSource;
5519 cache = adbase->addressCache;
5520 addressbook_exp_html( cache );
5526 static void addressbook_export_ldif_cb( GtkAction *action, gpointer data ) {
5527 GtkCMCTree *ctree = GTK_CMCTREE(addrbook.ctree);
5529 AddressDataSource *ds = NULL;
5530 AddrBookBase *adbase;
5531 AddressCache *cache;
5532 GtkCMCTreeNode *node = NULL;
5534 if( ! addrbook.treeSelected ) return;
5535 node = addrbook.treeSelected;
5536 if( GTK_CMCTREE_ROW(node)->level == 1 ) return;
5537 obj = gtk_cmctree_node_get_row_data( ctree, node );
5538 if( obj == NULL ) return;
5540 ds = addressbook_find_datasource( node );
5541 if( ds == NULL ) return;
5542 adbase = ( AddrBookBase * ) ds->rawDataSource;
5543 cache = adbase->addressCache;
5544 addressbook_exp_ldif( cache );
5547 static void addressbook_find_duplicates_cb(GtkAction *action, gpointer data)
5549 addrduplicates_find(GTK_WINDOW(addrbook.window));
5552 static void addressbook_edit_custom_attr_cb(GtkAction *action, gpointer data)
5554 addressbook_custom_attr_edit();
5557 static void addressbook_start_drag(GtkWidget *widget, gint button,
5561 GdkDragContext *context;
5562 if (addressbook_target_list == NULL)
5563 addressbook_target_list = gtk_target_list_new(
5564 addressbook_drag_types, 1);
5565 context = gtk_drag_begin(widget, addressbook_target_list,
5566 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
5567 gtk_drag_set_icon_default(context);
5570 static void addressbook_drag_data_get(GtkWidget *widget,
5571 GdkDragContext *drag_context,
5572 GtkSelectionData *selection_data,
5577 AddrItemObject *aio = NULL;
5578 AddressObject *pobj = NULL;
5579 AdapterDSource *ads = NULL;
5580 AddressDataSource *ds = NULL;
5583 pobj = gtk_cmctree_node_get_row_data( GTK_CMCTREE(addrbook.ctree), addrbook.treeSelected );
5585 if( pobj == NULL ) return;
5587 if( pobj->type == ADDR_DATASOURCE ) {
5588 ads = ADAPTER_DSOURCE(pobj);
5589 ds = ads->dataSource;
5590 } else if (pobj->type == ADDR_ITEM_GROUP) {
5595 else if( pobj->type != ADDR_INTERFACE ) {
5596 ds = addressbook_find_datasource( addrbook.treeSelected );
5602 for(cur = GTK_CMCLIST(addrbook.clist)->selection; cur; cur = cur->next) {
5603 aio = (AddrItemObject *)gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.clist),
5604 GTK_CMCTREE_NODE(cur->data));
5605 while (aio && aio->type != ADDR_ITEM_PERSON) {
5610 if (aio && aio->type == ADDR_ITEM_PERSON) {
5611 if( ds && ds->interface && ds->interface->readOnly)
5612 gtk_selection_data_set(selection_data,
5613 gtk_selection_data_get_target(selection_data), 8,
5614 (const guchar *)"Dummy_addr_copy", 15);
5616 gtk_selection_data_set(selection_data,
5617 gtk_selection_data_get_target(selection_data), 8,
5618 (const guchar *)"Dummy_addr_move", 15);
5622 static gboolean addressbook_drag_motion_cb(GtkWidget *widget,
5623 GdkDragContext *context,
5629 GtkAllocation allocation;
5630 GtkRequisition requisition;
5632 GtkCMCTreeNode *node = NULL;
5633 gboolean acceptable = FALSE;
5634 gtk_widget_get_allocation(GTK_WIDGET(addrbook.ctree), &allocation);
5635 gint height = allocation.height;
5636 gtk_widget_get_requisition(GTK_WIDGET(addrbook.ctree), &requisition);
5637 gint total_height = requisition.height;
5638 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
5639 GTK_SCROLLED_WINDOW(addrbook.ctree_swin));
5640 gfloat vpos = gtk_adjustment_get_value(pos);
5642 if (gtk_cmclist_get_selection_info
5643 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column)) {
5645 if (y > height - 24 && height + vpos < total_height) {
5646 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
5647 gtk_adjustment_changed(pos);
5649 if (y < 24 && y > 0) {
5650 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
5651 gtk_adjustment_changed(pos);
5653 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5656 AddressObject *obj = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node );
5657 if( obj->type == ADDR_ITEM_FOLDER
5658 || obj->type == ADDR_ITEM_GROUP)
5661 AdapterDSource *ads = NULL;
5662 AddressDataSource *ds = NULL;
5663 ads = ADAPTER_DSOURCE(obj);
5664 if (ads == NULL ){ return FALSE;}
5665 ds = ads->dataSource;
5666 if (ds == NULL ) { return FALSE;}
5674 g_signal_handlers_block_by_func
5676 G_CALLBACK(addressbook_tree_selected), NULL);
5677 gtk_sctree_select( GTK_SCTREE(widget), node);
5678 g_signal_handlers_unblock_by_func
5680 G_CALLBACK(addressbook_tree_selected), NULL);
5681 gdk_drag_status(context,
5682 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
5683 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
5685 gdk_drag_status(context, 0, time);
5690 static void addressbook_drag_leave_cb(GtkWidget *widget,
5691 GdkDragContext *context,
5695 if (addrbook.treeSelected) {
5696 g_signal_handlers_block_by_func
5698 G_CALLBACK(addressbook_tree_selected), NULL);
5699 gtk_sctree_select( GTK_SCTREE(widget), addrbook.opened);
5700 g_signal_handlers_unblock_by_func
5702 G_CALLBACK(addressbook_tree_selected), NULL);
5707 static void addressbook_drag_received_cb(GtkWidget *widget,
5708 GdkDragContext *drag_context,
5711 GtkSelectionData *data,
5717 GtkCMCTreeNode *node;
5718 GtkCMCTreeNode *lastopened = addrbook.opened;
5720 if (!strncmp(gtk_selection_data_get_data(data), "Dummy_addr", 10)) {
5721 if (gtk_cmclist_get_selection_info
5722 (GTK_CMCLIST(widget), x - 24, y - 24, &row, &column) == 0) {
5726 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
5727 if( !node || !gtk_cmctree_node_get_row_data(GTK_CMCTREE(addrbook.ctree), node))
5730 gtk_cmclist_freeze(GTK_CMCLIST(addrbook.clist));
5731 if (gdk_drag_context_get_selected_action(drag_context) == GDK_ACTION_COPY ||
5732 !strcmp(gtk_selection_data_get_data(data), "Dummy_addr_copy"))
5733 addressbook_clip_copy_cb(NULL, NULL);
5735 addressbook_clip_cut_cb(NULL, NULL);
5736 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), node);
5737 addressbook_clip_paste_cb(NULL,NULL);
5738 gtk_sctree_select( GTK_SCTREE(addrbook.ctree), lastopened);
5739 gtk_cmclist_thaw(GTK_CMCLIST(addrbook.clist));
5740 gtk_drag_finish(drag_context, TRUE, TRUE, time);