/* This file is part of GNUnet. Copyright (C) 2010, 2012 GNUnet e.V. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * @file src/fs/gnunet-fs-gtk_common.c * @brief Common functions used in various places * @author Christian Grothoff */ #include "gnunet-fs-gtk_common.h" #include "gnunet-fs-gtk_download-save-as.h" #include "gnunet-fs-gtk.h" #include "gnunet-fs-gtk_event-handler.h" /** * Converts metadata specified by @a data of size @a data_len * and saved in format @a format to UTF-8 encoded string. * Works only for C-string and UTF8 metadata formats * (returns NULL for everything else). * Verifies UTF-8 strings. * * @param format format of the @a data * @param data data to convert * @param data_len length of the @a data buffer (in bytes) * @return NULL if can't be converted, allocated string otherwise, * freeable with #GNUNET_free. */ char * GNUNET_FS_GTK_dubious_meta_to_utf8 (enum EXTRACTOR_MetaFormat format, const char *data, size_t data_len) { switch (format) { case EXTRACTOR_METAFORMAT_UTF8: /* data must not contain NULLs (hence the -1) */ if (g_utf8_validate (data, data_len - 1, NULL)) return GNUNET_strdup (data); GNUNET_log ( GNUNET_ERROR_TYPE_INFO, _ ( "Failed to validate supposedly utf-8 string `%s' of length %u, assuming it to be a C string\n"), data, (unsigned int) data_len); format = EXTRACTOR_METAFORMAT_C_STRING; /* fall-through */ case EXTRACTOR_METAFORMAT_C_STRING: if (data_len > 0) { /* There are no guarantees that data is NULL-terminated, AFAIU, * so let's play it safe, shall we? */ char data_copy[data_len + 1]; memcpy (data_copy, data, data_len); data_copy[data_len] = '\0'; return GNUNET_GTK_from_loc_to_utf8 (data_copy); } break; default: break; } return NULL; } /** * Add meta data to list store. * * @param cls closure (the GtkListStore) * @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 @a data * @return 0 to continue (always) */ int GNUNET_FS_GTK_add_meta_data_to_list_store (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) { GtkListStore *ls = GTK_LIST_STORE (cls); char *data_to_insert; data_to_insert = GNUNET_FS_GTK_dubious_meta_to_utf8 (format, data, data_len); if (NULL == data_to_insert) return 0; gtk_list_store_insert_with_values ( ls, NULL, G_MAXINT, GNUNET_GTK_FS_MAIN_WINDOW_META_DATA_MC_META_TYPE, type, GNUNET_GTK_FS_MAIN_WINDOW_META_DATA_MC_META_FORMAT, format, #if HAVE_EXTRACTOR GNUNET_GTK_FS_MAIN_WINDOW_META_DATA_MC_META_TYPE_STRING, EXTRACTOR_metatype_to_string (type), #endif GNUNET_GTK_FS_MAIN_WINDOW_META_DATA_MC_META_VALUE, data_to_insert, -1); GNUNET_free (data_to_insert); return 0; } /** * Obtain pixbuf from thumbnail data in meta data. * * @param meta input meta data * @return NULL on error, otherwise the embedded thumbnail */ GdkPixbuf * GNUNET_FS_GTK_get_thumbnail_from_meta_data ( const struct GNUNET_CONTAINER_MetaData *meta) { GdkPixbuf *pixbuf; GdkPixbufLoader *loader; size_t ts; unsigned char *thumb; thumb = NULL; ts = GNUNET_CONTAINER_meta_data_get_thumbnail (meta, &thumb); if (0 == ts) return NULL; loader = gdk_pixbuf_loader_new (); gdk_pixbuf_loader_write (loader, (const guchar *) thumb, ts, NULL); pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); gdk_pixbuf_loader_close (loader, NULL); if (NULL != pixbuf) g_object_ref (pixbuf); g_object_unref (loader); GNUNET_free (thumb); return pixbuf; } /** * mmap the given file and run the #GNUNET_FS_directory_list_contents * function on it. * * @param filename name with the directory * @param dep function to call on each entry * @param dep_cls closure for @a dep * @return #GNUNET_OK on success */ int GNUNET_FS_GTK_mmap_and_scan (const char *filename, GNUNET_FS_DirectoryEntryProcessor dep, void *dep_cls) { struct GNUNET_DISK_FileHandle *fh; struct GNUNET_DISK_MapHandle *mh; uint64_t fsize; void *ddata; int ret; if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fsize, GNUNET_YES, GNUNET_YES)) { GNUNET_break (0); return GNUNET_SYSERR; } if (0 == fsize) { /* empty file, cannot be a directory */ return GNUNET_SYSERR; } if (NULL == (fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE))) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename); return GNUNET_SYSERR; } if (NULL == (ddata = GNUNET_DISK_file_map (fh, &mh, GNUNET_DISK_MAP_TYPE_READ, (size_t) fsize))) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mmap", filename); GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh)); return GNUNET_SYSERR; } if (GNUNET_SYSERR == GNUNET_FS_directory_list_contents ((size_t) fsize, ddata, 0, dep, dep_cls)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Selected file `%s' is not a GNUnet directory!\n"), filename); ret = GNUNET_SYSERR; } else { ret = GNUNET_OK; } GNUNET_break (GNUNET_OK == GNUNET_DISK_file_unmap (mh)); GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh)); return ret; } /** * Obtain the string we will use to describe a search result from * the respective meta data. * * @param meta meta data to inspect * @param is_a_dup is set to #GNUNET_YES if the result is a dup, and there was * no description to be found. #GNUNET_NO otherwise. * @return description of the result in utf-8, never NULL */ char * GNUNET_FS_GTK_get_description_from_metadata ( const struct GNUNET_CONTAINER_MetaData *meta, int *is_a_dup) { char *desc; char *utf8_desc; desc = GNUNET_CONTAINER_meta_data_get_first_by_types ( meta, EXTRACTOR_METATYPE_PACKAGE_NAME, EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METATYPE_BOOK_TITLE, EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, EXTRACTOR_METATYPE_FILENAME, EXTRACTOR_METATYPE_DESCRIPTION, EXTRACTOR_METATYPE_ALBUM, EXTRACTOR_METATYPE_COMMENT, EXTRACTOR_METATYPE_SUBJECT, EXTRACTOR_METATYPE_KEYWORDS, -1); if (desc == NULL) { *is_a_dup = GNUNET_YES; return GNUNET_strdup (_ ("no description supplied")); } utf8_desc = GNUNET_FS_GTK_dubious_meta_to_utf8 (EXTRACTOR_METAFORMAT_UTF8, desc, strlen (desc) + 1); GNUNET_free (desc); if (utf8_desc == NULL) { *is_a_dup = GNUNET_YES; return GNUNET_strdup (_ ("no description supplied")); } *is_a_dup = GNUNET_NO; return utf8_desc; } /** * A URI was selected (or pasted into the application). Run * the appropriate action. * * @param uri the URI * @param anonymity_level anonymity level to use */ void GNUNET_FS_GTK_handle_uri (const struct GNUNET_FS_Uri *uri, guint anonymity_level) { GtkEntry *query_entry; GtkComboBox *ns_cb; GtkEntry *ns_entry; struct GNUNET_CRYPTO_EcdsaPublicKey want; struct GNUNET_IDENTITY_PublicKey pkey; if (GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri)) { struct DownloadEntry *de; de = GNUNET_new (struct DownloadEntry); de->anonymity = anonymity_level; de->uri = GNUNET_FS_uri_dup (uri); GNUNET_FS_GTK_open_download_as_dialog (de); return; } query_entry = GTK_ENTRY ( GNUNET_FS_GTK_get_main_window_object ("main_window_search_entry")); ns_cb = GTK_COMBO_BOX (GNUNET_FS_GTK_get_main_window_object ( "main_window_search_namespace_combobox")); ns_entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (ns_cb))); if (GNUNET_FS_uri_test_sks (uri)) { /* select the namespace */ if (GNUNET_OK != GNUNET_FS_uri_sks_get_namespace (uri, &want)) { GNUNET_break (0); return; } pkey.type = GNUNET_IDENTITY_TYPE_ECDSA; pkey.ecdsa_key = want; { const char *ns_zkey; ns_zkey = GNUNET_GNSRECORD_pkey_to_zkey (&pkey); gtk_entry_set_text (ns_entry, ns_zkey); } /* set search entry to the namespace identifier */ { char *query_string; query_string = GNUNET_FS_uri_sks_get_content_id (uri); gtk_entry_set_text (query_entry, query_string); GNUNET_free (query_string); } return; } if (GNUNET_FS_uri_test_ksk (uri)) { gtk_entry_set_text (ns_entry, ""); /* set search entry to the query string */ { char *query_string; query_string = GNUNET_FS_uri_ksk_to_string_fancy (uri); gtk_entry_set_text (query_entry, query_string); GNUNET_free (query_string); } return; } GNUNET_break (0); } /** * Converts a GtkTreeRowReference to a GtkTreeIter. * * @param rr row reference * @param iter pointer to an iter structure to fill * @return #GNUNET_OK if iter was filled, #GNUNET_SYSERR otherwise */ int GNUNET_GTK_get_iter_from_reference (GtkTreeRowReference *rr, GtkTreeIter *iter) { int result = GNUNET_SYSERR; if (rr != NULL) { if (gtk_tree_row_reference_valid (rr)) { GtkTreePath *path; GtkTreeModel *model; path = gtk_tree_row_reference_get_path (rr); model = gtk_tree_row_reference_get_model (rr); if ((path != NULL) && (model != NULL)) { if (gtk_tree_model_get_iter (model, iter, path)) result = GNUNET_OK; gtk_tree_path_free (path); } } } return result; } /** * Creates a GtkTreeRowReference from a GtkTreeIter. * * @param model a model to reference * @param iter an iter that points to a row in the model * @return newly created reference or NULL in case of error */ GtkTreeRowReference * GNUNET_GTK_get_reference_from_iter (GtkTreeModel *model, GtkTreeIter *iter) { GtkTreeRowReference *result = NULL; if ((iter != NULL) && (model != NULL)) { GtkTreePath *path = gtk_tree_model_get_path (model, iter); if (path != NULL) { result = gtk_tree_row_reference_new (model, path); gtk_tree_path_free (path); } } return result; } /** * Fills "next_iter" with iterator for an item that comes next in the tree * after "iter". * Next item is, in order of precedence: * 1) First child of "iter", if "iter" has children and "allow_children" * is enabled. * 2) Next sibling of "iter", unless "iter" is the last sibling. * If none of those are present, function recursively checks parents of * "iter" until it finds next item or runs out of parents. * * @param model a model to reference * @param iter an iter that points to current row in the model * @param allow_children whether child of "iter" is considered to be next. * @param next_iter will be filled with the next row in the model on success * @return TRUE if next_iter is set to a valid iter, * FALSE if ran out of parents */ gboolean GNUNET_GTK_tree_model_get_next_flat_iter (GtkTreeModel *model, GtkTreeIter *iter, gboolean allow_children, GtkTreeIter *next_iter) { GtkTreeIter current_iter = *iter; while (TRUE) { GtkTreeIter tmp_iter; tmp_iter = current_iter; if (gtk_tree_model_iter_next (model, &tmp_iter)) { *next_iter = tmp_iter; return TRUE; } if (allow_children) { if (gtk_tree_model_iter_children (model, &tmp_iter, ¤t_iter)) { *next_iter = tmp_iter; return TRUE; } } allow_children = FALSE; if (! gtk_tree_model_iter_parent (model, &tmp_iter, ¤t_iter)) return FALSE; current_iter = tmp_iter; } return FALSE; } /* end of gnunet-fs-gtk-common.c */