/* This file is part of GNUnet (C) 2005, 2006, 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/gnunet-fs-gtk-edit_publish_dialog.c * @author Christian Grothoff */ #include "gnunet-fs-gtk-common.h" #include "gnunet-fs-gtk-edit_publish_dialog.h" #include "gnunet-fs-gtk.h" #include #include #define PUBSTATE "edit-publication-state" struct EditPublicationState { int do_index; char *short_fn; guint anonymity_level; guint priority; struct GNUNET_FS_FileInformation *fip; gint preview_changed; gboolean allow_no_keywords; gboolean is_directory; GNUNET_FS_GTK_EditPublishDialogCallback cb; gchar *root; gpointer cls; }; static void metadata_selection_changed_cb (GtkTreeSelection * ts, gpointer user_data) { GtkTreeView *tv; GtkTreeSelection *sel; GtkWidget *button; GtkBuilder *builder; builder = GTK_BUILDER (user_data); tv = GTK_TREE_VIEW (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_metadata_tree_view")); sel = gtk_tree_view_get_selection (tv); button = GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_delete_button")); gtk_widget_set_sensitive (button, gtk_tree_selection_get_selected (sel, NULL, NULL)); } static void keywords_selection_changed_cb (GtkTreeSelection * ts, gpointer user_data) { GtkTreeView *tv; GtkTreeSelection *sel; GtkWidget *button; GtkBuilder *builder; builder = GTK_BUILDER (user_data); tv = GTK_TREE_VIEW (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_keyword_list_tree_view")); sel = gtk_tree_view_get_selection (tv); button = GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_keyword_list_del_button")); gtk_widget_set_sensitive (button, gtk_tree_selection_get_selected (sel, NULL, NULL)); button = GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_keyword_list_normalize_button")); gtk_widget_set_sensitive (button, gtk_tree_selection_get_selected (sel, NULL, NULL)); } void GNUNET_GTK_edit_publication_window_realize_cb (GtkWidget *widget, gpointer user_data) { GtkBuilder *builder; GtkListStore *metatypes_list; GtkTreeIter iter; GtkTreeView *tv; GtkTreeSelection *sel; guint type; guint max_type; builder = GTK_BUILDER (user_data); metatypes_list = GTK_LIST_STORE (gtk_builder_get_object (builder, "GNUNET_GTK_publication_metadata_types_liststore")); tv = GTK_TREE_VIEW (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_metadata_tree_view")); sel = gtk_tree_view_get_selection (tv); g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (metadata_selection_changed_cb), builder); tv = GTK_TREE_VIEW (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_keyword_list_tree_view")); sel = gtk_tree_view_get_selection (tv); g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (keywords_selection_changed_cb), builder); max_type = EXTRACTOR_metatype_get_max (); for (type = 1; type < max_type - 1; type++) gtk_list_store_insert_with_values (metatypes_list, &iter, G_MAXINT, 0, type, 1, EXTRACTOR_METAFORMAT_UTF8, 2, EXTRACTOR_metatype_to_string (type), 3, EXTRACTOR_metatype_to_description (type), -1); } void GNUNET_GTK_edit_publication_add_button_clicked_cb (GtkButton *button, gpointer user_data) { GtkBuilder *builder; GtkTreeView *meta_tree; GtkListStore *meta_list; GtkTreeIter iter; builder = GTK_BUILDER (user_data); meta_tree = GTK_TREE_VIEW (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_metadata_tree_view")); meta_list = GTK_LIST_STORE (gtk_tree_view_get_model (meta_tree)); gtk_list_store_insert (meta_list, &iter, 0); /* type == -1 means "not set" */ gtk_list_store_set (meta_list, &iter, 0, -1, 1, EXTRACTOR_METAFORMAT_UTF8, 2, _("Select a type"), 3, _("Specify a value"), 4, NULL, -1); } gboolean GNUNET_GTK_edit_publication_keyword_entry_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { GtkBuilder *builder; GtkButton *add_button; builder = GTK_BUILDER (user_data); if (event->keyval == GDK_KEY_Return) { add_button = GTK_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_add_button")); GNUNET_GTK_edit_publication_add_button_clicked_cb (add_button, user_data); return TRUE; } return FALSE; } void GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer_edited_cb (GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer user_data) { GtkBuilder *builder; GtkTreeView *meta_tree; GtkListStore *meta_list; GtkCellRendererCombo *combo; GtkTreeModel *combo_model; GtkTreeIter iter; gint type_id; gchar *description = NULL; GtkTreeIter *pass_data = NULL; builder = GTK_BUILDER (user_data); meta_tree = GTK_TREE_VIEW (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_metadata_tree_view")); meta_list = GTK_LIST_STORE (gtk_tree_view_get_model (meta_tree)); if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (meta_list), &iter, path)) return; combo = GTK_CELL_RENDERER_COMBO (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer")); pass_data = g_object_get_data (G_OBJECT (combo), "selected-type"); if (!pass_data) return; g_object_get (combo, "model", &combo_model, NULL); gtk_tree_model_get (combo_model, pass_data, 0, &type_id, 2, &description, -1); g_free (combo_model); g_free (pass_data); g_object_set_data (G_OBJECT (combo), "selected-type", NULL); gtk_list_store_set (meta_list, &iter, 0, type_id, 1, EXTRACTOR_METAFORMAT_UTF8, 2, new_text, 4, description, -1); g_free (description); } void GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer_changed_cb ( GtkCellRendererCombo *combo, gchar *path_string, GtkTreeIter *new_iter, gpointer user_data) { GtkTreeIter *pass_data; pass_data = g_object_get_data (G_OBJECT (combo), "selected-type"); if (pass_data) g_free (pass_data); pass_data = g_new0 (GtkTreeIter, 1); *pass_data = *new_iter; g_object_set_data (G_OBJECT (combo), "selected-type", pass_data); } void GNUNET_GTK_edit_publication_metadata_tree_view_value_renderer_edited_cb ( GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer user_data) { GtkBuilder *builder; GtkTreeView *meta_tree; GtkListStore *meta_list; GtkTreeIter iter; gint metatype; char *avalue; const char *ivalue; size_t slen; char *pos; GObject *pubwindow; struct EditPublicationState *state = NULL; builder = GTK_BUILDER (user_data); meta_tree = GTK_TREE_VIEW (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_metadata_tree_view")); meta_list = GTK_LIST_STORE (gtk_tree_view_get_model (meta_tree)); if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (meta_list), &iter, path)) return; pubwindow = gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_window"); state = g_object_get_data (pubwindow, PUBSTATE); if (!state) { GNUNET_break (0); return; } gtk_tree_model_get (GTK_TREE_MODEL (meta_list), &iter, 0, &metatype, -1); if (metatype == EXTRACTOR_METATYPE_FILENAME && new_text[strlen (new_text) - 1] != '/' && state->is_directory) { GNUNET_asprintf (&avalue, "%s/", new_text); /* if user typed '\' instead of '/', change it! */ slen = strlen (avalue); while ((slen > 1) && (avalue[slen - 2] == '\\')) { avalue[slen - 2] = '/'; avalue[slen - 1] = '\0'; slen--; } while (NULL != (pos = strstr (avalue, "\\"))) *pos = '/'; // remove '../' everywhere while (NULL != (pos = strstr (avalue, "../"))) { pos[0] = '_'; pos[1] = '_'; pos[2] = '_'; } ivalue = avalue; } else { ivalue = new_text; avalue = NULL; } gtk_list_store_set (meta_list, &iter, 3, ivalue, -1); GNUNET_free_non_null (avalue); } void GNUNET_GTK_edit_publication_delete_button_clicked_cb (GtkButton *button, gpointer user_data) { GtkTreeView *tv; GtkTreeSelection *sel; GtkTreeModel *tm; GtkTreeIter iter; GtkBuilder *builder = GTK_BUILDER (user_data); tv = GTK_TREE_VIEW (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_metadata_tree_view")); sel = gtk_tree_view_get_selection (tv); if (TRUE != gtk_tree_selection_get_selected (sel, &tm, &iter)) { GNUNET_break (0); return; } if (gtk_list_store_remove (GTK_LIST_STORE (tm), &iter)) gtk_tree_selection_select_iter (sel, &iter); } void GNUNET_GTK_edit_publication_keyword_list_add_button_clicked_cb ( GtkButton *button, gpointer user_data) { const char *keyword; GtkEntry *entry; GtkListStore *ls; GtkTreeIter iter; GtkBuilder *builder; GtkWidget *ok; builder = GTK_BUILDER (user_data); ls = GTK_LIST_STORE (gtk_builder_get_object (builder, "GNUNET_GTK_publication_keywords_liststore")); entry = GTK_ENTRY (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_keyword_entry")); keyword = gtk_entry_get_text (entry); if (strlen (keyword) > 0) { gtk_list_store_insert_with_values (ls, &iter, G_MAXINT, 0, keyword, 1, TRUE, -1); ok = GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_confirm_button")); gtk_widget_set_sensitive (ok, TRUE); } gtk_entry_set_text (entry, ""); } static gboolean gtk_tree_model_has_items_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { gboolean *val = (gboolean *) data; *val = TRUE; return TRUE; } static gboolean gtk_tree_model_has_items (GtkTreeModel *model) { gboolean b = FALSE; gtk_tree_model_foreach (model, >k_tree_model_has_items_cb, &b); return b; } void GNUNET_GTK_edit_publication_keyword_entry_changed_cb (GtkEditable *editable, gpointer user_data) { const char *keyword; GtkEntry *entry; GtkWidget *button; GtkBuilder *builder; builder = GTK_BUILDER (user_data); button = GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_keyword_list_add_button")); entry = GTK_ENTRY (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_keyword_entry")); keyword = gtk_entry_get_text (entry); gtk_widget_set_sensitive (button, (strlen (keyword) > 0) ? TRUE : FALSE); } void GNUNET_GTK_edit_publication_keyword_list_del_button_clicked_cb ( GtkButton *button, gpointer user_data) { GtkTreeView *tv; GtkTreeSelection *sel; GtkTreeModel *tm; GtkTreeIter iter; GtkBuilder *builder; GtkWidget *ok; GObject *pubwindow; struct EditPublicationState *state = NULL; builder = GTK_BUILDER (user_data); tv = GTK_TREE_VIEW (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_keyword_list_tree_view")); sel = gtk_tree_view_get_selection (tv); if (TRUE != gtk_tree_selection_get_selected (sel, &tm, &iter)) { GNUNET_break (0); return; } if (gtk_list_store_remove (GTK_LIST_STORE (tm), &iter)) gtk_tree_selection_select_iter (sel, &iter); ok = GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_confirm_button")); pubwindow = gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_window"); state = g_object_get_data (pubwindow, PUBSTATE); if (!state) { GNUNET_break (0); return; } if (!state->allow_no_keywords && !gtk_tree_model_has_items (tm)) gtk_widget_set_sensitive (ok, FALSE); } void GNUNET_GTK_edit_publication_keyword_list_normalize_button_clicked_cb ( GtkButton *button, gpointer user_data) { GtkTreeView *tv; GtkTreeSelection *sel; GtkTreeModel *tm; GtkTreeIter iter, inserted; gchar *value; struct GNUNET_FS_Uri *uri; struct GNUNET_FS_Uri *nuri; char *nvalue; char *emsg; GtkBuilder *builder; builder = GTK_BUILDER (user_data); tv = GTK_TREE_VIEW (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_keyword_list_tree_view")); sel = gtk_tree_view_get_selection (tv); if (TRUE != gtk_tree_selection_get_selected (sel, &tm, &iter)) return; gtk_tree_model_get (tm, &iter, 0, &value, -1); emsg = NULL; uri = GNUNET_FS_uri_ksk_create (value, &emsg); if (uri == NULL) { GNUNET_break (0); GNUNET_free (emsg); g_free (value); return; } nuri = GNUNET_FS_uri_ksk_canonicalize (uri); nvalue = GNUNET_FS_uri_ksk_to_string_fancy (nuri); if (strcmp (value, nvalue) != 0) { gtk_list_store_insert_after (GTK_LIST_STORE (tm), &inserted, &iter); gtk_list_store_set (GTK_LIST_STORE (tm), &inserted, 0, nvalue, -1); } GNUNET_FS_uri_destroy (nuri); GNUNET_FS_uri_destroy (uri); GNUNET_free (nvalue); g_free (value); } void GNUNET_GTK_edit_publication_normalization_checkbox_toggled_cb ( GtkToggleButton *button, gpointer user_data) { GtkBuilder *builder; GtkToggleButton *norm_button; builder = GTK_BUILDER (user_data); norm_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_keyword_list_normalize_button")); gtk_widget_set_sensitive (GTK_WIDGET (norm_button), !gtk_toggle_button_get_active (norm_button)); } void GNUNET_GTK_edit_publication_metadata_preview_file_chooser_button_file_set_cb ( GtkFileChooserButton *widget, gpointer user_data) { gchar *fn; GtkImage *image; GObject *pubwindow; GtkBuilder *builder = GTK_BUILDER (user_data); struct EditPublicationState *state = NULL; pubwindow = gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_window"); state = g_object_get_data (pubwindow, PUBSTATE); if (!state) { GNUNET_break (0); return; } fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget)); image = GTK_IMAGE (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_metadata_preview_image")); gtk_image_set_from_file (image, fn); state->preview_changed = GNUNET_YES; } struct FileInformationUpdateContext { GtkBuilder *builder; char *short_fn; gchar *root; struct GNUNET_CONTAINER_MetaData *md; gboolean allow_no_keywords; }; /** * Copy binary meta data from to the new container and also * preserve all entries that were not changed. * * @param cls closure, a 'struct FileInformationUpdateContext' * @param plugin_name name of the plugin that produced this value; * special values can be used (i.e. '' for zlib being * used in the main libextractor library and yielding * meta data). * @param type libextractor-type describing the meta data * @param format basic format information about data * @param data_mime_type mime-type of data (not of the original file); * can be NULL (if mime-type is not known) * @param data actual meta-data found * @param data_len number of bytes in data * @return 0 to continue extracting */ static int preserve_meta_items (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_len) { struct FileInformationUpdateContext *context = cls; GtkBuilder *builder = context->builder; struct GNUNET_CONTAINER_MetaData *md = context->md; GtkTreeModel *tm; GtkTreeIter iter; gchar *value; guint ntype; guint nformat; int keep; GObject *pubwindow; struct EditPublicationState *state = NULL; pubwindow = gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_window"); state = g_object_get_data (pubwindow, PUBSTATE); if (!state) { GNUNET_break (0); return 0; } keep = GNUNET_NO; switch (format) { case EXTRACTOR_METAFORMAT_UTF8: case EXTRACTOR_METAFORMAT_C_STRING: tm = GTK_TREE_MODEL (gtk_builder_get_object (builder, "GNUNET_GTK_publication_metadata_liststore")); if (TRUE == gtk_tree_model_get_iter_first (tm, &iter)) { do { gtk_tree_model_get (tm, &iter, 0, &ntype, 1, &nformat, 3, &value, -1); if ((ntype == type) && (nformat == format) && (0 == strcmp (value, data))) { gtk_list_store_remove (GTK_LIST_STORE (tm), &iter); keep = GNUNET_YES; g_free (value); break; } g_free (value); } while (TRUE == gtk_tree_model_iter_next (tm, &iter)); } break; case EXTRACTOR_METAFORMAT_UNKNOWN: break; case EXTRACTOR_METAFORMAT_BINARY: if (state->preview_changed == GNUNET_NO) keep = GNUNET_YES; break; default: GNUNET_break (0); break; } if (GNUNET_YES == keep) GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format, data_mime_type, data, data_len)); return 0; } /** * Function called to update the information in FI. * * @param cls closure with a 'struct FileInformationUpdateContext *' * @param fi the entry in the publish-structure * @param length length of the file or directory * @param meta metadata for the file or directory (can be modified) * @param uri pointer to the keywords that will be used for this entry (can be modified) * @param bo block options (can be modified) * @param do_index should we index (can be modified) * @param client_info pointer to client context set upon creation (can be modified) * @return GNUNET_SYSERR (aborts after first call) */ static int file_information_update (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) { struct FileInformationUpdateContext *context = cls; char **short_fn = &context->short_fn; GtkBuilder *builder = context->builder; struct GNUNET_CONTAINER_MetaData *nm; GtkTreeModel *tm; GtkTreeIter iter; struct GNUNET_FS_Uri *nxt; struct GNUNET_FS_Uri *mrg; gchar *value; guint ntype; guint nformat; GtkSpinButton *sb; gchar *fn; char *data; gsize data_size; const char *mime; GFile *f; GFileInfo *finfo; gboolean auto_normalize = FALSE; GObject *pubwindow; struct EditPublicationState *state = NULL; pubwindow = gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_window"); state = g_object_get_data (pubwindow, PUBSTATE); if (!state) { GNUNET_break (0); return GNUNET_SYSERR; } if (!GNUNET_GTK_get_selected_anonymity_level (builder, "GNUNET_GTK_edit_publication_anonymity_combobox", &bo->anonymity_level)) return GNUNET_SYSERR; bo->content_priority = gtk_spin_button_get_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_priority_spin_button"))); *do_index = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_index_checkbutton"))); auto_normalize = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_normalization_checkbox"))); sb = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_expiration_year_spin_button")); bo->expiration_time = GNUNET_FS_GTK_get_expiration_time (sb); if (! context->allow_no_keywords) { g_free (context->root); context->root = g_strdup (gtk_entry_get_text (GTK_ENTRY (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_root_entry")))); } /* update URI */ if (NULL != (*uri)) GNUNET_FS_uri_destroy (*uri); *uri = NULL; nxt = NULL; mrg = NULL; tm = GTK_TREE_MODEL (gtk_builder_get_object (builder, "GNUNET_GTK_publication_keywords_liststore")); if (TRUE == gtk_tree_model_get_iter_first (tm, &iter)) { do { gtk_tree_model_get (tm, &iter, 0, &value, -1); nxt = GNUNET_FS_uri_ksk_create_from_args (1, (const char **) &value); mrg = GNUNET_FS_uri_ksk_merge (nxt, *uri); GNUNET_FS_uri_destroy (nxt); if (NULL != *uri) GNUNET_FS_uri_destroy (*uri); *uri = mrg; if (auto_normalize) { char *emsg = NULL; struct GNUNET_FS_Uri *nuri; nuri = GNUNET_FS_uri_ksk_create (value, &emsg); if (nuri == NULL) GNUNET_free_non_null (emsg); else { nxt = GNUNET_FS_uri_ksk_canonicalize (nuri); mrg = GNUNET_FS_uri_ksk_merge (nxt, *uri); GNUNET_FS_uri_destroy (nxt); if (NULL != *uri) GNUNET_FS_uri_destroy (*uri); *uri = mrg; } } g_free (value); } while (TRUE == gtk_tree_model_iter_next (tm, &iter)); } /* update meta */ nm = GNUNET_CONTAINER_meta_data_create (); context->md = nm; GNUNET_CONTAINER_meta_data_iterate (meta, &preserve_meta_items, context); GNUNET_CONTAINER_meta_data_clear (meta); tm = GTK_TREE_MODEL (gtk_builder_get_object (builder, "GNUNET_GTK_publication_metadata_liststore")); if (TRUE == gtk_tree_model_get_iter_first (tm, &iter)) { do { gtk_tree_model_get (tm, &iter, 0, &ntype, 1, &nformat, 3, &value, -1); if (ntype >= 0) GNUNET_CONTAINER_meta_data_insert (nm, "", ntype, nformat, "text/plain", value, strlen (value) + 1); g_free (value); } while (TRUE == gtk_tree_model_iter_next (tm, &iter)); } GNUNET_CONTAINER_meta_data_merge (meta, nm); if (state->preview_changed == GNUNET_YES) { fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_metadata_preview_file_chooser_button"))); f = g_file_new_for_path (fn); finfo = g_file_query_info (f, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, 0, NULL, NULL); if (FALSE == g_file_load_contents (f, NULL, &data, &data_size, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Could not load preview `%s' into memory\n"), fn); } else { mime = g_file_info_get_attribute_string (finfo, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE); GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_THUMBNAIL, EXTRACTOR_METAFORMAT_BINARY, mime, data, data_size); } g_object_unref (finfo); g_object_unref (f); } GNUNET_CONTAINER_meta_data_destroy (nm); /* update short_fn */ GNUNET_free_non_null (*short_fn); *short_fn = GNUNET_CONTAINER_meta_data_get_first_by_types (meta, EXTRACTOR_METATYPE_FILENAME, -1); /* FIXME: update expiration time? (not yet in dialog!) */ return GNUNET_SYSERR; /* only visit top-level item */ } void GNUNET_GTK_edit_publication_cancel_button_clicked_cb ( GtkButton *button, gpointer user_data) { GtkBuilder *builder; GObject *pubwindow; struct EditPublicationState *state = NULL; builder = GTK_BUILDER (user_data); pubwindow = gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_window"); state = g_object_get_data (pubwindow, PUBSTATE); if (!state) { GNUNET_break (0); return; } state->cb (state->cls, state->do_index, state->short_fn, state->anonymity_level, state->priority, NULL, GTK_RESPONSE_CANCEL); g_free (state); g_object_set_data (pubwindow, PUBSTATE, NULL); gtk_widget_hide (GTK_WIDGET (pubwindow)); } void GNUNET_GTK_edit_publication_confirm_button_clicked_cb (GtkButton *button, gpointer user_data) { GtkBuilder *builder; GObject *pubwindow; struct EditPublicationState *state; struct FileInformationUpdateContext ctx; builder = GTK_BUILDER (user_data); pubwindow = gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_window"); state = g_object_get_data (pubwindow, PUBSTATE); if (!state) { GNUNET_break (0); return; } ctx.builder = builder; ctx.short_fn = state->short_fn; ctx.root = NULL; ctx.md = NULL; ctx.allow_no_keywords = state->allow_no_keywords; GNUNET_FS_file_information_inspect (state->fip, &file_information_update, &ctx); if (!GNUNET_GTK_get_selected_anonymity_level (builder, "GNUNET_GTK_edit_publication_anonymity_combobox", &state->anonymity_level)) state->priority = gtk_spin_button_get_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_priority_spin_button"))); state->do_index = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_index_checkbutton"))); state->cb (state->cls, state->do_index, state->short_fn, state->anonymity_level, state->priority, ctx.root, GTK_RESPONSE_OK); GNUNET_free (state->short_fn); GNUNET_free (state); g_object_set_data (pubwindow, PUBSTATE, NULL); gtk_widget_hide (GTK_WIDGET (pubwindow)); } gboolean GNUNET_GTK_edit_publication_window_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) { GtkBuilder *builder; GtkButton *button; builder = GTK_BUILDER (user_data); button = GTK_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_cancel_button")); GNUNET_GTK_edit_publication_cancel_button_clicked_cb (button, user_data); return TRUE; } /** * Add each of the keywords to the keyword list store. * * @param cls closure * @param keyword the keyword * @param is_mandatory is the keyword mandatory (in a search) * @return GNUNET_OK to continue to iterate */ static int add_keyword (void *cls, const char *keyword, int is_mandatory) { GtkListStore *ls; GtkTreeIter iter; ls = GTK_LIST_STORE (cls); gtk_list_store_insert_with_values (ls, &iter, G_MAXINT, 0, keyword, 1, FALSE, -1); return GNUNET_OK; } /** * Function called to extract the information from FI. * * @param cls closure * @param fi the entry in the publish-structure * @param length length of the file or directory * @param meta metadata for the file or directory (can be modified) * @param uri pointer to the keywords that will be used for this entry (can be modified) * @param bo block options * @param do_index should we index (can be modified) * @param client_info pointer to client context set upon creation (can be modified) * @return GNUNET_SYSERR (aborts after first call) */ static int file_information_extract (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) { GtkBuilder *builder = GTK_BUILDER (cls); GtkImage *img; GdkPixbuf *pixbuf; struct tm *t; int year; time_t tp; GtkListStore *ls; ls = GTK_LIST_STORE (gtk_builder_get_object (builder, "GNUNET_GTK_publication_keywords_liststore")); if (NULL != *uri) GNUNET_FS_uri_ksk_get_keywords (*uri, &add_keyword, ls); if (NULL != meta) { ls = GTK_LIST_STORE (gtk_builder_get_object (builder, "GNUNET_GTK_publication_metadata_liststore")); GNUNET_CONTAINER_meta_data_iterate (meta, &GNUNET_FS_GTK_add_meta_data_to_list_store, ls); pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta); if (pixbuf != NULL) { img = GTK_IMAGE (gtk_builder_get_object (builder, "GNUNET_GTK_publication_metadata_preview_image")); gtk_image_set_from_pixbuf (img, pixbuf); } } tp = bo->expiration_time.abs_value / 1000; /* ms to seconds */ t = gmtime (&tp); if (t == NULL) year = 0; else year = t->tm_year + 1900; gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_expiration_year_spin_button")), year); GNUNET_GTK_select_anonymity_level (builder, "GNUNET_GTK_edit_publication_anonymity_combobox", bo->anonymity_level); gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_priority_spin_button")), bo->content_priority); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_index_checkbutton")), *do_index); return GNUNET_SYSERR; /* only visit top-level item */ } /** * Open the dialog to edit file information data. */ void GNUNET_FS_GTK_edit_publish_dialog (GtkBuilder *builder, GtkWindow *parent, int do_index, const char *short_fn, uint32_t anonymity_level, uint32_t priority, struct GNUNET_FS_FileInformation *fip, gboolean allow_no_keywords, GNUNET_FS_GTK_EditPublishDialogCallback cb, gpointer cls) { GtkWidget *dialog; GObject *pubwindow; GtkEntry *entry; GtkWidget *ok; struct EditPublicationState *state; GNUNET_FS_GTK_setup_expiration_year_adjustment (builder); if (GNUNET_FS_file_information_is_directory (fip)) { /* indexing does not apply to directories */ gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_index_checkbutton"))); gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_index_label"))); } if (allow_no_keywords) { gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_root_entry"))); gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_root_label"))); } gtk_list_store_clear (GTK_LIST_STORE (gtk_builder_get_object ( builder, "GNUNET_GTK_publication_keywords_liststore"))); gtk_list_store_clear (GTK_LIST_STORE (gtk_builder_get_object ( builder, "GNUNET_GTK_publication_metadata_liststore"))); GNUNET_FS_file_information_inspect (fip, &file_information_extract, builder); dialog = GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_window")); gtk_window_set_title (GTK_WINDOW (dialog), short_fn); state = GNUNET_malloc (sizeof (struct EditPublicationState)); state->do_index = do_index; if (NULL != short_fn) state->short_fn = GNUNET_strdup (short_fn); state->anonymity_level = (guint) anonymity_level; state->priority = (guint) priority; state->fip = fip; state->preview_changed = GNUNET_NO; state->allow_no_keywords = allow_no_keywords; state->is_directory = GNUNET_FS_file_information_is_directory (fip); state->cb = cb; state->cls = cls; entry = GTK_ENTRY (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_keyword_entry")); gtk_entry_set_text (entry, ""); pubwindow = gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_window"); g_object_set_data (pubwindow, PUBSTATE, state); ok = GTK_WIDGET (gtk_builder_get_object (builder, "GNUNET_GTK_edit_publication_confirm_button")); gtk_widget_set_sensitive (ok, allow_no_keywords ? TRUE : FALSE); gtk_window_set_transient_for (GTK_WINDOW (pubwindow), parent); gtk_window_present (GTK_WINDOW (dialog)); } /* end of gnunet-fs-gtk-edit_publish_dialog.c */