/* This file is part of GNUnet. (C) 2010 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 2, 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/fs_event_handler.c * @brief Main event handler for file-sharing * @author Christian Grothoff */ #include "common.h" #include "download.h" #include /** * Context we keep for a search tab. */ struct SearchTab { struct SearchTab *next; struct SearchTab *prev; struct GNUNET_FS_SearchContext *sc; char *query_txt; GtkBuilder *builder; GtkWidget *frame; GtkWidget *tab_label; GtkWidget *close_button; GtkWidget *play_button; GtkWidget *pause_button; GtkLabel *label; unsigned int num_results; }; static struct SearchTab *open_head; static struct SearchTab *open_tail; struct SearchResult { GtkTreeRowReference *rr; struct SearchTab *tab; struct GNUNET_FS_SearchResult *result; /* FIXME: keep download status here? */ }; struct DownloadEntry { struct DownloadEntry *pde; struct SearchResult *sr; struct GNUNET_FS_DownloadContext *dc; struct GNUNET_FS_Uri *uri; struct GNUNET_CONTAINER_MetaData *meta; GtkTreeRowReference *rr; GtkTreeStore *ts; }; static struct DownloadEntry * change_download_colour (struct DownloadEntry *de, const char *colour) { GtkTreeIter iter; GtkTreePath *path; path = gtk_tree_row_reference_get_path (de->rr); if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts), &iter, path)) { GNUNET_break (0); gtk_tree_path_free (path); return de; } gtk_tree_path_free (path); gtk_tree_store_set (de->ts, &iter, 8, colour, -1); return de; } static void stop_download (struct DownloadEntry *de, int is_suspend) { change_download_colour (de, "white"); gtk_tree_row_reference_free (de->rr); if (is_suspend == GNUNET_NO) GNUNET_FS_download_stop (de->dc, GNUNET_YES); GNUNET_FS_uri_destroy (de->uri); GNUNET_CONTAINER_meta_data_destroy (de->meta); GNUNET_free (de); } static struct DownloadEntry * mark_download_progress (struct DownloadEntry *de, uint64_t size, uint64_t completed) { GtkTreeIter iter; GtkTreePath *path; path = gtk_tree_row_reference_get_path (de->rr); if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts), &iter, path)) { GNUNET_break (0); gtk_tree_path_free (path); return de; } gtk_tree_path_free (path); gtk_tree_store_set (de->ts, &iter, 4, (guint) ((size > 0) ? (100 * completed / size) : 100) /* progress */, -1); return de; } /** * Setup a new download entry. * * @param pde parent download entry, or NULL * @param sr search result, or NULL * @param dc download context (for stopping) * @param uri the URI * @param meta metadata * @param size total size * @param completed current progress */ static struct DownloadEntry * setup_download (struct DownloadEntry *pde, struct SearchResult *sr, struct GNUNET_FS_DownloadContext *dc, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta, uint64_t size, uint64_t completed) { struct DownloadEntry *de; GtkTreeIter iter; GtkTreePath *path; de = GNUNET_malloc (sizeof (struct DownloadEntry)); de->pde = pde; de->sr = sr; de->dc = dc; de->uri = GNUNET_FS_uri_dup (uri); if (meta != NULL) de->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); if (pde != NULL) { /* find 'rr' starting at parent */ GNUNET_break (0); } else if (sr != NULL) { de->rr = gtk_tree_row_reference_copy (sr->rr); de->ts = GTK_TREE_STORE (gtk_builder_get_object (sr->tab->builder, "GNUNET_GTK_file_sharing_result_tree_store")); } else { /* find or create tab with just download results and create new entry! */ GNUNET_break (0); } path = gtk_tree_row_reference_get_path (de->rr); if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts), &iter, path)) { GNUNET_break (0); gtk_tree_path_free (path); return de; } gtk_tree_path_free (path); gtk_tree_store_set (de->ts, &iter, 4, (guint) ((size > 0) ? (100 * completed / size) : 100) /* progress */, 8, "blue" /* status colour: pending */, -1); return de; } /** * Tell FS to start a download. Begins by opening the * "save as" window. */ static void start_download (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) { struct SearchTab *tab = user_data; GtkTreeModel *tm; GtkTreeIter iter; struct GNUNET_FS_Uri *uri; struct GNUNET_CONTAINER_MetaData *meta; struct SearchResult *sr; char *mime; struct DownloadContext *dlc; GNUNET_assert (tab->sc != NULL); tm = gtk_tree_view_get_model (tree_view); if (TRUE != gtk_tree_model_get_iter (tm, &iter, path)) { GNUNET_break (0); return; } gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, 9, &sr, 10, &mime, -1); dlc = GNUNET_malloc (sizeof (struct DownloadContext)); dlc->uri = GNUNET_FS_uri_dup (uri); dlc->mime = mime; dlc->filename = GNUNET_FS_meta_data_suggest_filename (meta); dlc->rr = gtk_tree_row_reference_new (tm, path); dlc->sr = sr->result; GNUNET_GTK_open_download_as_dialog (dlc); } /** * Row reference for the current search context menu. */ static GtkTreeRowReference *current_context_row_reference; /** * Search tab used for the current search context menu. */ static struct SearchTab *current_context_search_tab; /** * Download was selected in the current search context menu. */ static void start_download_ctx_menu (gpointer user_data, guint unused, GtkWidget *widget) { GtkTreePath *path; GtkTreeView *tv; if (current_context_row_reference == NULL) { GNUNET_break (0); return; } path = gtk_tree_row_reference_get_path (current_context_row_reference); gtk_tree_row_reference_free (current_context_row_reference); current_context_row_reference = NULL; tv = GTK_TREE_VIEW (gtk_builder_get_object (current_context_search_tab->builder, "_search_result_frame")); start_download (tv, path, NULL, current_context_search_tab); gtk_tree_path_free (path); current_context_search_tab = NULL; } /** * We got a right-click on the search result list. Display the context * menu. */ static int search_list_on_menu(GtkWidget *widget, GdkEvent *event, gpointer user_data) { GdkEventButton *event_button; struct SearchTab *tab = user_data; GtkTreeView *tv; GtkMenu *menu; GtkWidget *child; GtkTreePath *path; GtkTreeModel *tm; tv = GTK_TREE_VIEW (widget); if (event->type == GDK_BUTTON_PRESS) { event_button = (GdkEventButton *) event; if (event_button->button == 3) { current_context_search_tab = tab; if (current_context_row_reference != NULL) { gtk_tree_row_reference_free (current_context_row_reference); current_context_row_reference = NULL; } path = NULL; if (FALSE == gtk_tree_view_get_path_at_pos (tv, event_button->x, event_button->y, &path, NULL, NULL, NULL)) { /* nothing selected */ current_context_search_tab = NULL; return FALSE; } tm = gtk_tree_view_get_model (tv); current_context_row_reference = gtk_tree_row_reference_new (tm, path); gtk_tree_path_free (path); /* FIXME: have additional options, depending on status: - view full meta data (in new window) - copy URI to clipboard - start recursive download - abort active download (!) => need to know download status before creating menu! */ menu = GTK_MENU (gtk_menu_new ()); child = gtk_menu_item_new_with_label (_("_Download")); g_signal_connect (child, "activate", G_CALLBACK (start_download_ctx_menu), NULL /*FIXME */); gtk_label_set_use_underline (GTK_LABEL (gtk_bin_get_child (GTK_BIN (child))), TRUE); gtk_widget_show (child); gtk_menu_shell_append (GTK_MENU_SHELL (menu), child); gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event_button->button, event_button->time); } } return FALSE; } /** * Selected row has changed, update preview and metadata * areas. */ static void update_meta_data_views (GtkTreeView *tv, gpointer user_data) { struct SearchTab *tab = user_data; GtkImage *image; GtkListStore *ms; GtkTreeSelection *sel; GtkTreeModel *model; GtkTreeIter iter; struct GNUNET_CONTAINER_MetaData *meta; GdkPixbuf *pixbuf; GNUNET_assert (tab->sc != NULL); image = GTK_IMAGE (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_preview_image")); ms = GTK_LIST_STORE (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_meta_data_list_store")); sel = gtk_tree_view_get_selection (tv); gtk_list_store_clear (ms); if (TRUE != gtk_tree_selection_get_selected (sel, &model, &iter)) { gtk_image_clear (image); return; } meta = NULL; pixbuf = NULL; gtk_tree_model_get (model, &iter, 0, &meta, 3, &pixbuf, -1); if (pixbuf != NULL) { gtk_image_set_from_pixbuf (image, pixbuf); /* FIXME: unref pixbuf? */ } if (meta != NULL) { GNUNET_CONTAINER_meta_data_iterate (meta, &GNUNET_GTK_add_meta_data_to_list_store, ms); } } /** * Update the label for a search */ static void update_search_label (struct SearchTab *tab) { char *name; GNUNET_asprintf (&name, "%.*s%s (%u)", 20, tab->query_txt, strlen (tab->query_txt) > 20 ? "..." : "", tab->num_results); gtk_label_set_text (tab->label, name); GNUNET_free (name); } /** * Close a search tab and free associated state. */ static void close_search_tab (struct SearchTab *tab) { GtkNotebook *notebook; int index; int i; notebook = GTK_NOTEBOOK (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_notebook")); index = -1; for (i = gtk_notebook_get_n_pages (notebook) - 1; i >= 0; i--) if (tab->frame == gtk_notebook_get_nth_page (notebook, i)) index = i; gtk_notebook_remove_page (notebook, index); g_object_unref (tab->builder); GNUNET_free (tab->query_txt); GNUNET_CONTAINER_DLL_remove (open_head, open_tail, tab); GNUNET_free (tab); } /** * Tell FS to stop a search. */ static void stop_search (GtkButton *button, gpointer user_data) { struct SearchTab *tab = user_data; if (tab->sc != NULL) { GNUNET_FS_search_stop (tab->sc); tab->sc = NULL; } } /** * Tell FS to pause a search. */ static void pause_search (GtkButton *button, gpointer user_data) { struct SearchTab *tab = user_data; if (tab->sc != NULL) { GNUNET_FS_search_pause (tab->sc); gtk_widget_show (tab->play_button); gtk_widget_hide (tab->pause_button); } } /** * Tell FS to resume a search. */ static void continue_search (GtkButton *button, gpointer user_data) { struct SearchTab *tab = user_data; if (tab->sc != NULL) { GNUNET_FS_search_continue (tab->sc); gtk_widget_show (tab->pause_button); gtk_widget_hide (tab->play_button); } } /** * Setup a new search tab. * * @param sc context with FS for the search * @param query the query * @param anonymity anonymity level */ static struct SearchTab * setup_search (struct GNUNET_FS_SearchContext *sc, const struct GNUNET_FS_Uri *query, uint32_t anonymity) { struct SearchTab *tab; GtkTreeView *tv; GtkNotebook *notebook; GtkWindow *sf; gint pages; tab = GNUNET_malloc (sizeof (struct SearchTab)); GNUNET_CONTAINER_DLL_insert (open_head, open_tail, tab); tab->sc = sc; if (GNUNET_FS_uri_test_ksk (query)) tab->query_txt = GNUNET_FS_uri_ksk_to_string_fancy (query); else tab->query_txt = GNUNET_FS_uri_to_string (query); tab->builder = GNUNET_GTK_get_new_builder ("search_tab.glade"); /* load frame */ sf = GTK_WINDOW (gtk_builder_get_object (tab->builder, "_search_result_frame_window")); tab->frame = gtk_bin_get_child (GTK_BIN (sf)); gtk_widget_ref (tab->frame); gtk_container_remove (GTK_CONTAINER (sf), tab->frame); gtk_widget_destroy (GTK_WIDGET (sf)); /* load tab_label */ sf = GTK_WINDOW (gtk_builder_get_object (tab->builder, "_search_result_label_window")); tab->tab_label = gtk_bin_get_child (GTK_BIN (sf)); gtk_widget_ref (tab->tab_label); gtk_container_remove (GTK_CONTAINER (sf), tab->tab_label); gtk_widget_destroy (GTK_WIDGET (sf)); /* get refs to widgets */ tab->label = GTK_LABEL (gtk_builder_get_object (tab->builder, "_search_result_label_window_label")); tab->close_button = GTK_WIDGET (gtk_builder_get_object (tab->builder, "_search_result_label_close_button")); g_signal_connect(G_OBJECT(tab->close_button), "clicked", G_CALLBACK(stop_search), tab); tab->play_button = GTK_WIDGET (gtk_builder_get_object (tab->builder, "_search_result_label_play_button")); g_signal_connect(G_OBJECT(tab->play_button), "clicked", G_CALLBACK(continue_search), tab); tab->pause_button = GTK_WIDGET (gtk_builder_get_object (tab->builder, "_search_result_label_pause_button")); g_signal_connect(G_OBJECT(tab->pause_button), "clicked", G_CALLBACK(pause_search), tab); /* patch text */ update_search_label (tab); /* add signal handlers */ tv = GTK_TREE_VIEW (gtk_builder_get_object (tab->builder, "_search_result_frame")); g_signal_connect(G_OBJECT(tv), "row-activated", G_CALLBACK(start_download), tab); g_signal_connect(G_OBJECT(tv), "cursor-changed", G_CALLBACK(update_meta_data_views), tab); g_signal_connect (G_OBJECT(tv), "button_press_event", G_CALLBACK(search_list_on_menu), tab); /* make visible */ notebook = GTK_NOTEBOOK (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_notebook")); pages = gtk_notebook_get_n_pages (notebook); gtk_notebook_insert_page (notebook, tab->frame, tab->tab_label, pages - 1); gtk_notebook_set_current_page (notebook, pages - 1); gtk_widget_show (GTK_WIDGET (notebook)); return tab; } static struct SearchResult * process_search_result (void *cls, void *parent, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_SearchResult *result, uint32_t applicability_rank) { struct SearchTab *tab = cls; struct SearchResult *sr; GtkTreeIter iter; GtkTreePath *tp; GtkTreeStore *ts; char *desc; char *mime; char *uris; GdkPixbuf *pixbuf; if ( (!GNUNET_FS_uri_test_loc (uri)) && (!GNUNET_FS_uri_test_chk (uri)) ) { /* SKS support not implemented yet */ GNUNET_break (0); return NULL ; } desc = GNUNET_CONTAINER_meta_data_get_first_by_types (meta, EXTRACTOR_METATYPE_PACKAGE_NAME, EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METATYPE_BOOK_TITLE, EXTRACTOR_METATYPE_FILENAME, EXTRACTOR_METATYPE_DESCRIPTION, EXTRACTOR_METATYPE_SUMMARY, EXTRACTOR_METATYPE_ALBUM, EXTRACTOR_METATYPE_COMMENT, EXTRACTOR_METATYPE_SUBJECT, EXTRACTOR_METATYPE_KEYWORDS -1); if (desc == NULL) desc = GNUNET_strdup (_("no description supplied")); uris = GNUNET_FS_uri_to_string (uri); mime = GNUNET_CONTAINER_meta_data_get_first_by_types (meta, EXTRACTOR_METATYPE_MIMETYPE, EXTRACTOR_METATYPE_FORMAT, -1); pixbuf = GNUNET_GTK_get_thumbnail_from_meta_data (meta); sr = GNUNET_malloc (sizeof (struct SearchResult)); sr->result = result; sr->tab = tab; ts = GTK_TREE_STORE (gtk_builder_get_object (tab->builder, "GNUNET_GTK_file_sharing_result_tree_store")); gtk_tree_store_insert_with_values (ts, &iter, NULL, G_MAXINT, 0, GNUNET_CONTAINER_meta_data_duplicate (meta), 1, GNUNET_FS_uri_dup (uri), 2, GNUNET_FS_uri_chk_get_file_size (uri), 3, pixbuf /* preview */, 4, 0 /* percent progress */, 5, 0 /* percent availability */, 6, desc /* filename/description */, 7, uris, 8, "white" /* status colour */, 9, sr, 10, mime, 11, applicability_rank, 12, 0 /* avail-cert */, 13, 0 /* avail-rank */, -1); tab->num_results++; update_search_label (tab); if (pixbuf != NULL) g_object_unref (pixbuf); GNUNET_free (uris); GNUNET_free (desc); GNUNET_free_non_null (mime); tp = gtk_tree_model_get_path (GTK_TREE_MODEL (ts), &iter); sr->rr = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts), tp); gtk_tree_path_free (tp); return sr; } static struct SearchResult * update_search_result (struct SearchResult *sr, const struct GNUNET_CONTAINER_MetaData *meta, int32_t availability_rank, uint32_t availability_certainty, uint32_t applicability_rank) { GtkTreeIter iter; struct GNUNET_CONTAINER_MetaData *ometa; GtkTreeView *tv; GtkTreePath *tp; GtkTreeStore *ts; GtkTreeModel *tm; char *desc; char *mime; GdkPixbuf *pixbuf; guint percent_avail; GtkNotebook *notebook; gint page; if (sr == NULL) return NULL; desc = GNUNET_CONTAINER_meta_data_get_first_by_types (meta, EXTRACTOR_METATYPE_PACKAGE_NAME, EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METATYPE_BOOK_TITLE, EXTRACTOR_METATYPE_FILENAME, EXTRACTOR_METATYPE_DESCRIPTION, EXTRACTOR_METATYPE_SUMMARY, EXTRACTOR_METATYPE_ALBUM, EXTRACTOR_METATYPE_COMMENT, EXTRACTOR_METATYPE_SUBJECT, EXTRACTOR_METATYPE_KEYWORDS -1); if (desc == NULL) desc = GNUNET_strdup (_("no description supplied")); mime = GNUNET_CONTAINER_meta_data_get_first_by_types (meta, EXTRACTOR_METATYPE_MIMETYPE, EXTRACTOR_METATYPE_FORMAT, -1); pixbuf = GNUNET_GTK_get_thumbnail_from_meta_data (meta); tp = gtk_tree_row_reference_get_path (sr->rr); tm = gtk_tree_row_reference_get_model (sr->rr); ts = GTK_TREE_STORE (tm); gtk_tree_model_get_iter (tm, &iter, tp); gtk_tree_path_free (tp); gtk_tree_model_get (tm, &iter, 0, &ometa, -1); if (meta != NULL) GNUNET_CONTAINER_meta_data_destroy (ometa); if (availability_certainty > 0) percent_avail = (availability_certainty + availability_rank) * 50 / availability_certainty; else percent_avail = 0; gtk_tree_store_set (ts, &iter, 0, GNUNET_CONTAINER_meta_data_duplicate (meta), 3, pixbuf /* preview */, 5, (guint) percent_avail /* percent availability */, 6, desc /* filename/description */, 10, mime, 11, (guint) applicability_rank, 12, (guint) availability_certainty, 13, (gint) availability_rank, -1); if (pixbuf != NULL) g_object_unref (pixbuf); GNUNET_free (desc); GNUNET_free_non_null (mime); notebook = GTK_NOTEBOOK (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_notebook")); page = gtk_notebook_get_current_page (notebook); if (gtk_notebook_get_nth_page (notebook, page) == sr->tab->frame) { tv = GTK_TREE_VIEW (gtk_builder_get_object (sr->tab->builder, "_search_result_frame")); update_meta_data_views (tv, sr->tab); } return sr; } static void free_search_result (struct SearchResult *sr) { GtkTreePath *tp; GtkTreeModel *tm; GtkTreeIter iter; struct GNUNET_FS_Uri *uri; struct GNUNET_CONTAINER_MetaData *meta; tp = gtk_tree_row_reference_get_path (sr->rr); tm = gtk_tree_row_reference_get_model (sr->rr); gtk_tree_model_get_iter (tm, &iter, tp); gtk_tree_path_free (tp); gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, -1); if (uri != NULL) GNUNET_FS_uri_destroy (uri); if (meta != NULL) GNUNET_CONTAINER_meta_data_destroy (meta); gtk_tree_row_reference_free (sr->rr); gtk_tree_store_remove (GTK_TREE_STORE (tm), &iter); GNUNET_free (sr); } /** * Notification of FS to a client about the progress of an * operation. Callbacks of this type will be used for uploads, * downloads and searches. Some of the arguments depend a bit * in their meaning on the context in which the callback is used. * * @param cls closure * @param info details about the event, specifying the event type * and various bits about the event * @return client-context (for the next progress call * for this operation; should be set to NULL for * SUSPEND and STOPPED events). The value returned * will be passed to future callbacks in the respective * field in the GNUNET_FS_ProgressInfo struct. */ void* GNUNET_GTK_fs_event_handler (void *cls, const struct GNUNET_FS_ProgressInfo *info) { switch (info->status) { case GNUNET_FS_STATUS_PUBLISH_START: GNUNET_break (0); break; case GNUNET_FS_STATUS_PUBLISH_RESUME: GNUNET_break (0); break; case GNUNET_FS_STATUS_PUBLISH_SUSPEND: GNUNET_break (0); break; case GNUNET_FS_STATUS_PUBLISH_PROGRESS: GNUNET_break (0); break; case GNUNET_FS_STATUS_PUBLISH_ERROR: GNUNET_break (0); break; case GNUNET_FS_STATUS_PUBLISH_COMPLETED: GNUNET_break (0); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: GNUNET_break (0); break; case GNUNET_FS_STATUS_DOWNLOAD_START: return setup_download (info->value.download.pctx, info->value.download.sctx, info->value.download.dc, info->value.download.uri, info->value.download.specifics.start.meta, info->value.download.size, info->value.download.completed); case GNUNET_FS_STATUS_DOWNLOAD_RESUME: GNUNET_break (0); break; case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND: stop_download (info->value.download.cctx, GNUNET_YES); return NULL; case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: return mark_download_progress (info->value.download.cctx, info->value.download.size, info->value.download.completed); case GNUNET_FS_STATUS_DOWNLOAD_ERROR: return change_download_colour (info->value.download.cctx, "red"); case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: return change_download_colour (info->value.download.cctx, "green"); case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: stop_download (info->value.download.cctx, GNUNET_NO); return NULL; case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: return change_download_colour (info->value.download.cctx, "yellow"); case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: return change_download_colour (info->value.download.cctx, "blue"); case GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT: GNUNET_break (0); break; case GNUNET_FS_STATUS_SEARCH_START: if (info->value.search.pctx != NULL) { GNUNET_break (0); break; } return setup_search (info->value.search.sc, info->value.search.query, info->value.search.anonymity); case GNUNET_FS_STATUS_SEARCH_RESUME: GNUNET_break (0); break; case GNUNET_FS_STATUS_SEARCH_RESUME_RESULT: GNUNET_break (0); break; case GNUNET_FS_STATUS_SEARCH_SUSPEND: close_search_tab (info->value.search.cctx); return NULL; case GNUNET_FS_STATUS_SEARCH_RESULT: return process_search_result (info->value.search.cctx, info->value.search.pctx, info->value.search.specifics.result.uri, info->value.search.specifics.result.meta, info->value.search.specifics.result.result, info->value.search.specifics.result.applicability_rank); case GNUNET_FS_STATUS_SEARCH_RESULT_NAMESPACE: GNUNET_break (0); break; case GNUNET_FS_STATUS_SEARCH_UPDATE: return update_search_result (info->value.search.specifics.update.cctx, info->value.search.specifics.update.meta, info->value.search.specifics.update.applicability_rank, info->value.search.specifics.update.availability_certainty, info->value.search.specifics.update.availability_rank); case GNUNET_FS_STATUS_SEARCH_ERROR: GNUNET_break (0); break; case GNUNET_FS_STATUS_SEARCH_PAUSED: return info->value.search.cctx; case GNUNET_FS_STATUS_SEARCH_CONTINUED: return info->value.search.cctx; case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: free_search_result (info->value.search.specifics.result_suspend.cctx); return NULL; case GNUNET_FS_STATUS_SEARCH_RESULT_SUSPEND: free_search_result (info->value.search.specifics.result_suspend.cctx); return NULL; case GNUNET_FS_STATUS_SEARCH_STOPPED: close_search_tab (info->value.search.cctx); return NULL; case GNUNET_FS_STATUS_UNINDEX_START: GNUNET_break (0); break; case GNUNET_FS_STATUS_UNINDEX_RESUME: GNUNET_break (0); break; case GNUNET_FS_STATUS_UNINDEX_SUSPEND: GNUNET_break (0); break; case GNUNET_FS_STATUS_UNINDEX_PROGRESS: GNUNET_break (0); break; case GNUNET_FS_STATUS_UNINDEX_ERROR: GNUNET_break (0); break; case GNUNET_FS_STATUS_UNINDEX_COMPLETED: GNUNET_break (0); break; case GNUNET_FS_STATUS_UNINDEX_STOPPED: GNUNET_break (0); break; default: GNUNET_break (0); break; } return NULL; } /** * Page switched in main notebook, update thumbnail and * metadata views. */ void GNUNET_GTK_main_window_notebook_switch_page_cb (GtkWidget * dummy, gpointer data) { GtkNotebook *notebook; gint page; GtkWidget *w; struct SearchTab *tab; GtkImage *image; GtkListStore *ms; GtkTreeView *tv; notebook = GTK_NOTEBOOK (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_notebook")); page = gtk_notebook_get_current_page (notebook); w = gtk_notebook_get_nth_page (notebook, page); tab = open_head; while (tab != NULL) { if (tab->frame == w) { tv = GTK_TREE_VIEW (gtk_builder_get_object (tab->builder, "_search_result_frame")); update_meta_data_views (tv, tab); return; } tab = tab->next; } image = GTK_IMAGE (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_preview_image")); gtk_image_clear (image); ms = GTK_LIST_STORE (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_meta_data_list_store")); gtk_list_store_clear (ms); } /* end of fs_event_handler.c */