From 0b3cbf57875fd692e4ba0b336fefa4bee1ed00dc Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Mon, 26 Feb 2018 11:23:00 +0100 Subject: Initial commit for sylpheed 3.7.0 --- src/addressbook.c | 4919 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4919 insertions(+) create mode 100644 src/addressbook.c (limited to 'src/addressbook.c') diff --git a/src/addressbook.c b/src/addressbook.c new file mode 100644 index 0000000..b013507 --- /dev/null +++ b/src/addressbook.c @@ -0,0 +1,4919 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2017 Hiroyuki Yamamoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "defs.h" + +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "addressbook.h" +#include "manage_window.h" +#include "prefs_common.h" +#include "alertpanel.h" +#include "inputdialog.h" +#include "menu.h" +#include "stock_pixmap.h" +#include "xml.h" +#include "prefs.h" +#include "procmime.h" +#include "utils.h" +#include "gtkutils.h" +#include "codeconv.h" +#include "about.h" +#include "addr_compl.h" + +#include "mgutils.h" +#include "addressitem.h" +#include "addritem.h" +#include "addrcache.h" +#include "addrbook.h" +#include "addrindex.h" +#include "addressadd.h" +#include "vcard.h" +#include "editvcard.h" +#include "editgroup.h" +#include "editaddress.h" +#include "editbook.h" +#include "ldif.h" +#include "importldif.h" +#include "importcsv.h" +#include "exportcsv.h" + +#ifdef USE_JPILOT +#include "jpilot.h" +#include "editjpilot.h" +#endif + +#ifdef USE_LDAP +#include +#include "syldap.h" +#include "editldap.h" + +#define ADDRESSBOOK_LDAP_BUSYMSG "Busy" +#endif + +typedef enum +{ + COL_FOLDER_NAME, + COL_OBJ, + COL_PIXBUF, + COL_PIXBUF_OPEN, + + N_TREE_COLS +} AddressBookTreeColumnPos; + +typedef enum +{ + COL_NAME, + COL_ADDRESS, + COL_NICKNAME, + COL_REMARKS, + COL_L_OBJ, + COL_L_PIXBUF, + + N_LIST_COLS +} AddressBookListColumnPos; + +enum +{ + DRAG_TYPE_OBJ, + + N_DRAG_TYPES +}; + +#define COL_NAME_WIDTH 164 +#define COL_ADDRESS_WIDTH 156 + +#define COL_FOLDER_WIDTH 170 + +#define ADDRESSBOOK_MSGBUF_SIZE 2048 + +static GdkPixbuf *folderpix; +static GdkPixbuf *folderopenpix; +static GdkPixbuf *grouppix; +static GdkPixbuf *interfacepix; +static GdkPixbuf *bookpix; +static GdkPixbuf *personpix; +static GdkPixbuf *addresspix; +static GdkPixbuf *vcardpix; +static GdkPixbuf *jpilotpix; +static GdkPixbuf *categorypix; +static GdkPixbuf *ldappix; + +/* Address list selection */ +static GList *_addressListSelection_ = NULL; + +static gboolean can_toggle_list_selection = TRUE; +static gboolean list_on_drag = FALSE; + +/* Address index file and interfaces */ +static AddressIndex *_addressIndex_ = NULL; +static GList *_addressInterfaceList_ = NULL; +static GList *_addressIFaceSelection_ = NULL; +#define ADDRESSBOOK_IFACE_SELECTION "1/y,3/y,4/y,2/n" + +/* Address clipboard */ +static GList *_clipObjectList_ = NULL; + +static AddressBook_win addrbook; + +static GHashTable *_addressBookTypeHash_ = NULL; +static GList *_addressBookTypeList_ = NULL; + +static void addressbook_refresh (void); +static void addressbook_reopen (void); + +static void addressbook_create (void); +static gint addressbook_close (void); + +static void addressbook_menuitem_set_sensitive (void); + +/* callback functions */ +static void addressbook_del_clicked (GtkButton *button, + gpointer data); +static void addressbook_reg_clicked (GtkButton *button, + gpointer data); +static void addressbook_to_clicked (GtkButton *button, + gpointer data); +static void addressbook_lup_clicked (GtkButton *button, + gpointer data); +static void addressbook_close_clicked (GtkButton *button, + gpointer data); + +static void addressbook_tree_selection_changed (GtkTreeSelection *selection, + gpointer data); +static void addressbook_list_selection_changed (GtkTreeSelection *selection, + gpointer data); +static void addressbook_person_expand_node (GtkTreeView *treeview, + GtkTreeIter *iter, + GtkTreePath *path, + gpointer *data); +static void addressbook_person_collapse_node (GtkTreeView *treeview, + GtkTreeIter *iter, + GtkTreePath *path, + gpointer *data); + +static void addressbook_drag_begin (GtkWidget *widget, + GdkDragContext *drag_context, + gpointer data); +static void addressbook_drag_end (GtkWidget *widget, + GdkDragContext *drag_context, + gpointer data); +static void addressbook_drag_data_get (GtkWidget *widget, + GdkDragContext *drag_context, + GtkSelectionData *selection_data, + guint info, + guint time, + gpointer data); + +#if 0 +static void addressbook_entry_changed (GtkWidget *widget); +#endif +static void addressbook_entry_activated (GtkWidget *widget, + gpointer data); + +static gboolean addressbook_list_button_pressed (GtkWidget *widget, + GdkEventButton *event, + gpointer data); +static gboolean addressbook_list_button_released(GtkWidget *widget, + GdkEventButton *event, + gpointer data); +static gboolean addressbook_tree_button_pressed (GtkWidget *ctree, + GdkEventButton *event, + gpointer data); +static gboolean addressbook_tree_button_released(GtkWidget *ctree, + GdkEventButton *event, + gpointer data); + +static gboolean addressbook_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time, + gpointer data); +static void addressbook_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time, + gpointer data); +static void addressbook_drag_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *data, + guint info, + guint time, + gpointer user_data); + +static void addressbook_folder_resized (GtkWidget *widget, + GtkAllocation *allocation, + gpointer data); +static void addressbook_col_resized (GtkWidget *widget, + GtkAllocation *allocation, + gpointer data); + +static void addressbook_popup_close (GtkMenuShell *menu_shell, + gpointer data); + +static void addressbook_new_folder_cb (gpointer data, + guint action, + GtkWidget *widget); +static void addressbook_new_group_cb (gpointer data, + guint action, + GtkWidget *widget); +static void addressbook_treenode_edit_cb (gpointer data, + guint action, + GtkWidget *widget); +static void addressbook_treenode_delete_cb (gpointer data, + guint action, + GtkWidget *widget); + +static void addressbook_change_node_name (GtkTreeIter *iter, + const gchar *name); + +static void addressbook_new_address_cb (gpointer data, + guint action, + GtkWidget *widget); +static void addressbook_compose_to_cb (gpointer data, + guint action, + GtkWidget *widget); +static void addressbook_edit_address_cb (gpointer data, + guint action, + GtkWidget *widget); +static void addressbook_delete_address_cb (gpointer data, + guint action, + GtkWidget *widget); +static void addressbook_copy_address_cb (gpointer data, + guint action, + GtkWidget *widget); +static void addressbook_paste_address_cb (gpointer data, + guint action, + GtkWidget *widget); + +static void close_cb (gpointer data, + guint action, + GtkWidget *widget); +static void addressbook_file_save_cb (gpointer data, + guint action, + GtkWidget *widget); + +/* Data source edit stuff */ +static void addressbook_new_book_cb (gpointer data, + guint action, + GtkWidget *widget); +static void addressbook_new_vcard_cb (gpointer data, + guint action, + GtkWidget *widget); + +#ifdef USE_JPILOT +static void addressbook_new_jpilot_cb (gpointer data, + guint action, + GtkWidget *widget); +#endif + +#ifdef USE_LDAP +static void addressbook_new_ldap_cb (gpointer data, + guint action, + GtkWidget *widget); +#endif + +static void addressbook_set_list (AddressObject *obj); + +static void addressbook_load_tree (void); +void addressbook_read_file (void); + +static gboolean addressbook_add_object (GtkTreeIter *iter, + GtkTreeIter *new_iter, + AddressObject *obj); +static AddressDataSource *addressbook_find_datasource + (GtkTreeIter *iter); + +static AddressBookFile *addressbook_get_book_file(); + +static gboolean addressbook_node_add_folder (GtkTreeIter *iter, + AddressDataSource *ds, + ItemFolder *itemFolder, + AddressObjectType otype, + GtkTreeIter *new_iter); +static gboolean addressbook_node_add_group (GtkTreeIter *iter, + AddressDataSource *ds, + ItemGroup *itemGroup, + GtkTreeIter *new_iter); +static void addressbook_tree_remove_children (GtkTreeModel *model, + GtkTreeIter *parent); +static void addressbook_move_nodes_up (GtkTreeIter *iter); +static gboolean addressbook_find_group_node (GtkTreeIter *parent, + GtkTreeIter *iter, + ItemGroup *group); + +/* static void addressbook_delete_object (AddressObject *obj); */ + +static gboolean key_pressed (GtkWidget *widget, + GdkEventKey *event, + gpointer data); +static void size_allocated (GtkWidget *widget, + GtkAllocation *allocation, + gpointer data); + +static gint addressbook_tree_compare (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer data); +static gint addressbook_list_name_compare (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer data); +static gint addressbook_list_address_compare (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer data); +static gint addressbook_list_nickname_compare (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer data); +static gint addressbook_list_remarks_compare (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer data); + +static gboolean addressbook_list_select_func (GtkTreeSelection *selection, + GtkTreeModel *model, + GtkTreePath *path, + gboolean cur_selected, + gpointer data); + +/* static void addressbook_book_show_message (AddressBookFile *book); */ +/* static void addressbook_vcard_show_message (VCardFile *vcf); */ +#ifdef USE_JPILOT +/* static void addressbook_jpilot_show_message (JPilotFile *jpf); */ +#endif +#ifdef USE_LDAP +static void addressbook_ldap_show_message (SyldapServer *server); +#endif + +/* LUT's and IF stuff */ +static void addressbook_free_adapter (GtkTreeIter *iter); +static void addressbook_free_child_adapters (GtkTreeIter *iter); +AddressTypeControlItem *addrbookctl_lookup (gint ot); +AddressTypeControlItem *addrbookctl_lookup_iface(AddressIfType ifType); + +void addrbookctl_build_map (GtkWidget *window); +void addrbookctl_build_iflist (void); +AdapterInterface *addrbookctl_find_interface (AddressIfType ifType); +void addrbookctl_build_ifselect (void); + +static void addrbookctl_free_interface (AdapterInterface *adapter); +static void addrbookctl_free_datasource (AdapterDSource *adapter); +static void addrbookctl_free_folder (AdapterFolder *adapter); +static void addrbookctl_free_group (AdapterGroup *adapter); + +static void addressbook_list_select_clear (void); +static void addressbook_list_select_remove (AddressObject *obj); +static void addressbook_list_select_set (GList *row_list); + +static void addressbook_import_ldif_cb (void); +static void addressbook_import_csv_cb (void); + +static void addressbook_export_csv_cb (void); + +static void addressbook_modified (void); + + +static GtkTargetEntry addressbook_drag_types[] = +{ + {"application/octet-stream", GTK_TARGET_SAME_APP, DRAG_TYPE_OBJ} +}; + +static GtkItemFactoryEntry addressbook_entries[] = +{ + {N_("/_File"), NULL, NULL, 0, ""}, + {N_("/_File/New _Book"), NULL, addressbook_new_book_cb, 0, NULL}, + {N_("/_File/New _vCard"), NULL, addressbook_new_vcard_cb, 0, NULL}, +#ifdef USE_JPILOT + {N_("/_File/New _JPilot"), NULL, addressbook_new_jpilot_cb, 0, NULL}, +#endif +#ifdef USE_LDAP + {N_("/_File/New _LDAP Server"), NULL, addressbook_new_ldap_cb, 0, NULL}, +#endif + {N_("/_File/---"), NULL, NULL, 0, ""}, + {N_("/_File/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL}, + {N_("/_File/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL}, + {N_("/_File/---"), NULL, NULL, 0, ""}, + {N_("/_File/_Save"), "S", addressbook_file_save_cb, 0, NULL}, + {N_("/_File/_Close"), "W", close_cb, 0, NULL}, + + {N_("/_Edit"), NULL, NULL, 0, ""}, + {N_("/_Edit/_Copy"), "C", addressbook_copy_address_cb, 0, NULL}, + {N_("/_Edit/_Paste"), "V", addressbook_paste_address_cb, 0, NULL}, + + {N_("/_Address"), NULL, NULL, 0, ""}, + {N_("/_Address/New _Address"), "N", addressbook_new_address_cb, 0, NULL}, + {N_("/_Address/New _Group"), "G", addressbook_new_group_cb, 0, NULL}, + {N_("/_Address/New _Folder"), "F", addressbook_new_folder_cb, 0, NULL}, + {N_("/_Address/---"), NULL, NULL, 0, ""}, + {N_("/_Address/Add _to recipient"), + "M", addressbook_compose_to_cb, COMPOSE_ENTRY_TO, NULL}, + {N_("/_Address/Add to _Cc"), + NULL, addressbook_compose_to_cb, COMPOSE_ENTRY_CC, NULL}, + {N_("/_Address/Add to _Bcc"), + NULL, addressbook_compose_to_cb, COMPOSE_ENTRY_BCC, NULL}, + {N_("/_Address/---"), NULL, NULL, 0, ""}, + {N_("/_Address/_Edit"), "Return", addressbook_edit_address_cb, 0, NULL}, + {N_("/_Address/_Delete"), "Delete", addressbook_delete_address_cb, 0, NULL}, + + {N_("/_Tools"), NULL, NULL, 0, ""}, + {N_("/_Tools/Import _LDIF file"), NULL, addressbook_import_ldif_cb, 0, NULL}, + {N_("/_Tools/Import _CSV file"), NULL, addressbook_import_csv_cb, 0, NULL}, + {N_("/_Tools/---"), NULL, NULL, 0, ""}, + {N_("/_Tools/Export to C_SV file"), NULL, addressbook_export_csv_cb, 0, NULL}, + {N_("/_Help"), NULL, NULL, 0, ""}, + {N_("/_Help/_About"), NULL, about_show, 0, NULL} +}; + +/* New options to be added. */ +/* + {N_("/_Edit"), NULL, NULL, 0, ""}, + {N_("/_Edit/C_ut"), "X", NULL, 0, NULL}, + {N_("/_Tools"), NULL, NULL, 0, ""}, + {N_("/_Tools/Import _Mozilla"), NULL, NULL, 0, NULL}, + {N_("/_Tools/Import _vCard"), NULL, NULL, 0, NULL}, + {N_("/_Tools/---"), NULL, NULL, 0, ""}, + {N_("/_Tools/Export _LDIF file"), NULL, NULL, 0, NULL}, + {N_("/_Tools/Export v_Card"), NULL, NULL, 0, NULL}, +*/ + +static GtkItemFactoryEntry addressbook_tree_popup_entries[] = +{ + {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL}, + {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL}, + {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL}, + {N_("/---"), NULL, NULL, 0, ""}, + {N_("/_Edit"), NULL, addressbook_treenode_edit_cb, 0, NULL}, + {N_("/_Delete"), NULL, addressbook_treenode_delete_cb, 0, NULL} +}; + +static GtkItemFactoryEntry addressbook_list_popup_entries[] = +{ + {N_("/New _Address"), NULL, addressbook_new_address_cb, 0, NULL}, + {N_("/New _Group"), NULL, addressbook_new_group_cb, 0, NULL}, + {N_("/New _Folder"), NULL, addressbook_new_folder_cb, 0, NULL}, + {N_("/---"), NULL, NULL, 0, ""}, + {N_("/Add _to recipient"), + NULL, addressbook_compose_to_cb, COMPOSE_ENTRY_TO, NULL}, + {N_("/Add t_o Cc"), + NULL, addressbook_compose_to_cb, COMPOSE_ENTRY_CC, NULL}, + {N_("/Add to _Bcc"), + NULL, addressbook_compose_to_cb, COMPOSE_ENTRY_BCC, NULL}, + {N_("/---"), NULL, NULL, 0, ""}, + {N_("/_Edit"), NULL, addressbook_edit_address_cb, 0, NULL}, + {N_("/_Delete"), NULL, addressbook_delete_address_cb, 0, NULL}, + {N_("/---"), NULL, NULL, 0, ""}, + {N_("/_Copy"), NULL, addressbook_copy_address_cb, 0, NULL}, + {N_("/_Paste"), NULL, addressbook_paste_address_cb, 0, NULL} +}; + + +void addressbook_open(Compose *target) +{ + if (!addrbook.window) { + GtkTreeView *treeview; + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreePath *path; + + addressbook_read_file(); + addressbook_create(); + addressbook_load_tree(); + treeview = GTK_TREE_VIEW(addrbook.treeview); + model = gtk_tree_view_get_model(treeview); + if (gtk_tree_model_get_iter_first(model, &iter)) { + path = gtk_tree_model_get_path(model, &iter); + gtk_tree_view_set_cursor(treeview, path, NULL, FALSE); + gtk_tree_path_free(path); + } + addressbook_menuitem_set_sensitive(); + gtk_widget_show(addrbook.window); + } + + gtk_window_present(GTK_WINDOW(addrbook.window)); + + addressbook_set_target_compose(target); +} + +void addressbook_set_target_compose(Compose *target) +{ + addrbook.target_compose = target; +} + +Compose *addressbook_get_target_compose(void) +{ + return addrbook.target_compose; +} + +static void addressbook_refresh(void) +{ + if (addrbook.window) { + if (addrbook.tree_opened) { + addressbook_reopen(); + } + } + addressbook_export_to_file(); +} + +static void addressbook_reopen(void) +{ + GtkTreePath *path; + + if (addrbook.tree_selected) { + gtk_tree_row_reference_free(addrbook.tree_selected); + addrbook.tree_selected = NULL; + } + if (addrbook.tree_opened) { + path = gtk_tree_row_reference_get_path(addrbook.tree_opened); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(addrbook.treeview), path, NULL, FALSE); + gtk_tree_path_free(path); + } +} + +/* +* Create the address book widgets. The address book contains two CTree widgets: the +* address index tree on the left and the address list on the right. +* +* The address index tree displays a hierarchy of interfaces and groups. Each node in +* this tree is linked to an address Adapter. Adapters have been created for interfaces, +* data sources and folder objects. +* +* The address list displays group, person and email objects. These items are linked +* directly to ItemGroup, ItemPerson and ItemEMail objects inside the address book data +* sources. +* +* In the tradition of MVC architecture, the data stores have been separated from the +* GUI components. The addrindex.c file provides the interface to all data stores. +*/ +static void addressbook_create(void) +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *menubar; + GtkWidget *spc_hbox; + GtkWidget *vbox2; + GtkWidget *tree_swin; + GtkWidget *treeview; + GtkTreeStore *tree_store; + GtkTreeSelection *selection; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkWidget *list_vbox; + GtkWidget *list_swin; + GtkWidget *listview; + GtkTreeStore *list_store; + GtkWidget *paned; + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *entry; + GtkWidget *statusbar; + GtkWidget *hbbox; + GtkWidget *hbbox1; + GtkWidget *hbbox2; + GtkWidget *hsbox; + GtkWidget *to_btn; + GtkWidget *cc_btn; + GtkWidget *bcc_btn; + GtkWidget *del_btn; + GtkWidget *reg_btn; + GtkWidget *lup_btn; + GtkWidget *close_btn; + GtkWidget *tree_popup; + GtkWidget *list_popup; + GtkItemFactory *tree_factory; + GtkItemFactory *list_factory; + GtkItemFactory *menu_factory; + gint n_entries; + GList *nodeIf; + + debug_print("Creating addressbook window...\n"); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), _("Address book")); + gtk_window_set_wmclass(GTK_WINDOW(window), "addressbook", "Sylpheed"); + gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE); + gtk_widget_set_size_request(window, 620 * gtkut_get_dpi_multiplier(), 360 * gtkut_get_dpi_multiplier()); + gtk_window_set_default_size(GTK_WINDOW(window), + prefs_common.addressbook_width, + prefs_common.addressbook_height); + gtkut_window_move(GTK_WINDOW(window), prefs_common.addressbook_x, + prefs_common.addressbook_y); + gtk_widget_realize(window); + + g_signal_connect(G_OBJECT(window), "delete_event", + G_CALLBACK(addressbook_close), NULL); + g_signal_connect(G_OBJECT(window), "key_press_event", + G_CALLBACK(key_pressed), NULL); + g_signal_connect(G_OBJECT(window), "size_allocate", + G_CALLBACK(size_allocated), NULL); + MANAGE_WINDOW_SIGNALS_CONNECT(window); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(window), vbox); + + n_entries = sizeof(addressbook_entries) / + sizeof(addressbook_entries[0]); + menubar = menubar_create(window, addressbook_entries, n_entries, + "", NULL); + gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0); + menu_factory = gtk_item_factory_from_widget(menubar); + + spc_hbox = gtk_hbox_new(FALSE, 0); + gtk_widget_set_size_request(spc_hbox, -1, BORDER_WIDTH); + gtk_box_pack_start(GTK_BOX(vbox), spc_hbox, FALSE, FALSE, 0); + + vbox2 = gtk_vbox_new(FALSE, 4); + gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0); + + tree_swin = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tree_swin), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tree_swin), + GTK_SHADOW_IN); + gtk_widget_set_size_request(tree_swin, prefs_common.addressbook_folder_width, -1); + + /* Address index */ + tree_store = gtk_tree_store_new(N_TREE_COLS, G_TYPE_STRING, + G_TYPE_POINTER, GDK_TYPE_PIXBUF, + GDK_TYPE_PIXBUF); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(tree_store), + COL_FOLDER_NAME, + addressbook_tree_compare, + NULL, NULL); + + treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store)); + g_object_unref(G_OBJECT(tree_store)); + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), FALSE); + gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), + COL_FOLDER_NAME); + gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview), FALSE); + + gtk_container_add(GTK_CONTAINER(tree_swin), treeview); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_spacing(column, 1); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_set_resizable(column, TRUE); + + renderer = gtk_cell_renderer_pixbuf_new(); + g_object_set(renderer, "ypad", 0, NULL); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_set_title(column, _("Folder")); + gtk_tree_view_column_set_attributes + (column, renderer, "pixbuf", COL_PIXBUF, + "pixbuf-expander-open", COL_PIXBUF_OPEN, + "pixbuf-expander-closed", COL_PIXBUF, NULL); + + renderer = gtk_cell_renderer_text_new(); + g_object_set(renderer, +#if GTK_CHECK_VERSION(2, 6, 0) + "ellipsize", PANGO_ELLIPSIZE_END, +#endif + "ypad", 0, NULL); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_set_attributes(column, renderer, + "text", COL_FOLDER_NAME, NULL); + + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); + gtk_tree_view_set_expander_column(GTK_TREE_VIEW(treeview), column); + + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(tree_store), + COL_FOLDER_NAME, + GTK_SORT_ASCENDING); + + g_signal_connect(G_OBJECT(tree_swin), "size-allocate", + G_CALLBACK(addressbook_folder_resized), NULL); + + g_signal_connect(G_OBJECT(selection), "changed", + G_CALLBACK(addressbook_tree_selection_changed), NULL); + g_signal_connect(G_OBJECT(treeview), "button_press_event", + G_CALLBACK(addressbook_tree_button_pressed), + NULL); + g_signal_connect(G_OBJECT(treeview), "button_release_event", + G_CALLBACK(addressbook_tree_button_released), + NULL); + + gtk_drag_dest_set(treeview, GTK_DEST_DEFAULT_ALL, + addressbook_drag_types, N_DRAG_TYPES, + GDK_ACTION_MOVE | GDK_ACTION_COPY); + g_signal_connect(G_OBJECT(treeview), "drag-motion", + G_CALLBACK(addressbook_drag_motion), NULL); + g_signal_connect(G_OBJECT(treeview), "drag-leave", + G_CALLBACK(addressbook_drag_leave), NULL); + g_signal_connect(G_OBJECT(treeview), "drag-data-received", + G_CALLBACK(addressbook_drag_received), NULL); + + list_vbox = gtk_vbox_new(FALSE, 4); + + list_swin = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(list_swin), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(list_swin), + GTK_SHADOW_IN); + gtk_box_pack_start(GTK_BOX(list_vbox), list_swin, TRUE, TRUE, 0); + + /* Address list */ + list_store = gtk_tree_store_new(N_LIST_COLS, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_POINTER, + GDK_TYPE_PIXBUF); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(list_store), + COL_NAME, + addressbook_list_name_compare, + NULL, NULL); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(list_store), + COL_ADDRESS, + addressbook_list_address_compare, + NULL, NULL); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(list_store), + COL_NICKNAME, + addressbook_list_nickname_compare, + NULL, NULL); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(list_store), + COL_REMARKS, + addressbook_list_remarks_compare, + NULL, NULL); + + listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store)); + g_object_unref(G_OBJECT(list_store)); + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(listview)); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); + gtk_tree_selection_set_select_function + (selection, addressbook_list_select_func, NULL, NULL); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(listview), TRUE); + gtk_tree_view_set_search_column(GTK_TREE_VIEW(listview), COL_NAME); + gtk_tree_view_set_reorderable(GTK_TREE_VIEW(listview), FALSE); + gtk_container_add(GTK_CONTAINER(list_swin), listview); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_spacing(column, 1); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_set_fixed_width + (column, prefs_common.addressbook_col_name); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_column_set_title(column, _("Name")); +#if GTK_CHECK_VERSION(2, 14, 0) + /* gtk_tree_view_column_set_expand(column, TRUE); */ +#endif + + renderer = gtk_cell_renderer_pixbuf_new(); + g_object_set(renderer, "ypad", 0, NULL); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_set_attributes(column, renderer, + "pixbuf", COL_L_PIXBUF, NULL); + + renderer = gtk_cell_renderer_text_new(); + g_object_set(renderer, +#if GTK_CHECK_VERSION(2, 6, 0) + "ellipsize", PANGO_ELLIPSIZE_END, +#endif + "ypad", 0, NULL); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_set_attributes(column, renderer, + "text", COL_NAME, NULL); + + gtk_tree_view_column_set_sort_column_id(column, COL_NAME); + gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column); + gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column); + g_signal_connect(G_OBJECT(column->button), "size-allocate", + G_CALLBACK(addressbook_col_resized), + GINT_TO_POINTER(COL_NAME)); + + renderer = gtk_cell_renderer_text_new(); + g_object_set(renderer, +#if GTK_CHECK_VERSION(2, 6, 0) + "ellipsize", PANGO_ELLIPSIZE_END, +#endif + "ypad", 0, NULL); + column = gtk_tree_view_column_new_with_attributes + (_("E-Mail address"), renderer, "text", COL_ADDRESS, NULL); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_set_fixed_width + (column, prefs_common.addressbook_col_addr); + gtk_tree_view_column_set_resizable(column, TRUE); +#if GTK_CHECK_VERSION(2, 14, 0) + /* gtk_tree_view_column_set_expand(column, TRUE); */ +#endif + gtk_tree_view_column_set_sort_column_id(column, COL_ADDRESS); + gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column); + g_signal_connect(G_OBJECT(column->button), "size-allocate", + G_CALLBACK(addressbook_col_resized), + GINT_TO_POINTER(COL_ADDRESS)); + + renderer = gtk_cell_renderer_text_new(); + g_object_set(renderer, +#if GTK_CHECK_VERSION(2, 6, 0) + "ellipsize", PANGO_ELLIPSIZE_END, +#endif + "ypad", 0, NULL); + column = gtk_tree_view_column_new_with_attributes + (_("Nick Name"), renderer, "text", COL_NICKNAME, NULL); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_set_fixed_width + (column, prefs_common.addressbook_col_nickname); + gtk_tree_view_column_set_resizable(column, TRUE); +#if GTK_CHECK_VERSION(2, 14, 0) + /* gtk_tree_view_column_set_expand(column, TRUE); */ +#endif + gtk_tree_view_column_set_sort_column_id(column, COL_NICKNAME); + gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column); + g_signal_connect(G_OBJECT(column->button), "size-allocate", + G_CALLBACK(addressbook_col_resized), + GINT_TO_POINTER(COL_NICKNAME)); + + renderer = gtk_cell_renderer_text_new(); + g_object_set(renderer, +#if GTK_CHECK_VERSION(2, 6, 0) + "ellipsize", PANGO_ELLIPSIZE_END, +#endif + "ypad", 0, NULL); + column = gtk_tree_view_column_new_with_attributes + (_("Remarks"), renderer, "text", COL_REMARKS, NULL); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_set_resizable(column, TRUE); +#if GTK_CHECK_VERSION(2, 14, 0) + /* gtk_tree_view_column_set_expand(column, TRUE); */ +#endif + gtk_tree_view_column_set_sort_column_id(column, COL_REMARKS); + gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column); + g_signal_connect(G_OBJECT(column->button), "size-allocate", + G_CALLBACK(addressbook_col_resized), + GINT_TO_POINTER(COL_REMARKS)); + + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(list_store), + COL_NAME, GTK_SORT_ASCENDING); + + g_signal_connect(G_OBJECT(selection), "changed", + G_CALLBACK(addressbook_list_selection_changed), NULL); + g_signal_connect(G_OBJECT(listview), "button_press_event", + G_CALLBACK(addressbook_list_button_pressed), + NULL); + g_signal_connect(G_OBJECT(listview), "button_release_event", + G_CALLBACK(addressbook_list_button_released), + NULL); + g_signal_connect(G_OBJECT(listview), "row_expanded", + G_CALLBACK(addressbook_person_expand_node), NULL); + g_signal_connect(G_OBJECT(listview), "row_collapsed", + G_CALLBACK(addressbook_person_collapse_node), NULL); + + gtk_tree_view_enable_model_drag_source + (GTK_TREE_VIEW(listview), GDK_BUTTON1_MASK, + addressbook_drag_types, N_DRAG_TYPES, + GDK_ACTION_MOVE | GDK_ACTION_COPY); + + g_signal_connect_after(G_OBJECT(listview), "drag-begin", + G_CALLBACK(addressbook_drag_begin), NULL); + g_signal_connect_after(G_OBJECT(listview), "drag-end", + G_CALLBACK(addressbook_drag_end), NULL); + g_signal_connect(G_OBJECT(listview), "drag-data-get", + G_CALLBACK(addressbook_drag_data_get), NULL); + + hbox = gtk_hbox_new(FALSE, 4); + gtk_box_pack_start(GTK_BOX(list_vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new(_("Search:")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + entry = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); + + address_completion_register_entry(GTK_ENTRY(entry)); + +#if 0 + g_signal_connect(G_OBJECT(entry), "changed", + G_CALLBACK(addressbook_entry_changed), NULL); +#endif + g_signal_connect(G_OBJECT(entry), "activate", + G_CALLBACK(addressbook_entry_activated), NULL); + + paned = gtk_hpaned_new(); + gtk_box_pack_start(GTK_BOX(vbox2), paned, TRUE, TRUE, 0); + gtk_paned_add1(GTK_PANED(paned), tree_swin); + gtk_paned_add2(GTK_PANED(paned), list_vbox); + + /* Status bar */ + hsbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, 0); + statusbar = gtk_statusbar_new(); + gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, 0); + + hbbox = gtk_hbox_new(FALSE, 4); + gtk_box_pack_end(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + + /* Button panel */ + hbbox1 = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox1), GTK_BUTTONBOX_END); + gtk_box_set_spacing(GTK_BOX(hbbox1), 4); + gtk_container_set_border_width(GTK_CONTAINER(hbbox1), 4); + gtk_button_box_set_child_size(GTK_BUTTON_BOX(hbbox1), 64, -1); + gtk_box_pack_end(GTK_BOX(hbbox), hbbox1, FALSE, FALSE, 0); + + to_btn = gtk_button_new_with_label + (prefs_common.trans_hdr ? _("To:") : "To:"); + GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(hbbox1), to_btn, TRUE, TRUE, 0); + cc_btn = gtk_button_new_with_label + (prefs_common.trans_hdr ? _("Cc:") : "Cc:"); + GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(hbbox1), cc_btn, TRUE, TRUE, 0); + bcc_btn = gtk_button_new_with_label + (prefs_common.trans_hdr ? _("Bcc:") : "Bcc:"); + GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(hbbox1), bcc_btn, TRUE, TRUE, 0); + + g_signal_connect(G_OBJECT(to_btn), "clicked", + G_CALLBACK(addressbook_to_clicked), + GINT_TO_POINTER(COMPOSE_ENTRY_TO)); + g_signal_connect(G_OBJECT(cc_btn), "clicked", + G_CALLBACK(addressbook_to_clicked), + GINT_TO_POINTER(COMPOSE_ENTRY_CC)); + g_signal_connect(G_OBJECT(bcc_btn), "clicked", + G_CALLBACK(addressbook_to_clicked), + GINT_TO_POINTER(COMPOSE_ENTRY_BCC)); + + hbbox2 = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox2), GTK_BUTTONBOX_END); + gtk_box_set_spacing(GTK_BOX(hbbox2), 4); + gtk_container_set_border_width(GTK_CONTAINER(hbbox2), 4); + gtk_button_box_set_child_size(GTK_BUTTON_BOX(hbbox2), 64, -1); + gtk_box_pack_end(GTK_BOX(hbbox), hbbox2, TRUE, TRUE, 0); + + del_btn = gtk_button_new_with_label(_("Delete")); + GTK_WIDGET_SET_FLAGS(del_btn, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(hbbox2), del_btn, TRUE, TRUE, 0); + reg_btn = gtk_button_new_with_label(_("Add")); + GTK_WIDGET_SET_FLAGS(reg_btn, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(hbbox2), reg_btn, TRUE, TRUE, 0); + lup_btn = gtk_button_new_with_label(_("Search")); + GTK_WIDGET_SET_FLAGS(lup_btn, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(hbbox2), lup_btn, TRUE, TRUE, 0); + close_btn = gtk_button_new_with_mnemonic(_("_Close")); + GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(hbbox2), close_btn, TRUE, TRUE, 0); + gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(hbbox2), close_btn, + TRUE); + + g_signal_connect(G_OBJECT(del_btn), "clicked", + G_CALLBACK(addressbook_del_clicked), NULL); + g_signal_connect(G_OBJECT(reg_btn), "clicked", + G_CALLBACK(addressbook_reg_clicked), NULL); + g_signal_connect(G_OBJECT(lup_btn), "clicked", + G_CALLBACK(addressbook_lup_clicked), NULL); + g_signal_connect(G_OBJECT(close_btn), "clicked", + G_CALLBACK(addressbook_close_clicked), NULL); + + /* Build icons for interface */ + stock_pixbuf_gdk(window, STOCK_PIXMAP_INTERFACE, &interfacepix); + /* Build control tables */ + addrbookctl_build_map(window); + addrbookctl_build_iflist(); + addrbookctl_build_ifselect(); + + /* Add each interface into the tree as a root level folder */ + nodeIf = _addressInterfaceList_; + while( nodeIf ) { + AdapterInterface *adapter = nodeIf->data; + AddressInterface *iface = adapter->iface; + + nodeIf = g_list_next(nodeIf); + + if(iface->useInterface) { + AddressTypeControlItem *atci = adapter->atci; + gchar *text = atci->displayName; + GtkTreeIter iter; + GtkTreePath *path; + + debug_print("addressbook_create: adapter: %s\n", text); + gtk_tree_store_append(tree_store, &iter, NULL); + gtk_tree_store_set(tree_store, &iter, + COL_FOLDER_NAME, text, + COL_OBJ, adapter, + COL_PIXBUF, interfacepix, + COL_PIXBUF_OPEN, interfacepix, -1); + path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store), &iter); + adapter->tree_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(tree_store), path); + gtk_tree_path_free(path); + } + } + + /* Popup menu */ + n_entries = sizeof(addressbook_tree_popup_entries) / + sizeof(addressbook_tree_popup_entries[0]); + tree_popup = menu_create_items(addressbook_tree_popup_entries, + n_entries, + "", &tree_factory, + NULL); + g_signal_connect(G_OBJECT(tree_popup), "selection_done", + G_CALLBACK(addressbook_popup_close), NULL); + n_entries = sizeof(addressbook_list_popup_entries) / + sizeof(addressbook_list_popup_entries[0]); + list_popup = menu_create_items(addressbook_list_popup_entries, + n_entries, + "", &list_factory, + NULL); + + addrbook.window = window; + addrbook.menubar = menubar; + addrbook.treeview = treeview; + addrbook.listview = listview; + addrbook.entry = entry; + addrbook.statusbar = statusbar; + addrbook.status_cid = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar), "Address Book Window"); + + addrbook.to_btn = to_btn; + addrbook.cc_btn = cc_btn; + addrbook.bcc_btn = bcc_btn; + addrbook.del_btn = del_btn; + addrbook.reg_btn = reg_btn; + addrbook.lup_btn = lup_btn; + addrbook.close_btn = close_btn; + + addrbook.tree_popup = tree_popup; + addrbook.list_popup = list_popup; + addrbook.tree_factory = tree_factory; + addrbook.list_factory = list_factory; + addrbook.menu_factory = menu_factory; + + addrbook.tree_selected = NULL; + addrbook.list_selected = NULL; + address_completion_start(window); + gtk_widget_show_all(window); +} + +static gint addressbook_close(void) +{ + gtkut_widget_get_uposition(addrbook.window, + &prefs_common.addressbook_x, + &prefs_common.addressbook_y); + gtk_widget_hide(addrbook.window); + addressbook_export_to_file(); + return TRUE; +} + +static void addressbook_status_show(const gchar *msg) +{ + if (addrbook.statusbar != NULL) { + gtk_statusbar_pop(GTK_STATUSBAR(addrbook.statusbar), addrbook.status_cid); + if (msg) { + gtk_statusbar_push(GTK_STATUSBAR(addrbook.statusbar), addrbook.status_cid, msg); + } + } +} + +static void addressbook_ds_show_message(AddressDataSource *ds) +{ + gint retVal; + gchar *name; + gchar msgbuf[ADDRESSBOOK_MSGBUF_SIZE] = ""; + + if (ds) { + name = addrindex_ds_get_name(ds); + if (ds->type == ADDR_IF_BOOK && name && + !strcmp(name, ADDR_DS_AUTOREG)) + name = _("Auto-registered address"); + retVal = addrindex_ds_get_status_code(ds); + if (retVal == MGU_SUCCESS) { + g_snprintf(msgbuf, sizeof(msgbuf), "%s", name); + } else { + g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s", + name, mgu_error2string(retVal)); + } + } + + addressbook_status_show(msgbuf); +} + +/* +* Delete one or more objects from address list. +*/ +static void addressbook_del_clicked(GtkButton *button, gpointer data) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview); + GtkTreeModel *lmodel; + GtkTreeIter list_sel; + AddressObject *pobj = NULL; + AddressObject *obj = NULL; + AdapterDSource *ads = NULL; + gboolean procFlag; + AlertValue aval; + AddressBookFile *abf = NULL; + AddressDataSource *ds = NULL; + + if (!addrbook.tree_opened) + return; + + model = gtk_tree_view_get_model(treeview); + lmodel = gtk_tree_view_get_model(listview); + selection = gtk_tree_view_get_selection(treeview); + + gtkut_tree_row_reference_get_iter(model, addrbook.tree_opened, &iter); + gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1); + g_return_if_fail(pobj != NULL); + + gtkut_tree_row_reference_get_iter(lmodel, addrbook.list_selected, + &list_sel); + gtk_tree_model_get(lmodel, &list_sel, COL_L_OBJ, &obj, -1); + if (obj == NULL) + return; + if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) + return; + ds = addressbook_find_datasource(&iter); + if (ds == NULL) + return; + + procFlag = FALSE; + if (pobj->type == ADDR_DATASOURCE) { + ads = ADAPTER_DSOURCE(pobj); + if(ads->subType == ADDR_BOOK) + procFlag = TRUE; + } + else if (pobj->type == ADDR_ITEM_FOLDER) { + procFlag = TRUE; + } else if (pobj->type == ADDR_ITEM_GROUP) { + procFlag = TRUE; + } + if (!procFlag) + return; + abf = ds->rawDataSource; + if (abf == NULL) + return; + + /* Confirm deletion */ + aval = alertpanel(_("Delete address(es)"), + _("Really delete the address(es)?"), + GTK_STOCK_YES, GTK_STOCK_NO, NULL); + if (aval != G_ALERTDEFAULT) + return; + + /* Process deletions */ + if (pobj->type == ADDR_DATASOURCE || pobj->type == ADDR_ITEM_FOLDER) { + /* Items inside folders */ + GList *node; + + node = _addressListSelection_; + while (node) { + AddrItemObject *aio = node->data; + node = g_list_next(node); + if (aio->type == ADDR_ITEM_GROUP) { + ItemGroup *item = (ItemGroup *)aio; + GtkTreeIter giter; + + addressbook_find_group_node(&iter, &giter, item); + item = addrbook_remove_group(abf, item); + if (item) { + addritem_free_item_group(item); + item = NULL; + } + /* Remove group from parent node */ + gtk_tree_store_remove(GTK_TREE_STORE(model), &giter); + } else if (aio->type == ADDR_ITEM_PERSON) { + ItemPerson *item = (ItemPerson *)aio; + + if (_clipObjectList_) { + _clipObjectList_ = g_list_remove(_clipObjectList_, item); + } + item = addrbook_remove_person(abf, item); + if (item) { + addritem_free_item_person(item); + item = NULL; + } + } else if (aio->type == ADDR_ITEM_EMAIL) { + ItemEMail *item = (ItemEMail *)aio; + ItemPerson *person = (ItemPerson *)ADDRITEM_PARENT(item); + + item = addrbook_person_remove_email(abf, person, item); + if (item) { + addritem_free_item_email(item); + item = NULL; + } + } + } + addressbook_list_select_clear(); + addressbook_reopen(); + addressbook_modified(); + return; + } else if (pobj->type == ADDR_ITEM_GROUP) { + /* Items inside groups */ + GList *node; + ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup; + + node = _addressListSelection_; + while (node) { + AddrItemObject *aio = node->data; + node = g_list_next(node); + if (aio->type == ADDR_ITEM_EMAIL) { + ItemEMail *item = (ItemEMail *)aio; + item = addrbook_group_remove_email(abf, group, item); + } + } + addressbook_list_select_clear(); + addressbook_reopen(); + return; + } + + gtk_tree_store_remove(GTK_TREE_STORE(lmodel), &list_sel); + addressbook_list_select_remove(obj); +} + +static void addressbook_reg_clicked(GtkButton *button, gpointer data) +{ + addressbook_new_address_cb(NULL, 0, NULL); +} + +gchar *addressbook_format_address(AddressObject *obj) +{ + gchar *buf = NULL; + gchar *name = NULL; + gchar *address = NULL; + + if( obj->type == ADDR_ITEM_EMAIL ) { + ItemPerson *person = NULL; + ItemEMail *email = ( ItemEMail * ) obj; + + person = ( ItemPerson * ) ADDRITEM_PARENT(email); + if( email->address ) { + if( ADDRITEM_NAME(email) ) { + name = ADDRITEM_NAME(email); + if( *name == '\0' ) { + name = ADDRITEM_NAME(person); + } + } + else if( person && ADDRITEM_NAME(person) ) { + name = ADDRITEM_NAME(person); + } + else { + buf = g_strdup( email->address ); + } + address = email->address; + } + } + else if( obj->type == ADDR_ITEM_PERSON ) { + ItemPerson *person = ( ItemPerson * ) obj; + GList *node = person->listEMail; + + name = ADDRITEM_NAME(person); + if( node ) { + ItemEMail *email = ( ItemEMail * ) node->data; + address = email->address; + } + } + if( address ) { + if( !prefs_common.always_add_address_only && + name && name[0] != '\0' ) { + if( name[0] != '"' && strpbrk( name, ",.[]<>" ) != NULL ) + buf = g_strdup_printf( "\"%s\" <%s>", name, address ); + else + buf = g_strdup_printf( "%s <%s>", name, address ); + } + else { + buf = g_strdup( address ); + } + } + + return buf; +} + +static void addressbook_to_clicked(GtkButton *button, gpointer data) +{ + GList *node = _addressListSelection_; + gboolean new_compose = FALSE; + + if (!addrbook.target_compose) { + new_compose = TRUE; + addrbook.target_compose = compose_new(NULL, NULL, NULL, NULL); + if (!addrbook.target_compose) + return; + } + + if (new_compose) + compose_block_modified(addrbook.target_compose); + + while( node ) { + AddressObject *obj = node->data; + Compose *compose = addrbook.target_compose; + + node = g_list_next( node ); + if( obj->type == ADDR_ITEM_PERSON || obj->type == ADDR_ITEM_EMAIL ) { + gchar *addr = addressbook_format_address( obj ); + compose_entry_append( compose, addr, (ComposeEntryType) data ); + g_free( addr ); + addr = NULL; + } + else if( obj->type == ADDR_ITEM_GROUP ) { + ItemGroup *group = ( ItemGroup * ) obj; + GList *nodeMail = group->listEMail; + while( nodeMail ) { + ItemEMail *email = nodeMail->data; + gchar *addr = addressbook_format_address( ( AddressObject * ) email ); + compose_entry_append( compose, addr, (ComposeEntryType) data ); + g_free( addr ); + nodeMail = g_list_next( nodeMail ); + } + } + } + + if (new_compose) + compose_unblock_modified(addrbook.target_compose); +} + +static void addressbook_menuitem_set_sensitive(void) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview); + GtkTreeSelection *selection; + GtkTreeSelection *lselection; + GtkTreeModel *model; + GtkTreeModel *lmodel; + GtkTreeIter iter; + GtkTreeIter liter; + gboolean canAdd = FALSE; + gboolean canEditTree = TRUE; + gboolean canEditAddress = FALSE; + gboolean canDelete = FALSE; + gboolean canLookup = FALSE; + gboolean canCopy = FALSE; + gboolean canPaste = FALSE; + gboolean hasListSelection = _addressListSelection_ != NULL; + AddressTypeControlItem *atci = NULL; + AddressDataSource *ds = NULL; + AddressInterface *iface = NULL; + AddressObject *pobj = NULL; + AddressObject *obj = NULL; + + menu_set_sensitive(addrbook.menu_factory, "/File/New Book", FALSE); + menu_set_sensitive(addrbook.menu_factory, "/File/New vCard", FALSE); +#ifdef USE_JPILOT + menu_set_sensitive(addrbook.menu_factory, "/File/New JPilot", FALSE); +#endif +#ifdef USE_LDAP + menu_set_sensitive(addrbook.menu_factory, "/File/New LDAP Server", FALSE); +#endif + menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.tree_popup)); + menu_set_insensitive_all(GTK_MENU_SHELL(addrbook.list_popup)); + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + + gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1); + if (pobj == NULL) + return; + + lmodel = gtk_tree_view_get_model(listview); + lselection = gtk_tree_view_get_selection(listview); + + if (addrbook.list_selected) { + if (gtkut_tree_row_reference_get_iter(lmodel, addrbook.list_selected, &liter)) + gtk_tree_model_get(lmodel, &liter, COL_L_OBJ, &obj, -1); + } + + if (pobj->type == ADDR_INTERFACE) { + AdapterInterface *adapter = ADAPTER_INTERFACE(pobj); + + iface = adapter->iface; + if (iface && iface->haveLibrary) { + /* Enable appropriate File / New command */ + atci = adapter->atci; + menu_set_sensitive(addrbook.menu_factory, atci->menuCommand, TRUE); + } + canEditTree = FALSE; + } else if (pobj->type == ADDR_DATASOURCE) { + AdapterDSource *ads = ADAPTER_DSOURCE(pobj); + + ds = ads->dataSource; + iface = ds->iface; + if (!iface->readOnly) { + canAdd = canEditAddress = TRUE; + } + if (!iface->haveLibrary) { + canAdd = canEditAddress = FALSE; + } +#ifdef USE_LDAP + if (ads->subType == ADDR_LDAP) { + if (iface->haveLibrary && ds->rawDataSource) + canLookup = TRUE; + } else +#endif + canLookup = TRUE; + if (ads->subType == ADDR_BOOK && pobj->name && + !strcmp(pobj->name, ADDR_DS_AUTOREG)) + canEditTree = FALSE; + } else if (pobj->type == ADDR_ITEM_FOLDER) { + ds = addressbook_find_datasource(&iter); + if (ds) { + iface = ds->iface; + if (!iface->readOnly) { + canAdd = canEditAddress = TRUE; + } + canLookup = TRUE; + } + } else if (pobj->type == ADDR_ITEM_GROUP) { + ds = addressbook_find_datasource(&iter); + if (ds) { + iface = ds->iface; + if (!iface->readOnly) { + canEditAddress = TRUE; + } + canLookup = TRUE; + } + } + + if (obj == NULL) + canEditAddress = FALSE; + canDelete = canEditAddress; + if (gtk_tree_selection_count_selected_rows(lselection) > 1) + canEditAddress = FALSE; + if (_addressListSelection_) { + GList *cur; + AddressObject *item; + + for (cur = _addressListSelection_; cur != NULL; cur = cur->next) { + item = cur->data; + if (item->type == ADDR_ITEM_PERSON) { + canCopy = TRUE; + break; + } + } + } + if (_clipObjectList_ && canAdd) + canPaste = TRUE; + + /* Enable add */ + menu_set_sensitive(addrbook.menu_factory, "/Address/New Address", canAdd); + menu_set_sensitive(addrbook.menu_factory, "/Address/New Folder", canAdd); + menu_set_sensitive(addrbook.menu_factory, "/Address/New Group", canAdd); + + menu_set_sensitive(addrbook.menu_factory, "/Address/Add to recipient", hasListSelection); + menu_set_sensitive(addrbook.menu_factory, "/Address/Add to Cc", hasListSelection); + menu_set_sensitive(addrbook.menu_factory, "/Address/Add to Bcc", hasListSelection); + + /* Enable edit */ + menu_set_sensitive(addrbook.menu_factory, "/Address/Edit", canEditAddress); + menu_set_sensitive(addrbook.menu_factory, "/Address/Delete", canDelete); + + menu_set_sensitive(addrbook.menu_factory, "/File/Edit", canEditTree); + menu_set_sensitive(addrbook.menu_factory, "/File/Delete", canEditTree); + + menu_set_sensitive(addrbook.menu_factory, "/Edit/Copy", canCopy); + menu_set_sensitive(addrbook.menu_factory, "/Edit/Paste", canPaste); + + menu_set_sensitive(addrbook.menu_factory, "/Tools/Export to CSV file", canEditTree); + + /* Popup menu */ + menu_set_sensitive(addrbook.tree_factory, "/New Address", canAdd); + menu_set_sensitive(addrbook.tree_factory, "/New Folder", canAdd); + menu_set_sensitive(addrbook.tree_factory, "/New Group", canAdd); + menu_set_sensitive(addrbook.tree_factory, "/Edit", canEditTree); + menu_set_sensitive(addrbook.tree_factory, "/Delete", canEditTree); + + menu_set_sensitive(addrbook.list_factory, "/New Address", canAdd); + menu_set_sensitive(addrbook.list_factory, "/New Folder", canAdd); + menu_set_sensitive(addrbook.list_factory, "/New Group", canAdd); + menu_set_sensitive(addrbook.list_factory, "/Add to recipient", hasListSelection); + menu_set_sensitive(addrbook.list_factory, "/Add to Cc", hasListSelection); + menu_set_sensitive(addrbook.list_factory, "/Add to Bcc", hasListSelection); + menu_set_sensitive(addrbook.list_factory, "/Edit", canEditAddress); + menu_set_sensitive(addrbook.list_factory, "/Delete", canDelete); + menu_set_sensitive(addrbook.list_factory, "/Copy", canCopy); + menu_set_sensitive(addrbook.list_factory, "/Paste", canPaste); + + /* Buttons */ + gtk_widget_set_sensitive(addrbook.to_btn, hasListSelection); + gtk_widget_set_sensitive(addrbook.cc_btn, hasListSelection); + gtk_widget_set_sensitive(addrbook.bcc_btn, hasListSelection); + gtk_widget_set_sensitive(addrbook.reg_btn, canAdd); + gtk_widget_set_sensitive(addrbook.del_btn, canDelete); + gtk_widget_set_sensitive(addrbook.lup_btn, canLookup); +} + +static void addressbook_tree_selection_changed(GtkTreeSelection *selection, + gpointer data) +{ + GtkTreeModel *model; + GtkTreeModel *lmodel; + GtkTreeIter iter; + GtkTreePath *path; + AddressObject *obj = NULL; + AdapterDSource *ads = NULL; + AddressDataSource *ds = NULL; + ItemFolder *rootFolder = NULL; + + debug_print("addressbook_tree_selection_changed\n"); + + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) { + debug_print("addressbook_tree_selection_changed: no selection\n"); + gtk_tree_row_reference_free(addrbook.tree_selected); + addrbook.tree_selected = NULL; + gtk_tree_row_reference_free(addrbook.tree_opened); + addrbook.tree_opened = NULL; + addressbook_status_show(""); + if (addrbook.entry) + gtk_entry_set_text(GTK_ENTRY(addrbook.entry), ""); + if (addrbook.listview) { + lmodel = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.listview)); + gtk_tree_store_clear(GTK_TREE_STORE(lmodel)); + } + return; + } + + path = gtk_tree_model_get_path(model, &iter); + gtk_tree_row_reference_free(addrbook.tree_selected); + addrbook.tree_selected = gtk_tree_row_reference_new(model, path); + gtk_tree_row_reference_free(addrbook.list_selected); + addrbook.list_selected = NULL; + addressbook_status_show(""); + if (addrbook.entry) + gtk_entry_set_text(GTK_ENTRY(addrbook.entry), ""); + if (addrbook.listview) { + lmodel = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.listview)); + gtk_tree_store_clear(GTK_TREE_STORE(lmodel)); + } + gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1); + if (obj == NULL) { + gtk_tree_path_free(path); + return; + } + + gtk_tree_row_reference_free(addrbook.tree_opened); + addrbook.tree_opened = gtk_tree_row_reference_new(model, path); + + if (obj->type == ADDR_DATASOURCE) { + /* Read from file */ + static gboolean tVal = TRUE; + + ads = ADAPTER_DSOURCE(obj); + if (ads == NULL) return; + ds = ads->dataSource; + if (ds == NULL) return; + + if (addrindex_ds_get_modify_flag(ds)) { + addrindex_ds_read_data(ds); + } + + if (!addrindex_ds_get_read_flag(ds)) { + addrindex_ds_read_data(ds); + } + addressbook_ds_show_message(ds); + + if (!addrindex_ds_get_access_flag(ds)) { + /* Remove existing folders and groups */ + addressbook_tree_remove_children(model, &iter); + + /* Load folders into the tree */ + rootFolder = addrindex_ds_get_root_folder(ds); + if (ds->type == ADDR_IF_JPILOT) { + addressbook_node_add_folder(&iter, ds, rootFolder, ADDR_CATEGORY, NULL); + } else { + addressbook_node_add_folder(&iter, ds, rootFolder, ADDR_ITEM_FOLDER, NULL); + } + addrindex_ds_set_access_flag(ds, &tVal); + gtk_tree_view_expand_row(GTK_TREE_VIEW(addrbook.treeview), path, TRUE); + } + } + + gtk_tree_path_free(path); + + /* Update address list */ + addressbook_set_list(obj); + addressbook_menuitem_set_sensitive(); + addressbook_list_select_clear(); +} + +static void addressbook_list_selection_changed(GtkTreeSelection *selection, + gpointer data) +{ + GtkTreeModel *lmodel; + GtkTreePath *path; + GList *selected; + + debug_print("addressbook_list_selection_changed\n"); + + selected = gtk_tree_selection_get_selected_rows(selection, &lmodel); + addressbook_list_select_set(selected); + gtk_tree_row_reference_free(addrbook.list_selected); + if (selected) { + path = (GtkTreePath *)selected->data; + addrbook.list_selected = gtk_tree_row_reference_new(lmodel, path); + g_list_foreach(selected, (GFunc)gtk_tree_path_free, NULL); + g_list_free(selected); + } else + addrbook.list_selected = NULL; + + addressbook_menuitem_set_sensitive(); +} + +static void addressbook_list_select_clear(void) +{ + if (_addressListSelection_) { + g_list_free(_addressListSelection_); + } + _addressListSelection_ = NULL; +} + +static void addressbook_list_select_remove(AddressObject *obj) +{ + if (!obj) + return; + if (_addressListSelection_) { + _addressListSelection_ = g_list_remove(_addressListSelection_, obj); + } +} + +static void addressbook_list_select_set(GList *row_list) +{ + GtkTreeModel *model; + GtkTreeIter iter; + GList *cur; + AddressObject *obj; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.listview)); + + addressbook_list_select_clear(); + for (cur = row_list; cur != NULL; cur = cur->next) { + obj = NULL; + gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)cur->data); + gtk_tree_model_get(model, &iter, COL_L_OBJ, &obj, -1); + if (obj && (obj->type == ADDR_ITEM_PERSON || + obj->type == ADDR_ITEM_EMAIL || + obj->type == ADDR_ITEM_GROUP)) { + _addressListSelection_ = g_list_prepend(_addressListSelection_, obj); + } + } + _addressListSelection_ = g_list_reverse(_addressListSelection_); +} + +static void addressbook_entry_activated(GtkWidget *widget, gpointer data) +{ + addressbook_lup_clicked(NULL, NULL); +} + +static gboolean addressbook_list_button_pressed(GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + GtkTreePath *path = NULL; + GtkTreeSelection *selection; + gboolean is_selected = FALSE; + gboolean mod_pressed = FALSE; + + if (!event) + return FALSE; + + gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), event->x, event->y, + &path, NULL, NULL, NULL); + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); + if (path) + is_selected = gtk_tree_selection_path_is_selected + (selection, path); + mod_pressed = ((event->state & + (GDK_SHIFT_MASK|GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0); + + if (event->button == 1) { + if (is_selected && !mod_pressed) { + can_toggle_list_selection = FALSE; + } + + if (is_selected && event->type == GDK_2BUTTON_PRESS) { + debug_print("addressbook_list_button_pressed: GDK_2BUTTON_PRESS\n"); + /* Handle double click */ + if (prefs_common.add_address_by_click && + addrbook.target_compose) + addressbook_to_clicked + (NULL, GINT_TO_POINTER(COMPOSE_ENTRY_TO)); + else + addressbook_edit_address_cb(NULL, 0, NULL); + return TRUE; + } + } else if (event->button == 3) { + gtk_menu_popup(GTK_MENU(addrbook.list_popup), NULL, NULL, + NULL, NULL, event->button, event->time); + gtk_tree_path_free(path); + if (is_selected) + return TRUE; + } + + return FALSE; +} + +static gboolean addressbook_list_button_released(GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + if (!can_toggle_list_selection && !list_on_drag) { + GtkTreePath *path; + + if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), event->x, event->y, &path, NULL, NULL, NULL)) { + can_toggle_list_selection = TRUE; + gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), path, NULL, FALSE); + gtk_tree_path_free(path); + } + } + can_toggle_list_selection = TRUE; + list_on_drag = FALSE; + return FALSE; +} + +static gboolean addressbook_tree_button_pressed(GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(widget); + GtkTreeSelection *selection; + GtkTreePath *path; + + if (!event) + return FALSE; + + if (!gtk_tree_view_get_path_at_pos(treeview, event->x, event->y, + &path, NULL, NULL, NULL)) + return TRUE; + selection = gtk_tree_view_get_selection(treeview); + + addressbook_menuitem_set_sensitive(); + + if (event->button == 3) { + gtk_tree_selection_select_path(selection, path); + gtk_menu_popup(GTK_MENU(addrbook.tree_popup), + NULL, NULL, NULL, NULL, + event->button, event->time); + } else if (event->type == GDK_2BUTTON_PRESS) { + gtk_tree_view_expand_row(treeview, path, FALSE); + } + + gtk_tree_path_free(path); + return FALSE; +} + +static gboolean addressbook_tree_button_released(GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + return FALSE; +} + +static gboolean addressbook_obj_is_droppable(GtkTreeModel *model, + AddressObject *obj) +{ + gboolean acceptable = FALSE; + + if (!model || !obj) + return FALSE; + if (!_addressListSelection_) + return FALSE; + + if (obj->type == ADDR_DATASOURCE) { + AdapterDSource *ads; + AddressDataSource *ds; + AddressInterface *iface; + + ads = ADAPTER_DSOURCE(obj); + ds = ads ? ads->dataSource : NULL; + iface = ds ? ds->iface : NULL; + if (ads && ads->subType == ADDR_BOOK && + iface && !iface->readOnly) + acceptable = TRUE; + } else if (obj->type == ADDR_ITEM_FOLDER) { + acceptable = TRUE; + } + + if (acceptable && addrbook.tree_opened) { + AddressObject *open_obj; + GtkTreeIter opened; + + gtkut_tree_row_reference_get_iter(model, addrbook.tree_opened, + &opened); + gtk_tree_model_get(model, &opened, COL_OBJ, &open_obj, -1); + if (open_obj == obj) + acceptable = FALSE; + } + + if (acceptable) { + GList *node; + for (node = _addressListSelection_; node != NULL; node = node->next) { + AddressObject *obj = node->data; + if (obj && obj->type == ADDR_ITEM_PERSON) + break; + } + if (!node) + acceptable = FALSE; + } + + return acceptable; +} + +static gboolean addressbook_drag_motion(GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, + guint time, gpointer data) +{ + GtkTreeModel *model; + GtkTreePath *path = NULL; + GtkTreeIter iter; + AddressObject *obj, *src_obj; + AddressDataSource *src_ds; + AddressBookFile *src_abf; + gboolean acceptable; + + if (!gtk_tree_view_get_dest_row_at_pos + (GTK_TREE_VIEW(widget), x, y, &path, NULL)) { + gtk_tree_view_set_drag_dest_row + (GTK_TREE_VIEW(widget), NULL, + GTK_TREE_VIEW_DROP_INTO_OR_AFTER); + gdk_drag_status(context, 0, time); + return FALSE; + } + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1); + g_return_val_if_fail(obj != NULL, FALSE); + + /* source */ + gtkut_tree_row_reference_get_iter(model, addrbook.tree_opened, &iter); + gtk_tree_model_get(model, &iter, COL_OBJ, &src_obj, -1); + g_return_val_if_fail(src_obj != NULL, FALSE); + src_ds = addressbook_find_datasource(&iter); + g_return_val_if_fail(src_ds != NULL, FALSE); + src_abf = src_ds->rawDataSource; + g_return_val_if_fail(src_abf != NULL, FALSE); + +#ifdef G_OS_WIN32 + { + GdkModifierType state = 0; + + gdk_window_get_pointer(widget->window, NULL, NULL, &state); + if ((state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) == 0) + context->actions = GDK_ACTION_MOVE | GDK_ACTION_COPY; + } +#endif + + if (!src_ds->iface || + (src_ds->iface->readOnly || !src_ds->iface->haveLibrary)) + context->actions &= ~GDK_ACTION_MOVE; + + acceptable = addressbook_obj_is_droppable(model, obj); + if ((context->actions & (GDK_ACTION_MOVE | GDK_ACTION_COPY)) == 0) + acceptable = FALSE; + + if (!acceptable) { + gtk_tree_view_set_drag_dest_row + (GTK_TREE_VIEW(widget), NULL, + GTK_TREE_VIEW_DROP_INTO_OR_AFTER); + gdk_drag_status(context, 0, time); + } else { + GdkDragAction action = 0; + + if ((context->actions & GDK_ACTION_MOVE) != 0) + action = GDK_ACTION_MOVE; + else if ((context->actions & GDK_ACTION_COPY) != 0) + action = GDK_ACTION_COPY; + gtk_tree_view_set_drag_dest_row + (GTK_TREE_VIEW(widget), path, + GTK_TREE_VIEW_DROP_INTO_OR_AFTER); + gdk_drag_status(context, action, time); + } + + gtk_tree_path_free(path); + + return TRUE; +} + +static void addressbook_drag_leave(GtkWidget *widget, GdkDragContext *context, + guint time, gpointer data) +{ + gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), NULL, + GTK_TREE_VIEW_DROP_INTO_OR_AFTER); +} + +static void addressbook_drag_received(GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, + GtkSelectionData *data, + guint info, guint time, + gpointer user_data) +{ + GtkTreeModel *model; + GtkTreePath *path = NULL; + GtkTreeIter iter; + AddressObject *obj, *pobj, *src_obj; + AddressDataSource *ds, *src_ds; + AddressBookFile *abf, *src_abf; + gboolean acceptable; + gboolean is_move; + GList *node; + ItemFolder *folder = NULL; + ItemPerson *person, *new_person; + + if (!gtk_tree_view_get_dest_row_at_pos + (GTK_TREE_VIEW(widget), x, y, &path, NULL)) + return; + + debug_print("addressbook_drag_received_cb: received data\n"); + + /* dest */ + model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1); + g_return_if_fail(pobj != NULL); + ds = addressbook_find_datasource(&iter); + g_return_if_fail(ds != NULL); + + /* source */ + gtkut_tree_row_reference_get_iter(model, addrbook.tree_opened, &iter); + gtk_tree_model_get(model, &iter, COL_OBJ, &src_obj, -1); + g_return_if_fail(src_obj != NULL); + src_ds = addressbook_find_datasource(&iter); + g_return_if_fail(src_ds != NULL); + src_abf = src_ds->rawDataSource; + g_return_if_fail(src_abf != NULL); + + acceptable = addressbook_obj_is_droppable(model, pobj); + abf = ds->rawDataSource; + if (!abf) + acceptable = FALSE; + + if ((context->actions & (GDK_ACTION_MOVE | GDK_ACTION_COPY)) == 0) + acceptable = FALSE; + is_move = (context->actions & GDK_ACTION_MOVE) != 0; + + if (!src_ds->iface || + (src_ds->iface->readOnly || !src_ds->iface->haveLibrary)) + is_move = FALSE; + + if (!_addressListSelection_ || !acceptable) { + context->action = 0; + gtk_drag_finish(context, FALSE, FALSE, time); + gtk_tree_path_free(path); + return; + } + + if (pobj->type == ADDR_ITEM_FOLDER) + folder = ADAPTER_FOLDER(pobj)->itemFolder; + + node = _addressListSelection_; + while (node) { + GList *cur; + + obj = node->data; + node = g_list_next(node); + if (obj->type != ADDR_ITEM_PERSON) + continue; + + person = (ItemPerson *)obj; + new_person = addrbook_add_address_list(abf, folder, NULL); + ADDRITEM_NAME(new_person) = g_strdup(ADDRITEM_NAME(person)); + new_person->firstName = g_strdup(person->firstName); + new_person->lastName = g_strdup(person->lastName); + new_person->nickName = g_strdup(person->nickName); + for (cur = person->listEMail; cur != NULL; cur = cur->next) { + ItemEMail *email = cur->data; + addritem_person_add_email(new_person, addritem_copy_item_email(email)); + } + for (cur = person->listAttrib; cur != NULL; cur = cur->next) { + UserAttribute *attr = cur->data; + addritem_person_add_attribute(new_person, addritem_copy_attribute(attr)); + } + + if (is_move) { + if (_clipObjectList_) + _clipObjectList_ = g_list_remove(_clipObjectList_, person); + person = addrbook_remove_person(src_abf, person); + if (person) + addritem_free_item_person(person); + } + } + + if (is_move) { + addressbook_list_select_clear(); + addressbook_reopen(); + } + + context->action = 0; + gtk_drag_finish(context, TRUE, FALSE, time); + + gtk_tree_path_free(path); + + addressbook_modified(); +} + +static void addressbook_folder_resized(GtkWidget *widget, + GtkAllocation *allocation, + gpointer data) +{ + gint width = allocation->width; + + if (width < 8) + return; + + prefs_common.addressbook_folder_width = width; +} + +static void addressbook_col_resized(GtkWidget *widget, + GtkAllocation *allocation, gpointer data) +{ + AddressBookListColumnPos type = (gint)data; + gint width = allocation->width; + + if (width < 8) + return; + + switch (type) { + case COL_NAME: + prefs_common.addressbook_col_name = width; + break; + case COL_ADDRESS: + prefs_common.addressbook_col_addr = width; + break; + case COL_NICKNAME: + prefs_common.addressbook_col_nickname = width; + break; + case COL_REMARKS: + prefs_common.addressbook_col_rem = width; + break; + default: + break; + } +} + +static void addressbook_popup_close(GtkMenuShell *menu_shell, gpointer data) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreePath *path; + + if (!addrbook.tree_opened) + return; + + selection = gtk_tree_view_get_selection(treeview); + path = gtk_tree_row_reference_get_path(addrbook.tree_opened); + if (path) { + gtk_tree_selection_select_path(selection, path); + gtk_tree_path_free(path); + } +} + +static void addressbook_new_folder_cb(gpointer data, guint action, + GtkWidget *widget) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + AddressObject *obj = NULL; + AddressDataSource *ds = NULL; + AddressBookFile *abf = NULL; + ItemFolder *parentFolder = NULL; + ItemFolder *folder = NULL; + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + + gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1); + if (obj == NULL) + return; + ds = addressbook_find_datasource(&iter); + if (ds == NULL) + return; + + if (obj->type == ADDR_DATASOURCE) { + if (ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK) return; + } else if (obj->type == ADDR_ITEM_FOLDER) { + parentFolder = ADAPTER_FOLDER(obj)->itemFolder; + } else { + return; + } + + abf = ds->rawDataSource; + if (abf == NULL) return; + folder = addressbook_edit_folder(abf, parentFolder, NULL); + if (folder) { + GtkTreeIter new_iter; + GtkTreePath *path; + addressbook_node_add_folder(&iter, ds, folder, ADDR_ITEM_FOLDER, &new_iter); + path = gtk_tree_model_get_path(model, &iter); + gtk_tree_view_expand_row(treeview, path, TRUE); + gtk_tree_path_free(path); + if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) + addressbook_set_list(obj); + } + +} + +static void addressbook_new_group_cb(gpointer data, guint action, + GtkWidget *widget) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + AddressObject *obj = NULL; + AddressDataSource *ds = NULL; + AddressBookFile *abf = NULL; + ItemFolder *parentFolder = NULL; + ItemGroup *group = NULL; + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + + gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1); + if (obj == NULL) + return; + ds = addressbook_find_datasource(&iter); + if (ds == NULL) + return; + + if (obj->type == ADDR_DATASOURCE) { + if (ADAPTER_DSOURCE(obj)->subType != ADDR_BOOK) return; + } else if (obj->type == ADDR_ITEM_FOLDER) { + parentFolder = ADAPTER_FOLDER(obj)->itemFolder; + } else { + return; + } + + abf = ds->rawDataSource; + if (abf == NULL) return; + group = addressbook_edit_group(abf, parentFolder, NULL); + if (group) { + GtkTreeIter new_iter; + GtkTreePath *path; + addressbook_node_add_group(&iter, ds, group, &new_iter); + path = gtk_tree_model_get_path(model, &iter); + gtk_tree_view_expand_row(treeview, path, TRUE); + gtk_tree_path_free(path); + if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) + addressbook_set_list(obj); + } + +} + +static void addressbook_change_node_name(GtkTreeIter *iter, const gchar *name) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeStore *store; + + store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview)); + gtk_tree_store_set(store, iter, COL_FOLDER_NAME, name, -1); +} + +/* +* Edit data source. +* Enter: obj Address object to edit. +* node Node in tree. +* Return: New name of data source. +*/ +static gchar *addressbook_edit_datasource(AddressObject *obj, GtkTreeIter *iter) +{ + gchar *newName = NULL; + AddressDataSource *ds = NULL; + AddressInterface *iface = NULL; + AdapterDSource *ads = NULL; + + ds = addressbook_find_datasource(iter); + if (ds == NULL) + return NULL; + iface = ds->iface; + if (!iface->haveLibrary) + return NULL; + + /* Read data from data source */ + if (!addrindex_ds_get_read_flag(ds)) { + addrindex_ds_read_data(ds); + } + + /* Handle edit */ + ads = ADAPTER_DSOURCE(obj); + if (ads->subType == ADDR_BOOK) { + if (addressbook_edit_book(_addressIndex_, ads) == NULL) + return NULL; + } else if (ads->subType == ADDR_VCARD) { + if (addressbook_edit_vcard(_addressIndex_, ads) == NULL) + return NULL; +#ifdef USE_JPILOT + } else if (ads->subType == ADDR_JPILOT) { + if (addressbook_edit_jpilot(_addressIndex_, ads) == NULL) + return NULL; +#endif +#ifdef USE_LDAP + } else if (ads->subType == ADDR_LDAP) { + if (addressbook_edit_ldap(_addressIndex_, ads) == NULL) + return NULL; +#endif + } else { + return NULL; + } + newName = obj->name; + return newName; +} + +/* +* Edit an object that is in the address tree area. +*/ +static void addressbook_treenode_edit_cb(gpointer data, guint action, + GtkWidget *widget) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter, parent; + AddressObject *obj = NULL; + AddressDataSource *ds = NULL; + AddressBookFile *abf = NULL; + gchar *name = NULL; + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + + if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter) == 0) + return; + gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1); + if (obj == NULL) + return; + if (!gtk_tree_model_iter_parent(model, &parent, &iter)) + return; + + ds = addressbook_find_datasource(&iter); + if (ds == NULL) + return; + + if (obj->type == ADDR_DATASOURCE) { + name = addressbook_edit_datasource(obj, &iter); + if (name == NULL) + return; + } else { + abf = ds->rawDataSource; + if (abf == NULL) + return; + if (obj->type == ADDR_ITEM_FOLDER) { + AdapterFolder *adapter = ADAPTER_FOLDER(obj); + ItemFolder *item = adapter->itemFolder; + ItemFolder *parentFolder = NULL; + parentFolder = (ItemFolder *)ADDRITEM_PARENT(item); + if (addressbook_edit_folder(abf, parentFolder, item) == NULL) + return; + name = ADDRITEM_NAME(item); + } else if (obj->type == ADDR_ITEM_GROUP) { + AdapterGroup *adapter = ADAPTER_GROUP(obj); + ItemGroup *item = adapter->itemGroup; + ItemFolder *parentFolder = NULL; + parentFolder = (ItemFolder *)ADDRITEM_PARENT(item); + if (addressbook_edit_group(abf, parentFolder, item) == NULL) + return; + name = ADDRITEM_NAME(item); + } + } + + if (name) { + GtkTreePath *path; + + /* Update node in tree view */ + addressbook_change_node_name(&iter, name); + path = gtk_tree_model_get_path(model, &iter); + gtk_tree_view_expand_row(treeview, path, TRUE); + gtk_tree_view_set_cursor(treeview, path, NULL, FALSE); + gtk_tree_path_free(path); + } +} + +/* +* Delete an item from the tree widget. +*/ +static void addressbook_treenode_delete_cb(gpointer data, guint action, + GtkWidget *widget) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter, parent; + AddressObject *obj; + gchar *message; + AlertValue aval; + AddressBookFile *abf = NULL; + AdapterDSource *ads = NULL; + AddressInterface *iface = NULL; + AddressDataSource *ds = NULL; + gboolean remFlag = FALSE; + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + + if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter) == 0) + return; + gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1); + g_return_if_fail(obj != NULL); + + if (obj->type == ADDR_DATASOURCE) { + ads = ADAPTER_DSOURCE(obj); + if (ads == NULL) + return; + ds = ads->dataSource; + if (ds == NULL) + return; + } else { + /* Must be folder or something else */ + ds = addressbook_find_datasource(&iter); + if (ds == NULL) + return; + + /* Only allow deletion from non-readOnly data sources */ + iface = ds->iface; + if (iface->readOnly) + return; + } + + /* Confirm deletion */ + if (obj->type == ADDR_ITEM_FOLDER) { + message = g_strdup_printf + (_("Do you want to delete the folder AND all addresses in `%s' ?\n" + "If deleting the folder only, addresses will be moved into parent folder."), + obj->name); + aval = alertpanel(_("Delete folder"), message, _("_Folder only"), _("Folder and _addresses"), GTK_STOCK_CANCEL); + g_free(message); + if (aval != G_ALERTDEFAULT && aval != G_ALERTALTERNATE) + return; + } else { + message = g_strdup_printf(_("Really delete `%s' ?"), obj->name); + aval = alertpanel(_("Delete"), message, GTK_STOCK_YES, GTK_STOCK_NO, NULL); + g_free(message); + if (aval != G_ALERTDEFAULT) + return; + } + + /* Proceed with deletion */ + if (obj->type == ADDR_DATASOURCE) { + /* Remove data source. */ + if (addrindex_index_remove_datasource(_addressIndex_, ds)) { + addressbook_free_child_adapters(&iter); + abf = addressbook_get_book_file(); + if (abf) { + gchar *bookFile; + bookFile = g_strconcat(abf->path, G_DIR_SEPARATOR_S, abf->fileName, NULL); + debug_print("removing %s\n", bookFile); + g_unlink(bookFile); + g_free(bookFile); + } + remFlag = TRUE; + } + } else { + abf = addressbook_get_book_file(); + if (abf == NULL) + return; + } + + if (obj->type == ADDR_ITEM_FOLDER) { + AdapterFolder *adapter = ADAPTER_FOLDER(obj); + ItemFolder *item = adapter->itemFolder; + + if (aval == G_ALERTDEFAULT) { + /* Remove folder only */ + item = addrbook_remove_folder(abf, item); + if (item) { + addritem_free_item_folder(item); + addressbook_move_nodes_up(&iter); + remFlag = TRUE; + } + } else if (aval == G_ALERTALTERNATE) { + /* Remove folder and addresses */ + item = addrbook_remove_folder_delete(abf, item); + if (item) { + addritem_free_item_folder(item); + addressbook_free_child_adapters(&iter); + remFlag = TRUE; + } + } + } else if (obj->type == ADDR_ITEM_GROUP) { + AdapterGroup *adapter = ADAPTER_GROUP(obj); + ItemGroup *item = adapter->itemGroup; + + item = addrbook_remove_group(abf, item); + if (item) { + addritem_free_item_group(item); + remFlag = TRUE; + } + } + + if (remFlag) { + /* Free up adapter and remove node. */ + addressbook_free_adapter(&iter); + gtk_tree_model_iter_parent(model, &parent, &iter); + gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); + gtk_tree_selection_select_iter(selection, &parent); + } +} + +static void addressbook_new_address_cb(gpointer data, guint action, GtkWidget *widget) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + AddressObject *pobj = NULL; + AddressDataSource *ds = NULL; + AddressBookFile *abf = NULL; + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + + gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1); + if (pobj == NULL) + return; + ds = addressbook_find_datasource(&iter); + if (ds == NULL) + return; + + abf = ds->rawDataSource; + if (abf == NULL) + return; + + if (pobj->type == ADDR_DATASOURCE) { + if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK) { + /* New address */ + ItemPerson *person = addressbook_edit_person(abf, NULL, NULL, FALSE); + if (person) { + if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) { + addressbook_reopen(); + } + addressbook_modified(); + } + } + } + else if( pobj->type == ADDR_ITEM_FOLDER ) { + /* New address */ + ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder; + ItemPerson *person = addressbook_edit_person(abf, folder, NULL, FALSE); + if (person) { + if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) { + addressbook_reopen(); + } + addressbook_modified(); + } + } + else if( pobj->type == ADDR_ITEM_GROUP ) { + /* New address in group */ + ItemGroup *group = ADAPTER_GROUP(pobj)->itemGroup; + + if (addressbook_edit_group(abf, NULL, group) == NULL) + return; + if (gtkut_tree_row_reference_equal + (addrbook.tree_selected, addrbook.tree_opened)) { + /* Change node name in tree. */ + addressbook_change_node_name(&iter, ADDRITEM_NAME(group)); + addressbook_reopen(); + } + } +} + +static void addressbook_compose_to_cb(gpointer data, guint action, GtkWidget *widget) +{ + addressbook_to_clicked(NULL, GINT_TO_POINTER(action)); +} + +/* +* Search for specified group in address index tree. +*/ +static gboolean addressbook_find_group_node(GtkTreeIter *parent, GtkTreeIter *iter, ItemGroup *group) +{ + GtkTreeModel *model; + GtkTreeIter iter_; + gboolean valid = TRUE; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview)); + valid = gtk_tree_model_iter_children(model, &iter_, parent); + while (valid) { + AddressObject *obj = NULL; + + gtk_tree_model_get(model, &iter_, COL_OBJ, &obj, -1); + if (obj && obj->type == ADDR_ITEM_GROUP) { + ItemGroup *g = ADAPTER_GROUP(obj)->itemGroup; + if (g == group) { + *iter = iter_; + return TRUE; + } + } + valid = gtk_tree_model_iter_next(model, &iter_); + } + + return FALSE; +} + +static AddressBookFile *addressbook_get_book_file(void) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreeIter iter; + AddressBookFile *abf = NULL; + AddressDataSource *ds = NULL; + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) + return NULL; + ds = addressbook_find_datasource(&iter); + if (ds == NULL) + return NULL; + if (ds->type == ADDR_IF_BOOK) + abf = ds->rawDataSource; + return abf; +} + +static void addressbook_tree_remove_children(GtkTreeModel *model, + GtkTreeIter *parent) +{ + GtkTreeIter iter; + + /* Remove existing folders and groups */ + while (gtk_tree_model_iter_children(model, &iter, parent)) { + gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); + } +} + +static void addressbook_move_nodes_recursive(GtkTreeIter *iter, + GtkTreeIter *parent) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeModel *model; + GtkTreeIter child, new_iter; + gboolean valid; + + model = gtk_tree_view_get_model(treeview); + + valid = gtk_tree_model_iter_children(model, &child, iter); + while (valid) { + gchar *name = NULL; + AddressObject *obj = NULL; + GdkPixbuf *pixbuf = NULL; + GdkPixbuf *pixbuf_open = NULL; + + gtk_tree_model_get(model, &child, COL_FOLDER_NAME, &name, + COL_OBJ, &obj, COL_PIXBUF, &pixbuf, + COL_PIXBUF_OPEN, &pixbuf_open, -1); + gtk_tree_store_append(GTK_TREE_STORE(model), &new_iter, parent); + gtk_tree_store_set(GTK_TREE_STORE(model), &new_iter, + COL_FOLDER_NAME, name, + COL_OBJ, obj, + COL_PIXBUF, pixbuf, + COL_PIXBUF_OPEN, pixbuf_open, -1); + g_free(name); + addressbook_move_nodes_recursive(&child, &new_iter); + valid = gtk_tree_model_iter_next(model, &child); + } +} + +static void addressbook_move_nodes_up(GtkTreeIter *iter) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeModel *model; + GtkTreeIter parent; + + model = gtk_tree_view_get_model(treeview); + if (!gtk_tree_model_iter_parent(model, &parent, iter)) + return; + + addressbook_move_nodes_recursive(iter, &parent); +} + +static void addressbook_edit_address_cb(gpointer data, guint action, GtkWidget *widget) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter liter, iter, node, parent; + gboolean node_found; + gboolean parent_found = FALSE; + GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview); + GtkTreeModel *lmodel; + AddressObject *obj = NULL, *pobj = NULL; + AddressDataSource *ds = NULL; + gchar *name = NULL; + AddressBookFile *abf = NULL; + + if (addrbook.list_selected == NULL) + return; + + lmodel = gtk_tree_view_get_model(listview); + if (!gtkut_tree_row_reference_get_iter(lmodel, addrbook.list_selected, + &liter)) + return; + gtk_tree_model_get(lmodel, &liter, COL_L_OBJ, &obj, -1); + g_return_if_fail(obj != NULL); + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1); + node_found = gtkut_tree_model_find_by_column_data + (model, &node, &iter, COL_OBJ, obj); + + ds = addressbook_find_datasource(&iter); + if (ds == NULL) + return; + + abf = addressbook_get_book_file(); + if (abf == NULL) + return; + + if (obj->type == ADDR_ITEM_EMAIL) { + ItemEMail *email = (ItemEMail *)obj; + ItemPerson *person; + + if (email == NULL) + return; + if (pobj && pobj->type == ADDR_ITEM_GROUP) { + /* Edit parent group */ + AdapterGroup *adapter = ADAPTER_GROUP(pobj); + ItemGroup *itemGrp = adapter->itemGroup; + + if (addressbook_edit_group(abf, NULL, itemGrp) == NULL) + return; + name = ADDRITEM_NAME(itemGrp); + node = iter; + node_found = TRUE; + parent_found = gtk_tree_model_iter_parent(model, &parent, &node); + } else { + /* Edit person - email page */ + person = (ItemPerson *)ADDRITEM_PARENT(email); + if (addressbook_edit_person(abf, NULL, person, TRUE) == NULL) + return; + addressbook_reopen(); + addressbook_modified(); + return; + } + } else if (obj->type == ADDR_ITEM_PERSON) { + /* Edit person - basic page */ + ItemPerson *person = (ItemPerson *)obj; + + if (addressbook_edit_person(abf, NULL, person, FALSE) == NULL) + return; + addressbook_reopen(); + addressbook_modified(); + return; + } else if (obj->type == ADDR_ITEM_GROUP) { + ItemGroup *itemGrp = (ItemGroup *)obj; + + if (addressbook_edit_group(abf, NULL, itemGrp) == NULL) + return; + parent = iter; + parent_found = TRUE; + node_found = addressbook_find_group_node(&parent, &node, itemGrp); + name = ADDRITEM_NAME(itemGrp); + } else { + return; + } + + /* Update tree node with node name */ + if (node_found) { + addressbook_change_node_name(&node, name); + addressbook_reopen(); + } +} + +static void addressbook_delete_address_cb(gpointer data, guint action, + GtkWidget *widget) +{ + addressbook_del_clicked(NULL, NULL); +} + +static void addressbook_copy_address_cb(gpointer data, guint action, + GtkWidget *widget) +{ + AddressObject *obj; + GList *node; + + if (_addressListSelection_ == NULL) + return; + + g_list_free(_clipObjectList_); + _clipObjectList_ = NULL; + + node = _addressListSelection_; + while (node) { + obj = node->data; + if (obj->type == ADDR_ITEM_PERSON) { + _clipObjectList_ = g_list_append(_clipObjectList_, obj); + } + node = g_list_next(node); + } + + addressbook_menuitem_set_sensitive(); +} + +static void addressbook_paste_address_cb(gpointer data, guint action, + GtkWidget *widget) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + AddressObject *obj = NULL, *pobj = NULL; + AddressDataSource *ds = NULL; + AddressBookFile *abf = NULL; + ItemFolder *folder = NULL; + ItemPerson *clipPerson, *person; + GList *cur; + GList *node; + + if (!_clipObjectList_) + return; + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + gtk_tree_model_get(model, &iter, COL_OBJ, &pobj, -1); + if (pobj->type == ADDR_ITEM_FOLDER) + folder = ADAPTER_FOLDER(pobj)->itemFolder; + else if (pobj->type == ADDR_DATASOURCE) + folder = NULL; + else + return; + + ds = addressbook_find_datasource(&iter); + if (ds == NULL) + return; + + abf = ds->rawDataSource; + if (abf == NULL) + return; + + node = _clipObjectList_; + while (node) { + obj = node->data; + node = g_list_next(node); + if (obj->type != ADDR_ITEM_PERSON) + continue; + clipPerson = (ItemPerson *)obj; + + person = addrbook_add_address_list(abf, folder, NULL); + ADDRITEM_NAME(person) = g_strdup(ADDRITEM_NAME(clipPerson)); + person->firstName = g_strdup(clipPerson->firstName); + person->lastName = g_strdup(clipPerson->lastName); + person->nickName = g_strdup(clipPerson->nickName); + for (cur = clipPerson->listEMail; cur != NULL; cur = cur->next) { + ItemEMail *email = cur->data; + addritem_person_add_email(person, addritem_copy_item_email(email)); + } + for (cur = clipPerson->listAttrib; cur != NULL; cur = cur->next) { + UserAttribute *attr = cur->data; + addritem_person_add_attribute(person, addritem_copy_attribute(attr)); + } + } + + if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) + addressbook_reopen(); + addressbook_modified(); +} + +static void close_cb(gpointer data, guint action, GtkWidget *widget) +{ + addressbook_close(); +} + +static void addressbook_file_save_cb(gpointer data, guint action, GtkWidget *widget) +{ + addressbook_export_to_file(); +} + +static void addressbook_person_expand_node(GtkTreeView *treeview, + GtkTreeIter *iter, GtkTreePath *path, + gpointer *data) +{ + GtkTreeModel *model; + ItemPerson *person = NULL; + + model = gtk_tree_view_get_model(treeview); + gtk_tree_model_get(model, iter, COL_L_OBJ, &person, -1); + if (person) + addritem_person_set_opened(person, TRUE); +} + +static void addressbook_person_collapse_node(GtkTreeView *treeview, + GtkTreeIter *iter, + GtkTreePath *path, gpointer *data) +{ + GtkTreeModel *model; + ItemPerson *person = NULL; + + model = gtk_tree_view_get_model(treeview); + gtk_tree_model_get(model, iter, COL_L_OBJ, &person, -1); + if (person) + addritem_person_set_opened(person, FALSE); +} + +static void addressbook_drag_begin(GtkWidget *widget, + GdkDragContext *drag_context, gpointer data) +{ + list_on_drag = TRUE; + /* gtk_drag_set_icon_default(drag_context); */ +} + +static void addressbook_drag_end(GtkWidget *widget, + GdkDragContext *drag_context, gpointer data) +{ +} + +static void addressbook_drag_data_get(GtkWidget *widget, + GdkDragContext *drag_context, + GtkSelectionData *selection_data, + guint info, guint time, gpointer data) +{ + if (info == DRAG_TYPE_OBJ) { + gtk_selection_data_set(selection_data, selection_data->target, + 8, (guchar *)"drag-from-list", 14); + } +} + +static gchar *addressbook_format_item_list(ItemPerson *person, ItemEMail *email) +{ + gchar *str = NULL; + gchar *eMailAlias = ADDRITEM_NAME(email); + + if (eMailAlias && *eMailAlias != '\0') { + if (person) { + str = g_strdup_printf("%s - %s", ADDRITEM_NAME(person), eMailAlias); + } else { + str = g_strdup(eMailAlias); + } + } + return str; +} + +static gboolean addressbook_match_item(const gchar *name, + const gchar *email_alias, + const gchar *addr, + const gchar *remarks, + const gchar *str) +{ + if (!name) + return FALSE; + if (!str || str[0] == '\0') + return TRUE; + if (strcasestr(name, str)) + return TRUE; + else if (email_alias && strcasestr(email_alias, str)) + return TRUE; + else if (addr && strcasestr(addr, str)) + return TRUE; + else if (remarks && strcasestr(remarks, str)) + return TRUE; + + return FALSE; +} + +static void addressbook_load_group(ItemGroup *itemGroup) +{ + GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview); + GtkTreeModel *model; + GtkTreeIter iter; + GList *items = itemGroup->listEMail; + AddressTypeControlItem *atci = addrbookctl_lookup(ADDR_ITEM_EMAIL); + const gchar *search_str; + + model = gtk_tree_view_get_model(listview); + search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry)); + + for (; items != NULL; items = g_list_next(items)) { + ItemEMail *email = items->data; + ItemPerson *person; + const gchar *name; + gchar *str; + + if (!email) continue; + + person = (ItemPerson *)ADDRITEM_PARENT(email); + if (!person) { + g_warning("email %p (%s) don't have parent\n", email, email->address); + continue; + } + if (!addressbook_match_item(ADDRITEM_NAME(person), + ADDRITEM_NAME(email), + email->address, email->remarks, + search_str)) + continue; + + str = addressbook_format_item_list(person, email); + if (str) { + name = str; + } else { + name = ADDRITEM_NAME(person); + } + gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL); + gtk_tree_store_set(GTK_TREE_STORE(model), &iter, + COL_NAME, name, + COL_ADDRESS, email->address ? email->address : "", + COL_NICKNAME, person->nickName ? person->nickName : "", + COL_REMARKS, email->remarks ? email->remarks : "", + COL_L_OBJ, email, + COL_L_PIXBUF, atci->icon_pixbuf, + -1); + g_free(str); + } +} + +static void addressbook_folder_load_person(ItemFolder *itemFolder) +{ + GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview); + GtkTreeModel *model; + GList *items; + AddressTypeControlItem *atci = addrbookctl_lookup(ADDR_ITEM_PERSON); + AddressTypeControlItem *atciMail = addrbookctl_lookup(ADDR_ITEM_EMAIL); + const gchar *search_str; + + if (atci == NULL) + return; + if (atciMail == NULL) + return; + + model = gtk_tree_view_get_model(listview); + search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry)); + + /* Load email addresses */ + items = addritem_folder_get_person_list(itemFolder); + for (; items != NULL; items = g_list_next(items)) { + GtkTreeIter iperson, iemail; + gboolean flgFirst = TRUE, haveAddr = FALSE; + ItemPerson *person; + ItemEMail *email; + GList *node; + + person = (ItemPerson *)items->data; + if (!person) + continue; + + node = person->listEMail; + if (node && node->data) { + email = node->data; + if (!addressbook_match_item(ADDRITEM_NAME(person), ADDRITEM_NAME(email), email->address, email->remarks, search_str)) + continue; + } else { + if (!addressbook_match_item(ADDRITEM_NAME(person), NULL, NULL, NULL, search_str)) + continue; + } + + while (node) { + const gchar *name; + + email = node->data; + node = g_list_next(node); + + if (flgFirst) { + /* First email belongs with person */ + gchar *str = addressbook_format_item_list(person, email); + if (str) { + name = str; + } else { + name = ADDRITEM_NAME(person); + } + + gtk_tree_store_append(GTK_TREE_STORE(model), + &iperson, NULL); + gtk_tree_store_set(GTK_TREE_STORE(model), + &iperson, + COL_NAME, name, + COL_ADDRESS, email->address ? email->address : "", + COL_NICKNAME, person->nickName ? person->nickName : "", + COL_REMARKS, email->remarks ? email->remarks : "", + COL_L_OBJ, person, + COL_L_PIXBUF, atci->icon_pixbuf, + -1); + g_free(str); + } else { + /* Subsequent email is a child node of person */ + name = ADDRITEM_NAME(email); + gtk_tree_store_append(GTK_TREE_STORE(model), + &iemail, &iperson); + gtk_tree_store_set(GTK_TREE_STORE(model), + &iemail, + COL_NAME, name, + COL_ADDRESS, email->address ? email->address : "", + COL_NICKNAME, "", + COL_REMARKS, email->remarks ? email->remarks : "", + COL_L_OBJ, email, + COL_L_PIXBUF, atciMail->icon_pixbuf, + -1); + } + flgFirst = FALSE; + haveAddr = TRUE; + } + if (!haveAddr) { + /* Have name without EMail */ + gtk_tree_store_append(GTK_TREE_STORE(model), + &iperson, NULL); + gtk_tree_store_set(GTK_TREE_STORE(model), + &iperson, + COL_NAME, ADDRITEM_NAME(person), + COL_ADDRESS, "", + COL_NICKNAME, person->nickName ? person->nickName : "", + COL_REMARKS, "", + COL_L_OBJ, person, + COL_L_PIXBUF, atci->icon_pixbuf, + -1); + } + if (person->isOpened) { + GtkTreePath *path; + path = gtk_tree_model_get_path(model, &iperson); + gtk_tree_view_expand_row(listview, path, TRUE); + gtk_tree_path_free(path); + } + } + + /* Free up the list */ + mgu_clear_list(items); + g_list_free(items); +} + +static void addressbook_folder_load_group(ItemFolder *itemFolder) +{ + GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview); + GtkTreeModel *model; + GList *items; + AddressTypeControlItem *atci = addrbookctl_lookup(ADDR_ITEM_GROUP); + const gchar *search_str; + + if (!atci) + return; + + model = gtk_tree_view_get_model(listview); + search_str = gtk_entry_get_text(GTK_ENTRY(addrbook.entry)); + + /* Load any groups */ + items = addritem_folder_get_group_list(itemFolder); + for (; items != NULL; items = g_list_next(items)) { + GtkTreeIter iter; + ItemGroup *group = items->data; + + if (!group) + continue; + if (!addressbook_match_item(ADDRITEM_NAME(group), + NULL, NULL, NULL, search_str)) + continue; + + gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL); + gtk_tree_store_set(GTK_TREE_STORE(model), &iter, + COL_NAME, ADDRITEM_NAME(group), + COL_ADDRESS, "", + COL_NICKNAME, "", + COL_REMARKS, "", + COL_L_OBJ, group, + COL_L_PIXBUF, atci->icon_pixbuf, + -1); + } + + /* Free up the list */ + mgu_clear_list(items); + g_list_free(items); +} + +static AddressDataSource *addressbook_find_datasource(GtkTreeIter *iter) +{ + GtkTreeModel *model; + GtkTreeIter iter_, parent; + AddressDataSource *ds = NULL; + AddressObject *ao; + + g_return_val_if_fail(addrbook.treeview != NULL, NULL); + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview)); + parent = *iter; + + do { + iter_ = parent; + if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter_) < 1) + return NULL; + ao = NULL; + gtk_tree_model_get(model, &iter_, COL_OBJ, &ao, -1); + if (ao) { + /* g_print("ao->type = %d\n", ao->type); */ + if (ao->type == ADDR_DATASOURCE) { + AdapterDSource *ads = ADAPTER_DSOURCE(ao); + /* g_print("found it\n"); */ + ds = ads->dataSource; + break; + } + } + } while (gtk_tree_model_iter_parent(model, &parent, &iter_)); + + return ds; +} + +/* +* Load address list widget with children of specified object. +* Enter: obj Parent object to be loaded. +*/ +static void addressbook_set_list(AddressObject *obj) +{ + GtkTreeView *listview = GTK_TREE_VIEW(addrbook.listview); + GtkTreeModel *model; + AddressDataSource *ds = NULL; + AdapterDSource *ads = NULL; + gboolean sorted; + gint address_list_sort_id = COL_NAME; + GtkSortType order = GTK_SORT_ASCENDING; + + debug_print("addressbook_set_list\n"); + + model = gtk_tree_view_get_model(listview); + + if (obj == NULL) { + gtk_tree_store_clear(GTK_TREE_STORE(model)); + return; + } + + if (obj->type == ADDR_INTERFACE) { + return; + } + + gtk_tree_store_clear(GTK_TREE_STORE(model)); + sorted = gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(model), + &address_list_sort_id, + &order); + if (!sorted) { + address_list_sort_id = COL_NAME; + order = GTK_SORT_ASCENDING; + } + gtkut_tree_sortable_unset_sort_column_id(GTK_TREE_SORTABLE(model)); + + if (obj->type == ADDR_DATASOURCE) { + ads = ADAPTER_DSOURCE(obj); + ds = ADAPTER_DSOURCE(obj)->dataSource; + if (ds) { + /* Load root folder */ + ItemFolder *rootFolder = NULL; + rootFolder = addrindex_ds_get_root_folder(ds); + addressbook_folder_load_person(addrindex_ds_get_root_folder(ds)); + addressbook_folder_load_group(addrindex_ds_get_root_folder(ds)); + } + } else if (obj->type == ADDR_ITEM_GROUP) { + /* Load groups */ + ItemGroup *itemGroup = ADAPTER_GROUP(obj)->itemGroup; + addressbook_load_group(itemGroup); + } else if (obj->type == ADDR_ITEM_FOLDER) { + /* Load folders */ + ItemFolder *itemFolder = ADAPTER_FOLDER(obj)->itemFolder; + addressbook_folder_load_person(itemFolder); + addressbook_folder_load_group(itemFolder); + } + + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), + address_list_sort_id, order); +} + +/* +* Free adaptor for specified node. +*/ +static void addressbook_free_adapter(GtkTreeIter *iter) +{ + GtkTreeModel *model; + AddressObject *ao = NULL; + + g_return_if_fail(addrbook.treeview != NULL); + g_return_if_fail(iter != NULL); + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview)); + if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), iter) < 1) + return; + gtk_tree_model_get(model, iter, COL_OBJ, &ao, -1); + if (ao == NULL) + return; + + if (ao->type == ADDR_INTERFACE) { + AdapterInterface *ai = ADAPTER_INTERFACE(ao); + addrbookctl_free_interface(ai); + } else if (ao->type == ADDR_DATASOURCE) { + AdapterDSource *ads = ADAPTER_DSOURCE(ao); + addrbookctl_free_datasource(ads); + } else if (ao->type == ADDR_ITEM_FOLDER) { + AdapterFolder *af = ADAPTER_FOLDER(ao); + addrbookctl_free_folder(af); + } else if (ao->type == ADDR_ITEM_GROUP) { + AdapterGroup *ag = ADAPTER_GROUP(ao); + addrbookctl_free_group(ag); + } + + gtk_tree_store_set(GTK_TREE_STORE(model), iter, COL_OBJ, NULL, -1); +} + +/* +* Free all children adapters. +*/ +static void addressbook_free_child_adapters(GtkTreeIter *iter) +{ + GtkTreeModel *model; + GtkTreeIter child; + gboolean valid; + + g_return_if_fail(iter != NULL); + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview)); + valid = gtk_tree_model_iter_children(model, &child, iter); + while (valid) { + addressbook_free_child_adapters(&child); + addressbook_free_adapter(&child); + valid = gtk_tree_model_iter_next(model, &child); + } +} + +AdapterDSource *addressbook_create_ds_adapter(AddressDataSource *ds, + AddressObjectType otype, + gchar *name) +{ + AdapterDSource *adapter = g_new0(AdapterDSource, 1); + ADDRESS_OBJECT(adapter)->type = ADDR_DATASOURCE; + ADDRESS_OBJECT_NAME(adapter) = g_strdup(name); + adapter->dataSource = ds; + adapter->subType = otype; + return adapter; +} + +void addressbook_ads_set_name(AdapterDSource *adapter, gchar *value) +{ + ADDRESS_OBJECT_NAME(adapter) = + mgu_replace_string(ADDRESS_OBJECT_NAME(adapter), value); +} + +/* + * Load tree from address index with the initial data. + */ +static void addressbook_load_tree(void) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeModel *model; + GtkTreeIter iter, new_iter; + GtkTreePath *path; + GList *nodeIf, *nodeDS; + AdapterInterface *adapter; + AddressInterface *iface; + AddressTypeControlItem *atci; + AddressDataSource *ds; + AdapterDSource *ads; + gchar *name; + + model = gtk_tree_view_get_model(treeview); + + nodeIf = _addressInterfaceList_; + while (nodeIf) { + adapter = nodeIf->data; + gtkut_tree_row_reference_get_iter(model, adapter->tree_row, &iter); + iface = adapter->iface; + atci = adapter->atci; + if (iface) { + if (iface->useInterface) { + /* Load data sources below interface node */ + nodeDS = iface->listSource; + while (nodeDS) { + ds = nodeDS->data; + name = addrindex_ds_get_name(ds); + ads = addressbook_create_ds_adapter(ds, atci->objectType, name); + addressbook_add_object(&iter, &new_iter, ADDRESS_OBJECT(ads)); + nodeDS = g_list_next( nodeDS ); + } + path = gtk_tree_model_get_path(model, &iter); + gtk_tree_view_expand_row(treeview, path, TRUE); + gtk_tree_path_free(path); + } + } + nodeIf = g_list_next(nodeIf); + } +} + +/* + * Convert the old address book to new format. + */ +static gboolean addressbook_convert(AddressIndex *addrIndex) +{ + gboolean retVal = FALSE; + gboolean errFlag = TRUE; + gchar *msg = NULL; + + /* Read old address book, performing conversion */ + debug_print( "Reading and converting old address book...\n" ); + addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE ); + addrindex_read_data( addrIndex ); + if( addrIndex->retVal == MGU_NO_FILE ) { + /* We do not have a file - new user */ + debug_print( "New user... create new books...\n" ); + addrindex_create_new_books( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + /* Save index file */ + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + retVal = TRUE; + errFlag = FALSE; + } + else { + msg = _( "New user, could not save index file." ); + } + } + else { + msg = _( "New user, could not save address book files." ); + } + } + else { + /* We have an old file */ + if( addrIndex->wasConverted ) { + /* Converted successfully - save address index */ + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + msg = _( "Old address book converted successfully." ); + retVal = TRUE; + errFlag = FALSE; + } + else { + msg = _("Old address book converted,\n" + "could not save new address index file" ); + } + } + else { + /* File conversion failed - just create new books */ + debug_print( "File conversion failed... just create new books...\n" ); + addrindex_create_new_books( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + /* Save index */ + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + msg = _("Could not convert address book,\n" + "but created empty new address book files." ); + retVal = TRUE; + errFlag = FALSE; + } + else { + msg = _("Could not convert address book,\n" + "could not create new address book files." ); + } + } + else { + msg = _("Could not convert address book\n" + "and could not create new address book files." ); + } + } + } + if( errFlag ) { + debug_print( "Error\n%s\n", msg ); + alertpanel( _( "Address book conversion error" ), msg, GTK_STOCK_CLOSE, NULL, NULL ); + } + else if( msg ) { + debug_print( "Warning\n%s\n", msg ); + alertpanel( _( "Address book conversion" ), msg, GTK_STOCK_CLOSE, NULL, NULL ); + } + + return retVal; +} + +void addressbook_read_file(void) +{ + AddressIndex *addrIndex = NULL; + + debug_print( "Reading address index...\n" ); + if (_addressIndex_) { + debug_print("address book already read!\n"); + return; + } + + addrIndex = addrindex_create_index(); + + /* Use new address book index. */ + addrindex_set_file_path(addrIndex, get_rc_dir()); + addrindex_set_file_name(addrIndex, ADDRESSBOOK_INDEX_FILE); + addrindex_read_data(addrIndex); + if (addrIndex->retVal == MGU_NO_FILE) { + /* Conversion required */ + debug_print("Converting...\n"); + if (addressbook_convert(addrIndex)) { + addrindex_create_extra_books(addrIndex); + _addressIndex_ = addrIndex; + } + } else if (addrIndex->retVal == MGU_SUCCESS) { + addrindex_create_extra_books(addrIndex); + _addressIndex_ = addrIndex; + } else { + gchar msg[1024]; + + /* Error reading address book */ + debug_print("Could not read address index.\n"); + addrindex_print_index(addrIndex, stdout); + g_snprintf(msg, sizeof(msg), + _("Could not read address index:\n\n%s%c%s"), + addrIndex->filePath, G_DIR_SEPARATOR, + addrIndex->fileName); + alertpanel_message(_("Address Book Error"), msg, ALERT_ERROR); + } + debug_print( "done.\n" ); +} + +#if 0 +void addressbook_read_file_old( void ) { + AddressIndex *addrIndex = NULL; + gboolean errFlag = TRUE; + gchar *msg = NULL; + + if( _addressIndex_ ) { + debug_print( "address book already read!!!\n" ); + return; + } + + addrIndex = addrindex_create_index(); + + /* Use use new address book. */ + /* addrindex_set_file_path( addrIndex, "/home/match/tmp/empty-dir" ); */ + addrindex_set_file_path( addrIndex, get_rc_dir() ); + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + + debug_print( "Reading address index...\n" ); + addrindex_read_data( addrIndex ); + if( addrIndex->retVal == MGU_NO_FILE ) { + /* Read old address book, performing conversion */ + debug_print( "Reading and converting old address book...\n" ); + addrindex_set_file_name( addrIndex, ADDRESSBOOK_OLD_FILE ); + addrindex_read_data( addrIndex ); + if( addrIndex->retVal == MGU_NO_FILE ) { + /* We do not have a file - new user */ + debug_print( "New user... create new books...\n" ); + addrindex_create_new_books( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + /* Save index file */ + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + errFlag = FALSE; + } + else { + msg = g_strdup( _( "New user, could not save index file." ) ); + } + } + else { + msg = g_strdup( _( "New user, could not save address book files." ) ); + } + } + else { + /* We have an old file */ + if( addrIndex->wasConverted ) { + /* Converted successfully - save address index */ + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + msg = g_strdup( _( "Old address book converted successfully." ) ); + errFlag = FALSE; + } + else { + msg = g_strdup( _( + "Old address book converted, " \ + "could not save new address index file" ) ); + } + } + else { + /* File conversion failed - just create new books */ + debug_print( "File conversion failed... just create new books...\n" ); + addrindex_create_new_books( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + /* Save index */ + addrindex_set_file_name( addrIndex, ADDRESSBOOK_INDEX_FILE ); + addrindex_save_data( addrIndex ); + if( addrIndex->retVal == MGU_SUCCESS ) { + msg = g_strdup( _( + "Could not convert address book, " \ + "but created empty new address book files." ) ); + errFlag = FALSE; + } + else { + msg = g_strdup( _( + "Could not convert address book, " \ + "could not create new address book files." ) ); + } + } + else { + msg = g_strdup( _( + "Could not convert address book " \ + "and could not create new address book files." ) ); + } + } + } + } + else if( addrIndex->retVal == MGU_SUCCESS ) { + errFlag = FALSE; + } + else { + debug_print( "Could not read address index.\n" ); + addrindex_print_index( addrIndex, stdout ); + msg = g_strdup( _( "Could not read address index" ) ); + } + _addressIndex_ = addrIndex; + + if( errFlag ) { + debug_print( "Error\n%s\n", msg ); + alertpanel( _( "Address Book Conversion Error" ), msg, + GTK_STOCK_CLOSE, NULL, NULL ); + } + else { + if( msg ) { + debug_print( "Warning\n%s\n", msg ); + alertpanel( _( "Address Book Conversion" ), msg, + GTK_STOCK_CLOSE, NULL, NULL ); + } + } + if( msg ) g_free( msg ); + debug_print( "done.\n" ); +} +#endif + +/* +* Add object into the address index tree widget. +* Enter: node Parent node. +* obj Object to add. +* Return: Node that was added, or NULL if object not added. +*/ +static gboolean addressbook_add_object(GtkTreeIter *iter, GtkTreeIter *new_iter, + AddressObject *obj) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeModel *model; + GtkTreeIter added; + AddressObject *pobj; + AddressObjectType otype; + AddressTypeControlItem *atci = NULL; + const gchar *name; + + g_return_val_if_fail(iter != NULL, FALSE); + g_return_val_if_fail(obj != NULL, FALSE); + + model = gtk_tree_view_get_model(treeview); + gtk_tree_model_get(model, iter, COL_OBJ, &pobj, -1); + g_return_val_if_fail(pobj != NULL, FALSE); + + /* Determine object type to be displayed */ + if (obj->type == ADDR_DATASOURCE) { + otype = ADAPTER_DSOURCE(obj)->subType; + } else { + otype = obj->type; + } + + /* Handle any special conditions. */ + atci = addrbookctl_lookup(otype); + if (atci && atci->showInTree) { + /* Add object to tree */ + debug_print("addressbook_add_object: obj: %s\n", obj->name); + if (otype == ADDR_BOOK && obj->name && + !strcmp(obj->name, ADDR_DS_AUTOREG)) + name = _("Auto-registered address"); + else + name = obj->name; + gtk_tree_store_append(GTK_TREE_STORE(model), &added, iter); + gtk_tree_store_set(GTK_TREE_STORE(model), &added, + COL_FOLDER_NAME, name, + COL_OBJ, obj, + COL_PIXBUF, atci->icon_pixbuf, + COL_PIXBUF_OPEN, atci->icon_open_pixbuf, + -1); + if (new_iter) + *new_iter = added; + return TRUE; + } + + return FALSE; +} + +/* +* Add group into the address index tree. +* Enter: node Parent node. +* ds Data source. +* itemGroup Group to add. +* Return: Inserted node. +*/ +static gboolean addressbook_node_add_group(GtkTreeIter *iter, AddressDataSource *ds, ItemGroup *itemGroup, GtkTreeIter *new_iter) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeStore *store; + GtkTreeIter new_iter_; + AdapterGroup *adapter; + AddressTypeControlItem *atci = NULL; + gchar *name; + + if(ds == NULL) return FALSE; + if(iter == NULL || itemGroup == NULL) return FALSE; + + name = itemGroup->obj.name; + + atci = addrbookctl_lookup(ADDR_ITEM_GROUP); + + adapter = g_new0(AdapterGroup, 1); + ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_GROUP; + ADDRESS_OBJECT_NAME(adapter) = g_strdup(ADDRITEM_NAME(itemGroup)); + adapter->itemGroup = itemGroup; + + debug_print("addressbook_node_add_group: name: %s\n", name); + store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview)); + gtk_tree_store_append(store, &new_iter_, iter); + gtk_tree_store_set(store, &new_iter_, + COL_FOLDER_NAME, name, + COL_OBJ, adapter, + COL_PIXBUF, atci->icon_pixbuf, + COL_PIXBUF_OPEN, atci->icon_open_pixbuf, + -1); + if (new_iter) + *new_iter = new_iter_; + return TRUE; +} + +/* +* Add folder into the address index tree. +* Enter: iter Parent node. +* ds Data source. +* itemFolder Folder to add. +* otype Object type to display. +* new_iter Inserted node. +* Return: TRUE if inserted. +*/ +static gboolean addressbook_node_add_folder(GtkTreeIter *iter, AddressDataSource *ds, ItemFolder *itemFolder, AddressObjectType otype, GtkTreeIter *new_iter) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeStore *store; + GtkTreeIter new_iter_; + AdapterFolder *adapter; + AddressTypeControlItem *atci = NULL; + GList *listItems = NULL; + gchar *name; + ItemFolder *rootFolder; + + if (ds == NULL) + return FALSE; + if (iter == NULL || itemFolder == NULL) + return FALSE; + + /* Determine object type */ + atci = addrbookctl_lookup(otype); + if (atci == NULL) + return FALSE; + + store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview)); + + rootFolder = addrindex_ds_get_root_folder(ds); + if (itemFolder == rootFolder) { + new_iter_ = *iter; + } else { + name = itemFolder->obj.name; + + adapter = g_new0(AdapterFolder, 1); + ADDRESS_OBJECT_TYPE(adapter) = ADDR_ITEM_FOLDER; + ADDRESS_OBJECT_NAME(adapter) = g_strdup(ADDRITEM_NAME(itemFolder)); + adapter->itemFolder = itemFolder; + + debug_print("addressbook_node_add_folder: name: %s\n", name); + gtk_tree_store_append(store, &new_iter_, iter); + gtk_tree_store_set(store, &new_iter_, + COL_FOLDER_NAME, name, + COL_OBJ, adapter, + COL_PIXBUF, atci->icon_pixbuf, + COL_PIXBUF_OPEN, atci->icon_open_pixbuf, + -1); + } + + listItems = itemFolder->listFolder; + while (listItems) { + ItemFolder *item = listItems->data; + addressbook_node_add_folder(&new_iter_, ds, item, otype, NULL); + listItems = g_list_next(listItems); + } + listItems = itemFolder->listGroup; + while (listItems) { + ItemGroup *item = listItems->data; + addressbook_node_add_group(&new_iter_, ds, item, NULL); + listItems = g_list_next(listItems); + } + if (new_iter) + *new_iter = new_iter_; + return TRUE; +} + +#if 0 +static void addressbook_delete_object(AddressObject *obj) { + AdapterDSource *ads = NULL; + AddressDataSource *ds = NULL; + if (!obj) return; + + /* Remove data source. */ + /* printf( "Delete obj type : %d\n", obj->type ); */ + + ads = ADAPTER_DSOURCE(obj); + if( ads == NULL ) return; + ds = ads->dataSource; + if( ds == NULL ) return; + + /* Remove data source */ + if( addrindex_index_remove_datasource( _addressIndex_, ds ) ) { + addrindex_free_datasource( _addressIndex_, ds ); + } + /* Free up Adapter object */ + g_free( ADAPTER_DSOURCE(obj) ); +} +#endif + +void addressbook_export_to_file( void ) { + if( _addressIndex_ ) { + /* Save all new address book data */ + debug_print( "Saving address books...\n" ); + addrindex_save_all_books( _addressIndex_ ); + + debug_print( "Exporting addressbook to file...\n" ); + addrindex_save_data( _addressIndex_ ); + if( _addressIndex_->retVal != MGU_SUCCESS ) { + addrindex_print_index( _addressIndex_, stdout ); + } + + /* Notify address completion of new data */ + addressbook_modified(); + } +} + +static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, + gpointer data) +{ + if (event && event->keyval == GDK_Escape) + addressbook_close(); + return FALSE; +} + +static void size_allocated(GtkWidget *widget, GtkAllocation *allocation, + gpointer data) +{ + if (allocation->width <= 1 || allocation->height <= 1) + return; + + prefs_common.addressbook_width = allocation->width; + prefs_common.addressbook_height = allocation->height; +} + +/* +* Comparison using cell contents (text in first column). +*/ +static gint addressbook_tree_compare(GtkTreeModel *model, GtkTreeIter *a, + GtkTreeIter *b, gpointer data) +{ + gchar *name1 = NULL, *name2 = NULL; + AddressObject *obj1 = NULL, *obj2 = NULL; + gint ret; + + gtk_tree_model_get(model, a, COL_FOLDER_NAME, &name1, COL_OBJ, &obj1, + -1); + gtk_tree_model_get(model, b, COL_FOLDER_NAME, &name2, COL_OBJ, &obj2, + -1); + + /* Do not sort toplevel row */ + if (obj1 && obj1->type == ADDR_INTERFACE) + return 0; + + if (!name1 || !name2) { + if (!name1) + ret = (name2 != NULL); + else + ret = -1; + g_free(name2); + g_free(name1); + return ret; + } + ret = g_ascii_strcasecmp(name1, name2); + g_free(name2); + g_free(name1); + return ret; +} + +static gint addressbook_list_col_compare(GtkTreeModel *model, GtkTreeIter *a, + GtkTreeIter *b, gint col) +{ + gchar *name1 = NULL, *name2 = NULL; + gint ret; + + gtk_tree_model_get(model, a, col, &name1, -1); + gtk_tree_model_get(model, b, col, &name2, -1); + + if (!name1) + name1 = g_strdup(""); + if (!name2) + name2 = g_strdup(""); + ret = g_ascii_strcasecmp(name1, name2); + g_free(name2); + g_free(name1); + return ret; +} + +static gint addressbook_list_name_compare(GtkTreeModel *model, GtkTreeIter *a, + GtkTreeIter *b, gpointer data) +{ + gint ret; + + ret = addressbook_list_col_compare(model, a, b, COL_NAME); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_NICKNAME); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_ADDRESS); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_REMARKS); + + return ret; +} + +static gint addressbook_list_address_compare(GtkTreeModel *model, + GtkTreeIter *a, GtkTreeIter *b, + gpointer data) +{ + gint ret; + + ret = addressbook_list_col_compare(model, a, b, COL_ADDRESS); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_NAME); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_NICKNAME); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_REMARKS); + + return ret; +} + +static gint addressbook_list_nickname_compare(GtkTreeModel *model, + GtkTreeIter *a, GtkTreeIter *b, + gpointer data) +{ + gint ret; + + ret = addressbook_list_col_compare(model, a, b, COL_NICKNAME); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_NAME); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_ADDRESS); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_REMARKS); + + return ret; +} + +static gint addressbook_list_remarks_compare(GtkTreeModel *model, + GtkTreeIter *a, GtkTreeIter *b, + gpointer data) +{ + gint ret; + + ret = addressbook_list_col_compare(model, a, b, COL_REMARKS); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_NAME); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_NICKNAME); + if (ret == 0) + ret = addressbook_list_col_compare(model, a, b, COL_ADDRESS); + + return ret; +} + +static gboolean addressbook_list_select_func(GtkTreeSelection *selection, + GtkTreeModel *model, + GtkTreePath *path, + gboolean cur_selected, + gpointer data) +{ + return can_toggle_list_selection; +} + +/* static */ +gint addressbook_obj_name_compare(gconstpointer a, gconstpointer b) +{ + const AddressObject *obj = a; + const gchar *name = b; + AddressTypeControlItem *atci = NULL; + + if (!obj || !name) return -1; + + atci = addrbookctl_lookup( obj->type ); + if( ! atci ) return -1; + if( ! obj->name ) return -1; + return g_ascii_strcasecmp(obj->name, name); +} + +#if 0 +static void addressbook_book_show_message( AddressBookFile *abf ) { + gchar msgbuf[ADDRESSBOOK_MSGBUF_SIZE] = ""; + + if (abf) { + if (abf->retVal == MGU_SUCCESS) { + g_snprintf(msgbuf, sizeof(msgbuf), "%s", abf->name); + } else { + g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s", abf->name, mgu_error2string(abf->retVal)); + } + } + addressbook_status_show(msgbuf); +} +#endif + +static void addressbook_new_book_cb(gpointer data, guint action, GtkWidget *widget) +{ + GtkTreeModel *model; + GtkTreeIter iter; + AdapterDSource *ads; + AdapterInterface *adapter; + + adapter = addrbookctl_find_interface(ADDR_IF_BOOK); + if (adapter == NULL) + return; + if (!gtkut_tree_row_reference_equal(addrbook.tree_selected, adapter->tree_row)) + return; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview)); + gtkut_tree_row_reference_get_iter(model, addrbook.tree_selected, &iter); + + ads = addressbook_edit_book(_addressIndex_, NULL); + if (ads) { + addressbook_add_object(&iter, NULL, ADDRESS_OBJECT(ads)); + if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) { + addressbook_reopen(); + } + } +} + +static void addressbook_new_vcard_cb(gpointer data, guint action, GtkWidget *widget) +{ + GtkTreeModel *model; + GtkTreeIter iter; + AdapterDSource *ads; + AdapterInterface *adapter; + + adapter = addrbookctl_find_interface(ADDR_IF_VCARD); + if (adapter == NULL) + return; + if (!gtkut_tree_row_reference_equal(addrbook.tree_selected, adapter->tree_row)) + return; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview)); + gtkut_tree_row_reference_get_iter(model, addrbook.tree_selected, &iter); + + ads = addressbook_edit_vcard(_addressIndex_, NULL); + if (ads) { + addressbook_add_object(&iter, NULL, ADDRESS_OBJECT(ads)); + if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) { + addressbook_reopen(); + } + addressbook_modified(); + } +} + +#if 0 +static void addressbook_vcard_show_message( VCardFile *vcf ) { + gchar msgbuf[ADDRESSBOOK_MSGBUF_SIZE] = ""; + + if (vcf) { + if (vcf->retVal == MGU_SUCCESS) { + g_snprintf(msgbuf, sizeof(msgbuf), "%s", vcf->name); + } else { + g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s", vcf->name, mgu_error2string(vcf->retVal)); + } + } + addressbook_status_show(msgbuf); +} +#endif + +#ifdef USE_JPILOT +static void addressbook_new_jpilot_cb(gpointer data, guint action, GtkWidget *widget) +{ + GtkTreeModel *model; + GtkTreeIter iter; + AdapterDSource *ads; + AdapterInterface *adapter; + AddressInterface *iface; + + adapter = addrbookctl_find_interface(ADDR_IF_JPILOT); + if (adapter == NULL) + return; + if (!gtkut_tree_row_reference_equal(addrbook.tree_selected, adapter->tree_row)) + return; + iface = adapter->iface; + if (!iface->haveLibrary) + return; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview)); + gtkut_tree_row_reference_get_iter(model, addrbook.tree_selected, &iter); + + ads = addressbook_edit_jpilot(_addressIndex_, NULL); + if (ads) { + addressbook_add_object(&iter, NULL, ADDRESS_OBJECT(ads)); + if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) { + addressbook_reopen(); + } + } +} + +#if 0 +static void addressbook_jpilot_show_message( JPilotFile *jpf ) { + gchar msgbuf[ADDRESSBOOK_MSGBUF_SIZE] = ""; + + if (jpf) { + if (jpf->retVal == MGU_SUCCESS) { + g_snprintf(msgbuf, sizeof(msgbuf), "%s", jpf->name); + } else { + g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s", jpf->name, mgu_error2string(jpf->retVal)); + } + } + addressbook_status_show(msgbuf); +} +#endif +#endif /* USE_JPILOT */ + +#ifdef USE_LDAP +static void addressbook_new_ldap_cb(gpointer data, guint action, GtkWidget *widget) +{ + GtkTreeModel *model; + GtkTreeIter iter; + AdapterDSource *ads; + AdapterInterface *adapter; + AddressInterface *iface; + + adapter = addrbookctl_find_interface(ADDR_IF_LDAP); + if (adapter == NULL) + return; + if (!gtkut_tree_row_reference_equal(addrbook.tree_selected, adapter->tree_row)) + return; + iface = adapter->iface; + if (!iface->haveLibrary) + return; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(addrbook.treeview)); + gtkut_tree_row_reference_get_iter(model, addrbook.tree_selected, &iter); + + ads = addressbook_edit_ldap(_addressIndex_, NULL); + if( ads ) { + addressbook_add_object(&iter, NULL, ADDRESS_OBJECT(ads)); + if (gtkut_tree_row_reference_equal(addrbook.tree_selected, addrbook.tree_opened)) { + addressbook_reopen(); + } + } +} + +static void addressbook_ldap_show_message(SyldapServer *svr) +{ + gchar msgbuf[ADDRESSBOOK_MSGBUF_SIZE] = ""; + + if (svr) { + if (svr->busyFlag) { + g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s", svr->name, ADDRESSBOOK_LDAP_BUSYMSG); + } else { + if (svr->retVal == MGU_SUCCESS) { + g_snprintf(msgbuf, sizeof(msgbuf), "%s", svr->name); + } else { + g_snprintf(msgbuf, sizeof(msgbuf), "%s: %s", svr->name, mgu_error2string(svr->retVal)); + } + } + } + addressbook_status_show(msgbuf); +} + +static void ldapsearch_callback(SyldapServer *sls) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + AddressObject *obj; + AdapterDSource *ads = NULL; + AddressDataSource *ds = NULL; + AddressInterface *iface = NULL; + + if (sls == NULL) + return; + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter) == 0) + return; + + gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1); + if (obj == NULL) + return; + if (obj->type == ADDR_DATASOURCE) { + ads = ADAPTER_DSOURCE(obj); + if (ads->subType == ADDR_LDAP) { + SyldapServer *server; + + ds = ads->dataSource; + if (ds == NULL) + return; + iface = ds->iface; + if (!iface->haveLibrary) + return; + server = ds->rawDataSource; + if (server == sls) { + /* Read from cache */ + gtk_widget_show(addrbook.window); + addressbook_set_list(obj); + addressbook_ldap_show_message(sls); + gtk_widget_show(addrbook.window); + gtk_entry_set_text(GTK_ENTRY(addrbook.entry), ""); + } + } + } +} +#endif + +/* + * Lookup button handler. + */ +static void addressbook_lup_clicked(GtkButton *button, gpointer data) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + AddressObject *obj; + AdapterDSource *ads = NULL; +#ifdef USE_LDAP + AddressDataSource *ds = NULL; + AddressInterface *iface = NULL; +#endif /* USE_LDAP */ + gchar *sLookup; + + selection = gtk_tree_view_get_selection(treeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + if (gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter) == 0) + return; + + gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1); + if (obj == NULL) + return; + + sLookup = gtk_editable_get_chars(GTK_EDITABLE(addrbook.entry), 0, -1); + g_strstrip(sLookup); + + if (obj->type == ADDR_DATASOURCE) { + ads = ADAPTER_DSOURCE(obj); +#ifdef USE_LDAP + if (ads->subType == ADDR_LDAP) { + SyldapServer *server; + + ds = ads->dataSource; + if (ds == NULL) + return; + iface = ds->iface; + if (!iface->haveLibrary) + return; + server = ds->rawDataSource; + if (server) { + syldap_cancel_read(server); + if (*sLookup == '\0' || strlen(sLookup) < 1 ) + return; + syldap_set_search_value(server, sLookup); + syldap_set_callback(server, ldapsearch_callback); + syldap_read_data_th(server); + addressbook_ldap_show_message(server); + } + } else +#endif /* USE_LDAP */ + addressbook_set_list(obj); + } else { + addressbook_set_list(obj); + } + + g_free(sLookup); +} + +static void addressbook_close_clicked(GtkButton *button, gpointer data) +{ + addressbook_close(); +} + +/* ********************************************************************** +* Build lookup tables. +* *********************************************************************** +*/ + +/* +* Build table that controls the rendering of object types. +*/ +void addrbookctl_build_map(GtkWidget *window) +{ + AddressTypeControlItem *atci; + + /* Build icons */ + stock_pixbuf_gdk(window, STOCK_PIXMAP_FOLDER_CLOSE, &folderpix); + stock_pixbuf_gdk(window, STOCK_PIXMAP_FOLDER_OPEN, &folderopenpix); + stock_pixbuf_gdk(window, STOCK_PIXMAP_GROUP, &grouppix); + stock_pixbuf_gdk(window, STOCK_PIXMAP_VCARD, &vcardpix); + stock_pixbuf_gdk(window, STOCK_PIXMAP_BOOK, &bookpix); + stock_pixbuf_gdk(window, STOCK_PIXMAP_PERSON, &personpix); + stock_pixbuf_gdk(window, STOCK_PIXMAP_ADDRESS, &addresspix); + stock_pixbuf_gdk(window, STOCK_PIXMAP_JPILOT, &jpilotpix); + stock_pixbuf_gdk(window, STOCK_PIXMAP_CATEGORY, &categorypix); + stock_pixbuf_gdk(window, STOCK_PIXMAP_LDAP, &ldappix); + + _addressBookTypeHash_ = g_hash_table_new(g_int_hash, g_int_equal); + _addressBookTypeList_ = NULL; + + /* Interface */ + atci = g_new0(AddressTypeControlItem, 1); + atci->objectType = ADDR_INTERFACE; + atci->interfaceType = ADDR_IF_NONE; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = FALSE; + atci->displayName = _("Interface"); + atci->icon_pixbuf = folderpix; + atci->icon_open_pixbuf = folderopenpix; + atci->menuCommand = NULL; + g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci); + _addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci); + + /* Address book */ + atci = g_new0(AddressTypeControlItem, 1); + atci->objectType = ADDR_BOOK; + atci->interfaceType = ADDR_IF_BOOK; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = FALSE; + atci->displayName = _("Address Book"); + atci->icon_pixbuf = bookpix; + atci->icon_open_pixbuf = bookpix; + atci->menuCommand = "/File/New Book"; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); + + /* Item person */ + atci = g_new0(AddressTypeControlItem, 1); + atci->objectType = ADDR_ITEM_PERSON; + atci->interfaceType = ADDR_IF_NONE; + atci->showInTree = FALSE; + atci->treeExpand = FALSE; + atci->treeLeaf = FALSE; + atci->displayName = _("Person"); + atci->icon_pixbuf = personpix; + atci->icon_open_pixbuf = personpix; + atci->menuCommand = NULL; + g_hash_table_insert( _addressBookTypeHash_, &atci->objectType, atci ); + _addressBookTypeList_ = g_list_append( _addressBookTypeList_, atci ); + + /* Item email */ + atci = g_new0(AddressTypeControlItem, 1); + atci->objectType = ADDR_ITEM_EMAIL; + atci->interfaceType = ADDR_IF_NONE; + atci->showInTree = FALSE; + atci->treeExpand = FALSE; + atci->treeLeaf = TRUE; + atci->displayName = _("EMail Address"); + atci->icon_pixbuf = addresspix; + atci->icon_open_pixbuf = addresspix; + atci->menuCommand = NULL; + g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci); + _addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci); + + /* Item group */ + atci = g_new0(AddressTypeControlItem, 1); + atci->objectType = ADDR_ITEM_GROUP; + atci->interfaceType = ADDR_IF_BOOK; + atci->showInTree = TRUE; + atci->treeExpand = FALSE; + atci->treeLeaf = FALSE; + atci->displayName = _("Group"); + atci->icon_pixbuf = grouppix; + atci->icon_open_pixbuf = grouppix; + atci->menuCommand = NULL; + g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci); + _addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci); + + /* Item folder */ + atci = g_new0(AddressTypeControlItem, 1); + atci->objectType = ADDR_ITEM_FOLDER; + atci->interfaceType = ADDR_IF_BOOK; + atci->showInTree = TRUE; + atci->treeExpand = FALSE; + atci->treeLeaf = FALSE; + atci->displayName = _("Folder"); + atci->icon_pixbuf = folderpix; + atci->icon_open_pixbuf = folderopenpix; + atci->menuCommand = NULL; + g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci); + _addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci); + + /* vCard */ + atci = g_new0(AddressTypeControlItem, 1); + atci->objectType = ADDR_VCARD; + atci->interfaceType = ADDR_IF_VCARD; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = TRUE; + atci->displayName = _("vCard"); + atci->icon_pixbuf = vcardpix; + atci->icon_open_pixbuf = vcardpix; + atci->menuCommand = "/File/New vCard"; + g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci); + _addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci); + + /* JPilot */ + atci = g_new0(AddressTypeControlItem, 1); + atci->objectType = ADDR_JPILOT; + atci->interfaceType = ADDR_IF_JPILOT; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = FALSE; + atci->displayName = _("JPilot"); + atci->icon_pixbuf = jpilotpix; + atci->icon_open_pixbuf = jpilotpix; + atci->menuCommand = "/File/New JPilot"; + g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci); + _addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci); + + /* Category */ + atci = g_new0(AddressTypeControlItem, 1); + atci->objectType = ADDR_CATEGORY; + atci->interfaceType = ADDR_IF_JPILOT; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = TRUE; + atci->displayName = _("JPilot"); + atci->icon_pixbuf = categorypix; + atci->icon_open_pixbuf = categorypix; + atci->menuCommand = NULL; + g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci); + _addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci); + + /* LDAP Server */ + atci = g_new0(AddressTypeControlItem, 1); + atci->objectType = ADDR_LDAP; + atci->interfaceType = ADDR_IF_LDAP; + atci->showInTree = TRUE; + atci->treeExpand = TRUE; + atci->treeLeaf = TRUE; + atci->displayName = _("LDAP Server"); + atci->icon_pixbuf = ldappix; + atci->icon_open_pixbuf = ldappix; + atci->menuCommand = "/File/New LDAP Server"; + g_hash_table_insert(_addressBookTypeHash_, &atci->objectType, atci); + _addressBookTypeList_ = g_list_append(_addressBookTypeList_, atci); +} + +/* +* Search for specified object type. +*/ +AddressTypeControlItem *addrbookctl_lookup(gint ot) +{ + gint objType = ot; + return (AddressTypeControlItem *)g_hash_table_lookup(_addressBookTypeHash_, &objType); +} + +/* +* Search for specified interface type. +*/ +AddressTypeControlItem *addrbookctl_lookup_iface( AddressIfType ifType ) { + GList *node = _addressBookTypeList_; + while( node ) { + AddressTypeControlItem *atci = node->data; + if( atci->interfaceType == ifType ) return atci; + node = g_list_next( node ); + } + return NULL; +} + +static void addrbookctl_free_address( AddressObject *obj ) { + g_free( obj->name ); + obj->type = ADDR_NONE; + obj->name = NULL; +} + +static void addrbookctl_free_interface(AdapterInterface *adapter) +{ + addrbookctl_free_address(ADDRESS_OBJECT(adapter)); + adapter->iface = NULL; + adapter->interfaceType = ADDR_IF_NONE; + adapter->atci = NULL; + adapter->enabled = FALSE; + adapter->haveLibrary = FALSE; + if (adapter->tree_row) { + gtk_tree_row_reference_free(adapter->tree_row); + adapter->tree_row = NULL; + } + g_free(adapter); +} + +static void addrbookctl_free_datasource( AdapterDSource *adapter ) { + addrbookctl_free_address( ADDRESS_OBJECT(adapter) ); + adapter->dataSource = NULL; + adapter->subType = ADDR_NONE; + g_free( adapter ); +} + +static void addrbookctl_free_folder( AdapterFolder *adapter ) { + addrbookctl_free_address( ADDRESS_OBJECT(adapter) ); + adapter->itemFolder = NULL; + g_free( adapter ); +} + +static void addrbookctl_free_group( AdapterGroup *adapter ) { + addrbookctl_free_address( ADDRESS_OBJECT(adapter) ); + adapter->itemGroup = NULL; + g_free( adapter ); +} + +/* + * Build GUI interface list. + */ +void addrbookctl_build_iflist(void) +{ + AddressTypeControlItem *atci; + AdapterInterface *adapter; + GList *list = NULL; + + if(_addressIndex_ == NULL) { + _addressIndex_ = addrindex_create_index(); + } + _addressInterfaceList_ = NULL; + list = addrindex_get_interface_list(_addressIndex_); + while (list) { + AddressInterface *iface = list->data; + atci = addrbookctl_lookup_iface(iface->type); + if (atci) { + adapter = g_new0(AdapterInterface, 1); + adapter->interfaceType = iface->type; + adapter->atci = atci; + adapter->iface = iface; + adapter->tree_row = NULL; + adapter->enabled = TRUE; + adapter->haveLibrary = iface->haveLibrary; + ADDRESS_OBJECT(adapter)->type = ADDR_INTERFACE; + ADDRESS_OBJECT_NAME(adapter) = g_strdup(atci->displayName); + _addressInterfaceList_ = g_list_append(_addressInterfaceList_, adapter); + } + list = g_list_next(list); + } +} + +void addrbookctl_free_selection( GList *list ) { + GList *node = list; + while( node ) { + AdapterInterface *adapter = node->data; + adapter = NULL; + node = g_list_next( node ); + } + g_list_free( list ); +} + +/* +* Find GUI interface type specified interface type. +* Return: Interface item, or NULL if not found. +*/ +AdapterInterface *addrbookctl_find_interface( AddressIfType ifType ) { + GList *node = _addressInterfaceList_; + while( node ) { + AdapterInterface *adapter = node->data; + if( adapter->interfaceType == ifType ) return adapter; + node = g_list_next( node ); + } + return NULL; +} + +/* +* Build interface list selection. +*/ +void addrbookctl_build_ifselect(void) +{ + GList *newList = NULL; + gchar *selectStr; + gchar **splitStr; + gint ifType; + gint i; + gchar *endptr = NULL; + gboolean enabled; + AdapterInterface *adapter; + /* GList *node; */ + + selectStr = g_strdup( ADDRESSBOOK_IFACE_SELECTION ); + + /* Parse string */ + splitStr = g_strsplit( selectStr, ",", -1 ); + for( i = 0; i < ADDRESSBOOK_MAX_IFACE; i++ ) { + if( splitStr[i] ) { + /* printf( "%d : %s\n", i, splitStr[i] ); */ + ifType = strtol( splitStr[i], &endptr, 10 ); + enabled = TRUE; + if( *endptr ) { + if( strcmp( endptr, "/n" ) == 0 ) { + enabled = FALSE; + } + } + /* printf( "\t%d : %s\n", ifType, enabled ? "yes" : "no" ); */ + adapter = addrbookctl_find_interface( ifType ); + if( adapter ) { + newList = g_list_append( newList, adapter ); + } + } + else { + break; + } + } + /* printf( "i=%d\n", i ); */ + g_strfreev( splitStr ); + g_free( selectStr ); + + /* Replace existing list */ + mgu_clear_list( _addressIFaceSelection_ ); + g_list_free( _addressIFaceSelection_ ); + _addressIFaceSelection_ = newList; + newList = NULL; + +} + +/* ********************************************************************** +* Add sender to address book. +* *********************************************************************** +*/ + +/* + * This function is used by the Add sender to address book function. + */ +gboolean addressbook_add_contact(const gchar *name, const gchar *address, const gchar *remarks) +{ + debug_print("addressbook_add_contact: name/address: %s <%s>\n", name ? name : "", address); + if (addressadd_selection(_addressIndex_, name, address, remarks)) { + debug_print("addressbook_add_contact - added\n"); + addressbook_refresh(); + } + return TRUE; +} + +/* + * This function is used by the automatic address registration. + */ +gboolean addressbook_add_contact_autoreg(const gchar *name, const gchar *address, const gchar *remarks) +{ + debug_print("addressbook_add_contact_autoreg: name/address: %s <%s>\n", name ? name : "", address); + if (addressadd_autoreg(_addressIndex_, name, address, remarks)) { + addressbook_refresh(); + } + return TRUE; +} + +/* ********************************************************************** +* Address completion support. +* *********************************************************************** +*/ + +/* +* This function is used by the address completion function to load +* addresses. +* Enter: callBackFunc Function to be called when an address is +* to be loaded. +* Return: TRUE if data loaded, FALSE if address index not loaded. +*/ +gboolean addressbook_load_completion_full(AddressBookCompletionFunc func) +{ + /* AddressInterface *interface; */ + AddressDataSource *ds; + GList *nodeIf, *nodeDS; + GList *listP, *nodeP; + GList *nodeM; + gchar *sName, *sAddress, *sAlias, *sNickName; + gchar *sFirstName, *sLastName; + + debug_print( "addressbook_load_completion\n" ); + + if( _addressIndex_ == NULL ) return FALSE; + + nodeIf = addrindex_get_interface_list( _addressIndex_ ); + while( nodeIf ) { + AddressInterface *iface = nodeIf->data; + nodeDS = iface->listSource; + while( nodeDS ) { + ds = nodeDS->data; + + /* Read address book */ + if( ! addrindex_ds_get_read_flag( ds ) ) { + addrindex_ds_read_data( ds ); + } + + /* Get all persons */ + listP = addrindex_ds_get_all_persons( ds ); + nodeP = listP; + while( nodeP ) { + ItemPerson *person = nodeP->data; + nodeM = person->listEMail; + + /* Figure out name to use */ + sName = ADDRITEM_NAME(person); + sNickName = person->nickName; + if( sName == NULL || *sName == '\0' ) { + if (sNickName) + sName = sNickName; + } + sFirstName = person->firstName; + sLastName = person->lastName; + + /* Process each E-Mail address */ + while( nodeM ) { + ItemEMail *email = nodeM->data; + /* Have mail */ + sAddress = email->address; + if( sAddress && *sAddress != '\0' ) { + sAlias = ADDRITEM_NAME(email); + if( sAlias && *sAlias != '\0' ) { + func( sName, sFirstName, sLastName, sAlias, sAddress ); + } else { + func( sName, sFirstName, sLastName, sNickName, sAddress ); + } + } + nodeM = g_list_next( nodeM ); + } + nodeP = g_list_next( nodeP ); + } + /* Free up the list */ + g_list_free( listP ); + + nodeDS = g_list_next( nodeDS ); + } + nodeIf = g_list_next( nodeIf ); + } + debug_print( "addressbook_load_completion... done\n" ); + + return TRUE; +} + +static gint (*real_func)(const gchar *, const gchar *, const gchar *); + +static gint wrapper_func(const gchar *name, const gchar *firstname, const gchar *lastname, const gchar *nickname, const gchar *address) +{ + return real_func(name, address, nickname); +} + +gboolean addressbook_load_completion(gint (*callBackFunc)(const gchar *, const gchar *, const gchar *)) +{ + gboolean ret; + + real_func = callBackFunc; + ret = addressbook_load_completion_full(wrapper_func); + real_func = NULL; + + return ret; +} + +/* ********************************************************************** +* Address Import. +* *********************************************************************** +*/ + +/* +* Import LDIF file. +*/ +static void addressbook_import_ldif_cb(void) +{ + AddressDataSource *ds = NULL; + AdapterDSource *ads = NULL; + AddressBookFile *abf = NULL; + AdapterInterface *adapter; + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeModel *model; + GtkTreeIter iter, new_iter; + GtkTreePath *path; + + adapter = addrbookctl_find_interface(ADDR_IF_BOOK); + if (!adapter || !adapter->tree_row) + return; + + abf = addressbook_imp_ldif(_addressIndex_); + gtk_window_present(GTK_WINDOW(addrbook.window)); + if (!abf) + return; + + ds = addrindex_index_add_datasource(_addressIndex_, ADDR_IF_BOOK, abf); + ads = addressbook_create_ds_adapter(ds, ADDR_BOOK, NULL); + addressbook_ads_set_name(ads, abf->name); + + model = gtk_tree_view_get_model(treeview); + gtkut_tree_row_reference_get_iter(model, adapter->tree_row, &iter); + + if (addressbook_add_object(&iter, &new_iter, ADDRESS_OBJECT(ads))) { + path = gtk_tree_model_get_path(model, &new_iter); + gtk_tree_view_set_cursor(treeview, path, NULL, FALSE); + gtk_tree_path_free(path); + } + + /* Notify address completion */ + addressbook_modified(); +} + +gboolean addressbook_import_ldif_file(const gchar *file, const gchar *book_name) +{ + AddressBookFile *abf; + + g_return_val_if_fail(file != NULL, FALSE); + g_return_val_if_fail(book_name != NULL, FALSE); + + abf = addressbook_imp_ldif_file(_addressIndex_, file, book_name); + if (!abf) + return FALSE; + + addrindex_index_add_datasource(_addressIndex_, ADDR_IF_BOOK, abf); + addrindex_save_data(_addressIndex_); + addressbook_modified(); + + return TRUE; +} + +/* +* Import CSV file. +*/ +static void addressbook_import_csv_cb(void) +{ + AddressDataSource *ds = NULL; + AdapterDSource *ads = NULL; + AddressBookFile *abf = NULL; + AdapterInterface *adapter; + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeModel *model; + GtkTreeIter iter, new_iter; + GtkTreePath *path; + + adapter = addrbookctl_find_interface(ADDR_IF_BOOK); + if (!adapter || !adapter->tree_row) + return; + + abf = addressbook_imp_csv(_addressIndex_); + gtk_window_present(GTK_WINDOW(addrbook.window)); + if (!abf) + return; + + ds = addrindex_index_add_datasource(_addressIndex_, ADDR_IF_BOOK, abf); + ads = addressbook_create_ds_adapter(ds, ADDR_BOOK, NULL); + addressbook_ads_set_name(ads, abf->name); + + model = gtk_tree_view_get_model(treeview); + gtkut_tree_row_reference_get_iter(model, adapter->tree_row, &iter); + + if (addressbook_add_object(&iter, &new_iter, ADDRESS_OBJECT(ads))) { + path = gtk_tree_model_get_path(model, &new_iter); + gtk_tree_view_set_cursor(treeview, path, NULL, FALSE); + gtk_tree_path_free(path); + } + + /* Notify address completion */ + addressbook_modified(); +} + +/* +* Export CSV file. +*/ +static void addressbook_export_csv_cb(void) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(addrbook.treeview); + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreePath *path; + AddressObject *obj; + ItemFolder *itemFolder = NULL; + ItemGroup *itemGroup = NULL; + GList *items; + GList *cur; + gchar delim = ','; + + if (!addrbook.tree_opened) { + return; + } + + model = gtk_tree_view_get_model(treeview); + gtkut_tree_row_reference_get_iter(model, addrbook.tree_opened, &iter); + gtk_tree_model_get(model, &iter, COL_OBJ, &obj, -1); + g_return_if_fail(obj != NULL); + + if (obj->type == ADDR_INTERFACE) { + return; + } + + addressbook_exp_csv(obj); +} + +/* ********************************************************************** +* Address Book Fast Search. +* *********************************************************************** +*/ + +static GHashTable *addr_table; + +#if USE_THREADS +G_LOCK_DEFINE_STATIC(addr_table); +#define S_LOCK(name) G_LOCK(name) +#define S_UNLOCK(name) G_UNLOCK(name) +#else +#define S_LOCK(name) +#define S_UNLOCK(name) +#endif + +static gint load_address(const gchar *name, const gchar *address, + const gchar *nickname) +{ + gchar *addr; + + if (!address) + return -1; + + addr = g_ascii_strdown(address, -1); + + if (g_hash_table_lookup(addr_table, addr) == NULL) + g_hash_table_insert(addr_table, addr, addr); + else + g_free(addr); + + return 0; +} + +static void addressbook_modified(void) +{ + S_LOCK(addr_table); + + if (addr_table) { + hash_free_strings(addr_table); + g_hash_table_destroy(addr_table); + addr_table = NULL; + } + + S_UNLOCK(addr_table); + + invalidate_address_completion(); +} + +gboolean addressbook_has_address(const gchar *address) +{ + GSList *list, *cur; + gchar *addr; + gboolean found = FALSE; + + if (!address) + return FALSE; + + /* debug_print("addressbook_has_address: check if addressbook has address: %s\n", address); */ + + list = address_list_append(NULL, address); + if (!list) + return FALSE; + + S_LOCK(addr_table); + + if (!addr_table) { + addr_table = g_hash_table_new(g_str_hash, g_str_equal); + addressbook_load_completion(load_address); + } + + for (cur = list; cur != NULL; cur = cur->next) { + addr = g_ascii_strdown((gchar *)cur->data, -1); + + if (g_hash_table_lookup(addr_table, addr)) { + found = TRUE; + /* debug_print("<%s> is in addressbook\n", addr); */ + } else { + found = FALSE; + g_free(addr); + break; + } + g_free(addr); + } + + S_UNLOCK(addr_table); + + slist_free_strings(list); + + return found; +} + +/* +* End of Source. +*/ -- cgit v1.3