/* This file is part of GNUnet. (C) 2010-2014 Christian Grothoff (and other contributing authors) GNUnet 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 3, or (at your option) any later version. GNUnet 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 GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/conversation/gnunet-conversation-gtk_contacts.c * @brief display the address book with the list of known contacts * and launch calls if user activates entry in address book * @author yids * @author hark * @author Christian Grothoff */ #include "gnunet-conversation-gtk.h" #include "gnunet-conversation-gtk_contacts.h" #include "gnunet-conversation-gtk_phone.h" #include "gnunet-conversation-gtk_zones.h" /** * Columns in the #contacts_liststore. */ enum ContactsListstoreValues { /** * Human-readable name of the label in the zone. */ CONTACTS_LS_NAME = 0, /** * Type of the label (as a 'const char *') */ CONTACTS_LS_TYPE = 1 }; /** * List of contacts (records). */ static GtkListStore *contacts_liststore; /** * Tree model of the contacts treeview, same objects as #contacts_liststore. */ static GtkTreeModel *contacts_treemodel; /** * Monitor to view information in our current zone. */ static struct GNUNET_NAMESTORE_ZoneMonitor *zone_mon; /** * The tree view widget. */ static GtkWidget *contacts_treeview; /** * A row was activated in the contacts list. Initiate call. * * @param tree_view view where the row was activated * @param path path to the activated element * @param column column that was activated * @param user_data builder context (unused) */ void gnunet_conversation_gtk_contact_list_treeview_row_activated_cb (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) { char *address; gchar *type; GtkTreeIter iter; gchar *name; GtkEntry *address_entry; gtk_tree_model_get_iter (contacts_treemodel, &iter, path); gtk_tree_model_get (contacts_treemodel, &iter, CONTACTS_LS_NAME, &name, CONTACTS_LS_TYPE, &type, -1); if (0 == strcmp (type, "PKEY")) { GNUNET_asprintf (&address, "phone.%s.gnu", name); } else { GNUNET_asprintf (&address, "%s.gnu", name); } g_free (name); g_free (type); address_entry = GTK_ENTRY (GCG_get_main_window_object ("gnunet_conversation_gtk_address_entry")); gtk_entry_set_text (address_entry, address); GNUNET_free (address); } /** * Process a record that was stored or modified the namestore by * adding/modifying/removing it in the liststore. * * @param cls closure * @param zone private key of the zone; NULL on disconnect * @param label label of the records; NULL on disconnect * @param rd_count number of entries in @a rd array, 0 if label was deleted * @param rd array of records with data to store */ static void display_record (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, const char *rname, unsigned int rd_len, const struct GNUNET_GNSRECORD_Data *rd) { unsigned int i; GtkTreeIter iter; gboolean do_display; const char *type; gchar *lname; gboolean update; if (NULL == zone_key) { /* disconnect, clear (and possibly freeze) view */ gtk_list_store_clear (contacts_liststore); gtk_widget_hide (contacts_treeview); return; } do_display = FALSE; for (i = 0; i < rd_len; i++) { switch (rd[i].record_type) { case GNUNET_GNSRECORD_TYPE_PKEY: type = "PKEY"; do_display = TRUE; break; case GNUNET_DNSPARSER_TYPE_CNAME: type = "CNAME"; do_display = TRUE; break; case GNUNET_GNSRECORD_TYPE_PHONE: type = "PHONE"; do_display = TRUE; break; default: /* ignore, not useful for conversation */ break; } } /* check if exists, if so, update or remove */ update = FALSE; if (gtk_tree_model_get_iter_first (contacts_treemodel, &iter)) { do { gtk_tree_model_get (contacts_treemodel, &iter, CONTACTS_LS_NAME, &lname, -1); if (0 == strcmp (lname, rname)) { if (! do_display) { /* remove */ gtk_list_store_remove (contacts_liststore, &iter); g_free (lname); return; } /* update */ update = TRUE; break; } g_free (lname); } while (gtk_tree_model_iter_next (contacts_treemodel, &iter)); } /* insert new record */ if (! do_display) return; if (! update) gtk_list_store_append (contacts_liststore, &iter); gtk_list_store_set (contacts_liststore, &iter, CONTACTS_LS_NAME, rname, CONTACTS_LS_TYPE, type, -1); } /** * Function called once the monitor has caught up with the current * state of the database. Will be called AGAIN after each disconnect * (record monitor called with 'NULL' for zone_key) once we're again * in sync. * * Could be used to optimize visuals if we block GTK updates while the * list is not in sync. * * @param cls closure */ static void unfreeze_view (void *cls) { gtk_widget_show (contacts_treeview); } /** * A different zone was selected in the zone toggle bar. Load the * appropriate zone. * * @param widget combobox that was changed, unused * @param user_data builder, unused */ void gnunet_conversation_gtk_contacts_zone_combobox_changed_cb (GtkComboBox *widget, gpointer user_data) { struct GNUNET_IDENTITY_Ego *ego; const struct GNUNET_CRYPTO_EcdsaPrivateKey *temp_zone_pkey; if (NULL != zone_mon) { GNUNET_NAMESTORE_zone_monitor_stop (zone_mon); zone_mon = NULL; } gtk_list_store_clear (contacts_liststore); ego = GCG_ZONES_get_selected_zone (); if (NULL == ego) { /* ego deselected (likely shutdown) */ return; } gtk_widget_hide (contacts_treeview); temp_zone_pkey = GNUNET_IDENTITY_ego_get_private_key (ego); zone_mon = GNUNET_NAMESTORE_zone_monitor_start (GCG_get_configuration (), temp_zone_pkey, GNUNET_YES, &display_record, &unfreeze_view, NULL); } /** * User clicked the "paste" button. Copy address information * from the clipboard into our current zone / address book. * * @param button the button * @param user_data builder (unused) */ void gnunet_conversation_gtk_contacts_paste_button_clicked_cb (GtkButton *button, gpointer user_data) { GNUNET_break (0); // FIXME: not implemented } /** * Initialize the contact list */ void GCG_CONTACTS_init () { contacts_treeview = GTK_WIDGET (GCG_get_main_window_object ("gnunet_conversation_gtk_contact_list_treeview")); #if GTK_CHECK_VERSION(3,10,0) gtk_tree_view_set_activate_on_single_click (GTK_TREE_VIEW (contacts_treeview), TRUE); #endif contacts_liststore = GTK_LIST_STORE (GCG_get_main_window_object ("gnunet_conversation_gtk_contacts_liststore")); contacts_treemodel = GTK_TREE_MODEL (contacts_liststore); } /** * Shutdown the contact list */ void GCG_CONTACTS_shutdown () { if (NULL != zone_mon) { GNUNET_NAMESTORE_zone_monitor_stop (zone_mon); zone_mon = NULL; } gtk_list_store_clear (contacts_liststore); contacts_liststore = NULL; contacts_treemodel = NULL; } /* end of gnunet-conversation-gtk_contacts.c */