gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r19629 - gnunet-gtk/src/fs


From: gnunet
Subject: [GNUnet-SVN] r19629 - gnunet-gtk/src/fs
Date: Thu, 2 Feb 2012 14:28:32 +0100

Author: grothoff
Date: 2012-02-02 14:28:32 +0100 (Thu, 02 Feb 2012)
New Revision: 19629

Added:
   gnunet-gtk/src/fs/gnunet-fs-gtk_about.c
   gnunet-gtk/src/fs/gnunet-fs-gtk_anonymity-widgets.c
   gnunet-gtk/src/fs/gnunet-fs-gtk_anonymity-widgets.h
   gnunet-gtk/src/fs/gnunet-fs-gtk_common.c
   gnunet-gtk/src/fs/gnunet-fs-gtk_common.h
   gnunet-gtk/src/fs/gnunet-fs-gtk_download-save-as.c
   gnunet-gtk/src/fs/gnunet-fs-gtk_download-save-as.h
   gnunet-gtk/src/fs/gnunet-fs-gtk_event-handler.c
   gnunet-gtk/src/fs/gnunet-fs-gtk_event-handler.h
   gnunet-gtk/src/fs/gnunet-fs-gtk_publish-dialog.c
   gnunet-gtk/src/fs/gnunet-fs-gtk_publish-edit-dialog.c
   gnunet-gtk/src/fs/gnunet-fs-gtk_publish-edit-dialog.h
Removed:
   gnunet-gtk/src/fs/gnunet-fs-gtk-about.c
   gnunet-gtk/src/fs/gnunet-fs-gtk-anonymity_spin_buttons.c
   gnunet-gtk/src/fs/gnunet-fs-gtk-anonymity_spin_buttons.h
   gnunet-gtk/src/fs/gnunet-fs-gtk-common.c
   gnunet-gtk/src/fs/gnunet-fs-gtk-common.h
   gnunet-gtk/src/fs/gnunet-fs-gtk-download.c
   gnunet-gtk/src/fs/gnunet-fs-gtk-download.h
   gnunet-gtk/src/fs/gnunet-fs-gtk-edit_publish_dialog.c
   gnunet-gtk/src/fs/gnunet-fs-gtk-edit_publish_dialog.h
   gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.c
   gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.h
   gnunet-gtk/src/fs/gnunet-fs-gtk-main_window_file_publish.c
Modified:
   gnunet-gtk/src/fs/Makefile.am
Log:
-rename fest

Modified: gnunet-gtk/src/fs/Makefile.am
===================================================================
--- gnunet-gtk/src/fs/Makefile.am       2012-02-02 12:57:54 UTC (rev 19628)
+++ gnunet-gtk/src/fs/Makefile.am       2012-02-02 13:28:32 UTC (rev 19629)
@@ -10,18 +10,18 @@
 bin_PROGRAMS = gnunet-fs-gtk
 
 gnunet_fs_gtk_SOURCES = \
-  gnunet-fs-gtk-about.c \
-  gnunet-fs-gtk-common.c gnunet-fs-gtk-common.h \
-  gnunet-fs-gtk-download.c gnunet-fs-gtk-download.h \
-  gnunet-fs-gtk-edit_publish_dialog.c gnunet-fs-gtk-edit_publish_dialog.h \
-  gnunet-fs-gtk-event_handler.c gnunet-fs-gtk-event_handler.h \
-  gnunet-fs-gtk-anonymity_spin_buttons.c 
gnunet-fs-gtk-anonymity_spin_buttons.h \
+  gnunet-fs-gtk.c gnunet-fs-gtk.h \
+  gnunet-fs-gtk_about.c \
+  gnunet-fs-gtk_anonymity-widgets.c gnunet-fs-gtk_anonymity-widgets.h \
+  gnunet-fs-gtk_common.c gnunet-fs-gtk_common.h \
+  gnunet-fs-gtk_download-save-as.c gnunet-fs-gtk_download-save-as.h \
+  gnunet-fs-gtk_event-handler.c gnunet-fs-gtk_event-handler.h \
+  gnunet-fs-gtk_publish-dialog.c \
+  gnunet-fs-gtk_publish-edit-dialog.c gnunet-fs-gtk_publish-edit-dialog.h \
   gnunet-fs-gtk-main_window_meta_data_context_menu.c \
-  gnunet-fs-gtk.c gnunet-fs-gtk.h \
   gnunet-fs-gtk-main_window_adv_pseudonym.c \
   gnunet-fs-gtk-main_window_create_pseudonym.c \
   gnunet-fs-gtk-main_window_file_download.c \
-  gnunet-fs-gtk-main_window_file_publish.c \
   gnunet-fs-gtk-main_window_namespace.c \
   gnunet-fs-gtk-main_window_search.c \
   gnunet-fs-gtk-main_window_open_directory.c \

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-about.c
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-about.c     2012-02-02 12:57:54 UTC (rev 
19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-about.c     2012-02-02 13:28:32 UTC (rev 
19629)
@@ -1,44 +0,0 @@
-/*
-     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-about.c
- * @author Christian Grothoff
- * @author Igor Wronsky
- *
- * This file contains the about dialog.
- */
-#include "gnunet_gtk.h"
-
-
-/**
- * This displays an about window
- *
- * @param widget widget creating the event, unused
- * @param data global builder, unused
- */
-void
-GNUNET_GTK_main_menu_help_about_activate_cb (GtkWidget * dummy, gpointer data)
-{
-  GNUNET_GTK_display_about ("gnunet_fs_gtk_about_window.glade");
-}
-
-
-/* end of gnunet-fs-gtk-about.c */

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-anonymity_spin_buttons.c
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-anonymity_spin_buttons.c    2012-02-02 
12:57:54 UTC (rev 19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-anonymity_spin_buttons.c    2012-02-02 
13:28:32 UTC (rev 19629)
@@ -1,177 +0,0 @@
-/*
-     This file is part of GNUnet
-     (C) 2005, 2006, 2010, 2012 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-anonymtiy_spin_buttons.c
- * @author Christian Grothoff
- * @brief operations to manage user's anonymity level selections
- */
-#include "gnunet-fs-gtk-common.h"
-#include "gnunet-fs-gtk-anonymity_spin_buttons.h"
-#include <gdk/gdk.h>
-
-/**
- * Spin button is changed, update its color.  NOTE: This function will 
eventually
- * become obsolete as we migrate to the drop-down style of anonymity-level 
selection.
- *
- * @param w the spin button that changed
- * @param builder's closure, unused
- */
-void
-GNUNET_GTK_anonymity_spin_button_value_changed_cb (GtkWidget * w, gpointer 
data)
-{
-#ifdef GdkRBGA
-  GtkSpinButton *spin;
-  gint val;
-  GdkRGBA bcolor;
-  GdkRGBA fcolor;
-
-  spin = GTK_SPIN_BUTTON (w);
-  if (spin == NULL)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  val = gtk_spin_button_get_value_as_int (spin);
-  if (val == 0)
-  {
-    if ((TRUE == gdk_rgba_parse (&bcolor, "red")) &&
-        (TRUE == gdk_rgba_parse (&fcolor, "black")))
-    {
-      gtk_widget_override_background_color (w, GTK_STATE_NORMAL, &bcolor);
-      gtk_widget_override_color (w, GTK_STATE_NORMAL, &fcolor);
-    }
-    else
-    {
-      GNUNET_break (0);
-    }
-  }
-  else
-  {
-    gtk_widget_override_background_color (w, GTK_STATE_NORMAL, NULL);
-    gtk_widget_override_color (w, GTK_STATE_NORMAL, NULL);
-  }
-#endif
-}
-
-
-/**
- * Obtain the numeric anonymity level selected by a GtkComboBox.
- *
- * @param builder builder for looking up widgets
- * @param combo_name name of the GtkComboBox with the anonymity selection
- * @param p_level where to store the anonymity level
- * @return TRUE on success, FALSE on failure
- */
-gboolean
-GNUNET_GTK_get_selected_anonymity_level (GtkBuilder * builder,
-                                         gchar * combo_name, guint * p_level)
-{
-  GtkComboBox *combo;
-
-  combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, combo_name));
-  if (!combo)
-    return FALSE;
-  return GNUNET_GTK_get_selected_anonymity_combo_level (combo, p_level);
-}
-
-
-/**
- * Obtain the numeric anonymity level selected by a GtkComboBox.
- *
- * @param combo the GtkComboBox with the anonymity selection
- * @param p_level where to store the anonymity level
- * @return TRUE on success, FALSE on failure
- */
-gboolean
-GNUNET_GTK_get_selected_anonymity_combo_level (GtkComboBox *combo, guint 
*p_level)
-{
-  GtkTreeIter iter;
-  GtkTreeModel *model;
-  guint level;
-
-  if (! gtk_combo_box_get_active_iter (combo, &iter))
-    return FALSE;
-  model = gtk_combo_box_get_model (combo);
-  if (!model)
-    return FALSE;
-  gtk_tree_model_get (model, &iter, 1, &level, -1);
-  if (p_level)
-    *p_level = level;
-  return TRUE;
-}
-
-
-/**
- * Set the anonymity level displayed by a combo box.
- *
- * @param builder the builder of the combo box
- * @param combo_name name of the combo box
- * @param sel_level desired anonymity level
- * @return TRUE on success, FALSE on failure
- */
-gboolean
-GNUNET_GTK_select_anonymity_level (GtkBuilder * builder, gchar * combo_name,
-                                   guint sel_level)
-{
-  GtkComboBox *combo;
-
-  combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, combo_name));
-  if (!combo)
-    return FALSE;
-  return GNUNET_GTK_select_anonymity_combo_level (combo, sel_level);
-}
-
-
-/**
- * Set the anonymity level displayed by a combo box.
- *
- * @param combo the combo box
- * @param sel_level desired anonymity level
- * @return TRUE on success, FALSE on failure
- */
-gboolean
-GNUNET_GTK_select_anonymity_combo_level (GtkComboBox *combo, guint sel_level)
-{
-  GtkTreeIter iter;
-  GtkTreeModel *model;
-  guint level;
-
-  model = gtk_combo_box_get_model (combo);
-  if (!model)
-    return FALSE;
-  if (! gtk_tree_model_get_iter_first (model, &iter))
-    return FALSE;
-  do
-  {
-    gtk_tree_model_get (model, &iter, 1, &level, -1);
-    if (level == sel_level)
-    {
-      gtk_combo_box_set_active_iter (combo, &iter);
-      return TRUE;
-    }
-  } 
-  while (gtk_tree_model_iter_next (model, &iter));
-  return FALSE;
-}
-
-
-
-/* end of gnunet-fs-gtk-anonymtiy_spin_buttons.c */

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-anonymity_spin_buttons.h
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-anonymity_spin_buttons.h    2012-02-02 
12:57:54 UTC (rev 19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-anonymity_spin_buttons.h    2012-02-02 
13:28:32 UTC (rev 19629)
@@ -1,80 +0,0 @@
-/*
-     This file is part of GNUnet
-     (C) 2005, 2006, 2010, 2012 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-anonymtiy_spin_buttons.h
- * @author Christian Grothoff
- * @brief operations to manage user's anonymity level selections
- */
-#ifndef GNUNET_FS_GTK_ANONYMITY_SPIN_BUTTONS_H
-#define GNUNET_FS_GTK_ANONYMITY_SPIN_BUTTONS_H
-
-#include "gnunet-fs-gtk-common.h"
-#include <gdk/gdk.h>
-
-
-/**
- * Obtain the numeric anonymity level selected by a GtkComboBox.
- *
- * @param builder builder for looking up widgets
- * @param combo_name name of the GtkComboBox with the anonymity selection
- * @param p_level where to store the anonymity level
- * @return TRUE on success, FALSE on failure
- */
-gboolean
-GNUNET_GTK_get_selected_anonymity_level (GtkBuilder * builder,
-                                         gchar * combo_name, guint * p_level);
-
-
-/**
- * Obtain the numeric anonymity level selected by a GtkComboBox.
- *
- * @param combo the GtkComboBox with the anonymity selection
- * @param p_level where to store the anonymity level
- * @return TRUE on success, FALSE on failure
- */
-gboolean
-GNUNET_GTK_get_selected_anonymity_combo_level (GtkComboBox *combo, guint 
*p_level);
-
-
-/**
- * Set the anonymity level displayed by a combo box.
- *
- * @param builder the builder of the combo box
- * @param combo_name name of the combo box
- * @param sel_level desired anonymity level
- * @return TRUE on success, FALSE on failure
- */
-gboolean
-GNUNET_GTK_select_anonymity_level (GtkBuilder * builder, gchar * combo_name,
-                                   guint sel_level);
-
-
-/**
- * Set the anonymity level displayed by a combo box.
- *
- * @param combo the combo box
- * @param sel_level desired anonymity level
- * @return TRUE on success, FALSE on failure
- */
-gboolean
-GNUNET_GTK_select_anonymity_combo_level (GtkComboBox *combo, guint sel_level);
-
-#endif

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-common.c
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-common.c    2012-02-02 12:57:54 UTC (rev 
19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-common.c    2012-02-02 13:28:32 UTC (rev 
19629)
@@ -1,234 +0,0 @@
-/*
-     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/gnunet-fs-gtk-common.c
- * @brief Common functions used in various places
- * @author Christian Grothoff
- */
-#include "gnunet-fs-gtk-common.h"
-
-/**
- * Converts metadata specified by @data of size @data_len
- * and saved in format @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 @data
- * @param data data to convert
- * @param data_len length of the 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. '<zlib>' 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 (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, 0, type, 1, format,
-                                    2, EXTRACTOR_metatype_to_string (type),
-                                    3, data_to_insert, -1);
-  GNUNET_free (data_to_insert); 
-  return 0;
-}
-
-
-/**
- * Convert the year from the spin button to an expiration
- * time (on midnight, January 1st of that year).
- *
- * @param spin button with an expiration year
- * @return expiration time in the usual GNUnet format
- */
-struct GNUNET_TIME_Absolute
-GNUNET_FS_GTK_get_expiration_time (GtkSpinButton * spin)
-{
-  struct GNUNET_TIME_Absolute ret;
-  int year;
-
-  year = gtk_spin_button_get_value_as_int (spin);
-  GNUNET_assert (year >= 0);
-  ret = GNUNET_FS_year_to_time ((unsigned int) year);
-  GNUNET_break (GNUNET_TIME_absolute_get ().abs_value < ret.abs_value);
-  return ret;
-}
-
-
-/**
- * Initialize the 'expiration_year_adjustment' of the given
- * builder to have a lower range of current-year+1 and a
- * default of current-year+2.
- *
- * @param builder builder object for which we should manipulate
- * the adjustment
- */
-void
-GNUNET_FS_GTK_setup_expiration_year_adjustment (GtkBuilder * builder)
-{
-  GtkAdjustment *aj;
-  unsigned int year;
-
-  year = GNUNET_FS_get_current_year ();
-  aj = GTK_ADJUSTMENT (gtk_builder_get_object
-                       (builder, "expiration_year_adjustment"));
-  gtk_adjustment_set_value (aj, year + 2);
-  gtk_adjustment_set_lower (aj, year + 1);
-}
-
-
-/**
- * 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 'dep'
- */
-void
-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;
-
-  if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fsize, GNUNET_YES))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  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;
-  }
-  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;
-  }
-  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);
-  }
-  GNUNET_break (GNUNET_OK == GNUNET_DISK_file_unmap (mh));
-  GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh));
-}
-
-/* end of gnunet-fs-gtk-common.c */

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-common.h
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-common.h    2012-02-02 12:57:54 UTC (rev 
19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-common.h    2012-02-02 13:28:32 UTC (rev 
19629)
@@ -1,126 +0,0 @@
-/*
-     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/gnunet-fs-gtk-common.h
- * @brief Common includes for all gnunet-gtk source files
- * @author Christian Grothoff
- */
-#ifndef GNUNET_FS_GTK_COMMON_H
-#define GNUNET_FS_GTK_COMMON_H
-
-#include "gnunet_gtk.h"
-#include <gnunet/gnunet_fs_service.h>
-#include <extractor.h>
-
-
-/**
- * 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);
-
-
-/**
- * Initialize the 'expiration_year_adjustment' of the given
- * builder to have a lower range of current-year+1 and a
- * default of current-year+2.
- * FIXME: odd API...
- *
- * @param builder builder object for which we should manipulate
- * the adjustment
- */
-void
-GNUNET_FS_GTK_setup_expiration_year_adjustment (GtkBuilder * builder);
-
-
-/**
- * Convert the year from the spin button to an expiration
- * time (on midnight, January 1st of that year).
- *
- * @param spin button with the year
- * @param time converted from the spin button
- */
-struct GNUNET_TIME_Absolute
-GNUNET_FS_GTK_get_expiration_time (GtkSpinButton * spin);
-
-
-/**
- * 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 'dep'
- */
-void
-GNUNET_FS_GTK_mmap_and_scan (const char *filename,
-                             GNUNET_FS_DirectoryEntryProcessor dep,
-                             void *dep_cls);
-
-
-/**
- * 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. '<zlib>' 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 (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);
-
-
-/**
- * Converts metadata specified by @data of size @data_len
- * and saved in format @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 @data
- * @param data data to convert
- * @param data_len length of the 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);
-
-
-#endif
-/* end of gnunet-fs-gtk-common.h */

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-download.c
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-download.c  2012-02-02 12:57:54 UTC (rev 
19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-download.c  2012-02-02 13:28:32 UTC (rev 
19629)
@@ -1,295 +0,0 @@
-/*
-     This file is part of GNUnet.
-     (C) 2010, 2011, 2012 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-download.c
- * @brief functions for managing the 'save as' dialog 
- * @author Christian Grothoff
- */
-#include "gnunet-fs-gtk-download.h"
-#include "gnunet-fs-gtk.h"
-#include "gnunet-fs-gtk-event_handler.h"
-
-/**
- * State for a 'save as' dialog of a download.
- */
-struct DownloadAsDialogContext
-{
-
-  /**
-   * Download context for which this dialog determines the
-   * filename (and other options).
-   */
-  struct DownloadContext *dc;
-
-  /**
-   * Builder for the dialog.
-   */
-  GtkBuilder *builder;
-  
-  /**
-   * Main dialog object.
-   */
-  GtkWidget *dialog;
-
-  /**
-   * Final response code from the dialog.
-   */
-  gint response;
-};
-
-
-/**
- * Free resources associated with the given download context.
- *
- * @param dc context to free
- */
-static void
-save_as_dialog_free_download_context (struct DownloadContext *dc)
-{
-  if (NULL != dc->rr)
-    gtk_tree_row_reference_free (dc->rr);
-  GNUNET_free_non_null (dc->mime);
-  GNUNET_free_non_null (dc->filename);
-  if (NULL != dc->meta)
-    GNUNET_CONTAINER_meta_data_destroy (dc->meta);
-  if (NULL != dc->uri)
-    GNUNET_FS_uri_destroy (dc->uri);
-  GNUNET_free (dc);  
-}
-
-
-/**
- * The 'save_as' dialog is being deleted.  Check which state we're in
- * and either simply clean up or start the download with the
- * respective options (by calling the respective continuation).
- *
- * @param widget the dialog object
- * @param event the deletion event
- * @param user_data the 'structDownloadAsDialogContext' of the dialog
- * @return always FALSE
- */
-gboolean
-GNUNET_GTK_save_as_dialog_delete_event_cb (GtkWidget * widget, GdkEvent * 
event,
-                                           gpointer user_data)
-{
-  struct DownloadAsDialogContext *dlc = user_data;
-  GtkBuilder *builder;
-  struct DownloadContext *dc;
-  GtkWidget *cb;
-
-  builder = dlc->builder;
-  dc = dlc->dc;
-  cb = GTK_WIDGET (gtk_builder_get_object
-                   (builder, "GNUNET_GTK_save_as_recursive_check_button"));
-  if (GTK_RESPONSE_OK != dlc->response)
-  {
-    save_as_dialog_free_download_context (dc);
-    g_object_unref (G_OBJECT (dlc->builder));
-    GNUNET_free (dlc);
-    return FALSE;
-  }
-  GNUNET_free_non_null (dc->filename);
-  dc->filename =
-      GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER 
(dlc->dialog));
-  dc->is_recursive =
-      (TRUE ==
-       gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cb))) ? GNUNET_YES :
-      GNUNET_NO;
-  dc->anonymity =
-      gtk_spin_button_get_value (GTK_SPIN_BUTTON
-                                 (gtk_builder_get_object
-                                  (builder,
-                                   
"GNUNET_GTK_save_as_dialog_anonymity_spin_button")));
-  g_object_unref (G_OBJECT (builder));
-  GNUNET_free (dlc);
-  GNUNET_FS_GTK_download_context_start_download (dc);
-  return FALSE;
-}
-
-
-/**
- * The user clicked on the 'save as' button of the dialog.
- * Delete the window and start the download.
- *
- * @param dialog the dialog object
- * @param response_id response_id associated with the button
- * @param user_data the 'structDownloadAsDialogContext' of the dialog
- */
-void
-GNUNET_GTK_save_as_dialog_response_cb (GtkDialog * dialog, 
-                                      gint response_id,
-                                       gpointer user_data)
-{
-  struct DownloadAsDialogContext *dlc = user_data;
-
-  dlc->response = response_id;
-  /* dialogs don't get delete-event the way normal windows do,
-     call the handler manually */
-  GNUNET_GTK_save_as_dialog_delete_event_cb (GTK_WIDGET (dialog), NULL,
-                                             user_data);
-  /* FIXME-BUG-MAYBE: isn't the dialog going to be destroyed with the builder? 
-     Is this legal and/or required? */
-  gtk_widget_destroy (GTK_WIDGET (dialog));
-}
-
-
-/**
- * Open the 'save as' dialog for a download.  Calls the 'dc->cb'
- * continutation when the dialog is complete.  Will release the 'dc'
- * resources if the dialog is cancelled.
- *
- * @param dc download context for the file/directory 
- */
-void
-GNUNET_FS_GTK_open_download_as_dialog (struct DownloadContext *dc)
-{
-  struct DownloadAsDialogContext *dlc;
-  GtkWidget *cb;
-
-  dlc = GNUNET_malloc (sizeof (struct DownloadAsDialogContext));
-  dlc->dc = dc;
-  dlc->builder =
-    GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_download_as_dialog.glade",
-                               dlc);
-  if (NULL == dlc->builder)
-  {
-    GNUNET_break (0);
-    save_as_dialog_free_download_context (dc);
-    GNUNET_free (dlc);
-    return;
-  }
-  dlc->dialog = GTK_WIDGET (gtk_builder_get_object
-                           (dlc->builder, "GNUNET_GTK_save_as_dialog"));
-
-  /* Enable recursive button for directories and
-     set recursive 'default' value based on what the 'dc' tells us */
-  cb = GTK_WIDGET (gtk_builder_get_object
-                   (dlc->builder, 
"GNUNET_GTK_save_as_recursive_check_button"));
-  if (GNUNET_FS_meta_data_test_for_directory (dc->meta))
-    gtk_widget_set_sensitive (cb, TRUE);  
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb),
-                               dc->is_recursive);   
-
-  /* initialize filename based on filename from 'dc' */
-  if (NULL != dc->filename)
-  {
-    char *dirname;
-    char *basename;
-
-    dirname = GNUNET_strdup (dc->filename);
-    basename = (char *) GNUNET_STRINGS_get_short_name (dirname);
-    /* basename now points into 'dirname'; cut 'dirname' off at the '/' before 
basename */
-    if (basename > dirname)
-      basename[-1] = '\0';
-
-    /* FIXME: remove following lines after testing... */
-    fprintf (stderr,
-            "Splitting `%s' into `%s' + `%s' for file chooser dialog.\n",
-            dc->filename,
-            dirname,
-            basename);
-
-    gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dlc->dialog), 
dirname);
-    gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dlc->dialog), 
basename);
-    GNUNET_free (dirname);
-  }
-  gtk_window_present (GTK_WINDOW (dlc->dialog));
-}
-
-
-/**
- * Actually start the download that is specified by the given download
- * context and its options.  Will add a download entry to the
- * respective tree model and trigger a start of the download using the
- * FS-API.
- *
- * @param dc download context of the download to execute
- */
-void
-GNUNET_FS_GTK_download_context_start_download (struct DownloadContext *dc)
-{
-  enum GNUNET_FS_DownloadOptions opt;
-  struct GNUNET_FS_Handle *fs;
-  struct DownloadEntry *de;
-  uint64_t len;
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  de = GNUNET_malloc (sizeof (struct DownloadEntry));
-  de->uri = dc->uri;
-  dc->uri = NULL;
-  de->meta = dc->meta;
-  dc->meta = NULL;
-  if (NULL != dc->rr)
-  {
-    de->rr = gtk_tree_row_reference_copy (dc->rr);
-    de->ts = GTK_TREE_STORE (gtk_tree_row_reference_get_model (dc->rr));
-    path = gtk_tree_row_reference_get_path (de->rr);
-    if  ( (NULL != path) &&
-         (gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts), &iter, path)) )
-    {
-      /* Store filename and anonymity as specified by the user.
-       * These will be re-used when this is a directory, and the user
-       * downloads its children.
-       */
-      gtk_tree_store_set (de->ts, &iter, 15, dc->filename, 16, dc->anonymity, 
-1);
-    } 
-    else
-    {
-      /* We could not find the referenced row in the search tab; this is
-        conceivable as the search tab might have been closed by the 
-        user while the 'save as' dialog was open.  In this case, this
-        is equivalent to having no search, so we drop the (now invalid)
-        'sr' reference */
-      dc->sr = NULL;
-    }
-    if (NULL != path)
-      gtk_tree_path_free (path);
-  }
-  fs = GNUNET_FS_GTK_get_fs_handle ();
-  opt = GNUNET_FS_DOWNLOAD_OPTION_NONE;
-  if (dc->is_recursive)
-    opt |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE;
-  len = GNUNET_FS_uri_chk_get_file_size (dc->uri);
-  if (NULL != dc->sr)
-  {
-    GNUNET_break (NULL !=
-                  GNUNET_FS_download_start_from_search (fs, dc->sr,
-                                                        dc->filename,
-                                                        NULL /* tempname */ ,
-                                                        0 /* offset */ ,
-                                                        len, dc->anonymity, 
opt,
-                                                        de));
-  }
-  else
-  {
-    GNUNET_break (NULL !=
-                  GNUNET_FS_download_start (fs, de->uri, NULL /* meta */ ,
-                                            dc->filename, NULL /* tempname */ ,
-                                            0 /* offset */ ,
-                                            len, dc->anonymity, opt, de,
-                                            NULL /* parent download ctx */ ));
-  }
-  save_as_dialog_free_download_context (dc);
-}
-
-
-/* end of gnunet-fs-gtk-download.c */

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-download.h
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-download.h  2012-02-02 12:57:54 UTC (rev 
19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-download.h  2012-02-02 13:28:32 UTC (rev 
19629)
@@ -1,117 +0,0 @@
-/*
-     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/gnunet-fs-gtk-download.h
- * @brief functions for downloading
- * @author Christian Grothoff
- */
-#ifndef GNUNET_FS_GTK_DOWNLOAD_H
-#define GNUNET_FS_GTK_DOWNLOAD_H
-
-#include "gnunet-fs-gtk-common.h"
-
-
-/**
- * Information we keep for a download.
- */
-struct DownloadContext;
-
-
-/**
- * Information we keep for a download.
- */
-struct DownloadContext
-{
-  /**
-   * URI for the download.
-   */
-  struct GNUNET_FS_Uri *uri;
-
-  /**
-   * Meta data.
-   */
-  struct GNUNET_CONTAINER_MetaData *meta;
-
-  /**
-   * Mime type.
-   */
-  char *mime;
-
-  /**
-   * Suggested filename, or NULL.
-   */
-  char *filename;
-
-  /**
-   * Row reference (if URI was found by search, or
-   * part of directory, etc.); otherwise NULL (download by URI).
-   */
-  GtkTreeRowReference *rr;
-
-  /**
-   * Associated search result, or NULL.
-   */
-  struct GNUNET_FS_SearchResult *sr;
-
-  /**
-   * Is this a recursive download?
-   */
-  int is_recursive;
-
-  /**
-   * Desired (default) anonymity level.
-   */
-  int anonymity;
-
-  /**
-   * Tab where this download is currently on display.
-   * (this is the same as sr->tab, but sr is opaque here).
-   */
-  struct SearchTab *tab;
-
-};
-
-
-/**
- * Actually start the download that is specified by the given download
- * context and its options.  Will add a download entry to the
- * respective tree model and trigger a start of the download using the
- * FS-API.
- *
- * @param dc download context of the download to execute
- */
-void
-GNUNET_FS_GTK_download_context_start_download (struct DownloadContext *dc);
-
-
-/**
- * Open the 'save as' dialog for a download.  Calls
- * 'GNUNET_FS_GTK_download_context_start_download' when the dialog is
- * complete.  Will release the 'dc' resources if the dialog is
- * cancelled.
- *
- * @param dc download context for the file/directory 
- */
-void
-GNUNET_FS_GTK_open_download_as_dialog (struct DownloadContext *dc);
-
-
-#endif

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-edit_publish_dialog.c
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-edit_publish_dialog.c       2012-02-02 
12:57:54 UTC (rev 19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-edit_publish_dialog.c       2012-02-02 
13:28:32 UTC (rev 19629)
@@ -1,1163 +0,0 @@
-/*
-     This file is part of GNUnet
-     (C) 2005, 2006, 2010, 2012 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 <gnunet/gnunet_util_lib.h>
-
-#include "metatypes.c"
-
-
-/**
- * Internal state kept for each "edit" dialog where the user can edit
- * publishing information for a file.
- */
-struct EditPublicationDialogContext
-{
-  /**
-   * Builder for the dialog.
-   */
-  GtkBuilder *builder;
-
-  /**
-   * The 'window' object for the dialog.
-   */
-  GtkWindow *edit_publication_window;
-
-  /**
-   * The confirmation button which closes the dialog (only sensitive
-   * if the values entered are valid).
-   */
-  GtkWidget *confirm_button;
-
-  /**
-   * Tree view showing the meta data for the file.
-   */
-  GtkTreeView *meta_treeview;
-
-  /**
-   * Tree view showing the keywords for the file.
-   */
-  GtkTreeView *keywords_treeview;
-
-  /**
-   * Image showing the preview image for the file.
-   */
-  GtkImage *preview_image;
-
-  /**
-   * Combo box where the user can select the anonymity level.
-   */
-  GtkComboBox *anonymity_combo;
-
-  /**
-   * Liststore of possible publication types.
-   */
-  GtkListStore *pubtypes_liststore;
-
-  /**
-   * Liststore of all possible meta types the user can choose from.
-   * (updated to based on the selected publication type).
-   */
-  GtkListStore *metatypes_liststore;
-
-  /**
-   * Liststore showing the meta data of the file (associated with
-   * the 'meta_treeview'.
-   */
-  GtkListStore *meta_liststore;
-
-  /**
-   * Liststore with the keywords of the file (associated with the
-   * 'keywords_treeview'.
-   */
-  GtkListStore *keywords_liststore;
-
-  /**
-   * Spin button to select content priority level for the file.
-   */
-  GtkSpinButton *priority_spin;
-
-  /**
-   * Spin button to select the expiration year.
-   */
-  GtkSpinButton *expiration_year_spin;
-
-  /**
-   * Spin button to select the replication level.
-   */
-  GtkSpinButton *replication_spin;
-
-  /**
-   * Entry line for adding additional keywords.
-   */
-  GtkEntry *keyword_entry;
-
-  /**
-   * Entry line for setting a namespace root (possibly invisible).
-   */
-  GtkEntry *root_entry;
-
-  /**
-   * Entry line to check indexing vs. inserting (possibly invisible)
-   */
-  GtkToggleButton *index_checkbutton;
-
-  /**
-   * Type ID of the last selected item in the GtkCellRendererCombo
-   * of the meta data tree view.
-   */
-  gint meta_combo_selected_type_id;
-
-  /**
-   * Continuation to call once the dialog has been closed
-   */
-  GNUNET_FS_GTK_EditPublishDialogCallback cb;
-
-  /**
-   * Closure for 'cb'.
-   */
-  void *cb_cls;
-
-  /**
-   * Briefly used temporary meta data set.
-   */
-  struct GNUNET_CONTAINER_MetaData *md;
-
-  /**
-   * Information about the file being published as seen by the FS-API.
-   * This is what we are primarily editing.
-   */
-  struct GNUNET_FS_FileInformation *fip;
-
-  /**
-   * Flag to track if we changed the preview and thus should keep/discard
-   * certain metadata. (FIXME: yucky!)
-   */
-  int preview_changed;
-
-  /**
-   * Is this operation for a directory?
-   */
-  int is_directory;
-
-  /**
-   * Is it allowed for the user to supply keywords in this dialog?
-   */
-  int allow_no_keywords;
-
-};
-
-
-/**
- * Free resources associated with the edit publication dialog.
- *
- * @param ctx the context of the dialog to release resources of
- */
-static void
-free_edit_dialog_context (struct EditPublicationDialogContext *ctx)
-{
-  gtk_widget_destroy (GTK_WIDGET (ctx->edit_publication_window));
-  // FIXME-LEAK: destroy builder!
-  GNUNET_free (ctx);
-}
-
-
-
-/* ****************** metadata editing ******************** */
-
-
-
-/**
- * Update the set of metatypes listed in the dialog based on the
- * given code.
- *
- * @param ctx main dialog context
- * @param code which set of metatypes is desired?
- */
-static void
-change_metatypes (struct EditPublicationDialogContext *ctx, gint code)
-{
-  gint pubtype_count;
-  gint max_type;
-  gint i;
-  GtkTreeIter iter;
-
-  /* double-check that 'code' is valid */
-  for (pubtype_count = 0; NULL != types[pubtype_count]; pubtype_count++) ;
-  GNUNET_assert (code < pubtype_count);
-  
-  /* clear existing selection of metatypes */
-  gtk_list_store_clear (ctx->metatypes_liststore);
-  max_type = EXTRACTOR_metatype_get_max ();
-  /* add new types based on selection */
-  for (i = 0; types[code][i] != EXTRACTOR_METATYPE_RESERVED; i++)  
-    if ( (types[code][i] < max_type) && (types[code][i] > 0) )
-      gtk_list_store_insert_with_values (ctx->metatypes_liststore, 
-                                        &iter, G_MAXINT, 
-                                        0, types[code][i], 
-                                        1, EXTRACTOR_METAFORMAT_UTF8, 
-                                        2, EXTRACTOR_metatype_to_string (types 
[code][i]), 
-                                        3, EXTRACTOR_metatype_to_description 
(types[code][i]), 
-                                        -1);  
-}
-
-
-/**
- * The user has selected a different publication type.
- * Update the meta type selection.
- *
- * @param widget the publication type combo box widget
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-void
-GNUNET_GTK_edit_publication_type_combo_changed_cb (GtkComboBox * widget,
-                                                   gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-  GtkTreeIter iter;
-  gint code;
-
-  if (! gtk_combo_box_get_active_iter (widget, &iter))
-    return;
-  gtk_tree_model_get (GTK_TREE_MODEL (ctx->pubtypes_liststore), &iter, 0, 
&code, -1);
-  change_metatypes (ctx, code);
-}
-
-
-/**
- * The user has changed the selection in the meta data tree view.
- * Update the sensitivity of the 'delete' button.
- *
- * @param ts the tree selection object
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-/* FIXME: connect this signal via glade (modern versions of Glade support 
this) */
-static void
-metadata_selection_changed_cb (GtkTreeSelection *ts,
-                              gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-
-  gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object
-                                       (ctx->builder, 
-                                        
"GNUNET_GTK_edit_publication_delete_button")),
-                            gtk_tree_selection_get_selected (ts, NULL, NULL));
-}
-
-
-/**
- * The user changed (and confirmed the change) the type of a
- * meta-data item in the meta data tree view.  Update the type and
- * text in the list store accordingly.
- *
- * @param renderer widget where the change happened
- * @param path which item was changed in the tree view
- * @param new_text new value for the item
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-void 
-GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer_edited_cb 
(GtkCellRendererText *renderer, 
-                                                                       gchar * 
path, 
-                                                                       gchar * 
new_text,
-                                                                       
gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-  GtkTreeIter iter;
-  gint type_id;
-
-  if (! gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL 
(ctx->meta_liststore), 
-                                            &iter, 
-                                            path))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  if (-1 == ctx->meta_combo_selected_type_id)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  type_id = ctx->meta_combo_selected_type_id;
-  ctx->meta_combo_selected_type_id = -1;
-  gtk_list_store_set (ctx->meta_liststore, &iter, 
-                     0, type_id, 
-                     1, EXTRACTOR_METAFORMAT_UTF8, 
-                     2, EXTRACTOR_metatype_to_string (type_id),
-                     4, EXTRACTOR_metatype_to_description (type_id),
-                      -1);
-}
-
-
-/**
- * The user changed the type of a meta-data item in the meta data
- * tree view.  Obtain the selected type_id and store it in
- * the 'meta_combo_selected_type_id' field for use by
- * 'GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer_edited_cb'.
- *
- * @param combo combo box that was dropped down
- * @param path which item was changed in the tree view
- * @param new_iter item that is now selected in the drop-down combo box
- * @param user_data the 'struct EditPublicationDialogContext' 
- */
-void 
-GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer_changed_cb 
(GtkCellRendererCombo * combo, 
-                                                                        gchar 
* path_string,
-                                                                        
GtkTreeIter * new_iter,
-                                                                        
gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-  GtkTreeModel *combo_model;
-  gint type_id;
-
-  g_object_get (combo,
-               "model", &combo_model, NULL);
-  gtk_tree_model_get (combo_model, new_iter,
-                     0, &type_id,
-                     -1);
-  ctx->meta_combo_selected_type_id = type_id;
-}
-
-
-/**
- * The user changed (and confirmed the change) the value of a
- * meta-data item in the meta data tree view.  Update the value
- * in the list store accordingly.
- *
- * @param renderer widget where the change happened
- * @param path which item was changed in the tree view
- * @param new_text new value for the item
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-void 
-GNUNET_GTK_edit_publication_metadata_tree_view_value_renderer_edited_cb 
(GtkCellRendererText * renderer,
-                                                                        gchar 
* path,
-                                                                        gchar 
* new_text,
-                                                                        
gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-  GtkTreeIter iter;
-  gint metatype;
-  char *avalue;
-  const char *ivalue;
-  size_t slen;
-  char *pos;
-
-  if (! gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL 
(ctx->meta_liststore),
-                                            &iter, 
-                                            path))
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  gtk_tree_model_get (GTK_TREE_MODEL (ctx->meta_liststore), &iter, 
-                     0, &metatype, -1);
-  if (metatype == EXTRACTOR_METATYPE_FILENAME) 
-  {
-    /* apply filename rules */
-    /* First, use UNIX-style separators */
-    avalue = GNUNET_strdup (new_text);
-    while (NULL != (pos = strstr (avalue, "\\")))
-      *pos = '/';
-
-    /* if user put '/' at the end, remove it' */
-    slen = strlen (avalue);
-    while ( (slen > 1) && (avalue[slen - 1] == '\\'))
-    {
-      avalue[slen - 1] = '\0';
-      slen--;
-    }
-
-    /* However, directories must end with '/', so add it */
-    if ( (new_text[strlen (new_text) - 1] != '/') && 
-        ctx->is_directory )
-    {
-      char * tmp;
-      
-      GNUNET_asprintf (&tmp, "%s/", avalue);
-      GNUNET_free (avalue);
-      avalue = tmp;
-    }
-    
-    /* Also, replace '../' everywhere with "___" */
-    while (NULL != (pos = strstr (avalue, "../")))
-      memset (pos, '_', 3);
-
-    ivalue = avalue;
-  }
-  else
-  {
-    ivalue = new_text;
-    avalue = NULL;
-  }
-  gtk_list_store_set (ctx->meta_liststore, &iter, 
-                     3, ivalue, 
-                     -1);
-  GNUNET_free_non_null (avalue);
-}
-
-
-/**
- * The user has pushed the 'add' button for metadata.  Add a 'dummy' value
- * to our meta data store (to be edited by the user).
- *
- * @param button the 'add' button
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-void
-GNUNET_GTK_edit_publication_add_button_clicked_cb (GtkButton * button,
-                                                   gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-  GtkTreeIter iter;
-
-  gtk_list_store_insert_with_values (ctx->meta_liststore,
-                                    &iter, 0,
-                                    0, 0,
-                                    1, EXTRACTOR_METAFORMAT_UTF8, 
-                                    2, _("Select a type"), 
-                                    3, _("Specify a value"), 
-                                    4, NULL, 
-                                    -1);
-}
-
-
-/**
- * The user has pushed the 'del' button for metadata.
- * If there is a metadata selected, remove it from the list store.
- *
- * @param widget the button
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-void
-GNUNET_GTK_edit_publication_delete_button_clicked_cb (GtkButton * button,
-                                                      gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-  GtkTreeIter iter;
-  GtkTreeSelection *meta_selection;
-
-  meta_selection = gtk_tree_view_get_selection (ctx->meta_treeview);
-  if (! gtk_tree_selection_get_selected (meta_selection, NULL, &iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  if (gtk_list_store_remove (ctx->meta_liststore, &iter))
-    gtk_tree_selection_select_iter (meta_selection, &iter);
-}
-
-
-/**
- * The user has selected another preview image file.  Update the
- * preview image.
- *
- * @param widget the file chooser dialog that completed
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-void
-GNUNET_GTK_edit_publication_metadata_preview_file_chooser_button_file_set_cb 
(GtkFileChooserButton * widget, 
-                                                                             
gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-  gchar *fn;
-
-  fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
-  gtk_image_set_from_file (ctx->preview_image, fn);
-  g_free (fn);
-  ctx->preview_changed = GNUNET_YES;
-}
-
-
-/* ****************** keyword list editing ******************** */
-
-
-
-/**
- * The user has changed the selection in the keyword tree view.
- * Update the sensitivity of the 'delete' button.
- *
- * @param ts the tree selection object
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-/* FIXME: connect this signal via glade (modern versions of Glade support 
this) */
-static void
-keywords_selection_changed_cb (GtkTreeSelection *ts,
-                              gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-
-  gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object
-                                       (ctx->builder,
-                                        
"GNUNET_GTK_edit_publication_keyword_list_del_button")),
-                            gtk_tree_selection_get_selected (ts, NULL, NULL));
-}
-
-
-/**
- * The user has edited the keyword entry line.  Update the
- * sensitivity of the 'add' button.
- *
- * @param editable the entry line for keywords
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-void
-GNUNET_GTK_edit_publication_keyword_entry_changed_cb (GtkEditable * editable,
-                                                      gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-  const char *keyword;
-
-  keyword = gtk_entry_get_text (ctx->keyword_entry);
-  gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (ctx->builder,
-                                                               
"GNUNET_GTK_edit_publication_keyword_list_add_button")), 
-                           (strlen (keyword) > 0) ? TRUE : FALSE);
-}
-
-
-/**
- * The user has pushed the 'del' button for the keyword.
- * If there is a keyword selected, remove it from the list store.
- *
- * @param widget the button
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-void
-GNUNET_GTK_edit_publication_keyword_list_del_button_clicked_cb (GtkButton *
-                                                                button,
-                                                                gpointer 
user_data)
-{ 
-  struct EditPublicationDialogContext *ctx = user_data;
-  GtkTreeIter iter;
-  GtkTreeSelection *keywords_selection;
-
-  keywords_selection = gtk_tree_view_get_selection (ctx->keywords_treeview);
-  if (! gtk_tree_selection_get_selected (keywords_selection, NULL, &iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  if (gtk_list_store_remove (GTK_LIST_STORE (ctx->keywords_liststore), &iter))
-    gtk_tree_selection_select_iter (keywords_selection, &iter);
-
-  /* disable confirm button if keywords are required and we have no more 
keywords */
-  if ( (! ctx->allow_no_keywords) && 
-       (! gtk_tree_model_get_iter_first (GTK_TREE_MODEL 
(ctx->keywords_liststore),
-                                        &iter)) )
-    gtk_widget_set_sensitive (ctx->confirm_button, FALSE);
-}
-
-
-/**
- * The user has pushed the 'add' button for the keyword (or pressed RETURN).
- * If there is a keyword in the line, add it to the list store.
- *
- * @param widget the entry line, or NULL (if we are called from 'RETURN')
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-void
-GNUNET_GTK_edit_publication_keyword_list_add_button_clicked_cb (GtkButton *
-                                                                button,
-                                                                gpointer 
user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-  const char *keyword;
-  GtkTreeIter iter;
-
-  keyword = gtk_entry_get_text (ctx->keyword_entry);
-  if (strlen (keyword) == 0)
-    return;
-  gtk_list_store_insert_with_values (ctx->keywords_liststore, 
-                                    &iter, G_MAXINT,
-                                    0, keyword,
-                                    1, TRUE,
-                                    -1);
-  gtk_widget_set_sensitive (ctx->confirm_button, TRUE);
-  gtk_entry_set_text (ctx->keyword_entry, "");
-}
-
-
-/**
- * The user has pushed a button in the entry line.  Check if it was 'RETURN'
- * and if so consider executing the 'add' action.
- *
- * @param widget the entry line
- * @param event the event information
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-gboolean
-GNUNET_GTK_edit_publication_keyword_entry_key_press_event_cb (GtkWidget *
-                                                              widget,
-                                                              GdkEventKey *
-                                                              event,
-                                                              gpointer 
user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-
-  if (event->keyval != GDK_KEY_Return)
-    return FALSE;
-  GNUNET_GTK_edit_publication_keyword_list_add_button_clicked_cb (NULL, ctx);
-  return TRUE;
-}
-
-
-
-/* ****************** handlers for closing the dialog ******************** */
-
-
-/**
- * The user clicked the 'cancel' button.  Abort the operation.
- *
- * @param button the cancel button
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-void
-GNUNET_GTK_edit_publication_cancel_button_clicked_cb (GtkButton * button,
-                                                      gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-
-  ctx->cb (ctx->cb_cls, GTK_RESPONSE_CANCEL, NULL);
-  free_edit_dialog_context (ctx);
-}
-
-
-/**
- * The user closed the window.  Abort the operation.
- *
- * @param widget the window
- * @param event the event that caused the window to close
- * @param user_data the 'struct EditPublicationDialogContext'
- * @return TRUE (always)
- */
-gboolean
-GNUNET_GTK_edit_publication_window_delete_event_cb (GtkWidget * widget,
-                                                    GdkEvent * event,
-                                                    gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-
-  ctx->cb (ctx->cb_cls, GTK_RESPONSE_CANCEL, NULL);
-  free_edit_dialog_context (ctx);
-  return TRUE;
-}
-
-
-/**
- * Copy binary meta data from to the new container and also preserve
- * all entries that were not changed.  In particular, all binary meta
- * data is removed if the preview was changed, otherwise it is all
- * kept.  Similarly, if values are still in the liststore, they are
- * fully kept (including plugin name and original format).  "Keeping"
- * a value means that it is added to the 'md' meta data in the dialog
- * context.
- *
- * @param cls closure, a 'struct FileInformationUpdateContext';
- *        contains the 'new' meta data to construct in the 'md'
- *        field and the liststore to check the current value
- *        against in 'meta_liststore'.
- * @param plugin_name name of the plugin that produced this value;
- *        special values can be used (i.e. '<zlib>' 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 EditPublicationDialogContext *ctx = cls;
-  GtkTreeIter iter;
-  gchar *value;
-  guint ntype;
-  guint nformat;
-  int keep;
-
-  keep = GNUNET_NO;
-  switch (format)
-  {
-  case EXTRACTOR_METAFORMAT_UTF8:
-  case EXTRACTOR_METAFORMAT_C_STRING:
-    if (TRUE == gtk_tree_model_get_iter_first (GTK_TREE_MODEL 
(ctx->meta_liststore), &iter))
-    {
-      do
-      {
-        gtk_tree_model_get (GTK_TREE_MODEL (ctx->meta_liststore), &iter, 0, 
&ntype, 1, &nformat, 3, &value, -1);
-        if ((ntype == type) && (nformat == format) &&
-            (0 == strcmp (value, data)))
-        {
-          gtk_list_store_remove (ctx->meta_liststore, &iter);
-          keep = GNUNET_YES;
-          g_free (value);
-          break;
-        }
-        g_free (value);
-      }
-      while (TRUE == gtk_tree_model_iter_next (GTK_TREE_MODEL 
(ctx->meta_liststore), &iter));
-    }
-    break;
-  case EXTRACTOR_METAFORMAT_UNKNOWN:
-    break;
-  case EXTRACTOR_METAFORMAT_BINARY:
-    if (ctx->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 (ctx->md, plugin_name, 
type,
-                                                     format, data_mime_type,
-                                                     data, data_len));
-  return 0;
-}
-
-
-/**
- * Function called to update the information in FI based on the changes made in
- * the edit dialog.
- *
- * @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 EditPublicationDialogContext *ctx = cls;
-  GtkTreeIter iter;
-  gint year;
-
-  /* gather publishing options  */
-  *do_index = gtk_toggle_button_get_active (ctx->index_checkbutton);
-  GNUNET_break (GNUNET_GTK_get_selected_anonymity_combo_level 
(ctx->anonymity_combo,
-                                                              
&bo->anonymity_level));
-  bo->content_priority = gtk_spin_button_get_value (ctx->priority_spin);
-  bo->replication_level = gtk_spin_button_get_value (ctx->replication_spin);
-  year = gtk_spin_button_get_value (ctx->expiration_year_spin);
-  bo->expiration_time = GNUNET_FS_year_to_time (year);
-
-  /* update keyword-URI */
-  if (NULL != (*uri))
-    GNUNET_FS_uri_destroy (*uri);
-  *uri = NULL;
-  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ctx->keywords_liststore), 
&iter))
-  {
-    do
-    {
-      gchar *value;
-
-      gtk_tree_model_get (GTK_TREE_MODEL (ctx->keywords_liststore), &iter, 0, 
&value, -1);
-      if (NULL == *uri)
-       *uri = GNUNET_FS_uri_ksk_create_from_args (1, (const char **) &value);
-      else
-       GNUNET_FS_uri_ksk_add_keyword (*uri, value, GNUNET_NO);
-      g_free (value);
-    }
-    while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ctx->keywords_liststore), 
&iter));
-  }
-
-  /* update meta data; first, we copy the unchanged values from the original 
meta data */
-  ctx->md = GNUNET_CONTAINER_meta_data_create ();
-  GNUNET_CONTAINER_meta_data_iterate (meta, 
-                                     &preserve_meta_items, 
-                                     ctx);
-  /* clear original meta data */
-  GNUNET_CONTAINER_meta_data_clear (meta);
-  /* add all of the 'preserved' values */
-  GNUNET_CONTAINER_meta_data_merge (meta, ctx->md);
-  GNUNET_CONTAINER_meta_data_destroy (ctx->md);
-  ctx->md = NULL;
-  /* now add all of the values from the model; adding will simply do 
-     nothing for values that are already in the set because they were 
preserved */
-  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ctx->meta_liststore), 
&iter))
-  {
-    do
-    {
-      guint ntype;
-      guint nformat;
-      gchar *value;
-
-      gtk_tree_model_get (GTK_TREE_MODEL (ctx->meta_liststore), &iter, 0, 
&ntype, 1, &nformat, 3, &value, -1);
-      if (ntype > 0)
-        GNUNET_CONTAINER_meta_data_insert (ctx->md, "<user>", ntype, nformat,
-                                           "text/plain", value,
-                                           strlen (value) + 1);
-      g_free (value);
-    }
-    while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ctx->meta_liststore), 
&iter));
-  }
-  
-  /* finally, if we got a new preview, add it as well */
-  if (ctx->preview_changed == GNUNET_YES)
-  {
-    gchar *fn;
-    char *data;
-    gsize data_size;
-    const char *mime;
-    GFile *f;
-    GFileInfo *finfo;
-
-    fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER
-                                        (gtk_builder_get_object
-                                         (ctx->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 (! 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, "<user>",
-                                         EXTRACTOR_METATYPE_THUMBNAIL,
-                                         EXTRACTOR_METAFORMAT_BINARY, mime,
-                                         data, data_size);
-    }
-    g_object_unref (finfo);
-    g_object_unref (f);
-    g_free (fn);
-  }
-  return GNUNET_SYSERR;         /* only visit top-level item */
-}
-
-
-/**
- * The user clicked the 'confirm' button.  Push the edits back into the
- * FileInformation structure and given it and the options back to the 
- * callback.  Then clean up the dialog.
- *
- * @param button the cancel button
- * @param user_data the 'struct EditPublicationDialogContext'
- */
-void
-GNUNET_GTK_edit_publication_confirm_button_clicked_cb (GtkButton * button,
-                                                       gpointer user_data)
-{
-  struct EditPublicationDialogContext *ctx = user_data;
-
-  /* push back changes to file-information */
-  GNUNET_FS_file_information_inspect (ctx->fip, 
-                                     &file_information_update,
-                                     ctx);
-  /* call our continuation */
-  ctx->cb (ctx->cb_cls, 
-          GTK_RESPONSE_OK,
-          gtk_entry_get_text (ctx->root_entry));
-  /* free resources from the edit dialog */
-  free_edit_dialog_context (ctx);
-}
-
-
-
-/* ****************** code for initialization of the dialog 
******************** */
-
-
-
-/**
- * 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 to populate the edit 
dialog.
- *
- * @param cls the 'struct EditPublicationDialogContext'
- * @param fi the entry in the publish-structure (unused)
- * @param length length of the file or directory (unused)
- * @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_import (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 EditPublicationDialogContext *ctx = cls;
-  GdkPixbuf *pixbuf;
-  char *short_fn;
-  int year;
-
-  /* import options */
-  year = (int) GNUNET_FS_time_to_year (bo->expiration_time);
-  gtk_spin_button_set_value (ctx->expiration_year_spin, year);
-  GNUNET_GTK_select_anonymity_combo_level (ctx->anonymity_combo,
-                                          bo->anonymity_level);
-  gtk_spin_button_set_value (ctx->priority_spin, bo->content_priority);
-  gtk_spin_button_set_value (ctx->replication_spin, bo->replication_level);
-  gtk_toggle_button_set_active (ctx->index_checkbutton, *do_index);
-
-
-  /* import keywords */
-  if (NULL != *uri)
-    GNUNET_FS_uri_ksk_get_keywords (*uri, &add_keyword, 
ctx->keywords_liststore);
-
-  /* import meta data */
-  if (NULL != meta)
-  {
-    GNUNET_CONTAINER_meta_data_iterate (meta,
-                                        
&GNUNET_FS_GTK_add_meta_data_to_list_store,
-                                        ctx->meta_liststore);
-    pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta);
-    if (pixbuf != NULL)
-    {
-      gtk_image_set_from_pixbuf (ctx->preview_image, pixbuf);
-    }
-  }
-  
-  /* Also update window title based on filename */
-  short_fn = GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
-                                                           
EXTRACTOR_METATYPE_FILENAME,
-                                                           -1);
-  if (NULL == short_fn)
-  {
-    gtk_window_set_title (ctx->edit_publication_window, _("<unnamed>"));
-  }
-  else
-  {
-    /* FIXME: ensure that short_fn is UTF-8 encoded */
-    gtk_window_set_title (ctx->edit_publication_window, short_fn);
-    GNUNET_free (short_fn);
-  }
-  return GNUNET_SYSERR;         /* only visit top-level item */
-}
-
-
-/**
- * Open the dialog to edit file information data.
- *
- * @param parent parent window of the dialog
- * @param fip information about the file information that is to be edited
- * @param allow_no_keywords is it OK to close the dialog without any keywords?
- *                          also used to indicate that this is a namespace 
operation
- *                          (FIXME: overloaded/badly-named argument)
- * @param anon_liststore liststore with anonymity options (FIXME: bad sharing)
- * @param cb function to call when the dialog is closed
- * @param cb_cls closure for 'cb'
- */
-void
-GNUNET_FS_GTK_edit_publish_dialog (GtkWindow * parent,
-                                   struct GNUNET_FS_FileInformation *fip,
-                                   int allow_no_keywords,
-                                   GtkListStore *anon_liststore,
-                                   GNUNET_FS_GTK_EditPublishDialogCallback cb,
-                                   gpointer cb_cls)
-{
-  GtkTreeIter iter;
-  gint code;
-  GtkComboBox *pubtypes_combo;
-  GtkLabel *index_label;
-  GtkLabel *root_label;
-  struct EditPublicationDialogContext *ctx;
-  GtkTreeSelection *meta_selection;
-  GtkTreeSelection *keywords_selection;
-
-  ctx = GNUNET_malloc (sizeof (struct EditPublicationDialogContext));
-  ctx->fip = fip;
-  ctx->preview_changed = GNUNET_NO;
-  ctx->allow_no_keywords = allow_no_keywords;
-  ctx->is_directory = GNUNET_FS_file_information_is_directory (fip);
-  ctx->cb = cb;
-  ctx->cb_cls = cb_cls;
-  ctx->meta_combo_selected_type_id = -1;
-  ctx->builder = GNUNET_GTK_get_new_builder 
("gnunet_fs_gtk_edit_publication.glade", ctx);
-
-  if (ctx->builder == NULL)
-  {
-    GNUNET_free (ctx);
-    return;
-  }
-
-  /* obtain various widgets for use later */
-  ctx->pubtypes_liststore =
-      GTK_LIST_STORE (gtk_builder_get_object
-                      (ctx->builder, 
"GNUNET_GTK_publication_types_liststore"));
-  ctx->metatypes_liststore =
-      GTK_LIST_STORE (gtk_builder_get_object
-                      (ctx->builder,
-                       "GNUNET_GTK_publication_metadata_types_liststore"));
-  ctx->meta_treeview = GTK_TREE_VIEW (gtk_builder_get_object
-                      (ctx->builder,
-                       "GNUNET_GTK_edit_publication_metadata_tree_view"));
-  ctx->keywords_treeview = GTK_TREE_VIEW (gtk_builder_get_object
-                      (ctx->builder,
-                       "GNUNET_GTK_edit_publication_keyword_list_tree_view"));
-  ctx->edit_publication_window =
-    GTK_WINDOW (gtk_builder_get_object (ctx->builder, 
-                                       "GNUNET_GTK_edit_publication_window"));
-  ctx->keywords_liststore = GTK_LIST_STORE (gtk_builder_get_object
-                       (ctx->builder, 
"GNUNET_GTK_publication_keywords_liststore"));
-  ctx->keyword_entry =
-      GTK_ENTRY (gtk_builder_get_object
-                 (ctx->builder, "GNUNET_GTK_edit_publication_keyword_entry"));
-  ctx->confirm_button = GTK_WIDGET (gtk_builder_get_object
-                     (ctx->builder, 
"GNUNET_GTK_edit_publication_confirm_button"));
-  ctx->preview_image =
-      GTK_IMAGE (gtk_builder_get_object
-                 (ctx->builder,
-                  "GNUNET_GTK_edit_publication_metadata_preview_image"));
-  ctx->meta_liststore = GTK_LIST_STORE (gtk_builder_get_object
-                         (ctx->builder,
-                          "GNUNET_GTK_publication_metadata_liststore"));
-  ctx->root_entry = GTK_ENTRY (gtk_builder_get_object
-                    (ctx->builder, "GNUNET_GTK_edit_publication_root_entry"));
-  ctx->expiration_year_spin = GTK_SPIN_BUTTON
-                             (gtk_builder_get_object
-                              (ctx->builder,
-                               
"GNUNET_GTK_edit_publication_expiration_year_spin_button"));
-  ctx->priority_spin = GTK_SPIN_BUTTON
-                             (gtk_builder_get_object
-                              (ctx->builder,
-                               
"GNUNET_GTK_edit_publication_priority_spin_button"));
-  ctx->replication_spin = GTK_SPIN_BUTTON
-                             (gtk_builder_get_object
-                              (ctx->builder,
-                               
"GNUNET_GTK_edit_publication_replication_spin_button"));
-  ctx->index_checkbutton = GTK_TOGGLE_BUTTON
-                                (gtk_builder_get_object
-                                 (ctx->builder,
-                                  
"GNUNET_GTK_edit_publication_index_checkbutton"));
-  ctx->anonymity_combo = GTK_COMBO_BOX (gtk_builder_get_object (ctx->builder,
-                                                               
"GNUNET_GTK_edit_publication_anonymity_combobox"));
-
-  /* Basic initialization of widgets models and visibility */
-  gtk_combo_box_set_model (ctx->anonymity_combo, 
-                          GTK_TREE_MODEL (anon_liststore));
-  GNUNET_FS_GTK_setup_expiration_year_adjustment (ctx->builder);
-
-  /* FIXME-UNCLEAN: are the following three even required anymore? */
-  gtk_list_store_clear (ctx->keywords_liststore);
-  gtk_list_store_clear (ctx->meta_liststore);
-  gtk_entry_set_text (ctx->keyword_entry, "");
-
-  pubtypes_combo =
-      GTK_COMBO_BOX (gtk_builder_get_object
-                     (ctx->builder, "GNUNET_GTK_edit_publication_type_combo"));
-  if (gtk_combo_box_get_active_iter (pubtypes_combo, &iter))
-  {
-    gtk_tree_model_get (GTK_TREE_MODEL (ctx->pubtypes_liststore), &iter, 0, 
&code, -1);
-    change_metatypes (ctx, 0);
-  }
-  else
-    gtk_combo_box_set_active (pubtypes_combo, 0);
-
-  /* indexing does not apply to directories */
-  gtk_widget_set_visible (GTK_WIDGET (ctx->index_checkbutton),
-                         ! ctx->is_directory);
-  index_label = GTK_LABEL (gtk_builder_get_object
-                          (ctx->builder,
-                           "GNUNET_GTK_edit_publication_index_label"));
-  gtk_widget_set_visible (GTK_WIDGET (index_label),
-                         ! ctx->is_directory);
-
-  /* show root label only if we must have keywords, which is also only the
-     case for namespaces (FIXME-UNCLEAN: overloaded use of the argument) */
-  gtk_widget_set_visible (GTK_WIDGET (ctx->root_entry),
-                         !allow_no_keywords);
-  root_label = GTK_LABEL (gtk_builder_get_object
-                         (ctx->builder, 
"GNUNET_GTK_edit_publication_root_label"));
-  gtk_widget_set_visible (GTK_WIDGET (root_label),
-                         !allow_no_keywords);
-  
-  /* FIXME-UNCLEAN: what if we already have keywords? Again, does not really
-     apply to namespace-case, but this seems a bit ugly */
-  gtk_widget_set_sensitive (ctx->confirm_button, allow_no_keywords ? TRUE : 
FALSE);
-
-
-  /* FIXME: these signal handlers can be set by (modern) versions of Glade */
-  keywords_selection = gtk_tree_view_get_selection (ctx->keywords_treeview);
-  g_signal_connect (G_OBJECT (keywords_selection), "changed",
-                    G_CALLBACK (keywords_selection_changed_cb), ctx);
-  meta_selection = gtk_tree_view_get_selection (ctx->meta_treeview);
-  g_signal_connect (G_OBJECT (meta_selection), "changed",
-                    G_CALLBACK (metadata_selection_changed_cb), ctx);
-
-  /* import meta data and options */
-  GNUNET_FS_file_information_inspect (fip, &file_information_import, ctx);
-
-
-  /* Finally, display window */
-  gtk_window_set_transient_for (ctx->edit_publication_window, parent);
-  gtk_window_present (ctx->edit_publication_window);
-}
-
-
-/* end of gnunet-fs-gtk-edit_publish_dialog.c */

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-edit_publish_dialog.h
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-edit_publish_dialog.h       2012-02-02 
12:57:54 UTC (rev 19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-edit_publish_dialog.h       2012-02-02 
13:28:32 UTC (rev 19629)
@@ -1,66 +0,0 @@
-/*
-     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.h
- * @author Christian Grothoff
- */
-#ifndef GNUNET_FS_GTK_EDIT_PUBLISH_DIALOG_H
-#define GNUNET_FS_GTK_EDIT_PUBLISH_DIALOG_H
-
-#include "gnunet-fs-gtk-common.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <gnunet/gnunet_fs_service.h>
-
-
-/**
- * Function called when the edit publish dialog has been closed.
- *
- * @param cls closure
- * @param ret GTK_RESPONSE_OK if the dialog was closed with "OK"
- * @param root namespace root, NULL for file publishing
- */
-typedef void (*GNUNET_FS_GTK_EditPublishDialogCallback) (gpointer cls,
-                                                        int ret,
-                                                         const char *root);
-
-
-/**
- * Open the dialog to edit file information data.
- *
- * @param parent parent window of the dialog
- * @param fip information about the file information that is to be edited
- * @param allow_no_keywords is it OK to close the dialog without any keywords?
- *                          also used to indicate that this is a namespace 
operation
- *                          (FIXME: overloaded/badly-named argument)
- * @param anon_liststore liststore with anonymity options (FIXME: bad sharing)
- * @param cb function to call when the dialog is closed
- * @param cb_cls closure for 'cb'
- */
-void
-GNUNET_FS_GTK_edit_publish_dialog (GtkWindow * parent,
-                                   struct GNUNET_FS_FileInformation *fip,
-                                   int allow_no_keywords, 
-                                  GtkListStore *anon_liststore,
-                                   GNUNET_FS_GTK_EditPublishDialogCallback cb,
-                                   gpointer cls);
-
-#endif
-/* end of gnunet-fs-gtk-edit_publish_dialog.h */

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.c
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.c     2012-02-02 12:57:54 UTC 
(rev 19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.c     2012-02-02 13:28:32 UTC 
(rev 19629)
@@ -1,2658 +0,0 @@
-/*
-     This file is part of GNUnet.
-     (C) 2010, 2011, 2012 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-event_handler.c
- * @brief Main event handler for file-sharing
- * @author Christian Grothoff
- */
-#include "gnunet-fs-gtk.h"
-#include "gnunet-fs-gtk-download.h"
-#include "gnunet-fs-gtk-event_handler.h"
-#include <string.h>
-
-
-/**
- * We have a single tab where we display publishing operations.
- * So there is only one instance of this struct.
- */ 
-struct PublishTab
-{
-
-  /**
-   * Frame for the tab.
-   */
-  GtkWidget *frame;
-
-  /**
-   * Associated builder.
-   */
-  GtkBuilder *builder;
-
-  /**
-   * Associated tree store.
-   */
-  GtkTreeStore *ts;
-};
-
-
-/**
- * Information we keep for each file or directory being published.
- * Used to quickly identify the tab and row of the operation; stored
- * in the user-context of the FS library for the publish operation.
- */
-struct PublishEntry
-{
-  /**
-   * Associated FS publish operation.
-   */
-  struct GNUNET_FS_PublishContext *pc;
-
-  /**
-   * Tab storing this entry.
-   */
-  struct PublishTab *tab;
-
-  /**
-   * Where in the tab is this entry?
-   */
-  GtkTreeRowReference *rr;
-
-  /**
-   * URI of the file (set after completion).
-   */
-  struct GNUNET_FS_Uri *uri;
-
-  /**
-   * Is this the top-level entry for the publish operation
-   * or sub-operation?
-   */
-  int is_top;
-};
-
-
-/**
- * Information we keep for each search result entry in any search tab.
- * An entry like this is also generated for downloads by-URI.  Used to
- * quickly identify the tab and row of the result; stored in the
- * user-context of the FS library for the search result.
- */
-struct SearchResult
-{
-  /**
-   * Where in the tab is this result?
-   */
-  GtkTreeRowReference *rr;
-
-  /**
-   * Tab storing this result.
-   */
-  struct SearchTab *tab;
-
-  /**
-   * Search result for top-level results and
-   * namespace-update results.
-   */
-  struct GNUNET_FS_SearchResult *result;
-
-  /**
-   * Associated download, or NULL for none.
-   */
-  struct DownloadEntry *download;
-};
-
-
-
-/**
- * Head of linked list of tabs for searches.
- */
-static struct SearchTab *search_tab_head;
-
-/**
- * Tail of linked list of tabs for searches.
- */
-static struct SearchTab *search_tab_tail;
-
-/**
- * Special tab we use to for downloads-by-URIs and downloads
- * where the search tab has been closed ("parent lost").
- */
-static struct SearchTab *uri_tab;
-
-/**
- * Special tab we use to store publishing operations.
- */
-static struct PublishTab *publish_tab;
-
-/**
- * Row reference for the current search context menu.
- * FIXME-UNCLEAN: de-globalize?
- */
-static GtkTreeRowReference *current_context_row_reference;
-
-/**
- * Search tab used for the current search context menu.
- * FIXME-UNCLEAN: de-globalize?
- */
-static struct SearchTab *current_context_search_tab;
-
-
-
-/* ***************** Search event handling ****************** */
-
-/**
- * This should get the default download directory (so that GNUnet
- * won't offer the user to download files to the 'bin' subdirectory,
- * or whatever is the cwd).  Returns NULL on failure (such as
- * non-existend directory).  Should also preserve the last setting (so
- * if the user saves files somewhere else, next time we default to
- * somewhere else, at least until application restart, or maybe even
- * between application restarts).
- *
- * Fills the 'buffer' up to 'size' bytes, returns a pointer to it.
- */
-static char *
-get_default_download_directory (char *buffer, size_t size)
-{
-  /* FIXME-FEATURE: implement... */
-  return NULL;
-}
-
-
-/**
- * Called recursively to build a suggested filename by prepending
- * suggested names for its parent directories (if any).
- *
- * @param tm tree model this function gets the data from
- * @param iter current position in the tree, for which we want a suggested 
filename
- * @param top GNUNET_YES for the original call to this function,
- *            GNUNET_NO for recursive calls; used to decide if the
- *            current call is eligible to set 'anonymity' and 'local_parents'
- * @param local_parents set to GNUNET_YES if all parents are directories, and 
are downloaded.
- * @param anonymity set to the anonymity level of the closest ancestor 
download (if any);
- *                      set to "-1" for uninitialized initially (will be left 
at -1 if
- *                      no suitable parent download was found)
- * @param filename_is_absolute set to GNUNET_YES if the suggestion is an 
absolute filename,
- *                             GNUNET_NO for relative filenames (gotten from 
meta data)
- * @return suggested filename, possibly NULL
- */
-static char *
-get_suggested_filename_anonymity (GtkTreeModel *tm, 
-                                 GtkTreeIter *iter, 
-                                 int top,
-                                 int *local_parents, 
-                                 int *anonymity, 
-                                 int *filename_is_absolute)
-{
-  char *result;
-  char *dirname;
-  char *local_filename;
-  char *filename;
-  int downloaded_anonymity;
-  int have_a_parent;
-  struct GNUNET_CONTAINER_MetaData *meta;
-  GtkTreeIter parent;
-  const char *basename; 
-  char *dot;
-
-  /* FIXME-BUG-MAYBE: this function is likely responsible for not always
-     suggesting the best filename... To be investigated some more... */
-  gtk_tree_model_get (tm, iter, 0, &meta, 
-                     15, &local_filename, 
-                     16, &downloaded_anonymity, 
-                     -1);
-  if ( (NULL == local_filename) && (GNUNET_NO == top) )
-    *local_parents = GNUNET_NO;
-  if ( (downloaded_anonymity != -1) && (*anonymity == -1) && (GNUNET_NO == 
top) )
-    *anonymity = downloaded_anonymity;
-  if (gtk_tree_model_iter_parent (tm, &parent, iter))
-  {
-    have_a_parent = GNUNET_YES;
-    dirname = get_suggested_filename_anonymity (tm, &parent, GNUNET_NO,
-                                               local_parents, anonymity, 
-                                               filename_is_absolute);
-  }
-  else
-  {
-    have_a_parent = GNUNET_NO;
-    dirname = NULL;
-    if (GNUNET_NO == top)
-      *local_parents = GNUNET_NO;
-  }
-  if (local_filename == NULL)
-  {
-    filename = GNUNET_FS_meta_data_suggest_filename (meta);
-  }
-  else
-  {
-    /* This directory was downloaded as /foo/bar/baz/somedirname
-     * Hopefully, "somedirname" is actually "somedir.gnd"
-     * We need to strip the ".gnd" part to get "somedir", which is
-     * what we're going to use instead of suggested original filename
-     * Without the .gnd extension we're going to just use a copy
-     * of the directory file name - and that would fail. Sad.
-     */
-    if ( (NULL == dirname) && (GNUNET_NO == have_a_parent))
-    {
-      /* This is the ealderlest parent directory. Use absolute path. */
-      basename = (const char *) local_filename;
-      *filename_is_absolute = GNUNET_YES;
-    }
-    else
-    {
-      basename = GNUNET_STRINGS_get_short_name (local_filename);
-    }
-    if ( (NULL != basename) && (strlen (basename) > 0) )
-    {
-      filename = GNUNET_strdup (basename);
-      dot = strrchr (filename, '.');
-      if (dot)
-        *dot = '\0';
-    }
-    else
-    {
-      filename = GNUNET_FS_meta_data_suggest_filename (meta);
-    }
-  }
-  if ( (NULL != dirname) && (NULL != filename) )
-  {
-    GNUNET_asprintf (&result, "%s%s%s", dirname, DIR_SEPARATOR_STR, filename);
-    GNUNET_free (filename);
-    GNUNET_free (dirname);
-    return result;
-  }
-  if (NULL != filename)
-    return filename;
-  return NULL;
-}
-
-
-/**
- * This function is called when the user double-clicks on a search
- * result.  Begins the download, if necessary by opening the "save as"
- * window.
- *
- * @param tree_view tree view with the details
- * @param path path selecting which entry we want to download
- * @param tab the search tab where the user triggered the download request
- * @param is_recursive was the request for a recursive download?
- */
-static void
-start_download (GtkTreeView *tree_view, 
-               GtkTreePath *path,
-                struct SearchTab *tab,
-               int is_recursive)
-{
-  GtkTreeModel *tm;
-  GtkTreeIter iter;
-  struct GNUNET_FS_Uri *uri;
-  struct GNUNET_CONTAINER_MetaData *meta;
-  struct SearchResult *sr;
-  gchar *mime;
-  struct DownloadContext *dc;
-  char *buf = NULL;
-  char *tmp;
-  size_t tmplen;
-  char cwd[FILENAME_MAX];
-  char *download_directory;
-  char *filename;
-  int local_parents;
-  int have_a_suggestion;
-  int anonymity;
-  int filename_is_absolute;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Starting a %sdownload\n", 
-             is_recursive ? "recursive " : "");
-
-  GNUNET_assert (tab != 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);
-  if (NULL == uri)
-  {
-    /* user clicked on directory that was opened (not downloaded!), so we
-       have no URI and downloading makes no sense. Ignore! */
-    g_free (mime);
-    return;
-  }
-  if (!(GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri)))
-  {
-    /* can only download chk/loc URIs, ignore */
-    g_free (mime);
-    return;
-  }
-
-  download_directory = get_default_download_directory (cwd, sizeof (cwd));
-  /* If no download directory is known, try working directory */
-  if (download_directory == NULL)
-    download_directory = getcwd (cwd, sizeof (cwd));
-  /* Calculate suggested filename */
-  local_parents = GNUNET_YES;
-  anonymity = -1;
-  filename_is_absolute = GNUNET_NO;
-  filename = get_suggested_filename_anonymity (tm, &iter, GNUNET_YES,
-                                              &local_parents, &anonymity,
-                                              &filename_is_absolute);
-  have_a_suggestion = GNUNET_NO;
-  if (NULL != download_directory)
-  {
-    if (NULL == filename)
-    {
-      buf = GNUNET_strdup (download_directory);
-    }
-    else
-    {
-      have_a_suggestion = GNUNET_YES;
-      if (filename_is_absolute)
-        GNUNET_asprintf (&tmp, "%s", filename);
-      else
-        GNUNET_asprintf (&tmp, "%s%s%s",
-                        download_directory,
-                        DIR_SEPARATOR_STR,
-                        filename);
-      tmplen = strlen (tmp);
-      /* now, if we have a directory, replace trailing '/' with ".gnd" */
-      if (GNUNET_YES ==
-         GNUNET_FS_meta_data_test_for_directory (meta))
-      {
-       if ( (tmp[tmplen-1] == '/') ||
-            (tmp[tmplen-1] == '\\') )
-         tmp[tmplen-1] = '\0';
-       GNUNET_asprintf (&buf,
-                        "%s%s",
-                        tmp,
-                        GNUNET_FS_DIRECTORY_EXT);
-       GNUNET_free (tmp);           
-      }
-      else
-      {
-       buf = tmp;
-      }
-    }
-  }
-  GNUNET_free_non_null (filename);
-
-  /* now setup everything for the save-as dialog */
-  dc = GNUNET_malloc (sizeof (struct DownloadContext));
-  dc->uri = GNUNET_FS_uri_dup (uri);
-  dc->mime = mime;
-  dc->filename = buf;
-  dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
-  dc->rr = gtk_tree_row_reference_new (tm, path);
-  dc->sr = sr->result;
-  dc->anonymity = anonymity;
-  dc->is_recursive = is_recursive;
-  dc->tab = tab;
-  if ( (GNUNET_YES == local_parents) &&
-       (GNUNET_YES == have_a_suggestion) )
-    /* Skip the dialog, call directly */
-    GNUNET_FS_GTK_download_context_start_download (dc);
-  else
-    GNUNET_FS_GTK_open_download_as_dialog (dc);
-}
-
-
-/**
- * An item was selected from the context menu; destroy the menu shell.
- *
- * @param menushell menu to destroy
- * @parma user_data the 'struct DownloadEntry' for the menu (unused)
- */
-static void
-search_list_popup_selection_done (GtkMenuShell *menushell,
-                                 gpointer user_data)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Item selected in menu shell %p, destroying it.\n",
-             menushell);
-  gtk_widget_destroy (GTK_WIDGET (menushell));
-}
-
-
-/**
- * This function is called when the user double-clicks on a search
- * result.  Begins the download, if necessary by opening the "save as"
- * window.
- *
- * @param tree_view tree view with the details
- * @param path path selecting which entry we want to download
- * @param column unused entry specifying which column the mouse was in
- * @param user_data the 'struct SearchTab' that was activated
- */
-static void
-start_download_row_activated (GtkTreeView * tree_view, GtkTreePath * path,
-                             GtkTreeViewColumn * column, gpointer user_data)
-{
-  struct SearchTab *tab = user_data;
-
-  start_download (tree_view, path, tab, GNUNET_NO);
-}
-
-
-/**
- * "Download" was selected in the current search context menu.
- * 
- * @param item the 'download' menu item
- * @parma user_data the 'struct DownloadEntry' to download.
- */
-static void
-start_download_ctx_menu (GtkMenuItem *item, gpointer user_data)
-{
-  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, current_context_search_tab, GNUNET_NO);
-  gtk_tree_path_free (path);
-  current_context_search_tab = NULL;
-}
-
-
-/**
- * "Download recursively" was selected in the current search context menu.
- * 
- * @param item the 'download recursively' menu item
- * @parma user_data the 'struct DownloadEntry' to download.
- */
-static void
-start_download_recursively_ctx_menu (GtkMenuItem *item, gpointer user_data)
-{
-  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, current_context_search_tab, GNUNET_YES);
-  gtk_tree_path_free (path);
-  current_context_search_tab = NULL;
-}
-
-
-/**
- * Download "abort" was selected in the current search context menu.
- * 
- * @param item the 'abort' menu item
- * @parma user_data the 'struct DownloadEntry' to abort.
- */
-static void
-abort_download_ctx_menu (GtkMenuItem *item, gpointer user_data)
-{
-  struct DownloadEntry *de = user_data;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Aborting download DE=%p\n", 
-             de);
-  GNUNET_assert (de->dc != NULL);
-  GNUNET_FS_download_stop (de->dc, GNUNET_YES);
-  current_context_search_tab = NULL;
-}
-
-
-/**
- * Copy current URI to clipboard was selected in the current context menu.
- * 
- * @param item the 'copy-to-clipboard' menu item
- * @parma user_data NULL
- */
-static void
-copy_uri_to_clipboard_ctx_menu (GtkMenuItem *item, gpointer user_data)
-{
-  GtkTreePath *path;
-  GtkTreeView *tv;
-  GtkTreeModel *tm;
-  GtkTreeIter iter;
-  struct GNUNET_FS_Uri *uri;
-  char *uris;
-  GtkClipboard *cb;
-
-  if (NULL == current_context_row_reference)
-  {
-    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"));
-  tm = gtk_tree_view_get_model (tv);
-  if (! gtk_tree_model_get_iter (tm, &iter, path))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (path);
-    return;
-  }
-  gtk_tree_model_get (tm, &iter, 1, &uri, -1);
-  gtk_tree_path_free (path);
-  current_context_search_tab = NULL;
-  if (uri == NULL)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  uris = GNUNET_FS_uri_to_string (uri);
-  cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
-  gtk_clipboard_set_text (cb, uris, -1);
-  gtk_clipboard_store (cb);
-  GNUNET_free (uris);
-}
-
-
-/**
- * Context menu was requested for a search result list.
- * Compute which menu items are applicable and display
- * an appropriate menu.
- *
- * @param tm tree model underlying the tree view where the event happened
- * @param tab tab where the event happened
- * @param event_button the event
- * @return FALSE if no menu could be popped up,
- *         TRUE if there is now a pop-up menu
- */
-static gboolean
-search_list_popup (GtkTreeModel *tm, 
-                  struct SearchTab *tab, 
-                  gint init_button,
-                  guint32 event_time,
-                  GtkTreeIter *iter)
-{
-  GtkMenu *menu;
-  GtkWidget *child;
-  GtkTreePath *path;
-  struct SearchResult *sr;
-  struct GNUNET_FS_Uri *uri;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Creating a menu for SR=%p, DE=%p\n", 
-             sr,
-             sr->download);
-
-  /* FIXME-UNCLEAN: move these to some menu context struct
-     (de-globalize) */
-  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 = gtk_tree_model_get_path (tm, iter);
-  current_context_row_reference = gtk_tree_row_reference_new (tm, path);
-  gtk_tree_path_free (path);
-
-  gtk_tree_model_get (tm, iter, 1, &uri, 9, &sr, -1);
-
-  menu = GTK_MENU (gtk_menu_new ());
-  if ( (NULL == sr->download) &&
-       (NULL != uri) )
-  {
-    /* only display download menus if there is a URI */
-    child = gtk_menu_item_new_with_label (_("_Download"));
-    g_signal_connect (child, "activate",
-                     G_CALLBACK (start_download_ctx_menu), NULL);
-    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);
-    
-    child = gtk_menu_item_new_with_label (_("Download _recursively"));
-    g_signal_connect (child, "activate",
-                     G_CALLBACK (start_download_recursively_ctx_menu), NULL);
-    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);
-  }
-  if (NULL != sr->download)
-  {
-    child = gtk_menu_item_new_with_label (_("_Abort download"));
-    g_signal_connect (child, "activate",
-                      G_CALLBACK (abort_download_ctx_menu), sr->download);
-    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);
-  }
-  if (NULL != uri)
-  {
-    child = gtk_menu_item_new_with_label (_("_Copy URI to Clipboard"));
-    g_signal_connect (child, "activate",
-                     G_CALLBACK (copy_uri_to_clipboard_ctx_menu), NULL);
-    gtk_label_set_use_underline (GTK_LABEL
-                                (gtk_bin_get_child (GTK_BIN (child))), TRUE);
-    gtk_widget_show (child);
-  }
-  g_signal_connect (menu, "selection-done",
-                   G_CALLBACK (search_list_popup_selection_done), NULL);
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), child);
-  gtk_menu_popup (menu, NULL, NULL, NULL, NULL, init_button, event_time);
-  return TRUE;
-}
-
-
-/**
- * We got a 'popup-menu' event, display the context menu.
- *
- * @param widget the tree view where the event happened
- * @param user_data the 'struct SearchTab' of the tree view
- * @return FALSE if no menu could be popped up,
- *         TRUE if there is now a pop-up menu
- */
-static gboolean
-search_list_on_popup (GtkWidget *widget, gpointer user_data)
-{
-  GtkTreeView *tv = GTK_TREE_VIEW (widget);
-  struct SearchTab *tab = user_data;
-  GtkTreeSelection *sel;
-  GtkTreeIter iter;
-  GtkTreeModel *tm;
-
-  sel = gtk_tree_view_get_selection (tv);
-  if (! gtk_tree_selection_get_selected (sel, &tm, &iter))
-    return FALSE; /* nothing selected */
-  return search_list_popup (tm, tab, 0, gtk_get_current_event_time (), &iter);
-}
-
-
-/**
- * We got a right-click on the search result list. Display the context
- * menu.
- *
- * @param widget the GtkTreeView with the search result list
- * @param event the event, we only care about button events
- * @param user_data the 'struct SearchTab' the widget is in
- * @return FALSE if no menu could be popped up,
- *         TRUE if there is now a pop-up menu
- */
-static gboolean
-search_list_on_menu (GtkWidget * widget, 
-                    GdkEvent * event,
-                    gpointer user_data)
-{
-  GtkTreeView *tv = GTK_TREE_VIEW (widget);
-  GdkEventButton *event_button = (GdkEventButton *) event;
-  struct SearchTab *tab = user_data;
-  GtkTreeModel *tm;
-  GtkTreePath *path;
-  GtkTreeIter iter;
-
-  if ( (event->type != GDK_BUTTON_PRESS) ||
-       (event_button->button != 3) )
-    return FALSE; /* not a right-click */
-  if (! gtk_tree_view_get_path_at_pos (tv,
-                                      event_button->x, event_button->y,
-                                       &path, NULL, NULL, NULL))
-    return FALSE; /* click outside of area with values, ignore */    
-  tm = gtk_tree_view_get_model (tv);
-  if (! gtk_tree_model_get_iter (tm, &iter, path))
-    return FALSE; /* not sure how we got a path but no iter... */  
-  gtk_tree_path_free (path);
-  return search_list_popup (tm, tab, 
-                           event_button->button,
-                           event_button->time,
-                           &iter);
-}
-
-
-/**
- * Recalculate and update the label for a search, as we have
- * received additional search results.
- *
- * @param tab search tab for which we should update the label
- */
-static void
-update_search_label (struct SearchTab *tab)
-{
-  char *label_text;
-
-  while (tab->parent != NULL)
-    tab = tab->parent->tab;
-  if (tab->num_results > 0)
-    GNUNET_asprintf (&label_text, "%.*s%s (%u)", 20, tab->query_txt,
-                     strlen (tab->query_txt) > 20 ? "..." : "",
-                     tab->num_results);
-  else
-    GNUNET_asprintf (&label_text, "%.*s%s", 20, tab->query_txt,
-                     strlen (tab->query_txt) > 20 ? "..." : "");
-  gtk_label_set_text (tab->label, label_text);
-  gtk_widget_set_tooltip_text (GTK_WIDGET (tab->label), tab->query_txt);
-  GNUNET_free (label_text);
-}
-
-
-/**
- * Close a search tab and free associated state.  Assumes that the
- * respective tree model has already been cleaned up (this just
- * updates the notebook and frees the 'tab' itself).
- *
- * @param tab search tab to close
- */
-static void
-close_search_tab (struct SearchTab *tab)
-{
-  GtkNotebook *notebook;
-  int index;
-  int i;
-
-  if (tab->parent != NULL)
-  {
-    /* not a top-level search (namespace update search), do not close
-       tab here! */
-    GNUNET_free (tab);
-    return;
-  }
-  notebook =
-      GTK_NOTEBOOK (GNUNET_FS_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 (search_tab_head, search_tab_tail, tab);
-  if (tab == uri_tab)
-    uri_tab = NULL;
-  GNUNET_free (tab);
-}
-
-
-/**
- * Free a particular search result and remove the respective
- * entries from the respective tree store.  This function
- * is called when a search is stopped to clean up the state
- * of the tab.
- *
- * @param sr the search result to clean up
- */
-static void
-free_search_result (struct SearchResult *sr)
-{
-  GtkTreePath *tp;
-  GtkTreeModel *tm;
-  GtkTreeIter iter;
-  struct GNUNET_FS_Uri *uri;
-  struct GNUNET_CONTAINER_MetaData *meta;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Freeing a search result SR=%p\n", 
-             sr);
-  if ( (NULL == sr) ||
-       (NULL == sr->rr) ||
-       (NULL == (tm = gtk_tree_row_reference_get_model (sr->rr))) ||
-       (NULL == (tp = gtk_tree_row_reference_get_path (sr->rr))) )
-  {
-    GNUNET_break (0);
-    return;
-  }
-  if (! gtk_tree_model_get_iter (tm, &iter, tp))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (tp);
-    return;
-  }
-  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);
-  (void) gtk_tree_store_remove (GTK_TREE_STORE (tm), &iter);
-  GNUNET_free (sr);
-}
-
-
-/**
- * Selected row has changed in search result tree view, update preview
- * and metadata areas.
- *
- * @param tv the tree view in a search tab where the selection changed
- * @param user_data the 'struct SearchTab' that contains the tree view
- */
-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->query_txt != NULL);
-  image =
-      GTK_IMAGE (GNUNET_FS_GTK_get_main_window_object
-                 ("GNUNET_GTK_main_window_preview_image"));
-  ms = GTK_LIST_STORE (GNUNET_FS_GTK_get_main_window_object
-                       ("GNUNET_GTK_meta_data_list_store"));
-  sel = gtk_tree_view_get_selection (tv);
-  gtk_list_store_clear (ms);
-  if (! gtk_tree_selection_get_selected (sel, &model, &iter))
-  {
-    /* nothing selected, clear preview */
-    gtk_image_clear (image);
-    return;
-  }
-  meta = NULL;
-  pixbuf = NULL;
-  gtk_tree_model_get (model, &iter, 0, &meta, 3, &pixbuf, -1);
-  if (NULL != pixbuf)
-  {
-    gtk_image_set_from_pixbuf (image, pixbuf);
-    g_object_unref (G_OBJECT (pixbuf));
-  }
-  if (NULL != meta)  
-    GNUNET_CONTAINER_meta_data_iterate (meta,
-                                        
&GNUNET_FS_GTK_add_meta_data_to_list_store,
-                                        ms);
-}
-
-
-/**
- * Page switched in main notebook, update thumbnail and
- * metadata views.
- *
- * @param dummy widget emitting the event, unused
- * @param data master Gtk builder, unused
- */
-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_FS_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);
-  for (tab = search_tab_head; NULL != tab; tab = tab->next)
-  {
-    if (tab->frame != w)
-      continue;
-    tv = GTK_TREE_VIEW (gtk_builder_get_object
-                       (tab->builder, "_search_result_frame"));
-    update_meta_data_views (tv, tab);
-    return;
-  }
-  /* active tab is not a search tab (likely the 'publish' tab), 
-     clear meta data and preview widgets */
-  image =
-      GTK_IMAGE (GNUNET_FS_GTK_get_main_window_object
-                 ("GNUNET_GTK_main_window_preview_image"));
-  gtk_image_clear (image);
-  ms = GTK_LIST_STORE (GNUNET_FS_GTK_get_main_window_object
-                       ("GNUNET_GTK_meta_data_list_store"));
-  gtk_list_store_clear (ms);
-}
-
-
-/**
- * User clicked on the 'close' button for a search tab.  Tell FS to stop the 
search.
- *
- * @param button the 'close' button
- * @param user_data the 'struct SearchTab' of the tab to close
- */
-static void
-stop_search (GtkButton *button, gpointer user_data)
-{
-  struct SearchTab *tab = user_data;
-  struct GNUNET_FS_SearchContext *sc;
-
-  sc = tab->sc;
-  if (NULL == sc)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  tab->sc = NULL;
-  GNUNET_FS_search_stop (sc);
-  gtk_widget_hide (GTK_WIDGET (button));
-  gtk_widget_hide (tab->pause_button);
-  gtk_widget_hide (tab->play_button);  
-}
-
-
-/**
- * The user clicked on the 'pause' button for a search tab.  Tell FS to pause 
the search.
- *
- * @param button the 'pause' button
- * @param user_data the 'struct SearchTab' of the tab to pause
- */
-static void
-pause_search (GtkButton *button, gpointer user_data)
-{
-  struct SearchTab *tab = user_data;
-
-  if (NULL == tab->sc)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  GNUNET_FS_search_pause (tab->sc);
-  gtk_widget_show (tab->play_button);
-  gtk_widget_hide (tab->pause_button);
-}
-
-
-/**
- * The user clicked on the 'resume' button for a search tab.  Tell FS to 
resume the search.
- *
- * @param button the 'resume' button
- * @param user_data the 'struct SearchTab' of the tab to resume
- */
-static void
-continue_search (GtkButton * button, gpointer user_data)
-{
-  struct SearchTab *tab = user_data;
-
-  if (NULL == tab->sc)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  GNUNET_FS_search_continue (tab->sc);
-  gtk_widget_show (tab->pause_button);
-  gtk_widget_hide (tab->play_button); 
-}
-
-
-/**
- * User clicked on the 'clean' button of a search tab.
- * Stop completed downloads (or those that failed).  Should
- * iterate over the underlying tree store and stop all
- * completed entries.  Furthermore, if the resulting tree
- * store is empty and has no search associated with it,
- * the tab should be closed.
- *
- * @param button the button pressed by the user
- * @param user_data the 'struct SearchTab' of the respective tab to clean up
- */
-static void
-clear_downloads (GtkButton * button, gpointer user_data)
-{
-  struct SearchTab *tab = user_data;
-  struct SearchResult *sr;
-  GtkTreeModel *tm;
-  GtkTreeIter iter;
-
-  tm = GTK_TREE_MODEL (tab->ts);
-  if (TRUE != gtk_tree_model_get_iter_first (tm, &iter))
-    return;
-  /* FIXME-BUG: this is a tree, what about cleaning up
-     of the children? */
-  do
-  {
-    gtk_tree_model_get (tm, &iter, 9, &sr, -1);
-    if ( (sr->download != NULL) &&
-        (sr->download->is_done == GNUNET_YES) )
-    {
-      /* got a finished download, stop it */
-      GNUNET_FS_download_stop (sr->download->dc, GNUNET_YES);
-    }
-    if ( (NULL == sr->download) &&
-        (NULL == sr->result) )
-    {
-      /* no active download and no associated FS-API search result;
-        so this must be some left-over entry from an opened 
-        directory; clean it up */
-      free_search_result (sr);
-    }
-  }
-  while (TRUE == gtk_tree_model_iter_next (tm, &iter));
-}
-
-
-/**
- * We received a search error message from the FS library.
- * Present it to the user in an appropriate form.
- *
- * @param tab search tab affected by the error
- * @param emsg the error message
- */
-static void
-handle_search_error (struct SearchTab *tab, 
-                    const char *emsg)
-{
-  gtk_label_set_text (tab->label, _("Error!"));
-  gtk_widget_set_tooltip_text (GTK_WIDGET (tab->label), emsg);
-}
-
-
-/**
- * Obtain the string we will use to describe a search result from
- * the respective meta data.
- *
- * @param meta meta data to inspect
- * @return description of the result in utf-8, never NULL
- */
-static char *
-get_description_from_metadata (const struct GNUNET_CONTAINER_MetaData *meta)
-{
-  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_FILENAME,
-                                                     
EXTRACTOR_METATYPE_DESCRIPTION,
-                                                     
EXTRACTOR_METATYPE_SUMMARY,
-                                                     EXTRACTOR_METATYPE_ALBUM,
-                                                     
EXTRACTOR_METATYPE_COMMENT,
-                                                     
EXTRACTOR_METATYPE_SUBJECT,
-                                                     
EXTRACTOR_METATYPE_KEYWORDS,
-                                                     -1);
-  if (desc == NULL)
-    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)
-    return GNUNET_strdup (_("no description supplied"));
-  return utf8_desc;
-}
-
-
-/**
- * Obtain the mime type (or format description) will use to describe a search 
result from
- * the respective meta data.
- *
- * @param meta meta data to inspect
- * @return mime type to use, possibly NULL
- */
-static char *
-get_mimetype_from_metadata (const struct GNUNET_CONTAINER_MetaData *meta)
-{
-  return GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
-                                                       
EXTRACTOR_METATYPE_MIMETYPE,
-                                                       
EXTRACTOR_METATYPE_FORMAT,
-                                                       -1);
-}
-
-
-/**
- * Some additional information about a search result has been
- * received.  Update the view accordingly.
- *
- * @param sr search result that is being updated
- * @param meta updated meta data
- * @param availability_rank updated availability information
- * @param availability_certainty updated availability certainty
- * @param applicability_rank updated applicability information
- */
-static void
-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)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Updating search result SR=%p with %d, %u, %u\n",
-             sr, availability_rank,
-             availability_certainty, applicability_rank);
-  desc = get_description_from_metadata (meta);
-  mime = get_mimetype_from_metadata (meta);
-  pixbuf = GNUNET_FS_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 (NULL != ometa)
-    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_FS_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);
-  }
-}
-
-
-/**
- * Add a search result to the given search tab.  This function is called 
- * not only for 'normal' search results but also for directories that
- * are being opened and if the user manually enters a URI.
- *
- * @param tab search tab to extend, never NULL
- * @param iter set to position where search result is added (OUT only)
- * @param parent_rr reference to parent entry in search tab, NULL for normal
- *                  search results, 
- * @param uri uri to add, can be NULL for top-level entry of a directory 
opened from disk
- *                        (in this case, we don't know the URI and should 
probably not
- *                         bother to calculate it)
- * @param meta metadata of the entry
- * @param result associated FS search result (can be NULL if this result
- *                        was part of a directory)
- * @param applicability_rank how relevant is the result
- * @return struct representing the search result (also stored in the tree
- *                model at 'iter')
- */
-struct SearchResult *
-GNUNET_GTK_add_search_result (struct SearchTab *tab, 
-                             GtkTreeIter *iter,
-                              GtkTreeRowReference *parent_rr,
-                              const struct GNUNET_FS_Uri *uri,
-                              const struct GNUNET_CONTAINER_MetaData *meta,
-                              struct GNUNET_FS_SearchResult *result,
-                              uint32_t applicability_rank)
-{
-  struct SearchResult *sr;
-  GtkTreePath *tp;
-  const char *status_colour;
-  char *desc;
-  char *mime;
-  char *uris;
-  GdkPixbuf *pixbuf;
-  GtkTreeIter *pitr;
-  GtkTreeIter pmem;
-  GtkTreePath *path;
-  GtkTreeModel *tm;
-  GtkTreeStore *ts;
-  uint64_t fsize;
-
-  if (NULL == uri)
-  {
-    /* opened directory file */
-    fsize = 0;
-    status_colour = "gray";
-    mime = NULL; /* FIXME-FEATURE-MAYBE: should we set mime to directory? */
-    uris = GNUNET_strdup (_("no URI"));
-  }
-  else
-  {
-    if ( (GNUNET_FS_uri_test_loc (uri)) ||
-        (GNUNET_FS_uri_test_chk (uri)) )
-    {
-      fsize = GNUNET_FS_uri_chk_get_file_size (uri);
-      mime = get_mimetype_from_metadata (meta);
-      status_colour = "white";
-    }
-    else
-    {
-      /* FIXME-FEATURE-MAYBE: create mime type for namespaces? */
-      /* FIXME-BUG-MAYBE: can we encounter ksk URIs here too? */
-      fsize = 0;
-      mime = GNUNET_strdup ("GNUnet namespace"); 
-      status_colour = "lightgreen";
-    }
-    uris = GNUNET_FS_uri_to_string (uri);
-  }
-  desc = get_description_from_metadata (meta);
-  pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta);
-
-  sr = GNUNET_malloc (sizeof (struct SearchResult));
-  sr->result = result;
-  sr->tab = tab;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Allocated a search result SR=%p\n",
-             sr);
-  if (parent_rr != NULL)
-  {
-    /* get piter from parent */
-    path = gtk_tree_row_reference_get_path (parent_rr);
-    tm = gtk_tree_row_reference_get_model (parent_rr);
-    if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (tm), &pmem, path))
-    {
-      GNUNET_break (0);
-      gtk_tree_path_free (path);
-      /* desperate measure: make top-level entry */
-      pitr = NULL;
-    }
-    else
-    {
-      pitr = &pmem;
-    }
-    ts = GTK_TREE_STORE (tm);
-  }
-  else
-  {
-    /* top-level result */
-    pitr = NULL;
-    ts = tab->ts;
-  }
-  gtk_tree_store_insert_with_values (ts, iter, pitr, G_MAXINT, 
-                                    0, GNUNET_CONTAINER_meta_data_duplicate 
(meta), 
-                                    1, (uri == NULL) ? NULL : 
GNUNET_FS_uri_dup (uri), 
-                                    2, fsize, 
-                                    3, pixbuf /* preview */ ,
-                                     4, 0 /* percent progress */ ,
-                                     5, 0 /* percent availability */ ,
-                                     6, desc /* filename/description */ ,
-                                     7, uris, 
-                                    8, status_colour, 
-                                    9, sr, 
-                                    10, mime,
-                                     11, applicability_rank, 
-                                    12, 0 /* avail-cert */ ,
-                                     13, 0, /* avail-rank */
-                                     14, (guint64) 0, /* completed */
-                                     15, NULL, /* downloaded_filename */
-                                     16, -1, /* downloaded_anonymity */
-                                     -1);
-  if (pixbuf != NULL)
-    g_object_unref (pixbuf);
-  GNUNET_free (uris);
-  GNUNET_free (desc);
-  GNUNET_free_non_null (mime);
-
-  /* remember in 'sr' where we added the result */
-  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);
-
-  /* move up to the outermost tab, in case this is an 'inner'
-     search (namespace update case) */
-  while (tab->parent != NULL)
-    tab = tab->parent->tab;
-  tab->num_results++;
-  
-  return sr;
-}
-
-
-/**
- * We have received a search result from the FS API.  Add it to the
- * respective search tab.  The search result can be an 'inner'
- * search result (updated result for a namespace search) or a
- * top-level search result.  Update the tree view and the label
- * of the search tab accordingly.
- *
- * @param tab the search tab where the new result should be added
- * @param parent parent search result (if this is a namespace update result), 
or NULL
- * @param uri URI of the search result
- * @param meta meta data for the result
- * @param result FS API handle to the result
- * @param applicability_rank how applicable is the result to the query
- * @return struct representing the search result (also stored in the tree
- *                model at 'iter')
- */
-static struct SearchResult *
-process_search_result (struct SearchTab *tab, 
-                      struct SearchResult *parent,
-                       const struct GNUNET_FS_Uri *uri,
-                       const struct GNUNET_CONTAINER_MetaData *meta,
-                       struct GNUNET_FS_SearchResult *result,
-                       uint32_t applicability_rank)
-{
-  struct SearchResult *sr;
-  GtkTreeIter iter;
-
-  sr = GNUNET_GTK_add_search_result (tab, &iter,
-                                     (parent != NULL) ? parent->rr : NULL,
-                                    uri,
-                                     meta, result, applicability_rank);
-  update_search_label (tab);
-  return sr;
-}
-
-
-/**
- * Setup a new search tab.
- *
- * @param sc context with FS for the search, NULL for none (open-URI/orphan 
tab)
- * @param query the query, NULL for none (open-URI/orphan tab)
- * @return search tab handle
- */
-static struct SearchTab *
-setup_search_tab (struct GNUNET_FS_SearchContext *sc,
-                 const struct GNUNET_FS_Uri *query)
-{
-  struct SearchTab *tab;
-  GtkTreeView *tv;
-  GtkNotebook *notebook;
-  GtkWindow *sf;
-  gint pages;
-
-  tab = GNUNET_malloc (sizeof (struct SearchTab));
-  GNUNET_CONTAINER_DLL_insert (search_tab_head, search_tab_tail, tab);
-  tab->sc = sc;
-  if (query == NULL)
-  {
-    /* no real query, tab is for non-queries, use special label */
-    tab->query_txt = GNUNET_strdup ("*");
-  }
-  else
-  {
-    /* FS_uri functions should produce UTF-8, so let them be */
-    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 ("gnunet_fs_gtk_search_tab.glade",
-                                            tab);
-  tab->ts =
-      GTK_TREE_STORE (gtk_builder_get_object
-                      (tab->builder,
-                       "GNUNET_GTK_file_sharing_result_tree_store"));
-  /* load frame */
-  sf = GTK_WINDOW (gtk_builder_get_object
-                   (tab->builder, "_search_result_frame_window"));
-  tab->frame = gtk_bin_get_child (GTK_BIN (sf));
-  g_object_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));
-  g_object_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"));
-
-  /* FIXME-UNCLEAN: connect these signals using glade!!! */
-  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->clear_button =
-      GTK_WIDGET (gtk_builder_get_object
-                  (tab->builder, "_search_result_label_clear_button"));
-  g_signal_connect (G_OBJECT (tab->clear_button), "clicked",
-                    G_CALLBACK (clear_downloads), 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; FIXME-UNCLEAN: again, connect these with glade...  */
-  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_row_activated), 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);
-  g_signal_connect (G_OBJECT (tv), "popup-menu",
-                    G_CALLBACK (search_list_on_popup), tab);
-
-
-  /* make visible */
-  notebook =
-      GTK_NOTEBOOK (GNUNET_FS_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;
-}
-
-
-/**
- * Setup an "inner" search, that is a subtree representing namespace
- * 'update' results.  We use a 'struct SearchTab' to represent this
- * sub-search.  In the GUI, the presentation is similar to search
- * results in a directory, except that this is for a namespace search
- * result that gave pointers to an alternative keyword to use and this
- * is the set of the results found for this alternative keyword.
- *
- * All of the 'widget' elements of the returned 'search tab' reference
- * the parent search.  The whole construction is essentially a trick
- * to allow us to store the FS-API's 'SearchContext' somewhere and to
- * find it when we get this kind of 'inner' search results (so that we
- * can then place them in the tree view in the right spot).
- *
- * FIXME-BUG-MAYBE: don't we need a bit more information then? Like exactly 
where
- * this 'right spot' is?  Not sure how just having 'sc' helps there,
- * as it is not a search result (!) to hang this up on!  This might
- * essentially boil down to an issue with the FS API, not sure...
- *
- * @param sc context with FS for the search
- * @param parent parent search tab
- * @return struct representing the search result (also stored in the tree
- *                model at 'iter')
- */
-static struct SearchTab *
-setup_inner_search (struct GNUNET_FS_SearchContext *sc,
-                    struct SearchResult *parent)
-{
-  struct SearchTab *ret;
-
-  ret = GNUNET_malloc (sizeof (struct SearchTab));
-  ret->parent = parent;
-  ret->sc = sc;
-  ret->query_txt = parent->tab->query_txt;
-  ret->builder = parent->tab->builder;
-  ret->frame = parent->tab->frame;
-  ret->tab_label = parent->tab->tab_label;
-  ret->close_button = parent->tab->close_button;
-  ret->clear_button = parent->tab->clear_button;
-  ret->play_button = parent->tab->play_button;
-  ret->label = parent->tab->label;
-
-  return ret;
-}
-
-
-/**
- * Setup a new top-level entry in the URI/orphan tab.  If necessary, create
- * the URI tab first.
- *
- * @param iter set to the new entry (OUT only)
- * @param srp set to search result (can be NULL)
- * @param meta metadata for the new entry
- * @param uri URI for the new entry
- * @return the 'uri_tab' the result was added to
- */
-struct SearchTab *
-GNUNET_GTK_add_to_uri_tab (GtkTreeIter *iter, struct SearchResult **srp,
-                           const struct GNUNET_CONTAINER_MetaData *meta,
-                           const struct GNUNET_FS_Uri *uri)
-{
-  struct SearchResult *sr;
-  GtkNotebook *notebook;
-  gint page;
-
-  if (NULL == uri_tab)
-  {
-    uri_tab = setup_search_tab (NULL, NULL);
-    gtk_widget_set_visible (uri_tab->close_button, FALSE);
-    gtk_widget_set_visible (uri_tab->pause_button, FALSE);
-  }
-  /* make 'uri_tab' the current page */
-  notebook =
-    GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
-                 ("GNUNET_GTK_main_window_notebook"));
-  for (page = 0; page < gtk_notebook_get_n_pages (notebook); page++)
-    if (uri_tab->frame == gtk_notebook_get_nth_page (notebook, page))
-    {
-      gtk_notebook_set_current_page (notebook, page);
-      break;
-    }
-  sr = GNUNET_GTK_add_search_result (uri_tab, iter, NULL, uri, meta, NULL, 0);
-  if (NULL != srp)
-    *srp = sr;
-  return uri_tab;
-}
-
-
-
-/* ***************** Download event handling ****************** */
-
-
-
-/**
- * Change the (background) color of the given download entry.
- *
- * @param de entry to change 
- * @param color name of the color to use
- */
-static void
-change_download_color (struct DownloadEntry *de, 
-                       const char *color)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-             "Changing download DE=%p color to %s\n", 
-             de, color);
-  path = gtk_tree_row_reference_get_path (de->rr);
-  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts), &iter, path))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (path);
-    return;
-  }
-  gtk_tree_path_free (path);
-  gtk_tree_store_set (de->ts, &iter, 8, color, -1);
-}
-
-
-/**
- * A download operation was stopped.  Remove all state associated with
- * it and reset the search result's background color to 'white'.
- *
- * @param de the download that was stopped
- */
-static void
-stop_download (struct DownloadEntry *de)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-  GtkTreeModel *tm;
-  struct SearchResult *search_result;
-
-  tm = gtk_tree_row_reference_get_model (de->rr);
-  path = gtk_tree_row_reference_get_path (de->rr);
-  if (! gtk_tree_model_get_iter (tm, &iter, path))
-  {
-    gtk_tree_path_free (path);
-    GNUNET_break (0);
-    return;
-  }
-  gtk_tree_path_free (path);
-  gtk_tree_model_get (tm, &iter, 9, &search_result, -1);
-  GNUNET_assert (search_result->download == de); 
-  search_result->download = NULL;
-  change_download_color (de, "white");
-  gtk_tree_row_reference_free (de->rr);
-  GNUNET_FS_uri_destroy (de->uri);
-  GNUNET_CONTAINER_meta_data_destroy (de->meta);
-  GNUNET_free (de);
-}
-
-
-/**
- * Closure for 'add_directory_entry'.
- */
-struct AddDirectoryEntryContext
-{
-
-  /**
-   * Search tab where we need to expand the result list.
-   */
-  struct SearchTab *tab;
-
-  /**
-   * Row reference of parent (the directory).
-   */
-  GtkTreeRowReference *prr;
-
-  /**
-   * Do we need to check if the given entry already exists to
-   * avoid adding it twice?  Set to YES if 'add_directory_entry'
-   * is called upon directory completion (so we might see all
-   * entries again) and to NO if this is the initial download
-   * and we're calling during a 'PROGRESS' event.
-   */
-  int check_duplicates;
-
-};
-
-
-/**
- * Function used to process entries in a directory.  Whenever we
- * download a directory, this function is called on the entries in the
- * directory to add them to the search tab.  Note that the function
- * maybe called twice for the same entry, once during incremental
- * processing and later once more when we have the complete directory.
- *
- * For the second round, the 'check_duplicates' flag will be set in
- * the closure.  If called on an entry that already exists, the
- * function should simply do nothing.
- *
- * @param cls closure, our 'struct AddDirectoryEntryContext*'
- * @param filename name of the file in the directory
- * @param uri URI of the file, NULL for the directory itself
- * @param metadata metadata for the file; metadata for
- *        the directory if everything else is NULL/zero
- * @param length length of the available data for the file
- *           (of type size_t since data must certainly fit
- *            into memory; if files are larger than size_t
- *            permits, then they will certainly not be
- *            embedded with the directory itself).
- * @param data data available for the file (length bytes)
- */
-static void
-add_directory_entry (void *cls, const char *filename,
-                     const struct GNUNET_FS_Uri *uri,
-                     const struct GNUNET_CONTAINER_MetaData *meta,
-                     size_t length, const void *data)
-{
-  struct AddDirectoryEntryContext *ade = cls;
-  GtkTreeIter iter;
-  GtkTreeIter piter;
-  GtkTreePath *path;
-  GtkTreeModel *tm;
-  struct GNUNET_FS_Uri *xuri;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-             "Adding directory entry `%s'\n", 
-             filename);
-
-  if (NULL == uri)
-  {
-    /* directory meta data itself */
-    /* FIXME-FEATURE-MAYBE: consider merging it with the meta data from
-       the original search result... */
-    return;
-  }
-  if (ade->check_duplicates == GNUNET_YES)
-  {
-    tm = gtk_tree_row_reference_get_model (ade->prr);
-    path = gtk_tree_row_reference_get_path (ade->prr);
-    if (! gtk_tree_model_get_iter (tm, &piter, path)) 
-    {
-      GNUNET_break (0);
-      gtk_tree_path_free (path);
-      return;
-    }
-    gtk_tree_path_free (path);
-    if (TRUE == gtk_tree_model_iter_children (tm, &iter, &piter))
-    {
-      do
-      {
-        gtk_tree_model_get (tm, &iter, 1, &xuri, -1);
-        if (GNUNET_YES == GNUNET_FS_uri_test_equal (xuri, uri))
-          return;               /* already present */
-      }
-      while (TRUE == gtk_tree_model_iter_next (tm, &iter));
-    }
-  }
-  GNUNET_GTK_add_search_result (ade->tab, &iter, ade->prr, uri, meta, NULL,
-                                0);
-}
-
-
-/**
- * We got an event that some download is progressing.  Update the tree
- * model accordingly.  If the download is a directory, try to display
- * the contents.
- *
- * @param de download entry that is progressing
- * @param size overall size of the download
- * @param completed number of bytes we have completed
- * @param block_data current block we've downloaded
- * @param offset offset of block_data in the overall file
- * @param block_size number of bytes in block_data
- * @param depth depth of the block in the ECRS tree
- */
-static void
-mark_download_progress (struct DownloadEntry *de, uint64_t size,
-                        uint64_t completed, const void *block_data,
-                        uint64_t offset, uint64_t block_size,
-                        unsigned int depth)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Marking download progress for DE=%p, %llu/%llu, address@hidden 
depth=%u\n",
-             de, completed, size, block_size, offset, depth);
-
-  path = gtk_tree_row_reference_get_path (de->rr);
-  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts), &iter, path))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (path);
-    return;
-  }
-  gtk_tree_path_free (path);
-  /* FIXME-FEATURE: update availability-score here as well! */
-  gtk_tree_store_set (de->ts, &iter, 
-                     4, (guint) ((size >
-                                  0) ? (100 * completed /
-                                        size) : 100) /* progress */ ,
-                      14, completed, 
-                     -1);
-  if ( (depth == 0) &&
-       (block_size > 0) &&
-       (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (de->meta)) )
-  {
-    /* got a data block of a directory, list its contents */
-    struct AddDirectoryEntryContext ade;
-
-    ade.tab = de->tab;
-    ade.prr = de->rr;
-    ade.check_duplicates = GNUNET_NO;
-    if (GNUNET_SYSERR ==
-        GNUNET_FS_directory_list_contents ((size_t) block_size, block_data,
-                                           offset, &add_directory_entry, &ade))
-    {
-      /* Mime type was wrong, this is not a directory, update model! */
-      GNUNET_break (GNUNET_OK ==
-                   GNUNET_CONTAINER_meta_data_delete (de->meta,
-                                                      
EXTRACTOR_METATYPE_MIMETYPE, NULL, 0));
-      gtk_tree_store_set (de->ts, &iter, 
-                         10, "" /* unknown mime type */, -1);
-    }
-  }
-}
-
-
-/**
- * FS-API encountered an error downloading a file.  Update the
- * view accordingly.
- *
- * @param de download that had an error
- * @param emsg error message to display
- */
-static void
-mark_download_error (struct DownloadEntry *de,
-                    const char *emsg)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  change_download_color (de, "red");
-  de->is_done = GNUNET_YES;
-  path = gtk_tree_row_reference_get_path (de->rr);
-  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (de->tab->ts), &iter, path))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (path);
-    return;
-  }
-  gtk_tree_path_free (path);
-  gtk_tree_store_set (de->tab->ts, &iter, 4, 0, 7, emsg, -1);
-}
-
-
-/**
- * FS-API notified us that we're done with a download.  Update the
- * view accordingly. If the download is a directory, try to display
- * the contents.
- *
- * @param de download that has finished
- * @param size overall size of the file
- * @param filename name of the downloaded file on disk (possibly a temporary 
file)
- */
-static void
-mark_download_completed (struct DownloadEntry *de, uint64_t size,
-                         const char *filename)
-{
-  struct AddDirectoryEntryContext ade;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Marking download completed for DE=%p, %llu-byte `%s'\n",
-             de, size, filename);
-
-  de->is_done = GNUNET_YES;
-  mark_download_progress (de, size, size, NULL, 0, 0, 0);
-  if ( (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (de->meta)) &&
-       (filename != NULL) )
-  {
-    /* download was for a directory (and we have a temp file for scanning);
-       add contents of the directory to the view */
-    ade.tab = de->tab;
-    ade.prr = de->rr;
-    ade.check_duplicates = GNUNET_YES;
-    GNUNET_FS_GTK_mmap_and_scan (filename, &add_directory_entry, &ade);
-  }
-  change_download_color (de, "green");
-}
-
-
-/**
- * Copy all of the children of 'src_iter' from the 'src_model' to
- * become children of 'dst_iter' in the 'dst_model'.  The models are
- * both 'GNUNET_GTK_file_sharing_result_tree_store' models.
- *
- * Note that we also need to update the 'struct SearchResult'
- * and (if it exists) the respective 'struct DownloadEntry'
- * to refer to the new model.
- *
- * @param src_model source model
- * @param src_iter parent of the nodes to move 
- * @param dst_model destination model
- * @param dst_iter new parent of the entries we are moving
- */
-static void
-copy_children (GtkTreeModel * src_model, GtkTreeIter * src_iter,
-               GtkTreeModel * dst_model, GtkTreeIter * dst_iter)
-{
-  GtkTreeIter src_child;
-  GtkTreeIter dst_child;
-  GtkTreePath *path;
-  struct GNUNET_CONTAINER_MetaData *meta;
-  struct GNUNET_FS_Uri *uri;
-  guint64 filesize, completed;
-  GdkPixbuf *preview;
-  guint percent_progress;
-  guint percent_availability;
-  gchar *filename;
-  gchar *uri_as_string;
-  gchar *status_colour;
-  struct SearchResult *search_result;
-  gchar *mimetype;
-  guint applicability_rank;
-  guint availability_certainty;
-  gint availability_rank;
-  gchar *downloaded_filename;
-  gint downloaded_anonymity;
-
-  if (! gtk_tree_model_iter_children (src_model, &src_child, src_iter))
-    return;
-  do
-  {
-    gtk_tree_model_get (src_model, &src_child, 0, &meta, 1, &uri, 2,
-                       &filesize, 3, &preview, 4, &percent_progress, 5,
-                       &percent_availability, 6, &filename, 7,
-                       &uri_as_string, 8, &status_colour, 9, &search_result,
-                       10, &mimetype, 11, &applicability_rank, 12,
-                       &availability_certainty, 13, &availability_rank, 14,
-                       &completed, 15, &downloaded_filename, 16,
-                       &downloaded_anonymity, -1);
-    gtk_tree_store_insert_with_values (GTK_TREE_STORE (dst_model), &dst_child,
-                                      dst_iter, G_MAXINT, 0, meta, 1, uri, 2,
-                                      filesize, 3, preview, 4,
-                                      percent_progress, 5,
-                                      percent_availability, 6, filename, 7,
-                                      uri_as_string, 8, status_colour, 9,
-                                      search_result, 10, mimetype, 11,
-                                      applicability_rank, 12,
-                                      availability_certainty, 13,
-                                      availability_rank, 14, completed, 15,
-                                      downloaded_filename, 16,
-                                      downloaded_anonymity, -1);
-    g_free (filename);
-    g_free (downloaded_filename);
-    g_free (uri_as_string);
-    g_free (status_colour);
-    g_free (mimetype);
-    if (preview != NULL)
-      g_object_unref (preview);
-    gtk_tree_row_reference_free (search_result->rr);
-    path = gtk_tree_model_get_path (dst_model, &dst_child);
-    search_result->rr = gtk_tree_row_reference_new (dst_model, path);
-    search_result->result = NULL;
-    gtk_tree_path_free (path);
-    if (search_result->download != NULL)
-    {
-      search_result->download->ts = GTK_TREE_STORE (dst_model);
-      gtk_tree_row_reference_free (search_result->download->rr);
-      search_result->download->rr =
-       gtk_tree_row_reference_copy (search_result->rr);
-    }
-    copy_children (src_model, &src_child, dst_model, &dst_child);
-  }
-  while (TRUE == gtk_tree_model_iter_next (src_model, &src_child));
-}
-
-
-/**
- * Delete the entire given subtree from the model.  Does not free
- * anything inside of the respective model's fields (since they have
- * been moved).
- *
- * @param model model that contains the subtree to remove
- * @param iter root of the subtree to remove
- */
-static void
-delete_stale_subtree (GtkTreeModel * model, GtkTreeIter * iter)
-{
-  GtkTreeIter child;
-
-  while (TRUE == gtk_tree_model_iter_children (model, &child, iter))
-    delete_stale_subtree (model, &child);
-  gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
-}
-
-
-/**
- * Handle the case where an active download lost its
- * search parent by moving it to the URI tab.
- *
- * @param de download where the parent (i.e. search) was lost
- */
-static void
-download_lost_parent (struct DownloadEntry *de)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-  struct SearchTab *tab;
-  GtkTreeRowReference *rr_old;
-  GtkTreeModel *tm_old;
-  GtkTreeIter iter_old;
-  GtkTreeIter child;
-  GtkTreeModel *model;
-
-  /* first, move the root of the respective 'de'-tree */
-  rr_old = de->rr;
-  tab = GNUNET_GTK_add_to_uri_tab (&iter, &de->sr, de->meta, de->uri);
-  de->sr->download = de;
-  de->ts = tab->ts;
-  model = GTK_TREE_MODEL (de->ts);
-  path = gtk_tree_model_get_path (model, &iter);
-  de->rr = gtk_tree_row_reference_new (model, path);
-  gtk_tree_path_free (path);
-  tm_old = gtk_tree_row_reference_get_model (rr_old);
-  path = gtk_tree_row_reference_get_path (rr_old);
-  gtk_tree_row_reference_free (rr_old);
-  if (! gtk_tree_model_get_iter (tm_old, &iter_old, path))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (path);
-    return;
-  }
-  gtk_tree_path_free (path);
-
-  /* finally, move all children over as well */
-  copy_children (tm_old, &iter_old, model, &iter);
-  while (gtk_tree_model_iter_children (model, &child, &iter))
-    delete_stale_subtree (model, &child);
-}
-
-
-/**
- * Setup a new download entry.
- *
- * @param de existing download entry for the download, or NULL (in which case 
we create a fresh one)
- * @param pde parent download entry, or NULL
- * @param sr search result, or NULL
- * @param dc download context (for stopping)
- * @param uri the URI, must not be NULL
- * @param filename filename on disk
- * @param meta metadata
- * @param size total size
- * @param completed current progress
- * @return download entry struct for the download (equal to 'de' if 'de' was 
not NULL)
- */
-static struct DownloadEntry *
-setup_download (struct DownloadEntry *de, struct DownloadEntry *pde,
-                struct SearchResult *sr, struct GNUNET_FS_DownloadContext *dc,
-                const struct GNUNET_FS_Uri *uri, const char *filename,
-                const struct GNUNET_CONTAINER_MetaData *meta, uint64_t size,
-                uint64_t completed)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-  struct SearchResult *srp;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Setting up download, initially DE=%p, PDE=%p for %p & %p into 
%llu/%llu `%s'\n",
-             de, pde, sr, dc, completed, size, filename);
-  GNUNET_assert (NULL != uri);
-  srp = NULL;
-  if (NULL == de)
-  {
-    /* no existing download entry to build on, create a fresh one */
-    de = GNUNET_malloc (sizeof (struct DownloadEntry));
-    de->uri = GNUNET_FS_uri_dup (uri);
-  }
-  else
-  {
-    GNUNET_assert (GNUNET_YES == GNUNET_FS_uri_test_equal (de->uri, uri));
-  }
-  de->dc = dc;
-  de->sr = sr;
-  de->pde = pde;
-  if ( (meta != NULL) && (de->meta == NULL) )
-    de->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
-  if (NULL != sr)
-  {
-    /* got a search result; display the download in the same location as the 
search result */
-    GNUNET_assert (sr->download == NULL);
-    sr->download = de;
-    de->rr = gtk_tree_row_reference_copy (sr->rr);
-    de->ts = sr->tab->ts;
-    de->tab = sr->tab;
-    srp = sr;
-  }
-  if (NULL == de->rr)
-  {
-    /* Stand-alone download with no 'row'/search result affiliated
-       with the download so far; create a fresh entry for this
-       download in the URI tab */
-    de->tab = GNUNET_GTK_add_to_uri_tab (&iter, &srp, meta, uri);
-    de->ts = de->tab->ts;
-    path = gtk_tree_model_get_path (GTK_TREE_MODEL (de->ts), &iter);
-    de->rr = gtk_tree_row_reference_new (GTK_TREE_MODEL (de->ts), path);
-    gtk_tree_path_free (path);
-    srp->download = de;
-  }
-  path = gtk_tree_row_reference_get_path (de->rr);
-  if (! 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 */ ,
-                      6, filename /* filename/description */ ,
-                      8, "blue" /* status colour: pending */ ,
-                     9, srp,
-                     14, completed,
-                      -1);
-  return de;
-}
-
-
-
-/* ***************** Publish event handling ****************** */
-
-
-
-/**
- * Change the (background) color of the given publish entry.
- *
- * @param pe entry to change 
- * @param color name of the color to use
- */
-static void
-change_publish_color (struct PublishEntry *pe,
-                     const char *color)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-             "Changing publish PE=%p color to %s\n", 
-             pe, color);
-  path = gtk_tree_row_reference_get_path (pe->rr);
-  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (path);
-    return;
-  }
-  gtk_tree_path_free (path);
-  gtk_tree_store_set (pe->tab->ts, &iter, 2, color, -1);
-}
-
-
-/**
- * We got an event that some publishing operation is progressing.
- * Update the tree model accordingly.
- *
- * @param pe publish entry that is progressing
- * @param size overall size of the file or directory
- * @param completed number of bytes we have completed
- */
-static void
-mark_publish_progress (struct PublishEntry *pe, uint64_t size,
-                       uint64_t completed)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  path = gtk_tree_row_reference_get_path (pe->rr);
-  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (path);
-    return;
-  }
-  gtk_tree_path_free (path);
-  gtk_tree_store_set (pe->tab->ts, &iter, 3,
-                      (guint) ((size >
-                                0) ? (100 * completed /
-                                      size) : 100) /* progress */ ,
-                      -1);
-}
-
-
-/**
- * FS-API notified us that we're done with some publish operation.
- * Update the view accordingly.
- *
- * @param pe publish operation that has finished
- * @param uri resulting URI
- */
-static void
-handle_publish_completed (struct PublishEntry *pe,
-                          const struct GNUNET_FS_Uri *uri)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-  char *uris;
-
-  path = gtk_tree_row_reference_get_path (pe->rr);
-  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (path);
-    return;
-  }
-  gtk_tree_path_free (path);
-  pe->uri = GNUNET_FS_uri_dup (uri);
-  uris = GNUNET_FS_uri_to_string (uri);
-  gtk_tree_store_set (pe->tab->ts, &iter, 
-                     5, uris,
-                      -1);
-  GNUNET_free (uris);
-  change_publish_color (pe, "green");
-}
-
-
-/**
- * We received a publish error message from the FS library.
- * Present it to the user in an appropriate form.
- *
- * @param pe publishing operation affected by the error 
- * @param emsg the error message
- */
-static void
-handle_publish_error (struct PublishEntry *pe,
-                     const char *emsg)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  path = gtk_tree_row_reference_get_path (pe->rr);
-  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (path);
-    return;
-  }
-  gtk_tree_path_free (path);
-  gtk_tree_store_set (pe->tab->ts, &iter, 
-                     5, emsg,
-                      -1);
-  change_publish_color (pe, "red");
-}
-
-
-/**
- * A publishing operation was stopped (in FS API).  Free an entry in
- * the publish tab and its associated state.
- *
- * @param pe publishing operation that was stopped
- */
-static void
-handle_publish_stop (struct PublishEntry *pe)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
-
-  path = gtk_tree_row_reference_get_path (pe->rr);
-  /* This is a child of a directory, and we've had that directory
-     free'd already  */
-  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  (void) gtk_tree_store_remove (pe->tab->ts, &iter);
-  gtk_tree_path_free (path);
-  gtk_tree_row_reference_free (pe->rr);
-  if (pe->uri != NULL)
-  {
-    GNUNET_FS_uri_destroy (pe->uri);
-    pe->uri = NULL;
-  }
-  GNUNET_free (pe);
-}
-
-
-/**
- * The user clicked on the "close" button of the publishing tab.
- * Tell FS to stop all active publish operations.  Then close the tab.
- *
- * @param button the stop button
- * @param user_data the 'struct PublishTab' that is being closed
- */
-static void
-stop_publishing (GtkButton * button, gpointer user_data)
-{
-  struct PublishTab *tab = user_data;
-  struct PublishEntry *ent;
-  GtkTreeIter iter;
-  GtkTreeModel *tm;
-  GtkNotebook *notebook;
-  int index;
-  int i;
-
-  GNUNET_assert (tab == publish_tab);
-  /* stop all active operations */
-  tm = GTK_TREE_MODEL (publish_tab->ts);
-  if (gtk_tree_model_iter_children (tm, &iter, NULL))
-  {
-    do
-    {
-      gtk_tree_model_get (tm, &iter, 4, &ent, -1);
-      GNUNET_FS_publish_stop (ent->pc);
-      ent->pc = NULL;
-    }
-    while (TRUE == gtk_tree_model_iter_next (tm, &iter));
-  }
-
-  /* remove tab from notebook */
-  notebook =
-      GTK_NOTEBOOK (GNUNET_FS_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 (publish_tab->frame == gtk_notebook_get_nth_page (notebook, i))
-      index = i;
-  gtk_notebook_remove_page (notebook, index);
-
-  /* fully destroy tab */
-  g_object_unref (publish_tab->builder);
-  GNUNET_free (publish_tab);
-  publish_tab = NULL;
-}
-
-
-/**
- * The user started a publishing operation.  Add it to the publishing
- * tab.  If needed, create the publishing tab.
- *
- * @param pc the FS-API's publishing context for the operation
- * @param fn the name of the file (or directory) that is being published
- * @param fsize size of the file
- * @param parent parent of this publishing operation (for recursive 
operations), NULL for top-level operations
- * @return the publishing entry that will represent this operation
- */
-static struct PublishEntry *
-setup_publish (struct GNUNET_FS_PublishContext *pc, const char *fn,
-               uint64_t fsize, struct PublishEntry *parent)
-{
-  struct PublishEntry *ent;
-  GtkTreeIter *pitrptr;
-  GtkTreeIter iter;
-  GtkTreeIter piter;
-  GtkTreePath *path;
-  GtkWindow *df;
-  GtkWidget *tab_label;
-  GtkWidget *close_button;
-  GtkNotebook *notebook;
-  char *size_fancy;
-  
-  if (NULL == publish_tab)
-  {
-    /* create new tab */
-    publish_tab = GNUNET_malloc (sizeof (struct PublishTab));
-    publish_tab->builder =
-      GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_publish_tab.glade",
-                                 publish_tab);
-    df = GTK_WINDOW (gtk_builder_get_object
-                    (publish_tab->builder, "_publish_frame_window"));
-    publish_tab->frame = gtk_bin_get_child (GTK_BIN (df));
-    g_object_ref (publish_tab->frame);
-    gtk_container_remove (GTK_CONTAINER (df), publish_tab->frame);
-    gtk_widget_destroy (GTK_WIDGET (df));
-    
-    /* load tab_label */
-    df = GTK_WINDOW (gtk_builder_get_object
-                    (publish_tab->builder, "_publish_label_window"));
-    tab_label = gtk_bin_get_child (GTK_BIN (df));
-    g_object_ref (tab_label);
-    gtk_container_remove (GTK_CONTAINER (df), tab_label);
-    gtk_widget_destroy (GTK_WIDGET (df));
-    
-    /* FIXME-UNCLEAN: connect these signals using GLADE!!! */
-    /* get refs to widgets */
-    close_button =
-      GTK_WIDGET (gtk_builder_get_object
-                 (publish_tab->builder, "_publish_label_close_button"));
-    g_signal_connect (G_OBJECT (close_button), "clicked",
-                     G_CALLBACK (stop_publishing), publish_tab);
-    /* make visible */
-    notebook =
-      GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
-                   ("GNUNET_GTK_main_window_notebook"));
-    gtk_notebook_insert_page (notebook, publish_tab->frame, tab_label, 0);
-    gtk_widget_show (GTK_WIDGET (notebook));
-    gtk_notebook_set_current_page (notebook, 0);
-    publish_tab->ts =
-      GTK_TREE_STORE (gtk_builder_get_object
-                     (publish_tab->builder, "_publish_frame_tree_store"));
-  }
-
-  /* decide where to insert in the tab */
-  if (NULL == parent)
-  {
-    pitrptr = NULL;
-  }
-  else
-  {
-    /* create new iter from parent */
-    path = gtk_tree_row_reference_get_path (parent->rr);
-    if (TRUE !=
-        gtk_tree_model_get_iter (GTK_TREE_MODEL (publish_tab->ts), &piter,
-                                 path))
-    {
-      GNUNET_break (0);
-      return NULL;
-    }
-    pitrptr = &piter;
-  }
-  
-  /* create entry and perform insertion */
-  ent = GNUNET_malloc (sizeof (struct PublishEntry));
-  ent->is_top = (parent == NULL) ? GNUNET_YES : GNUNET_NO;
-  ent->tab = publish_tab;
-  ent->pc = pc;
-  size_fancy = GNUNET_STRINGS_byte_size_fancy (fsize);
-  gtk_tree_store_insert_with_values (publish_tab->ts, &iter, pitrptr, G_MAXINT,
-                                     0, fn, 1, size_fancy, 2, "white", 3,
-                                     (guint) 0 /* progress */ ,
-                                     4, ent, -1);
-  GNUNET_free (size_fancy);
-  path = gtk_tree_model_get_path (GTK_TREE_MODEL (publish_tab->ts), &iter);
-  ent->rr = gtk_tree_row_reference_new (GTK_TREE_MODEL (publish_tab->ts), 
path);
-  gtk_tree_path_free (path);
-  return ent;
-}
-
-
-
-/* ***************** Master event handler ****************** */
-
-
-
-/**
- * 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)
-{
-  void *ret;
-
-  switch (info->status)
-  {
-  case GNUNET_FS_STATUS_PUBLISH_START:
-    return setup_publish (info->value.publish.pc, info->value.publish.filename,
-                          info->value.publish.size, info->value.publish.pctx);
-  case GNUNET_FS_STATUS_PUBLISH_RESUME:
-    ret =
-        setup_publish (info->value.publish.pc, info->value.publish.filename,
-                       info->value.publish.size, info->value.publish.pctx);
-    if (ret == NULL)
-      return ret;
-    if (info->value.publish.specifics.resume.message != NULL)
-    {
-      handle_publish_error (ret,
-                           info->value.publish.specifics.resume.message);
-    }
-    else if (info->value.publish.specifics.resume.chk_uri != NULL)
-    {
-      handle_publish_completed (ret,
-                               info->value.publish.specifics.resume.chk_uri);
-    }
-    return ret;
-  case GNUNET_FS_STATUS_PUBLISH_SUSPEND:
-    handle_publish_stop (info->value.publish.cctx);
-    return NULL;
-  case GNUNET_FS_STATUS_PUBLISH_PROGRESS:
-    mark_publish_progress (info->value.publish.cctx,
-                          info->value.publish.size,
-                          info->value.publish.completed);
-    return info->value.publish.cctx;
-  case GNUNET_FS_STATUS_PUBLISH_ERROR:
-    handle_publish_error (info->value.publish.cctx,
-                         info->value.publish.specifics.error.message);
-    return info->value.publish.cctx;
-  case GNUNET_FS_STATUS_PUBLISH_COMPLETED:
-    handle_publish_completed (info->value.publish.cctx,
-                             info->value.publish.specifics.completed.chk_uri);
-    return info->value.publish.cctx;
-  case GNUNET_FS_STATUS_PUBLISH_STOPPED:
-    handle_publish_stop (info->value.publish.cctx);
-    return NULL;
-  case GNUNET_FS_STATUS_DOWNLOAD_START:
-    return setup_download (info->value.download.cctx, 
info->value.download.pctx,
-                           info->value.download.sctx, info->value.download.dc,
-                           info->value.download.uri,
-                           info->value.download.filename,
-                           info->value.download.specifics.start.meta,
-                           info->value.download.size,
-                           info->value.download.completed);
-  case GNUNET_FS_STATUS_DOWNLOAD_RESUME:
-    ret =
-        setup_download (info->value.download.cctx, info->value.download.pctx,
-                        info->value.download.sctx, info->value.download.dc,
-                        info->value.download.uri, 
info->value.download.filename,
-                        info->value.download.specifics.resume.meta,
-                        info->value.download.size,
-                        info->value.download.completed);
-    if (info->value.download.specifics.resume.message != NULL)
-      mark_download_error (ret,
-                          info->value.download.specifics.resume.message);   
-    return ret;
-  case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND:
-    stop_download (info->value.download.cctx);
-    return NULL;
-  case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
-    mark_download_progress (info->value.download.cctx,
-                           info->value.download.size,
-                           info->value.download.completed,
-                           info->value.download.specifics.progress.data,
-                           info->value.download.specifics.progress.
-                           offset,
-                           info->value.download.specifics.progress.
-                           data_len,
-                           info->value.download.specifics.progress.
-                           depth);
-    return info->value.download.cctx;
-  case GNUNET_FS_STATUS_DOWNLOAD_ERROR:
-    mark_download_error (info->value.download.cctx,
-                        info->value.download.specifics.error.message);
-    return info->value.download.cctx;
-  case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
-    mark_download_completed (info->value.download.cctx,
-                            info->value.download.size,
-                            info->value.download.filename);
-    return info->value.download.cctx;
-  case GNUNET_FS_STATUS_DOWNLOAD_STOPPED:
-    stop_download (info->value.download.cctx);
-    return NULL;
-  case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
-    change_download_color (info->value.download.cctx, "yellow");
-    return info->value.download.cctx;
-  case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
-    change_download_color (info->value.download.cctx, "blue");
-    return info->value.download.cctx;
-  case GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT:
-    download_lost_parent (info->value.download.cctx);
-    return info->value.download.cctx;
-  case GNUNET_FS_STATUS_SEARCH_START:
-    if (info->value.search.pctx != NULL)
-      return setup_inner_search (info->value.search.sc,
-                                 info->value.search.pctx);
-    return setup_search_tab (info->value.search.sc, info->value.search.query);
-  case GNUNET_FS_STATUS_SEARCH_RESUME:
-    ret = setup_search_tab (info->value.search.sc, info->value.search.query);
-    if (info->value.search.specifics.resume.message)
-      handle_search_error (ret,
-                          info->value.search.specifics.resume.message);
-    return ret;
-  case GNUNET_FS_STATUS_SEARCH_RESUME_RESULT:
-    ret =
-        process_search_result (info->value.search.cctx, 
info->value.search.pctx,
-                               info->value.search.specifics.resume_result.uri,
-                               info->value.search.specifics.resume_result.meta,
-                               info->value.search.specifics.resume_result.
-                               result,
-                               info->value.search.specifics.resume_result.
-                               applicability_rank);
-    update_search_result (ret,
-                         info->value.search.specifics.resume_result.
-                         meta,
-                         info->value.search.specifics.resume_result.
-                         applicability_rank,
-                         info->value.search.specifics.resume_result.
-                         availability_certainty,
-                         info->value.search.specifics.resume_result.
-                         availability_rank);
-    return ret;
-  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:
-    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);
-    return info->value.search.specifics.update.cctx;
-  case GNUNET_FS_STATUS_SEARCH_ERROR:
-    handle_search_error (info->value.search.cctx,
-                        info->value.search.specifics.error.message);
-    return info->value.search.cctx;
-  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_stopped.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;
-}
-
-
-/* end of gnunet-fs-gtk-event_handler.c */

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.h
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.h     2012-02-02 12:57:54 UTC 
(rev 19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.h     2012-02-02 13:28:32 UTC 
(rev 19629)
@@ -1,241 +0,0 @@
-/*
-     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/gnunet-fs-gtk-event_handler.h
- * @brief Main event handler for file-sharing
- * @author Christian Grothoff
- */
-#include "gnunet-fs-gtk-common.h"
-
-
-/**
- * State we keep for each (search) result entry in the
- * tree view of a search tab.
- */
-struct SearchResult;
-
-
-/**
- * Context we keep for a search tab.
- */
-struct SearchTab
-{
-  /**
-   * This is a doubly-linked list.
-   */
-  struct SearchTab *next;
-
-  /**
-   * This is a doubly-linked list.
-   */
-  struct SearchTab *prev;
-
-  /**
-   * Set in case this is an inner search, otherwise NULL.
-   */
-  struct SearchResult *parent;
-
-  /**
-   * Handle for this search with FS library.
-   */
-  struct GNUNET_FS_SearchContext *sc;
-
-  /**
-   * Text of the search query.
-   */
-  char *query_txt;
-
-  /**
-   * GtkBuilder object for the search tab.
-   */ 
-  GtkBuilder *builder;
-
-  /**
-   * Frame instance of the search tab.
-   */
-  GtkWidget *frame;
-
-  /**
-   * The widget representing this search in the tab bar (not
-   * a GtkLabel, contains the actual label and the buttons).
-   */
-  GtkWidget *tab_label;
-
-  /**
-   * Button to stop and close the search.
-   */
-  GtkWidget *close_button;
-
-  /**
-   * Button to clear all entries for downloads that have completed.
-   */
-  GtkWidget *clear_button;
-
-  /**
-   * Button to resume the search.
-   */
-  GtkWidget *play_button;
-
-  /**
-   * Button to pause the search.
-   */
-  GtkWidget *pause_button;
-
-  /**
-   * Textual label in the 'tab_label'
-   */
-  GtkLabel *label;
-
-  /**
-   * Tree store with the search results.
-   */
-  GtkTreeStore *ts;
-
-  /**
-   * Number of results we got for this search.
-   */
-  unsigned int num_results;
-
-};
-
-
-/**
- * Information we keep for each download.
- */
-struct DownloadEntry
-{
-
-  /**
-   * Download entry of the parent (for recursive downloads),
-   * NULL if we are either a top-level download (from URI,
-   * from opened directory, orphaned from search or direct
-   * search result).
-   */
-  struct DownloadEntry *pde;
-
-  /**
-   * Associated search result, or NULL if we don't belong
-   * to a search directly (download entry).
-   */
-  struct SearchResult *sr;
-
-  /**
-   * FS handle to control the download.
-   */
-  struct GNUNET_FS_DownloadContext *dc;
-
-  /**
-   * URI for the download.
-   */
-  struct GNUNET_FS_Uri *uri;
-
-  /**
-   * Meta data for the download.
-   */
-  struct GNUNET_CONTAINER_MetaData *meta;
-
-  /**
-   * Where in the tree view is this download being displayed.
-   */
-  GtkTreeRowReference *rr;
-
-  /**
-   * Tree store where we are stored.
-   */
-  GtkTreeStore *ts;
-
-  /**
-   * Tab where this download is currently on display.
-   */
-  struct SearchTab *tab;
-
-  /**
-   * Has the download completed (or errored)?
-   */
-  int is_done;
-
-};
-
-
-/**
- * Setup a new top-level entry in the URI/orphan tab.  If necessary, create
- * the URI tab first.
- *
- * @param iter set to the new entry (OUT only)
- * @param srp set to search result (can be NULL)
- * @param meta metadata for the new entry
- * @param uri URI for the new entry
- * @return the 'uri_tab' the result was added to
- */
-struct SearchTab *
-GNUNET_GTK_add_to_uri_tab (GtkTreeIter * iter, struct SearchResult **sr,
-                           const struct GNUNET_CONTAINER_MetaData *meta,
-                           const struct GNUNET_FS_Uri *uri);
-
-
-/**
- * Add a search result to the given search tab.
- *
- * @param tab search tab to extend, never NULL
- * @param iter set to position where search result is added (OUT only)
- * @param parent_rr reference to parent entry in search tab, NULL for normal
- *                  search results, 
- * @param uri uri to add, can be NULL for top-level entry of a directory 
opened from disk
- *                        (in this case, we don't know the URI and should 
probably not
- *                         bother to calculate it)
- * @param meta metadata of the entry
- * @param result associated FS search result (can be NULL if this result
- *                        was part of a directory)
- * @param applicability_rank how relevant is the result
- * @return struct representing the search result (also stored in the tree
- *                model at 'iter')
- */
-struct SearchResult *
-GNUNET_GTK_add_search_result (struct SearchTab *tab, 
-                             GtkTreeIter *iter,
-                              GtkTreeRowReference *parent_rr,
-                              const struct GNUNET_FS_Uri *uri,
-                              const struct GNUNET_CONTAINER_MetaData *meta,
-                              struct GNUNET_FS_SearchResult *result,
-                              uint32_t applicability_rank);
-
-
-/**
- * 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);
-
-
-/* end of gnunet-fs-gtk-event_handler.h */

Deleted: gnunet-gtk/src/fs/gnunet-fs-gtk-main_window_file_publish.c
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-main_window_file_publish.c  2012-02-02 
12:57:54 UTC (rev 19628)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-main_window_file_publish.c  2012-02-02 
13:28:32 UTC (rev 19629)
@@ -1,1596 +0,0 @@
-/*
-     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-main_window_file_publish.c
- * @author Christian Grothoff
- */
-#include "gnunet-fs-gtk-common.h"
-#include "gnunet-fs-gtk.h"
-#include "gnunet-fs-gtk-edit_publish_dialog.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <gnunet/gnunet_fs_service.h>
-
-#define MARKER_DIR_FILE_SIZE "-"
-
-#define VERBOSE_PROGRESS GNUNET_NO
-
-struct AddDirClientContext;
-
-struct MainPublishingDialogContext
-{
-  GtkBuilder *builder;
-  GtkBuilder *main_window_builder;
-  GtkTreeView *pseudonym_treeview;
-  GtkTreeSelection *pseudonym_selection;
-  GtkTreeModel *pseudonym_treemodel;
-  GtkWidget *up_button;
-  GtkWidget *down_button;
-  GtkWidget *left_button;
-  GtkWidget *right_button;
-  GtkWidget *delete_button;
-  GtkWidget *edit_button;
-  GtkWidget *execute_button;
-  GtkWidget *cancel_button;
-  GtkTreeView *file_info_treeview;
-  GtkTreeSelection *file_info_selection;
-  GtkTreeModel *file_info_treemodel;  
-  GtkWindow *master_pubdialog;
-
-  gulong open_directory_handler_id;
-  GtkBuilder *open_directory_builder;
-
-  gulong open_file_handler_id;
-  GtkBuilder *open_file_builder;
-
-  /* To keep multiple scanners running */
-  struct AddDirClientContext *adddir_head;
-  struct AddDirClientContext *adddir_tail;
-};
-
-/* One of these is kept for every directory being opened */
-struct AddDirClientContext
-{
-  struct AddDirClientContext *prev;
-  struct AddDirClientContext *next;
-
-  struct GNUNET_FS_ProcessMetadataContext *pmc;
-
-  struct MainPublishingDialogContext *ctx;
-  struct GNUNET_FS_DirScanner *ds;
-
-  struct GNUNET_FS_ShareTreeItem *directory_scan_result;
-
-  struct GNUNET_FS_BlockOptions directory_scan_bo;
-  int directory_scan_do_index;
-
-  GtkBuilder *progress_dialog_builder;
-  GtkWidget *progress_dialog;
-  GtkProgressBar *progress_dialog_bar;
-  GtkButton *progress_dialog_cancel;
-  GtkTextView *progress_dialog_textview;
-  GtkTextBuffer *progress_dialog_textbuffer;
-  GtkTextMark *progress_dialog_textmark;
-  GtkAdjustment *textview_vertial_adjustment;
-
-  unsigned int done;
-  unsigned int total;
-};
-
-
-static void
-selection_changed_cb (GtkTreeSelection * ts, struct 
MainPublishingDialogContext *ctx);
-
-
-/**
- * Check if two GtkTreeIters refer to the same element.
- *
- * @param tm tree model of the iterators
- * @param i1 first iterator
- * @param i2 second iterator
- * @return GNUNET_YES if they are equal
- */
-static int
-gtk_tree_iter_equals (GtkTreeModel * tm, GtkTreeIter * i1, GtkTreeIter * i2)
-{
-  GtkTreePath *p1;
-  GtkTreePath *p2;
-  int ret;
-
-  p1 = gtk_tree_model_get_path (tm, i1);
-  p2 = gtk_tree_model_get_path (tm, i2);
-  ret = gtk_tree_path_compare (p1, p2);
-  gtk_tree_path_free (p1);
-  gtk_tree_path_free (p2);
-  return (0 == ret) ? GNUNET_YES : GNUNET_NO;
-}
-
-/* Fill out the main publishing dialog context structure */
-static void
-init_ctx (struct MainPublishingDialogContext *ctx)
-{
-  ctx->pseudonym_treeview = GTK_TREE_VIEW (gtk_builder_get_object
-      (ctx->builder, "GNUNET_GTK_master_publish_dialog_pseudonym_tree_view"));
-
-  ctx->up_button = GTK_WIDGET (gtk_builder_get_object
-      (ctx->builder, "GNUNET_GTK_master_publish_dialog_up_button"));
-  ctx->down_button = GTK_WIDGET (gtk_builder_get_object
-      (ctx->builder, "GNUNET_GTK_master_publish_dialog_down_button"));
-  ctx->left_button = GTK_WIDGET (gtk_builder_get_object
-      (ctx->builder, "GNUNET_GTK_master_publish_dialog_left_button"));
-  ctx->right_button = GTK_WIDGET (gtk_builder_get_object
-      (ctx->builder, "GNUNET_GTK_master_publish_dialog_right_button"));
-  ctx->delete_button = GTK_WIDGET (gtk_builder_get_object
-      (ctx->builder, "GNUNET_GTK_master_publish_dialog_delete_button"));
-  ctx->edit_button = GTK_WIDGET (gtk_builder_get_object
-      (ctx->builder, "GNUNET_GTK_master_publish_dialog_edit_button"));
-  ctx->execute_button = GTK_WIDGET (gtk_builder_get_object
-      (ctx->builder, "GNUNET_GTK_master_publish_dialog_execute_button"));
-  ctx->cancel_button = GTK_WIDGET (gtk_builder_get_object
-      (ctx->builder , "GNUNET_GTK_master_publish_dialog_cancel_button"));
-  ctx->file_info_treeview = GTK_TREE_VIEW (gtk_builder_get_object
-      (ctx->builder, 
"GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
-
-  ctx->master_pubdialog =
-      GTK_WINDOW (gtk_builder_get_object
-                  (ctx->builder, "GNUNET_GTK_master_publish_dialog"));
-
-  ctx->file_info_selection = gtk_tree_view_get_selection 
(ctx->file_info_treeview);
-  ctx->file_info_treemodel = gtk_tree_view_get_model (ctx->file_info_treeview);
-  ctx->pseudonym_selection = gtk_tree_view_get_selection 
(ctx->pseudonym_treeview);
-  ctx->pseudonym_treemodel = gtk_tree_view_get_model (ctx->pseudonym_treeview);
-
-  g_signal_connect (G_OBJECT (ctx->file_info_selection), "changed",
-                    G_CALLBACK (selection_changed_cb), ctx);
-  g_signal_connect (G_OBJECT (ctx->pseudonym_selection), "changed",
-                    G_CALLBACK (selection_changed_cb), ctx);
-}
-
-/**
- * Update selectivity in the master dialog.
- */
-static void
-update_selectivity (struct MainPublishingDialogContext *ctx)
-{
-  GtkTreeIter iter;
-  GtkTreeIter parent;
-  GtkTreeIter pred;
-  int is_dir;
-  struct GNUNET_FS_FileInformation *fip;
-  int ns_ok;
-  gchar *namespace_id;
-
-  ns_ok = GNUNET_YES;
-  if (TRUE == gtk_tree_selection_get_selected (ctx->pseudonym_selection, NULL, 
&iter))
-  {
-    gtk_tree_model_get (ctx->pseudonym_treemodel, &iter, 2, &namespace_id, -1);
-    if (namespace_id == NULL)
-      ns_ok = GNUNET_NO;
-    else
-      g_free (namespace_id);
-  }
-  /* Don't let the user close the dialog until all scanners are finished and
-   * their windows are closed
-   */
-  if ((gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &iter))
-      && (ns_ok == GNUNET_YES) && ctx->adddir_head == NULL)
-    gtk_widget_set_sensitive (ctx->execute_button, TRUE);
-  else
-    gtk_widget_set_sensitive (ctx->execute_button, FALSE);
-  if (ctx->adddir_head == NULL)
-    gtk_widget_set_sensitive (ctx->cancel_button, TRUE);
-  else
-    gtk_widget_set_sensitive (ctx->cancel_button, FALSE);
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
-  {
-    gtk_widget_set_sensitive (ctx->up_button, FALSE);
-    gtk_widget_set_sensitive (ctx->down_button, FALSE);
-    gtk_widget_set_sensitive (ctx->left_button, FALSE);
-    gtk_widget_set_sensitive (ctx->right_button, FALSE);
-    gtk_widget_set_sensitive (ctx->delete_button, FALSE);
-    gtk_widget_set_sensitive (ctx->edit_button, FALSE);
-    return;
-  }
-  gtk_widget_set_sensitive (ctx->delete_button, TRUE);
-  gtk_widget_set_sensitive (ctx->edit_button, TRUE);
-
-  /* now figure out which move operations are currently legal */
-  GNUNET_assert (TRUE == gtk_tree_selection_get_selected 
(ctx->file_info_selection, NULL, &iter));
-  if (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, &iter))
-  {
-    gtk_widget_set_sensitive (ctx->down_button, TRUE);
-  }
-  else
-  {
-    gtk_widget_set_sensitive (ctx->down_button, FALSE);
-  }
-  GNUNET_assert (TRUE == gtk_tree_selection_get_selected 
(ctx->file_info_selection, NULL, &iter));
-  if (TRUE == gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, 
&iter))
-  {
-    gtk_widget_set_sensitive (ctx->left_button, TRUE);
-    GNUNET_assert (TRUE == gtk_tree_model_iter_children 
(ctx->file_info_treemodel, &pred, &parent));
-  }
-  else
-  {
-    gtk_widget_set_sensitive (ctx->left_button, FALSE);
-    GNUNET_assert (TRUE == gtk_tree_model_get_iter_first 
(ctx->file_info_treemodel, &pred));
-  }
-  /* iterate over 'next' of pred to find out if our
-   * predecessor is a directory! */
-  is_dir = GNUNET_SYSERR;
-  while (GNUNET_YES != gtk_tree_iter_equals (ctx->file_info_treemodel, &pred, 
&iter))
-  {
-    gtk_tree_model_get (ctx->file_info_treemodel, &pred, 5, &fip, -1);
-    is_dir = GNUNET_FS_file_information_is_directory (fip);
-    GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, 
&pred));
-  }
-  if (GNUNET_YES == is_dir)
-  {
-    gtk_widget_set_sensitive (ctx->right_button, TRUE);
-  }
-  else
-  {
-    gtk_widget_set_sensitive (ctx->right_button, FALSE);
-  }
-  if (GNUNET_SYSERR != is_dir)
-  {
-    gtk_widget_set_sensitive (ctx->up_button, TRUE);
-  }
-  else
-  {
-    gtk_widget_set_sensitive (ctx->up_button, FALSE);
-  }
-}
-
-
-/**
- * Add an empty directory to the tree model.
- *
- * @param name name for the directory
- * @param bo block options
- * @param iter parent entry, or NULL for top-level addition
- * @param pos iterator to set to the location of the new element
- */
-static void
-create_dir_at_iter (struct MainPublishingDialogContext *ctx, const char *name,
-                    const struct GNUNET_FS_BlockOptions *bo, GtkTreeIter * 
iter,
-                    GtkTreeIter * pos)
-{
-  struct GNUNET_FS_FileInformation *fi;
-  GtkTreeRowReference *row_reference;
-  GtkTreePath *path;
-  struct GNUNET_CONTAINER_MetaData *meta;
-
-  meta = GNUNET_CONTAINER_meta_data_create ();
-  GNUNET_FS_meta_data_make_directory (meta);
-  GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet-gtk>",
-                                     EXTRACTOR_METATYPE_FILENAME,
-                                     EXTRACTOR_METAFORMAT_UTF8, "text/plain",
-                                     name, strlen (name) + 1);
-  gtk_tree_store_insert_before (GTK_TREE_STORE (ctx->file_info_treemodel), 
pos, iter, NULL);
-  path = gtk_tree_model_get_path (ctx->file_info_treemodel, pos);
-  row_reference = gtk_tree_row_reference_new (ctx->file_info_treemodel, path);
-  gtk_tree_path_free (path);
-  fi = GNUNET_FS_file_information_create_empty_directory
-      (GNUNET_FS_GTK_get_fs_handle (), row_reference, NULL, meta, bo, name);
-  GNUNET_CONTAINER_meta_data_destroy (meta);
-  gtk_tree_store_set (GTK_TREE_STORE (ctx->file_info_treemodel), pos, 0, 
MARKER_DIR_FILE_SIZE, 1, (gboolean) GNUNET_NO,
-                      2, name, 3, (guint) bo->anonymity_level, 4,
-                      (guint) bo->content_priority, 5, fi,
-                     6, (guint64) bo->expiration_time.abs_value,
-                     7, (guint) bo->replication_level,
-                     -1);
-  update_selectivity (ctx);
-}
-
-static void
-selection_changed_cb (GtkTreeSelection * ts, struct 
MainPublishingDialogContext *ctx)
-{
-  update_selectivity (ctx);
-}
-
-static void
-remove_old_entry (GtkTreeStore * ts, GtkTreeIter * root)
-{
-  GtkTreeIter child;
-
-  while (TRUE ==
-         gtk_tree_model_iter_children (GTK_TREE_MODEL (ts), &child, root))
-    remove_old_entry (ts, &child);
-  gtk_tree_store_remove (ts, root);
-}
-
-
-/**
- * Move an entry in the tree.
- */
-static void
-move_entry (struct MainPublishingDialogContext *ctx, GtkTreeModel * tm, 
GtkTreeIter * old,
-            GtkTreeIter * newpos, int dsel)
-{
-  struct GNUNET_FS_FileInformation *fip;
-  gint do_index;
-  gchar *short_fn;
-  guint anonymity_level;
-  guint priority;
-  guint replication_level;
-  guint64 expiration_time_abs;
-  char *fsf;
-  GtkTreePath *path;
-  GtkTreeIter child;
-  GtkTreeIter cnewpos;
-  GtkTreeRowReference *rr;
-  GtkTreeRowReference *rr2;
-
-  gtk_tree_model_get (tm, old, 0, &fsf, 1, &do_index, 2, &short_fn, 3,
-                      &anonymity_level, 4, &priority, 5, &fip, 
-                     6, &expiration_time_abs, 7, &replication_level, -1);
-  gtk_tree_store_set (GTK_TREE_STORE (tm), newpos, 0, fsf, 1, do_index, 2,
-                      short_fn, 3, (guint) anonymity_level, 4, (guint) 
priority,
-                      5, fip, 
-                     6, expiration_time_abs,
-                     7, replication_level, -1);
-  if (dsel == GNUNET_YES)
-  {
-    path = gtk_tree_model_get_path (tm, newpos);
-    rr = gtk_tree_row_reference_new (tm, path);
-    gtk_tree_path_free (path);
-  }
-  else
-  {
-    rr = NULL;
-  }
-  if (TRUE == gtk_tree_model_iter_children (tm, &child, old))
-  {
-    do
-    {
-      path = gtk_tree_model_get_path (tm, &child);
-      rr2 = gtk_tree_row_reference_new (tm, path);
-      gtk_tree_path_free (path);
-      gtk_tree_store_insert_before (GTK_TREE_STORE (tm), &cnewpos, newpos,
-                                    NULL);
-      move_entry (ctx, tm, &child, &cnewpos, GNUNET_NO);
-      path = gtk_tree_row_reference_get_path (rr2);
-      gtk_tree_row_reference_free (rr2);
-      GNUNET_assert (TRUE == gtk_tree_model_get_iter (tm, &child, path));
-      gtk_tree_path_free (path);
-    }
-    while (TRUE == gtk_tree_model_iter_next (tm, &child));
-  }
-  g_free (short_fn);
-  g_free (fsf);
-  if (dsel == GNUNET_YES)
-  {
-    path = gtk_tree_row_reference_get_path (rr);
-    gtk_tree_row_reference_free (rr);
-    gtk_tree_view_expand_to_path (ctx->file_info_treeview, path);
-    GNUNET_assert (TRUE == gtk_tree_model_get_iter (tm, newpos, path));
-    gtk_tree_path_free (path);
-    gtk_tree_selection_select_iter (ctx->file_info_selection, newpos);
-  }
-  update_selectivity (ctx);
-}
-
-
-/**
- * User has changed the "current" identifier for the content in
- * the GtkTreeView.  Update the model.
- */
-void GNUNET_GTK_master_publish_dialog_pseudonym_updates_renderer_edited_cb
-    (GtkCellRendererText * renderer, gchar * cpath, gchar * new_text,
-     struct MainPublishingDialogContext *ctx)
-{
-  GtkTreeIter iter;
-
-  if (TRUE !=
-      gtk_tree_model_get_iter_from_string (ctx->pseudonym_treemodel, &iter, 
cpath))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  gtk_tree_store_set (GTK_TREE_STORE (ctx->pseudonym_treemodel), &iter, 5, 
new_text, -1);
-  update_selectivity (ctx);
-}
-
-
-/**
- * User has changed the "current" identifier for the content in
- * the GtkTreeView.  Update the model.
- */
-void GNUNET_GTK_master_publish_dialog_pseudonym_identifier_renderer_edited_cb
-    (GtkCellRendererText * renderer, gchar * cpath, gchar * new_text,
-     struct MainPublishingDialogContext *ctx)
-{
-  GtkTreeIter iter;
-
-  if (TRUE !=
-      gtk_tree_model_get_iter_from_string (ctx->pseudonym_treemodel, &iter, 
cpath))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  gtk_tree_store_set (GTK_TREE_STORE (ctx->pseudonym_treemodel), &iter, 2, 
new_text, -1);
-  update_selectivity (ctx);
-}
-
-
-void
-GNUNET_GTK_master_publish_dialog_right_button_clicked_cb (GtkWidget * dummy,
-                                                          struct 
MainPublishingDialogContext *ctx)
-{
-  GtkTreeIter iter;
-  GtkTreeIter parent;
-  GtkTreeIter pred;
-  GtkTreeIter prev;
-  GtkTreeIter pos;
-
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  if (TRUE == gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, 
&iter))
-  {
-    GNUNET_assert (TRUE == gtk_tree_model_iter_children 
(ctx->file_info_treemodel, &pred, &parent));
-  }
-  else if (TRUE != gtk_tree_model_get_iter_first (ctx->file_info_treemodel, 
&pred))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  /* iterate over 'next' of pred to find out who our predecessor is! */
-  memset (&prev, 0, sizeof (GtkTreeIter));
-  while (GNUNET_YES != gtk_tree_iter_equals (ctx->file_info_treemodel, &pred, 
&iter))
-  {
-    prev = pred;
-    GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, 
&pred));
-  }
-  gtk_tree_store_insert_before (GTK_TREE_STORE (ctx->file_info_treemodel), 
&pos, &prev, NULL);
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
-  remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
-}
-
-
-void
-GNUNET_GTK_master_publish_dialog_left_button_clicked_cb (GtkWidget * dummy,
-                                                         struct 
MainPublishingDialogContext *ctx)
-{
-  GtkTreeIter iter;
-  GtkTreeIter parent;
-  GtkTreeIter pos;
-
-
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  if (TRUE != gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, 
&iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  gtk_tree_store_insert_after (GTK_TREE_STORE (ctx->file_info_treemodel), 
&pos, NULL, &parent);
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
-  remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
-}
-
-
-void
-GNUNET_GTK_master_publish_dialog_up_button_clicked_cb (GtkWidget * dummy,
-                                                       struct 
MainPublishingDialogContext *ctx)
-{
-  GtkTreeIter iter;
-  GtkTreeIter parent;
-  GtkTreeIter pred;
-  GtkTreeIter prev;
-  GtkTreeIter *pprev;
-  GtkTreeIter pos;
-
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  if (TRUE == gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, 
&iter))
-  {
-    GNUNET_assert (TRUE == gtk_tree_model_iter_children 
(ctx->file_info_treemodel, &pred, &parent));
-    pprev = &parent;
-  }
-  else if (TRUE == gtk_tree_model_get_iter_first (ctx->file_info_treemodel, 
&pred))
-  {
-    pprev = NULL;
-  }
-  else
-  {
-    GNUNET_break (0);
-    return;
-  }
-  /* iterate over 'next' of pred to find out who our predecessor is! */
-  while (GNUNET_YES != gtk_tree_iter_equals (ctx->file_info_treemodel, &pred, 
&iter))
-  {
-    prev = pred;
-    pprev = &prev;
-    GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, 
&pred));
-  }
-  gtk_tree_store_insert_before (GTK_TREE_STORE (ctx->file_info_treemodel), 
&pos, NULL, pprev);
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
-  remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
-}
-
-
-void
-GNUNET_GTK_master_publish_dialog_down_button_clicked_cb (GtkWidget * dummy,
-                                                         struct 
MainPublishingDialogContext *ctx)
-{
-  GtkTreeIter iter;
-  GtkTreeIter next;
-  GtkTreeIter pos;
-
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&next))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, 
&next));
-  gtk_tree_store_insert_after (GTK_TREE_STORE (ctx->file_info_treemodel), 
&pos, NULL, &next);
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
-  remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
-}
-
-
-void
-GNUNET_GTK_master_publish_dialog_new_button_clicked_cb (GtkWidget * dummy,
-                                                        struct 
MainPublishingDialogContext *ctx)
-{
-  GtkTreeIter iter;
-  GtkTreeIter pos;
-  struct GNUNET_FS_BlockOptions bo;
-
-  /* FIXME: consider opening a dialog to get
-   * anonymity, priority and expiration prior
-   * to calling this function (currently we
-   * use default values for those).
-   * Or getting these values from the configuration.
-   */
-  bo.anonymity_level = 1;
-  bo.content_priority = 1000;
-  bo.expiration_time =
-      GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS);
-  bo.replication_level = 1;
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
-  {
-    create_dir_at_iter (ctx, "unnamed/", &bo, NULL, &pos);
-    return;
-  }
-  create_dir_at_iter (ctx, "unnamed/", &bo, &iter, &pos);
-}
-
-
-static void
-insert_progress_dialog_text (struct AddDirClientContext *adcc,
-                            const char *text)
-{
-  gtk_text_buffer_insert_at_cursor (adcc->progress_dialog_textbuffer,
-                                   text, -1);
-  gtk_text_view_place_cursor_onscreen (adcc->progress_dialog_textview);
-  gtk_adjustment_set_value (adcc->textview_vertial_adjustment,
-                           gtk_adjustment_get_upper 
(adcc->textview_vertial_adjustment));
-}
-
-
-static void
-add_item (struct AddDirClientContext *adcc, GtkTreeStore *ts,
-         struct GNUNET_FS_ShareTreeItem *item, 
-         GtkTreeIter *parent, 
-         GtkTreeIter *sibling,
-         GtkTreeIter *item_iter)
-{
-  char *file_size_fancy;
-  struct GNUNET_FS_FileInformation *fi;
-  GtkTreeRowReference *row_reference;
-  GtkTreePath *path;
-  struct stat sbuf;
-  
-  if (0 != stat (item->filename,
-                &sbuf))
-  {
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "stat", item->filename);
-    return;
-  }
-
-  gtk_tree_store_insert_after (ts, item_iter, parent, sibling);
-  path = gtk_tree_model_get_path (GTK_TREE_MODEL (ts), item_iter);
-  row_reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts), path);
-  gtk_tree_path_free (path);
-
-  if (item->is_directory)
-  {
-    if (NULL != item->meta)
-      GNUNET_CONTAINER_meta_data_delete (item->meta,
-                                        EXTRACTOR_METATYPE_MIMETYPE, NULL, 0);
-    else
-      item->meta = GNUNET_CONTAINER_meta_data_create ();
-    GNUNET_FS_meta_data_make_directory (item->meta);
-    if (NULL == item->ksk_uri)
-      item->ksk_uri = GNUNET_FS_uri_ksk_create (GNUNET_FS_DIRECTORY_MIME, 
NULL);
-    else
-      GNUNET_FS_uri_ksk_add_keyword (item->ksk_uri, GNUNET_FS_DIRECTORY_MIME,
-                                    GNUNET_NO);
-    fi = GNUNET_FS_file_information_create_empty_directory (
-        GNUNET_FS_GTK_get_fs_handle (), row_reference, item->ksk_uri,
-        item->meta, &adcc->directory_scan_bo, item->filename);
-  }
-  else
-  {
-    fi = GNUNET_FS_file_information_create_from_file (
-        GNUNET_FS_GTK_get_fs_handle (), row_reference, item->filename,
-        item->ksk_uri, item->meta, adcc->directory_scan_do_index,
-        &adcc->directory_scan_bo);
-  }
-  if (item->is_directory)
-    file_size_fancy = GNUNET_strdup (MARKER_DIR_FILE_SIZE);
-  else
-    file_size_fancy = GNUNET_STRINGS_byte_size_fancy (sbuf.st_size);
-  
-  gtk_tree_store_set (ts, item_iter, 0, file_size_fancy,
-      1, (gboolean) adcc->directory_scan_do_index,
-      2, item->short_filename,
-      3, (guint) adcc->directory_scan_bo.anonymity_level,
-      4, (guint) adcc->directory_scan_bo.content_priority,
-      5, fi,
-      6, (guint64) adcc->directory_scan_bo.expiration_time.abs_value,
-      7, (guint) adcc->directory_scan_bo.replication_level, -1);
-  GNUNET_free (file_size_fancy);
-}
-
-
-/**
- * Traverse the share tree and add it to the tree store
- *
- */
-static void
-add_share_items_to_treestore (struct AddDirClientContext *adcc,
-                             struct GNUNET_FS_ShareTreeItem *toplevel,
-                             GtkTreeIter *parent_iter)
-{
-  struct MainPublishingDialogContext *ctx = adcc->ctx;
-  GtkTreeStore *ts = GTK_TREE_STORE (ctx->file_info_treemodel);
-  GtkTreeIter *sibling_iter;
-  GtkTreeIter last_added;
-  struct GNUNET_FS_ShareTreeItem *item;
-
-  sibling_iter = NULL;  
-  for (item = toplevel; item != NULL; item = item->next)
-  {
-    add_item (adcc, ts, item, parent_iter, sibling_iter, &last_added);
-    sibling_iter = &last_added;
-    if (item->is_directory) 
-      add_share_items_to_treestore (adcc,
-                                   item->children_head,
-                                   sibling_iter);
-  }
-}
-
-
-static void
-close_scan (struct AddDirClientContext *adcc)
-{
-  gtk_widget_destroy (adcc->progress_dialog);
-  g_object_unref (G_OBJECT (adcc->progress_dialog_builder));  
-  GNUNET_CONTAINER_DLL_remove (adcc->ctx->adddir_head,
-                              adcc->ctx->adddir_tail, 
-                              adcc);
-  update_selectivity (adcc->ctx);
-  GNUNET_free (adcc);
-}
-
-
-static void
-directory_scan_cb (void *cls, 
-                  const char *filename, int is_directory,
-                  enum GNUNET_FS_DirScannerProgressUpdateReason reason)
-{
-  static struct GNUNET_TIME_Absolute last_pulse;
-  struct AddDirClientContext *adcc = cls;
-  char *s;
-  gdouble fraction;
-
-  switch (reason)
-  {
-  case GNUNET_FS_DIRSCANNER_FILE_START:
-    GNUNET_assert (filename != NULL);
-    if (GNUNET_TIME_absolute_get_duration (last_pulse).rel_value > 100)
-    {
-      gtk_progress_bar_pulse (adcc->progress_dialog_bar);
-      last_pulse = GNUNET_TIME_absolute_get ();
-    }
-#if VERBOSE_PROGRESS
-    if (is_directory)
-    {
-      GNUNET_asprintf (&s, _("Scanning directory `%s'.\n"), filename);
-      insert_progress_dialog_text (adcc, s);
-      GNUNET_free (s);
-    }
-    else
-      adcc->total++;
-#else
-    if (! is_directory)
-      adcc->total++;
-#endif
-    break;
-  case GNUNET_FS_DIRSCANNER_FILE_IGNORED:
-    GNUNET_assert (filename != NULL);
-    GNUNET_asprintf (&s,
-                    _("Failed to scan `%s' (access error). Skipping.\n"),
-                    filename);
-#if ! VERBOSE_PROGRESS
-    gtk_widget_show (GTK_WIDGET (gtk_builder_get_object 
(adcc->progress_dialog_builder,
-                                                        
"GNUNET_FS_GTK_progress_dialog_scrolled_window")));
-#endif
-    insert_progress_dialog_text (adcc, s);
-    GNUNET_free (s);    
-    break;
-  case GNUNET_FS_DIRSCANNER_ALL_COUNTED:
-    fraction = (adcc->total == 0) ? 1.0 : (1.0 * adcc->done) / adcc->total;
-    GNUNET_asprintf (&s, "%u/%u (%3f%%)", 
-                    adcc->done,
-                    adcc->total,
-                    100.0 * fraction);
-    gtk_progress_bar_set_text (adcc->progress_dialog_bar,
-                              s);    
-    GNUNET_free (s);
-    gtk_progress_bar_set_fraction (adcc->progress_dialog_bar,
-                                  fraction);
-    break;
-  case GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED:
-#if VERBOSE_PROGRESS
-    GNUNET_asprintf (&s, _("Processed file `%s'.\n"), filename);
-    insert_progress_dialog_text (adcc, s);
-    GNUNET_free (s);
-#endif
-    adcc->done++;
-    GNUNET_assert (adcc->done <= adcc->total);
-    fraction = (adcc->total == 0) ? 1.0 : (1.0 * adcc->done) / adcc->total;
-    GNUNET_asprintf (&s, "%u/%u (%3f%%)", 
-                    adcc->done,
-                    adcc->total,
-                    100.0 * fraction);
-    gtk_progress_bar_set_text (adcc->progress_dialog_bar,
-                              s);    
-    GNUNET_free (s);
-    gtk_progress_bar_set_fraction (adcc->progress_dialog_bar,
-                                  fraction);
-    break;
-  case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR:
-    insert_progress_dialog_text (adcc, _("Operation failed (press cancel)\n"));
-    GNUNET_FS_directory_scan_abort (adcc->ds);
-    adcc->ds = NULL;
-    break;
-  case GNUNET_FS_DIRSCANNER_FINISHED:
-    insert_progress_dialog_text (adcc, _("Scanner has finished.\n"));
-    adcc->directory_scan_result = GNUNET_FS_directory_scan_get_result 
(adcc->ds);
-    adcc->ds = NULL;
-    GNUNET_FS_share_tree_trim (adcc->directory_scan_result);
-    add_share_items_to_treestore (adcc, 
-                                 adcc->directory_scan_result,
-                                 NULL);
-    GNUNET_FS_share_tree_free (adcc->directory_scan_result);
-    adcc->directory_scan_result = NULL;
-    update_selectivity (adcc->ctx);
-    close_scan (adcc);
-    break;
-  default:
-    GNUNET_break (0);
-    break;
-  }
-}
-
-
-static void
-scan_file_or_directory (struct MainPublishingDialogContext *ctx, 
-                       gchar *filename,
-                       struct GNUNET_FS_BlockOptions *bo, 
-                       int do_index)
-{
-  struct AddDirClientContext *adcc;
-  GtkTextIter iter;
-
-  adcc = GNUNET_malloc (sizeof (struct AddDirClientContext));
-  adcc->ctx = ctx;
-  GNUNET_CONTAINER_DLL_insert_tail (ctx->adddir_head, ctx->adddir_tail, adcc);
-  adcc->ds = GNUNET_FS_directory_scan_start (filename,
-      GNUNET_NO, NULL, &directory_scan_cb, adcc);
-  adcc->directory_scan_bo = *bo;
-  adcc->directory_scan_do_index = do_index;
-
-  adcc->progress_dialog_builder = GNUNET_GTK_get_new_builder (
-      "gnunet_fs_gtk_progress_dialog.glade", adcc);
-  adcc->progress_dialog = GTK_WIDGET (gtk_builder_get_object (
-      adcc->progress_dialog_builder,
-      "GNUNET_FS_GTK_progress_dialog"));
-  adcc->progress_dialog_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (
-      adcc->progress_dialog_builder,
-      "GNUNET_FS_GTK_progress_dialog_progressbar"));
-  adcc->progress_dialog_cancel = GTK_BUTTON (gtk_builder_get_object (
-      adcc->progress_dialog_builder,
-      "GNUNET_FS_GTK_progress_dialog_cancel_button"));
-  adcc->progress_dialog_textview = GTK_TEXT_VIEW (
-      gtk_builder_get_object (adcc->progress_dialog_builder,
-      "GNUNET_FS_GTK_progress_dialog_textview"));
-  adcc->textview_vertial_adjustment  = GTK_ADJUSTMENT (
-      gtk_builder_get_object (adcc->progress_dialog_builder,
-      "GNUNET_FS_GTK_progress_dialog_textview_vertical_adjustment"));
-  adcc->progress_dialog_textbuffer = GTK_TEXT_BUFFER (
-      gtk_builder_get_object (adcc->progress_dialog_builder,
-      "GNUNET_FS_GTK_progress_dialog_textbuffer"));
-  gtk_text_buffer_get_end_iter (adcc->progress_dialog_textbuffer,
-      &iter);
-  adcc->progress_dialog_textmark = gtk_text_buffer_create_mark (
-      adcc->progress_dialog_textbuffer, "scroll",
-      &iter, FALSE);
-#if VERBOSE_PROGRESS
-  gtk_widget_show (GTK_WIDGET (gtk_builder_get_object 
(adcc->progress_dialog_builder,
-                                                      
"GNUNET_FS_GTK_progress_dialog_scrolled_window")));
-#endif
-
-  gtk_window_set_transient_for (GTK_WINDOW (adcc->progress_dialog), 
adcc->ctx->master_pubdialog);
-  gtk_window_set_title (GTK_WINDOW (adcc->progress_dialog), filename);
-  gtk_window_present (GTK_WINDOW (adcc->progress_dialog));
-
-  update_selectivity (ctx);
-}
-
-
-static void
-publish_directory_dialog_response_cb (GtkDialog * dialog,
-                                     gint response_id,
-                                     struct MainPublishingDialogContext *ctx)
-{
-  char *filename;
-  int do_index;
-  GtkSpinButton *sb;
-  struct GNUNET_FS_BlockOptions bo;
-  GtkWidget *ad;
-
-  if (g_signal_handler_is_connected (G_OBJECT (dialog), 
ctx->open_directory_handler_id))
-    g_signal_handler_disconnect (G_OBJECT (dialog), 
ctx->open_directory_handler_id);
-  ctx->open_directory_handler_id = 0;
-
-  ad = GTK_WIDGET (gtk_builder_get_object
-                   (ctx->open_directory_builder, 
"GNUNET_GTK_publish_directory_dialog"));
-  if (response_id == -5)
-  {
-    filename = GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER 
(ad));
-    sb = GTK_SPIN_BUTTON (gtk_builder_get_object
-                          (ctx->open_directory_builder,
-                           
"GNUNET_GTK_publish_directory_dialog_expiration_year_spin_button"));
-    if (!GNUNET_GTK_get_selected_anonymity_level
-        (ctx->open_directory_builder, 
"GNUNET_GTK_publish_directory_dialog_anonymity_combobox",
-         &bo.anonymity_level))
-      bo.anonymity_level = 1;
-    bo.content_priority =
-      gtk_spin_button_get_value (GTK_SPIN_BUTTON
-                                   (gtk_builder_get_object
-                                    (ctx->open_directory_builder,
-                                     
"GNUNET_GTK_publish_directory_dialog_priority_spin_button")));
-    bo.replication_level = 
-      gtk_spin_button_get_value (GTK_SPIN_BUTTON
-                                (gtk_builder_get_object
-                                 (ctx->open_directory_builder,
-                                  
"GNUNET_GTK_publish_directory_dialog_replication_spin_button")));
-    bo.expiration_time = GNUNET_FS_GTK_get_expiration_time (sb);
-    do_index =
-        gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
-                                      (gtk_builder_get_object
-                                       (ctx->open_directory_builder,
-                                        
"GNUNET_GTK_publish_directory_dialog_do_index_checkbutton")));
-
-    scan_file_or_directory (ctx, filename, &bo, do_index);
-    g_free (filename);
-  }
-  gtk_widget_destroy (ad);
-  g_object_unref (G_OBJECT (ctx->open_directory_builder));
-}
-
-
-static void
-publish_file_dialog_response_cb (GtkDialog * dialog,
-                                gint response_id,
-                                struct MainPublishingDialogContext *ctx)
-{
-  char *filename;
-  struct GNUNET_FS_BlockOptions bo;
-  int do_index;
-  GtkSpinButton *sb;
-  GtkWidget *ad;
-
-  if (g_signal_handler_is_connected (G_OBJECT (dialog), 
ctx->open_file_handler_id))
-    g_signal_handler_disconnect (G_OBJECT (dialog), ctx->open_file_handler_id);
-  ctx->open_file_handler_id = 0;
-
-  ad = GTK_WIDGET (gtk_builder_get_object
-                   (ctx->open_file_builder, "GNUNET_GTK_publish_file_dialog"));
-
-  if (response_id == -5)
-  {
-    /* OK */
-    sb = GTK_SPIN_BUTTON (gtk_builder_get_object
-                          (ctx->open_file_builder,
-                           
"GNUNET_GTK_publish_file_dialog_expiration_year_spin_button"));
-
-    if (!GNUNET_GTK_get_selected_anonymity_level
-        (ctx->open_file_builder, 
"GNUNET_GTK_publish_file_dialog_anonymity_combobox",
-         &bo.anonymity_level))
-      bo.anonymity_level = 1;
-    bo.content_priority =
-        gtk_spin_button_get_value (GTK_SPIN_BUTTON
-                                   (gtk_builder_get_object
-                                    (ctx->open_file_builder,
-                                     
"GNUNET_GTK_publish_file_dialog_priority_spin_button")));
-    bo.expiration_time = GNUNET_FS_GTK_get_expiration_time (sb);
-    bo.replication_level =
-      gtk_spin_button_get_value (GTK_SPIN_BUTTON
-                                (gtk_builder_get_object
-                                 (ctx->open_file_builder,
-                                  
"GNUNET_GTK_publish_file_dialog_replication_spin_button")));
-    do_index =
-        gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
-                                      (gtk_builder_get_object
-                                       (ctx->open_file_builder,
-                                        
"GNUNET_GTK_publish_file_dialog_do_index_checkbutton")));
-
-    filename = GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER 
(ad));
-
-    scan_file_or_directory (ctx, filename, &bo, do_index);
-
-    g_free (filename);
-  }
-  else
-  {
-    /* Cancel/Escape/close/etc */
-  }
-  gtk_widget_destroy (ad);
-}
-
-
-void
-GNUNET_GTK_master_publish_dialog_add_button_clicked_cb (GtkWidget * dummy,
-                                                        struct 
MainPublishingDialogContext *ctx)
-{
-  GtkWidget *ad;
-
-  GtkComboBox *combo;
-  GtkTreeModel *anon_treemodel;
-
-  ctx->open_file_builder = GNUNET_GTK_get_new_builder 
("gnunet_fs_gtk_publish_file_dialog.glade", ctx);
-  GNUNET_FS_GTK_setup_expiration_year_adjustment (ctx->open_file_builder);
-  ad = GTK_WIDGET (gtk_builder_get_object
-                   (ctx->open_file_builder, "GNUNET_GTK_publish_file_dialog"));
-
-  /* FIXME: Use some kind of adjustable defaults instead of 1000, 0 and TRUE */
-  gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
-      ctx->open_file_builder,
-      "GNUNET_GTK_publish_file_dialog_priority_spin_button")), 1000);
-  gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
-      ctx->open_file_builder,
-      "GNUNET_GTK_publish_file_dialog_replication_spin_button")), 0);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (
-      ctx->open_file_builder,
-      "GNUNET_GTK_publish_file_dialog_do_index_checkbutton")), TRUE);
-
-  ctx->open_file_handler_id = g_signal_connect (G_OBJECT (ad), "response", 
G_CALLBACK (publish_file_dialog_response_cb), ctx);
-
-  anon_treemodel = GTK_TREE_MODEL (gtk_builder_get_object 
(ctx->main_window_builder,
-      "main_window_search_anonymity_liststore"));
-  combo = GTK_COMBO_BOX (gtk_builder_get_object (ctx->open_file_builder,
-      "GNUNET_GTK_publish_file_dialog_anonymity_combobox"));
-  gtk_combo_box_set_model (combo, anon_treemodel);
-
-  gtk_window_set_transient_for (GTK_WINDOW (ad), ctx->master_pubdialog);
-
-  gtk_window_present (GTK_WINDOW (ad));
-}
-
-
-struct EditPublishContext
-{
-  struct GNUNET_FS_FileInformation *fip;
-
-  GtkTreeModel *tm;
-
-  GtkTreeIter iter;
-};
-
-
-/**
- * Update tree view based on the information from the
- * GNUNET_FS_FileInformation publish-structure.
- *
- * @param cls closure, a 'struct EditPublishContext *'
- * @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_OK to continue, GNUNET_NO to remove
- *         this entry from the directory, GNUNET_SYSERR
- *         to abort the iteration
- */
-static int
-update_treeview_after_edit (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 EditPublishContext *epc = cls;
-  
-  gtk_tree_store_set (GTK_TREE_STORE (epc->tm), &epc->iter, 
-                     1, *do_index,
-                     3, (guint) bo->anonymity_level, 
-                     4, (guint) bo->content_priority, 
-                     6, (guint64) bo->expiration_time.abs_value,
-                     7, (guint) bo->replication_level,                 
-                     -1); 
-  return GNUNET_SYSERR;
-}
-
-
-/**
- * Function called when the edit publish dialog has been closed.
- *
- * @param cls closure
- * @param ret GTK_RESPONSE_OK if the dialog was closed with "OK"
- * @param root unused (namespace root name)
- */
-static void
-master_publish_edit_publish_dialog_cb (gpointer cls,
-                                      gint ret,
-                                       const char *root)
-{
-  struct EditPublishContext *cbargs = cls;
-
-  if (ret == GTK_RESPONSE_OK)
-    GNUNET_FS_file_information_inspect (cbargs->fip, 
&update_treeview_after_edit, cbargs);
-  GNUNET_free (cbargs);
-}
-
-
-void
-GNUNET_GTK_master_publish_dialog_edit_button_clicked_cb (GtkWidget * dummy,
-                                                         struct 
MainPublishingDialogContext *ctx)
-{
-  struct EditPublishContext *cbargs;
-  GtkListStore *anon_liststore;
-
-  anon_liststore = GTK_LIST_STORE (gtk_builder_get_object 
(ctx->main_window_builder, 
-                                                          
"main_window_search_anonymity_liststore"));
-  cbargs = GNUNET_malloc (sizeof (struct EditPublishContext));
-  cbargs->tm = ctx->file_info_treemodel;
-  if (! gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&cbargs->iter))
-  {
-    GNUNET_break (0);
-    GNUNET_free (cbargs);
-    return;
-  }
-  gtk_tree_model_get (ctx->file_info_treemodel, &cbargs->iter,
-                     5, &cbargs->fip, 
-                     -1);
-  /* FIXME: can we just give our anon_liststore out like this? What about
-     (unintended) sharing of state? */
-  GNUNET_FS_GTK_edit_publish_dialog (ctx->master_pubdialog, 
-                                     cbargs->fip, 
-                                    GNUNET_YES, 
-                                    anon_liststore,
-                                     &master_publish_edit_publish_dialog_cb,
-                                     cbargs);
-}
-
-
-/**
- * Free row reference stored in the file information's
- * client-info pointer.
- */
-static int
-free_fi_row_reference (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)
-{
-  GtkTreeRowReference *row = *client_info;
-
-  if (row == NULL)
-  {
-    GNUNET_break (0);
-    return GNUNET_OK;
-  }
-  gtk_tree_row_reference_free (row);
-  return GNUNET_OK;
-}
-
-
-void
-GNUNET_GTK_master_publish_dialog_delete_button_clicked_cb (GtkWidget * dummy,
-                                                           struct 
MainPublishingDialogContext *ctx)
-{
-  GtkTreeIter iter;
-  struct GNUNET_FS_FileInformation *fip;
-
-  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  gtk_tree_model_get (ctx->file_info_treemodel, &iter, 5, &fip, -1);
-  GNUNET_FS_file_information_destroy (fip, &free_fi_row_reference, NULL);
-  gtk_tree_store_remove (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
-  update_selectivity (ctx);
-}
-
-
-void
-GNUNET_FS_GTK_progress_dialog_cancel_button_clicked_cb (GtkButton *button,
-                                                       void *cls)
-{
-  struct AddDirClientContext *adcc = cls;
-
-  if (adcc->ds != NULL)
-  {
-    /* Still scanning - signal the scanner to finish */
-    GNUNET_FS_directory_scan_abort (adcc->ds);
-    adcc->ds = NULL;
-  }
-  close_scan (adcc);
-}
-
-
-gboolean
-GNUNET_FS_GTK_progress_dialog_delete_event_cb (GtkWidget *widget,
-                                              GdkEvent * event,
-                                              void *cls)
-{
-  /* Don't allow GTK to kill the window, until the scan is finished */
-  return GNUNET_NO;
-}
-
-
-void
-GNUNET_GTK_master_publish_dialog_open_button_clicked_cb (GtkWidget * dummy,
-                                                         struct 
MainPublishingDialogContext *ctx)
-{
-  GtkWidget *ad;
-
-  GtkComboBox *combo;
-  GtkTreeModel *anon_treemodel;
-
-  ctx->open_directory_builder = GNUNET_GTK_get_new_builder 
("gnunet_fs_gtk_publish_directory_dialog.glade", ctx);
-  GNUNET_FS_GTK_setup_expiration_year_adjustment (ctx->open_directory_builder);
-
-  /* FIXME: Use some kind of adjustable defaults instead of 1000, 0 and TRUE */
-  gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
-      ctx->open_directory_builder,
-      "GNUNET_GTK_publish_directory_dialog_priority_spin_button")), 1000);
-  gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
-      ctx->open_directory_builder,
-      "GNUNET_GTK_publish_directory_dialog_replication_spin_button")), 0);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (
-      ctx->open_directory_builder,
-      "GNUNET_GTK_publish_directory_dialog_do_index_checkbutton")), TRUE);
-
-  ad = GTK_WIDGET (gtk_builder_get_object
-                   (ctx->open_directory_builder, 
"GNUNET_GTK_publish_directory_dialog"));
-
-  ctx->open_directory_handler_id = g_signal_connect (G_OBJECT (ad), 
"response", G_CALLBACK (publish_directory_dialog_response_cb), ctx);
-
-  anon_treemodel = GTK_TREE_MODEL (gtk_builder_get_object 
(ctx->main_window_builder,
-      "main_window_search_anonymity_liststore"));
-  combo = GTK_COMBO_BOX (gtk_builder_get_object (ctx->open_directory_builder,
-      "GNUNET_GTK_publish_directory_dialog_anonymity_combobox"));
-  gtk_combo_box_set_model (combo, anon_treemodel);
-
-  gtk_window_set_transient_for (GTK_WINDOW (ad), ctx->master_pubdialog);
-
-  gtk_window_present (GTK_WINDOW (ad));
-}
-
-
-/**
- * Get the file information struct corresponding to the
- * given iter in the publish dialog tree model.  Recursively
- * builds the file information struct from the subtree.
- *
- * @param tm model to grab fi from
- * @param iter position to grab fi from
- * @return file information from the given position (never NULL)
- */
-static struct GNUNET_FS_FileInformation *
-get_file_information (GtkTreeModel * tm, GtkTreeIter * iter)
-{
-  struct GNUNET_FS_FileInformation *fi;
-  struct GNUNET_FS_FileInformation *fic;
-  GtkTreeIter child;
-
-  gtk_tree_model_get (tm, iter, 5, &fi, -1);
-  gtk_tree_store_set (GTK_TREE_STORE (tm), iter, 5, NULL, -1);
-  GNUNET_assert (fi != NULL);
-  if (gtk_tree_model_iter_children (tm, &child, iter))
-  {
-    GNUNET_break (GNUNET_YES == GNUNET_FS_file_information_is_directory (fi));
-    do
-    {
-      fic = get_file_information (tm, &child);
-      GNUNET_break (GNUNET_OK == GNUNET_FS_file_information_add (fi, fic));
-    }
-    while (gtk_tree_model_iter_next (tm, &child));
-  }
-  return fi;
-}
-
-
-/**
- * Closure for 'add_updateable_to_ts'.
- */
-struct UpdateableContext
-{
-  /**
-   * Parent of current insertion.
-   */
-  GtkTreeIter *parent;
-
-  /**
-   * Tree store we are modifying.
-   */
-  GtkTreeStore *ts;
-
-  /**
-   * Name of the namespace.
-   */
-  const char *namespace_name;
-
-  /**
-   * Handle to the namespace.
-   */
-  struct GNUNET_FS_Namespace *ns;
-
-  /**
-   * Hash codes of identifiers already added to tree store.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap *seen;
-
-  /**
-   * Did the iterator get called?
-   */
-  int update_called;
-};
-
-
-/**
- * Add updateable entries to the tree view.
- *
- * @param cls closure
- * @param last_id ID to add
- * @param last_uri associated URI
- * @param last_meta associate meta data
- * @param next_id ID for future updates
- */
-static void
-add_updateable_to_ts (void *cls, const char *last_id,
-                      const struct GNUNET_FS_Uri *last_uri,
-                      const struct GNUNET_CONTAINER_MetaData *last_meta,
-                      const char *next_id)
-{
-  struct UpdateableContext *uc = cls;
-  struct UpdateableContext sc;
-  GtkTreeIter iter;
-  GtkTreeIter titer;
-  char *desc;
-  GNUNET_HashCode hc;
-
-  uc->update_called = GNUNET_YES;
-  GNUNET_CRYPTO_hash (last_id, strlen (last_id), &hc);
-  if (NULL != GNUNET_CONTAINER_multihashmap_get (uc->seen, &hc))
-    return;
-  GNUNET_CONTAINER_multihashmap_put (uc->seen, &hc, "dummy",
-                                     
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
-  /* FIXME: what if this put fails?  Not convinced it cannot... */
-  desc =
-      GNUNET_CONTAINER_meta_data_get_first_by_types (last_meta,
-                                                     
EXTRACTOR_METATYPE_DESCRIPTION,
-                                                     EXTRACTOR_METATYPE_TITLE,
-                                                     
EXTRACTOR_METATYPE_BOOK_TITLE,
-                                                     
EXTRACTOR_METATYPE_FILENAME,
-                                                     
EXTRACTOR_METATYPE_SUMMARY,
-                                                     EXTRACTOR_METATYPE_ALBUM,
-                                                     
EXTRACTOR_METATYPE_COMMENT,
-                                                     
EXTRACTOR_METATYPE_SUBJECT,
-                                                     -1);
-  if (desc == NULL)
-    desc = GNUNET_strdup (_("no description supplied"));
-  else
-  {
-    char *utf8_desc = NULL;
-
-    utf8_desc =
-        GNUNET_FS_GTK_dubious_meta_to_utf8 (EXTRACTOR_METAFORMAT_UTF8, desc,
-                                            strlen (desc) + 1);
-    GNUNET_free (desc);
-    if (utf8_desc != NULL)
-      desc = utf8_desc;
-    else
-      desc = NULL;
-  }
-  gtk_tree_store_insert_with_values (uc->ts, &iter, uc->parent, G_MAXINT, 0,
-                                     uc->namespace_name, 1, uc->ns, 2, last_id,
-                                     3, GNUNET_FS_uri_dup (last_uri), 4,
-                                     GNUNET_CONTAINER_meta_data_duplicate
-                                     (last_meta), 5, "", 6, desc, 7,
-                                     TRUE /* update editable (always) */ ,
-                                     8, FALSE
-                                     /* current not editable (only for 
top-level) */
-                                     , -1);
-  GNUNET_free_non_null (desc);
-  sc.parent = &iter;
-  sc.ts = uc->ts;
-  sc.namespace_name = uc->namespace_name;
-  sc.ns = uc->ns;
-  sc.seen = uc->seen;
-  sc.update_called = GNUNET_NO;
-  GNUNET_FS_namespace_list_updateable (uc->ns, next_id, &add_updateable_to_ts,
-                                       &sc);
-  if ((sc.update_called == GNUNET_NO) && (next_id != NULL) &&
-      (strlen (next_id) > 0))
-  {
-    /* add leaf */
-    gtk_tree_store_insert_with_values (uc->ts, &titer, &iter, G_MAXINT, 0,
-                                       uc->namespace_name, 1, uc->ns, 2,
-                                       next_id, 3, NULL, 4, NULL, 5, "", 6, "",
-                                       7, TRUE /* update editable (always) */ ,
-                                       8, FALSE
-                                       /* current not editable (only for 
top-level) */
-                                       , -1);
-  }
-}
-
-
-/**
- * Add all updateable entries of the current namespace to the
- * tree store.
- *
- * @param cls the 'GtkTreeStore' to update
- * @param name name of the namespace to add
- * @param id identity of the namespace to add
- */
-static void
-add_namespace_to_ts (void *cls, const char *name, const GNUNET_HashCode * id)
-{
-  GtkTreeStore *ts = cls;
-  struct UpdateableContext uc;
-  GtkTreeIter iter;
-
-  uc.parent = &iter;
-  uc.namespace_name = name;
-  uc.ts = ts;
-  uc.ns = GNUNET_FS_namespace_create (GNUNET_FS_GTK_get_fs_handle (), name);
-  uc.update_called = GNUNET_NO;
-  gtk_tree_store_insert_with_values (ts, &iter, NULL, G_MAXINT, 0, name, 1,
-                                     uc.ns, 2, NULL /* last-id */ ,
-                                     3, NULL /* last-uri (as string!) */ ,
-                                     4, NULL /* meta */ ,
-                                     5, NULL /* next-ID */ ,
-                                     6, NULL /* last-description */ ,
-                                     7, TRUE /* update editable */ ,
-                                     8, TRUE /* current editable */ ,
-                                     -1);
-  uc.seen = GNUNET_CONTAINER_multihashmap_create (128);
-  GNUNET_FS_namespace_list_updateable (uc.ns, NULL, &add_updateable_to_ts, 
&uc);
-  GNUNET_CONTAINER_multihashmap_destroy (uc.seen);
-}
-
-
-static void
-free_pseudonym_tree_store (GtkTreeModel * tm, GtkTreeIter * iter)
-{
-  struct GNUNET_CONTAINER_MetaData *meta;
-  struct GNUNET_FS_Namespace *ns;
-  GtkTreeIter child;
-
-  gtk_tree_model_get (tm, iter, 1, &ns, 4, &meta, -1);
-  if (meta != NULL)
-    GNUNET_CONTAINER_meta_data_destroy (meta);
-  if (ns != NULL)
-  {
-    // FIXME: delete ns?
-    // GNUNET_FS_namespace_delete (nso, GNUNET_NO);
-  }
-  if (TRUE == gtk_tree_model_iter_children (tm, &child, iter))
-  {
-    do
-    {
-      free_pseudonym_tree_store (tm, &child);
-    }
-    while (TRUE == gtk_tree_model_iter_next (tm, &child));
-  }
-}
-
-
-static void
-free_file_information_tree_store (GtkTreeModel * tm, GtkTreeIter * iter)
-{
-  GtkTreeIter child;
-  struct GNUNET_FS_FileInformation *fip;
-
-  gtk_tree_model_get (tm, iter, 5, &fip, -1);
-  if (fip != NULL)
-    GNUNET_FS_file_information_destroy (fip, NULL, NULL);
-  if (TRUE == gtk_tree_model_iter_children (tm, &child, iter))
-  {
-    do
-    {
-      free_file_information_tree_store (tm, &child);
-    }
-    while (TRUE == gtk_tree_model_iter_next (tm, &child));
-  }
-}
-
-static int
-hide_master_publish_dialog (struct MainPublishingDialogContext *ctx, gint ret)
-{
-  GtkTreeIter iter;
-  gpointer namespace;
-  gchar *namespace_id;
-  gchar *namespace_uid;
-  struct GNUNET_FS_FileInformation *fi;
-
-  /* Don't close until all scanners are finished */
-  if (ctx->adddir_head != NULL)
-    return GNUNET_NO;
-
-  if (ret == GTK_RESPONSE_OK)
-  {
-    if (TRUE == gtk_tree_selection_get_selected (ctx->pseudonym_selection, 
NULL, &iter))
-    {
-      gtk_tree_model_get (ctx->pseudonym_treemodel, &iter, 1, &namespace, 2, 
&namespace_id, 5,
-                          &namespace_uid, -1);
-    }
-    else
-    {
-      namespace = NULL;
-      namespace_id = NULL;
-      namespace_uid = NULL;
-    }
-    if (gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &iter))
-      do
-      {
-        fi = get_file_information (ctx->file_info_treemodel, &iter);
-        /* FIXME: should we convert namespace id and uid from UTF8? */
-        GNUNET_FS_publish_start (GNUNET_FS_GTK_get_fs_handle (), fi, namespace,
-                                 namespace_id, namespace_uid,
-                                 GNUNET_FS_PUBLISH_OPTION_NONE);
-      }
-      while (gtk_tree_model_iter_next (ctx->file_info_treemodel, &iter));
-    g_free (namespace_id);
-    g_free (namespace_uid);
-  }
-
-  /* free state from 'ptm' */
-  if (TRUE == gtk_tree_model_get_iter_first (ctx->pseudonym_treemodel, &iter))
-    do
-    {
-      free_pseudonym_tree_store (ctx->pseudonym_treemodel, &iter);
-    }
-    while (TRUE == gtk_tree_model_iter_next (ctx->pseudonym_treemodel, &iter));
-  gtk_tree_store_clear (GTK_TREE_STORE (ctx->pseudonym_treemodel));
-
-  /* free state from 'tm' */
-  if (TRUE == gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &iter))
-    do
-    {
-      free_file_information_tree_store (ctx->file_info_treemodel, &iter);
-    }
-    while (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, &iter));
-  gtk_tree_store_clear (GTK_TREE_STORE (ctx->file_info_treemodel));
-  gtk_widget_destroy (GTK_WIDGET (ctx->master_pubdialog));
-  g_object_unref (G_OBJECT (ctx->builder));
-  GNUNET_free (ctx);
-  return GNUNET_YES;
-}
-
-
-void
-GNUNET_GTK_master_publish_dialog_execute_button_clicked_cb (GtkButton * button,
-                                                            struct 
MainPublishingDialogContext *ctx)
-{
-  hide_master_publish_dialog (ctx, GTK_RESPONSE_OK);
-}
-
-
-void
-GNUNET_GTK_master_publish_dialog_cancel_button_clicked_cb (GtkButton * button,
-                                                           struct 
MainPublishingDialogContext *ctx)
-{
-  hide_master_publish_dialog (ctx, GTK_RESPONSE_CANCEL);
-}
-
-
-gboolean
-GNUNET_GTK_master_publish_dialog_delete_event_cb (GtkWidget * widget,
-                                                  GdkEvent * event,
-                                                  struct 
MainPublishingDialogContext *ctx)
-{
-  if (GNUNET_NO == hide_master_publish_dialog (ctx, GTK_RESPONSE_CANCEL))
-    return TRUE;
-  return FALSE;
-}
-
-
-/**
- */
-void
-GNUNET_GTK_main_menu_file_publish_activate_cb (GtkWidget * dummy, gpointer 
user_data)
-{
-  struct MainPublishingDialogContext *ctx;
-
-  ctx = GNUNET_malloc (sizeof (struct MainPublishingDialogContext));
-  ctx->builder = GNUNET_GTK_get_new_builder 
("gnunet_fs_gtk_publish_dialog.glade", ctx);
-
-  if (ctx->builder == NULL)
-  {
-    GNUNET_free (ctx);
-    return;
-  }
-
-  init_ctx (ctx);
-  ctx->main_window_builder = GTK_BUILDER (user_data);
-  GNUNET_FS_namespace_list (GNUNET_FS_GTK_get_fs_handle (),
-                            &add_namespace_to_ts, GTK_TREE_STORE 
(ctx->pseudonym_treemodel));
-  gtk_window_present (GTK_WINDOW (ctx->master_pubdialog));
-}
-
-
-/* end of gnunet-fs-gtk-main_window_file_publish.c */

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_about.c (from rev 19624, 
gnunet-gtk/src/fs/gnunet-fs-gtk-about.c)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_about.c                             (rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_about.c     2012-02-02 13:28:32 UTC (rev 
19629)
@@ -0,0 +1,44 @@
+/*
+     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_about.c
+ * @author Christian Grothoff
+ * @author Igor Wronsky
+ *
+ * This file contains the about dialog.
+ */
+#include "gnunet_gtk.h"
+
+
+/**
+ * This displays an about window
+ *
+ * @param widget widget creating the event, unused
+ * @param data global builder, unused
+ */
+void
+GNUNET_GTK_main_menu_help_about_activate_cb (GtkWidget * dummy, gpointer data)
+{
+  GNUNET_GTK_display_about ("gnunet_fs_gtk_about_window.glade");
+}
+
+
+/* end of gnunet-fs-gtk-about.c */

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_anonymity-widgets.c (from rev 19625, 
gnunet-gtk/src/fs/gnunet-fs-gtk-anonymity_spin_buttons.c)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_anonymity-widgets.c                         
(rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_anonymity-widgets.c 2012-02-02 13:28:32 UTC 
(rev 19629)
@@ -0,0 +1,177 @@
+/*
+     This file is part of GNUnet
+     (C) 2005, 2006, 2010, 2012 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_anonymtiy-widgets.c
+ * @author Christian Grothoff
+ * @brief operations to manage user's anonymity level selections
+ */
+#include "gnunet-fs-gtk-common.h"
+#include "gnunet-fs-gtk-anonymity_spin_buttons.h"
+#include <gdk/gdk.h>
+
+/**
+ * Spin button is changed, update its color.  NOTE: This function will 
eventually
+ * become obsolete as we migrate to the drop-down style of anonymity-level 
selection.
+ *
+ * @param w the spin button that changed
+ * @param builder's closure, unused
+ */
+void
+GNUNET_GTK_anonymity_spin_button_value_changed_cb (GtkWidget * w, gpointer 
data)
+{
+#ifdef GdkRBGA
+  GtkSpinButton *spin;
+  gint val;
+  GdkRGBA bcolor;
+  GdkRGBA fcolor;
+
+  spin = GTK_SPIN_BUTTON (w);
+  if (spin == NULL)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  val = gtk_spin_button_get_value_as_int (spin);
+  if (val == 0)
+  {
+    if ((TRUE == gdk_rgba_parse (&bcolor, "red")) &&
+        (TRUE == gdk_rgba_parse (&fcolor, "black")))
+    {
+      gtk_widget_override_background_color (w, GTK_STATE_NORMAL, &bcolor);
+      gtk_widget_override_color (w, GTK_STATE_NORMAL, &fcolor);
+    }
+    else
+    {
+      GNUNET_break (0);
+    }
+  }
+  else
+  {
+    gtk_widget_override_background_color (w, GTK_STATE_NORMAL, NULL);
+    gtk_widget_override_color (w, GTK_STATE_NORMAL, NULL);
+  }
+#endif
+}
+
+
+/**
+ * Obtain the numeric anonymity level selected by a GtkComboBox.
+ *
+ * @param builder builder for looking up widgets
+ * @param combo_name name of the GtkComboBox with the anonymity selection
+ * @param p_level where to store the anonymity level
+ * @return TRUE on success, FALSE on failure
+ */
+gboolean
+GNUNET_GTK_get_selected_anonymity_level (GtkBuilder * builder,
+                                         gchar * combo_name, guint * p_level)
+{
+  GtkComboBox *combo;
+
+  combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, combo_name));
+  if (!combo)
+    return FALSE;
+  return GNUNET_GTK_get_selected_anonymity_combo_level (combo, p_level);
+}
+
+
+/**
+ * Obtain the numeric anonymity level selected by a GtkComboBox.
+ *
+ * @param combo the GtkComboBox with the anonymity selection
+ * @param p_level where to store the anonymity level
+ * @return TRUE on success, FALSE on failure
+ */
+gboolean
+GNUNET_GTK_get_selected_anonymity_combo_level (GtkComboBox *combo, guint 
*p_level)
+{
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  guint level;
+
+  if (! gtk_combo_box_get_active_iter (combo, &iter))
+    return FALSE;
+  model = gtk_combo_box_get_model (combo);
+  if (!model)
+    return FALSE;
+  gtk_tree_model_get (model, &iter, 1, &level, -1);
+  if (p_level)
+    *p_level = level;
+  return TRUE;
+}
+
+
+/**
+ * Set the anonymity level displayed by a combo box.
+ *
+ * @param builder the builder of the combo box
+ * @param combo_name name of the combo box
+ * @param sel_level desired anonymity level
+ * @return TRUE on success, FALSE on failure
+ */
+gboolean
+GNUNET_GTK_select_anonymity_level (GtkBuilder * builder, gchar * combo_name,
+                                   guint sel_level)
+{
+  GtkComboBox *combo;
+
+  combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, combo_name));
+  if (!combo)
+    return FALSE;
+  return GNUNET_GTK_select_anonymity_combo_level (combo, sel_level);
+}
+
+
+/**
+ * Set the anonymity level displayed by a combo box.
+ *
+ * @param combo the combo box
+ * @param sel_level desired anonymity level
+ * @return TRUE on success, FALSE on failure
+ */
+gboolean
+GNUNET_GTK_select_anonymity_combo_level (GtkComboBox *combo, guint sel_level)
+{
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  guint level;
+
+  model = gtk_combo_box_get_model (combo);
+  if (!model)
+    return FALSE;
+  if (! gtk_tree_model_get_iter_first (model, &iter))
+    return FALSE;
+  do
+  {
+    gtk_tree_model_get (model, &iter, 1, &level, -1);
+    if (level == sel_level)
+    {
+      gtk_combo_box_set_active_iter (combo, &iter);
+      return TRUE;
+    }
+  } 
+  while (gtk_tree_model_iter_next (model, &iter));
+  return FALSE;
+}
+
+
+
+/* end of gnunet-fs-gtk-anonymtiy_spin_buttons.c */

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_anonymity-widgets.h (from rev 19625, 
gnunet-gtk/src/fs/gnunet-fs-gtk-anonymity_spin_buttons.h)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_anonymity-widgets.h                         
(rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_anonymity-widgets.h 2012-02-02 13:28:32 UTC 
(rev 19629)
@@ -0,0 +1,80 @@
+/*
+     This file is part of GNUnet
+     (C) 2005, 2006, 2010, 2012 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_anonymtiy-widgets.h
+ * @author Christian Grothoff
+ * @brief operations to manage user's anonymity level selections
+ */
+#ifndef GNUNET_FS_GTK_ANONYMITY_SPIN_BUTTONS_H
+#define GNUNET_FS_GTK_ANONYMITY_SPIN_BUTTONS_H
+
+#include "gnunet-fs-gtk-common.h"
+#include <gdk/gdk.h>
+
+
+/**
+ * Obtain the numeric anonymity level selected by a GtkComboBox.
+ *
+ * @param builder builder for looking up widgets
+ * @param combo_name name of the GtkComboBox with the anonymity selection
+ * @param p_level where to store the anonymity level
+ * @return TRUE on success, FALSE on failure
+ */
+gboolean
+GNUNET_GTK_get_selected_anonymity_level (GtkBuilder * builder,
+                                         gchar * combo_name, guint * p_level);
+
+
+/**
+ * Obtain the numeric anonymity level selected by a GtkComboBox.
+ *
+ * @param combo the GtkComboBox with the anonymity selection
+ * @param p_level where to store the anonymity level
+ * @return TRUE on success, FALSE on failure
+ */
+gboolean
+GNUNET_GTK_get_selected_anonymity_combo_level (GtkComboBox *combo, guint 
*p_level);
+
+
+/**
+ * Set the anonymity level displayed by a combo box.
+ *
+ * @param builder the builder of the combo box
+ * @param combo_name name of the combo box
+ * @param sel_level desired anonymity level
+ * @return TRUE on success, FALSE on failure
+ */
+gboolean
+GNUNET_GTK_select_anonymity_level (GtkBuilder * builder, gchar * combo_name,
+                                   guint sel_level);
+
+
+/**
+ * Set the anonymity level displayed by a combo box.
+ *
+ * @param combo the combo box
+ * @param sel_level desired anonymity level
+ * @return TRUE on success, FALSE on failure
+ */
+gboolean
+GNUNET_GTK_select_anonymity_combo_level (GtkComboBox *combo, guint sel_level);
+
+#endif

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_common.c (from rev 19624, 
gnunet-gtk/src/fs/gnunet-fs-gtk-common.c)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_common.c                            (rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_common.c    2012-02-02 13:28:32 UTC (rev 
19629)
@@ -0,0 +1,234 @@
+/*
+     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/gnunet-fs-gtk_common.c
+ * @brief Common functions used in various places
+ * @author Christian Grothoff
+ */
+#include "gnunet-fs-gtk-common.h"
+
+/**
+ * Converts metadata specified by @data of size @data_len
+ * and saved in format @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 @data
+ * @param data data to convert
+ * @param data_len length of the 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. '<zlib>' 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 (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, 0, type, 1, format,
+                                    2, EXTRACTOR_metatype_to_string (type),
+                                    3, data_to_insert, -1);
+  GNUNET_free (data_to_insert); 
+  return 0;
+}
+
+
+/**
+ * Convert the year from the spin button to an expiration
+ * time (on midnight, January 1st of that year).
+ *
+ * @param spin button with an expiration year
+ * @return expiration time in the usual GNUnet format
+ */
+struct GNUNET_TIME_Absolute
+GNUNET_FS_GTK_get_expiration_time (GtkSpinButton * spin)
+{
+  struct GNUNET_TIME_Absolute ret;
+  int year;
+
+  year = gtk_spin_button_get_value_as_int (spin);
+  GNUNET_assert (year >= 0);
+  ret = GNUNET_FS_year_to_time ((unsigned int) year);
+  GNUNET_break (GNUNET_TIME_absolute_get ().abs_value < ret.abs_value);
+  return ret;
+}
+
+
+/**
+ * Initialize the 'expiration_year_adjustment' of the given
+ * builder to have a lower range of current-year+1 and a
+ * default of current-year+2.
+ *
+ * @param builder builder object for which we should manipulate
+ * the adjustment
+ */
+void
+GNUNET_FS_GTK_setup_expiration_year_adjustment (GtkBuilder * builder)
+{
+  GtkAdjustment *aj;
+  unsigned int year;
+
+  year = GNUNET_FS_get_current_year ();
+  aj = GTK_ADJUSTMENT (gtk_builder_get_object
+                       (builder, "expiration_year_adjustment"));
+  gtk_adjustment_set_value (aj, year + 2);
+  gtk_adjustment_set_lower (aj, year + 1);
+}
+
+
+/**
+ * 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 'dep'
+ */
+void
+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;
+
+  if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fsize, GNUNET_YES))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  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;
+  }
+  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;
+  }
+  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);
+  }
+  GNUNET_break (GNUNET_OK == GNUNET_DISK_file_unmap (mh));
+  GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh));
+}
+
+/* end of gnunet-fs-gtk-common.c */

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_common.h (from rev 19624, 
gnunet-gtk/src/fs/gnunet-fs-gtk-common.h)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_common.h                            (rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_common.h    2012-02-02 13:28:32 UTC (rev 
19629)
@@ -0,0 +1,126 @@
+/*
+     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/gnunet-fs-gtk_common.h
+ * @brief Common includes for all gnunet-gtk source files
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_FS_GTK_COMMON_H
+#define GNUNET_FS_GTK_COMMON_H
+
+#include "gnunet_gtk.h"
+#include <gnunet/gnunet_fs_service.h>
+#include <extractor.h>
+
+
+/**
+ * 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);
+
+
+/**
+ * Initialize the 'expiration_year_adjustment' of the given
+ * builder to have a lower range of current-year+1 and a
+ * default of current-year+2.
+ * FIXME: odd API...
+ *
+ * @param builder builder object for which we should manipulate
+ * the adjustment
+ */
+void
+GNUNET_FS_GTK_setup_expiration_year_adjustment (GtkBuilder * builder);
+
+
+/**
+ * Convert the year from the spin button to an expiration
+ * time (on midnight, January 1st of that year).
+ *
+ * @param spin button with the year
+ * @param time converted from the spin button
+ */
+struct GNUNET_TIME_Absolute
+GNUNET_FS_GTK_get_expiration_time (GtkSpinButton * spin);
+
+
+/**
+ * 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 'dep'
+ */
+void
+GNUNET_FS_GTK_mmap_and_scan (const char *filename,
+                             GNUNET_FS_DirectoryEntryProcessor dep,
+                             void *dep_cls);
+
+
+/**
+ * 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. '<zlib>' 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 (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);
+
+
+/**
+ * Converts metadata specified by @data of size @data_len
+ * and saved in format @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 @data
+ * @param data data to convert
+ * @param data_len length of the 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);
+
+
+#endif
+/* end of gnunet-fs-gtk-common.h */

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_download-save-as.c (from rev 19624, 
gnunet-gtk/src/fs/gnunet-fs-gtk-download.c)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_download-save-as.c                          
(rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_download-save-as.c  2012-02-02 13:28:32 UTC 
(rev 19629)
@@ -0,0 +1,295 @@
+/*
+     This file is part of GNUnet.
+     (C) 2010, 2011, 2012 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_download-save-as.c
+ * @brief functions for managing the 'save as' dialog 
+ * @author Christian Grothoff
+ */
+#include "gnunet-fs-gtk-download.h"
+#include "gnunet-fs-gtk.h"
+#include "gnunet-fs-gtk-event_handler.h"
+
+/**
+ * State for a 'save as' dialog of a download.
+ */
+struct DownloadAsDialogContext
+{
+
+  /**
+   * Download context for which this dialog determines the
+   * filename (and other options).
+   */
+  struct DownloadContext *dc;
+
+  /**
+   * Builder for the dialog.
+   */
+  GtkBuilder *builder;
+  
+  /**
+   * Main dialog object.
+   */
+  GtkWidget *dialog;
+
+  /**
+   * Final response code from the dialog.
+   */
+  gint response;
+};
+
+
+/**
+ * Free resources associated with the given download context.
+ *
+ * @param dc context to free
+ */
+static void
+save_as_dialog_free_download_context (struct DownloadContext *dc)
+{
+  if (NULL != dc->rr)
+    gtk_tree_row_reference_free (dc->rr);
+  GNUNET_free_non_null (dc->mime);
+  GNUNET_free_non_null (dc->filename);
+  if (NULL != dc->meta)
+    GNUNET_CONTAINER_meta_data_destroy (dc->meta);
+  if (NULL != dc->uri)
+    GNUNET_FS_uri_destroy (dc->uri);
+  GNUNET_free (dc);  
+}
+
+
+/**
+ * The 'save_as' dialog is being deleted.  Check which state we're in
+ * and either simply clean up or start the download with the
+ * respective options (by calling the respective continuation).
+ *
+ * @param widget the dialog object
+ * @param event the deletion event
+ * @param user_data the 'structDownloadAsDialogContext' of the dialog
+ * @return always FALSE
+ */
+gboolean
+GNUNET_GTK_save_as_dialog_delete_event_cb (GtkWidget * widget, GdkEvent * 
event,
+                                           gpointer user_data)
+{
+  struct DownloadAsDialogContext *dlc = user_data;
+  GtkBuilder *builder;
+  struct DownloadContext *dc;
+  GtkWidget *cb;
+
+  builder = dlc->builder;
+  dc = dlc->dc;
+  cb = GTK_WIDGET (gtk_builder_get_object
+                   (builder, "GNUNET_GTK_save_as_recursive_check_button"));
+  if (GTK_RESPONSE_OK != dlc->response)
+  {
+    save_as_dialog_free_download_context (dc);
+    g_object_unref (G_OBJECT (dlc->builder));
+    GNUNET_free (dlc);
+    return FALSE;
+  }
+  GNUNET_free_non_null (dc->filename);
+  dc->filename =
+      GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER 
(dlc->dialog));
+  dc->is_recursive =
+      (TRUE ==
+       gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cb))) ? GNUNET_YES :
+      GNUNET_NO;
+  dc->anonymity =
+      gtk_spin_button_get_value (GTK_SPIN_BUTTON
+                                 (gtk_builder_get_object
+                                  (builder,
+                                   
"GNUNET_GTK_save_as_dialog_anonymity_spin_button")));
+  g_object_unref (G_OBJECT (builder));
+  GNUNET_free (dlc);
+  GNUNET_FS_GTK_download_context_start_download (dc);
+  return FALSE;
+}
+
+
+/**
+ * The user clicked on the 'save as' button of the dialog.
+ * Delete the window and start the download.
+ *
+ * @param dialog the dialog object
+ * @param response_id response_id associated with the button
+ * @param user_data the 'structDownloadAsDialogContext' of the dialog
+ */
+void
+GNUNET_GTK_save_as_dialog_response_cb (GtkDialog * dialog, 
+                                      gint response_id,
+                                       gpointer user_data)
+{
+  struct DownloadAsDialogContext *dlc = user_data;
+
+  dlc->response = response_id;
+  /* dialogs don't get delete-event the way normal windows do,
+     call the handler manually */
+  GNUNET_GTK_save_as_dialog_delete_event_cb (GTK_WIDGET (dialog), NULL,
+                                             user_data);
+  /* FIXME-BUG-MAYBE: isn't the dialog going to be destroyed with the builder? 
+     Is this legal and/or required? */
+  gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+
+/**
+ * Open the 'save as' dialog for a download.  Calls the 'dc->cb'
+ * continutation when the dialog is complete.  Will release the 'dc'
+ * resources if the dialog is cancelled.
+ *
+ * @param dc download context for the file/directory 
+ */
+void
+GNUNET_FS_GTK_open_download_as_dialog (struct DownloadContext *dc)
+{
+  struct DownloadAsDialogContext *dlc;
+  GtkWidget *cb;
+
+  dlc = GNUNET_malloc (sizeof (struct DownloadAsDialogContext));
+  dlc->dc = dc;
+  dlc->builder =
+    GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_download_as_dialog.glade",
+                               dlc);
+  if (NULL == dlc->builder)
+  {
+    GNUNET_break (0);
+    save_as_dialog_free_download_context (dc);
+    GNUNET_free (dlc);
+    return;
+  }
+  dlc->dialog = GTK_WIDGET (gtk_builder_get_object
+                           (dlc->builder, "GNUNET_GTK_save_as_dialog"));
+
+  /* Enable recursive button for directories and
+     set recursive 'default' value based on what the 'dc' tells us */
+  cb = GTK_WIDGET (gtk_builder_get_object
+                   (dlc->builder, 
"GNUNET_GTK_save_as_recursive_check_button"));
+  if (GNUNET_FS_meta_data_test_for_directory (dc->meta))
+    gtk_widget_set_sensitive (cb, TRUE);  
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb),
+                               dc->is_recursive);   
+
+  /* initialize filename based on filename from 'dc' */
+  if (NULL != dc->filename)
+  {
+    char *dirname;
+    char *basename;
+
+    dirname = GNUNET_strdup (dc->filename);
+    basename = (char *) GNUNET_STRINGS_get_short_name (dirname);
+    /* basename now points into 'dirname'; cut 'dirname' off at the '/' before 
basename */
+    if (basename > dirname)
+      basename[-1] = '\0';
+
+    /* FIXME: remove following lines after testing... */
+    fprintf (stderr,
+            "Splitting `%s' into `%s' + `%s' for file chooser dialog.\n",
+            dc->filename,
+            dirname,
+            basename);
+
+    gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dlc->dialog), 
dirname);
+    gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dlc->dialog), 
basename);
+    GNUNET_free (dirname);
+  }
+  gtk_window_present (GTK_WINDOW (dlc->dialog));
+}
+
+
+/**
+ * Actually start the download that is specified by the given download
+ * context and its options.  Will add a download entry to the
+ * respective tree model and trigger a start of the download using the
+ * FS-API.
+ *
+ * @param dc download context of the download to execute
+ */
+void
+GNUNET_FS_GTK_download_context_start_download (struct DownloadContext *dc)
+{
+  enum GNUNET_FS_DownloadOptions opt;
+  struct GNUNET_FS_Handle *fs;
+  struct DownloadEntry *de;
+  uint64_t len;
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  de = GNUNET_malloc (sizeof (struct DownloadEntry));
+  de->uri = dc->uri;
+  dc->uri = NULL;
+  de->meta = dc->meta;
+  dc->meta = NULL;
+  if (NULL != dc->rr)
+  {
+    de->rr = gtk_tree_row_reference_copy (dc->rr);
+    de->ts = GTK_TREE_STORE (gtk_tree_row_reference_get_model (dc->rr));
+    path = gtk_tree_row_reference_get_path (de->rr);
+    if  ( (NULL != path) &&
+         (gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts), &iter, path)) )
+    {
+      /* Store filename and anonymity as specified by the user.
+       * These will be re-used when this is a directory, and the user
+       * downloads its children.
+       */
+      gtk_tree_store_set (de->ts, &iter, 15, dc->filename, 16, dc->anonymity, 
-1);
+    } 
+    else
+    {
+      /* We could not find the referenced row in the search tab; this is
+        conceivable as the search tab might have been closed by the 
+        user while the 'save as' dialog was open.  In this case, this
+        is equivalent to having no search, so we drop the (now invalid)
+        'sr' reference */
+      dc->sr = NULL;
+    }
+    if (NULL != path)
+      gtk_tree_path_free (path);
+  }
+  fs = GNUNET_FS_GTK_get_fs_handle ();
+  opt = GNUNET_FS_DOWNLOAD_OPTION_NONE;
+  if (dc->is_recursive)
+    opt |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE;
+  len = GNUNET_FS_uri_chk_get_file_size (dc->uri);
+  if (NULL != dc->sr)
+  {
+    GNUNET_break (NULL !=
+                  GNUNET_FS_download_start_from_search (fs, dc->sr,
+                                                        dc->filename,
+                                                        NULL /* tempname */ ,
+                                                        0 /* offset */ ,
+                                                        len, dc->anonymity, 
opt,
+                                                        de));
+  }
+  else
+  {
+    GNUNET_break (NULL !=
+                  GNUNET_FS_download_start (fs, de->uri, NULL /* meta */ ,
+                                            dc->filename, NULL /* tempname */ ,
+                                            0 /* offset */ ,
+                                            len, dc->anonymity, opt, de,
+                                            NULL /* parent download ctx */ ));
+  }
+  save_as_dialog_free_download_context (dc);
+}
+
+
+/* end of gnunet-fs-gtk-download.c */

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_download-save-as.h (from rev 19624, 
gnunet-gtk/src/fs/gnunet-fs-gtk-download.h)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_download-save-as.h                          
(rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_download-save-as.h  2012-02-02 13:28:32 UTC 
(rev 19629)
@@ -0,0 +1,117 @@
+/*
+     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/gnunet-fs-gtk_download-save-as.h
+ * @brief functions for downloading
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_FS_GTK_DOWNLOAD_SAVE_AS_H
+#define GNUNET_FS_GTK_DOWNLOAD_SAVE_AS_H
+
+#include "gnunet-fs-gtk-common.h"
+
+
+/**
+ * Information we keep for a download.
+ */
+struct DownloadContext;
+
+
+/**
+ * Information we keep for a download.
+ */
+struct DownloadContext
+{
+  /**
+   * URI for the download.
+   */
+  struct GNUNET_FS_Uri *uri;
+
+  /**
+   * Meta data.
+   */
+  struct GNUNET_CONTAINER_MetaData *meta;
+
+  /**
+   * Mime type.
+   */
+  char *mime;
+
+  /**
+   * Suggested filename, or NULL.
+   */
+  char *filename;
+
+  /**
+   * Row reference (if URI was found by search, or
+   * part of directory, etc.); otherwise NULL (download by URI).
+   */
+  GtkTreeRowReference *rr;
+
+  /**
+   * Associated search result, or NULL.
+   */
+  struct GNUNET_FS_SearchResult *sr;
+
+  /**
+   * Is this a recursive download?
+   */
+  int is_recursive;
+
+  /**
+   * Desired (default) anonymity level.
+   */
+  int anonymity;
+
+  /**
+   * Tab where this download is currently on display.
+   * (this is the same as sr->tab, but sr is opaque here).
+   */
+  struct SearchTab *tab;
+
+};
+
+
+/**
+ * Actually start the download that is specified by the given download
+ * context and its options.  Will add a download entry to the
+ * respective tree model and trigger a start of the download using the
+ * FS-API.
+ *
+ * @param dc download context of the download to execute
+ */
+void
+GNUNET_FS_GTK_download_context_start_download (struct DownloadContext *dc);
+
+
+/**
+ * Open the 'save as' dialog for a download.  Calls
+ * 'GNUNET_FS_GTK_download_context_start_download' when the dialog is
+ * complete.  Will release the 'dc' resources if the dialog is
+ * cancelled.
+ *
+ * @param dc download context for the file/directory 
+ */
+void
+GNUNET_FS_GTK_open_download_as_dialog (struct DownloadContext *dc);
+
+
+#endif

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_event-handler.c (from rev 19624, 
gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.c)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_event-handler.c                             
(rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_event-handler.c     2012-02-02 13:28:32 UTC 
(rev 19629)
@@ -0,0 +1,2658 @@
+/*
+     This file is part of GNUnet.
+     (C) 2010, 2011, 2012 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_event-handler.c
+ * @brief Main event handler for file-sharing
+ * @author Christian Grothoff
+ */
+#include "gnunet-fs-gtk.h"
+#include "gnunet-fs-gtk-download.h"
+#include "gnunet-fs-gtk-event_handler.h"
+#include <string.h>
+
+
+/**
+ * We have a single tab where we display publishing operations.
+ * So there is only one instance of this struct.
+ */ 
+struct PublishTab
+{
+
+  /**
+   * Frame for the tab.
+   */
+  GtkWidget *frame;
+
+  /**
+   * Associated builder.
+   */
+  GtkBuilder *builder;
+
+  /**
+   * Associated tree store.
+   */
+  GtkTreeStore *ts;
+};
+
+
+/**
+ * Information we keep for each file or directory being published.
+ * Used to quickly identify the tab and row of the operation; stored
+ * in the user-context of the FS library for the publish operation.
+ */
+struct PublishEntry
+{
+  /**
+   * Associated FS publish operation.
+   */
+  struct GNUNET_FS_PublishContext *pc;
+
+  /**
+   * Tab storing this entry.
+   */
+  struct PublishTab *tab;
+
+  /**
+   * Where in the tab is this entry?
+   */
+  GtkTreeRowReference *rr;
+
+  /**
+   * URI of the file (set after completion).
+   */
+  struct GNUNET_FS_Uri *uri;
+
+  /**
+   * Is this the top-level entry for the publish operation
+   * or sub-operation?
+   */
+  int is_top;
+};
+
+
+/**
+ * Information we keep for each search result entry in any search tab.
+ * An entry like this is also generated for downloads by-URI.  Used to
+ * quickly identify the tab and row of the result; stored in the
+ * user-context of the FS library for the search result.
+ */
+struct SearchResult
+{
+  /**
+   * Where in the tab is this result?
+   */
+  GtkTreeRowReference *rr;
+
+  /**
+   * Tab storing this result.
+   */
+  struct SearchTab *tab;
+
+  /**
+   * Search result for top-level results and
+   * namespace-update results.
+   */
+  struct GNUNET_FS_SearchResult *result;
+
+  /**
+   * Associated download, or NULL for none.
+   */
+  struct DownloadEntry *download;
+};
+
+
+
+/**
+ * Head of linked list of tabs for searches.
+ */
+static struct SearchTab *search_tab_head;
+
+/**
+ * Tail of linked list of tabs for searches.
+ */
+static struct SearchTab *search_tab_tail;
+
+/**
+ * Special tab we use to for downloads-by-URIs and downloads
+ * where the search tab has been closed ("parent lost").
+ */
+static struct SearchTab *uri_tab;
+
+/**
+ * Special tab we use to store publishing operations.
+ */
+static struct PublishTab *publish_tab;
+
+/**
+ * Row reference for the current search context menu.
+ * FIXME-UNCLEAN: de-globalize?
+ */
+static GtkTreeRowReference *current_context_row_reference;
+
+/**
+ * Search tab used for the current search context menu.
+ * FIXME-UNCLEAN: de-globalize?
+ */
+static struct SearchTab *current_context_search_tab;
+
+
+
+/* ***************** Search event handling ****************** */
+
+/**
+ * This should get the default download directory (so that GNUnet
+ * won't offer the user to download files to the 'bin' subdirectory,
+ * or whatever is the cwd).  Returns NULL on failure (such as
+ * non-existend directory).  Should also preserve the last setting (so
+ * if the user saves files somewhere else, next time we default to
+ * somewhere else, at least until application restart, or maybe even
+ * between application restarts).
+ *
+ * Fills the 'buffer' up to 'size' bytes, returns a pointer to it.
+ */
+static char *
+get_default_download_directory (char *buffer, size_t size)
+{
+  /* FIXME-FEATURE: implement... */
+  return NULL;
+}
+
+
+/**
+ * Called recursively to build a suggested filename by prepending
+ * suggested names for its parent directories (if any).
+ *
+ * @param tm tree model this function gets the data from
+ * @param iter current position in the tree, for which we want a suggested 
filename
+ * @param top GNUNET_YES for the original call to this function,
+ *            GNUNET_NO for recursive calls; used to decide if the
+ *            current call is eligible to set 'anonymity' and 'local_parents'
+ * @param local_parents set to GNUNET_YES if all parents are directories, and 
are downloaded.
+ * @param anonymity set to the anonymity level of the closest ancestor 
download (if any);
+ *                      set to "-1" for uninitialized initially (will be left 
at -1 if
+ *                      no suitable parent download was found)
+ * @param filename_is_absolute set to GNUNET_YES if the suggestion is an 
absolute filename,
+ *                             GNUNET_NO for relative filenames (gotten from 
meta data)
+ * @return suggested filename, possibly NULL
+ */
+static char *
+get_suggested_filename_anonymity (GtkTreeModel *tm, 
+                                 GtkTreeIter *iter, 
+                                 int top,
+                                 int *local_parents, 
+                                 int *anonymity, 
+                                 int *filename_is_absolute)
+{
+  char *result;
+  char *dirname;
+  char *local_filename;
+  char *filename;
+  int downloaded_anonymity;
+  int have_a_parent;
+  struct GNUNET_CONTAINER_MetaData *meta;
+  GtkTreeIter parent;
+  const char *basename; 
+  char *dot;
+
+  /* FIXME-BUG-MAYBE: this function is likely responsible for not always
+     suggesting the best filename... To be investigated some more... */
+  gtk_tree_model_get (tm, iter, 0, &meta, 
+                     15, &local_filename, 
+                     16, &downloaded_anonymity, 
+                     -1);
+  if ( (NULL == local_filename) && (GNUNET_NO == top) )
+    *local_parents = GNUNET_NO;
+  if ( (downloaded_anonymity != -1) && (*anonymity == -1) && (GNUNET_NO == 
top) )
+    *anonymity = downloaded_anonymity;
+  if (gtk_tree_model_iter_parent (tm, &parent, iter))
+  {
+    have_a_parent = GNUNET_YES;
+    dirname = get_suggested_filename_anonymity (tm, &parent, GNUNET_NO,
+                                               local_parents, anonymity, 
+                                               filename_is_absolute);
+  }
+  else
+  {
+    have_a_parent = GNUNET_NO;
+    dirname = NULL;
+    if (GNUNET_NO == top)
+      *local_parents = GNUNET_NO;
+  }
+  if (local_filename == NULL)
+  {
+    filename = GNUNET_FS_meta_data_suggest_filename (meta);
+  }
+  else
+  {
+    /* This directory was downloaded as /foo/bar/baz/somedirname
+     * Hopefully, "somedirname" is actually "somedir.gnd"
+     * We need to strip the ".gnd" part to get "somedir", which is
+     * what we're going to use instead of suggested original filename
+     * Without the .gnd extension we're going to just use a copy
+     * of the directory file name - and that would fail. Sad.
+     */
+    if ( (NULL == dirname) && (GNUNET_NO == have_a_parent))
+    {
+      /* This is the ealderlest parent directory. Use absolute path. */
+      basename = (const char *) local_filename;
+      *filename_is_absolute = GNUNET_YES;
+    }
+    else
+    {
+      basename = GNUNET_STRINGS_get_short_name (local_filename);
+    }
+    if ( (NULL != basename) && (strlen (basename) > 0) )
+    {
+      filename = GNUNET_strdup (basename);
+      dot = strrchr (filename, '.');
+      if (dot)
+        *dot = '\0';
+    }
+    else
+    {
+      filename = GNUNET_FS_meta_data_suggest_filename (meta);
+    }
+  }
+  if ( (NULL != dirname) && (NULL != filename) )
+  {
+    GNUNET_asprintf (&result, "%s%s%s", dirname, DIR_SEPARATOR_STR, filename);
+    GNUNET_free (filename);
+    GNUNET_free (dirname);
+    return result;
+  }
+  if (NULL != filename)
+    return filename;
+  return NULL;
+}
+
+
+/**
+ * This function is called when the user double-clicks on a search
+ * result.  Begins the download, if necessary by opening the "save as"
+ * window.
+ *
+ * @param tree_view tree view with the details
+ * @param path path selecting which entry we want to download
+ * @param tab the search tab where the user triggered the download request
+ * @param is_recursive was the request for a recursive download?
+ */
+static void
+start_download (GtkTreeView *tree_view, 
+               GtkTreePath *path,
+                struct SearchTab *tab,
+               int is_recursive)
+{
+  GtkTreeModel *tm;
+  GtkTreeIter iter;
+  struct GNUNET_FS_Uri *uri;
+  struct GNUNET_CONTAINER_MetaData *meta;
+  struct SearchResult *sr;
+  gchar *mime;
+  struct DownloadContext *dc;
+  char *buf = NULL;
+  char *tmp;
+  size_t tmplen;
+  char cwd[FILENAME_MAX];
+  char *download_directory;
+  char *filename;
+  int local_parents;
+  int have_a_suggestion;
+  int anonymity;
+  int filename_is_absolute;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Starting a %sdownload\n", 
+             is_recursive ? "recursive " : "");
+
+  GNUNET_assert (tab != 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);
+  if (NULL == uri)
+  {
+    /* user clicked on directory that was opened (not downloaded!), so we
+       have no URI and downloading makes no sense. Ignore! */
+    g_free (mime);
+    return;
+  }
+  if (!(GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri)))
+  {
+    /* can only download chk/loc URIs, ignore */
+    g_free (mime);
+    return;
+  }
+
+  download_directory = get_default_download_directory (cwd, sizeof (cwd));
+  /* If no download directory is known, try working directory */
+  if (download_directory == NULL)
+    download_directory = getcwd (cwd, sizeof (cwd));
+  /* Calculate suggested filename */
+  local_parents = GNUNET_YES;
+  anonymity = -1;
+  filename_is_absolute = GNUNET_NO;
+  filename = get_suggested_filename_anonymity (tm, &iter, GNUNET_YES,
+                                              &local_parents, &anonymity,
+                                              &filename_is_absolute);
+  have_a_suggestion = GNUNET_NO;
+  if (NULL != download_directory)
+  {
+    if (NULL == filename)
+    {
+      buf = GNUNET_strdup (download_directory);
+    }
+    else
+    {
+      have_a_suggestion = GNUNET_YES;
+      if (filename_is_absolute)
+        GNUNET_asprintf (&tmp, "%s", filename);
+      else
+        GNUNET_asprintf (&tmp, "%s%s%s",
+                        download_directory,
+                        DIR_SEPARATOR_STR,
+                        filename);
+      tmplen = strlen (tmp);
+      /* now, if we have a directory, replace trailing '/' with ".gnd" */
+      if (GNUNET_YES ==
+         GNUNET_FS_meta_data_test_for_directory (meta))
+      {
+       if ( (tmp[tmplen-1] == '/') ||
+            (tmp[tmplen-1] == '\\') )
+         tmp[tmplen-1] = '\0';
+       GNUNET_asprintf (&buf,
+                        "%s%s",
+                        tmp,
+                        GNUNET_FS_DIRECTORY_EXT);
+       GNUNET_free (tmp);           
+      }
+      else
+      {
+       buf = tmp;
+      }
+    }
+  }
+  GNUNET_free_non_null (filename);
+
+  /* now setup everything for the save-as dialog */
+  dc = GNUNET_malloc (sizeof (struct DownloadContext));
+  dc->uri = GNUNET_FS_uri_dup (uri);
+  dc->mime = mime;
+  dc->filename = buf;
+  dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
+  dc->rr = gtk_tree_row_reference_new (tm, path);
+  dc->sr = sr->result;
+  dc->anonymity = anonymity;
+  dc->is_recursive = is_recursive;
+  dc->tab = tab;
+  if ( (GNUNET_YES == local_parents) &&
+       (GNUNET_YES == have_a_suggestion) )
+    /* Skip the dialog, call directly */
+    GNUNET_FS_GTK_download_context_start_download (dc);
+  else
+    GNUNET_FS_GTK_open_download_as_dialog (dc);
+}
+
+
+/**
+ * An item was selected from the context menu; destroy the menu shell.
+ *
+ * @param menushell menu to destroy
+ * @parma user_data the 'struct DownloadEntry' for the menu (unused)
+ */
+static void
+search_list_popup_selection_done (GtkMenuShell *menushell,
+                                 gpointer user_data)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Item selected in menu shell %p, destroying it.\n",
+             menushell);
+  gtk_widget_destroy (GTK_WIDGET (menushell));
+}
+
+
+/**
+ * This function is called when the user double-clicks on a search
+ * result.  Begins the download, if necessary by opening the "save as"
+ * window.
+ *
+ * @param tree_view tree view with the details
+ * @param path path selecting which entry we want to download
+ * @param column unused entry specifying which column the mouse was in
+ * @param user_data the 'struct SearchTab' that was activated
+ */
+static void
+start_download_row_activated (GtkTreeView * tree_view, GtkTreePath * path,
+                             GtkTreeViewColumn * column, gpointer user_data)
+{
+  struct SearchTab *tab = user_data;
+
+  start_download (tree_view, path, tab, GNUNET_NO);
+}
+
+
+/**
+ * "Download" was selected in the current search context menu.
+ * 
+ * @param item the 'download' menu item
+ * @parma user_data the 'struct DownloadEntry' to download.
+ */
+static void
+start_download_ctx_menu (GtkMenuItem *item, gpointer user_data)
+{
+  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, current_context_search_tab, GNUNET_NO);
+  gtk_tree_path_free (path);
+  current_context_search_tab = NULL;
+}
+
+
+/**
+ * "Download recursively" was selected in the current search context menu.
+ * 
+ * @param item the 'download recursively' menu item
+ * @parma user_data the 'struct DownloadEntry' to download.
+ */
+static void
+start_download_recursively_ctx_menu (GtkMenuItem *item, gpointer user_data)
+{
+  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, current_context_search_tab, GNUNET_YES);
+  gtk_tree_path_free (path);
+  current_context_search_tab = NULL;
+}
+
+
+/**
+ * Download "abort" was selected in the current search context menu.
+ * 
+ * @param item the 'abort' menu item
+ * @parma user_data the 'struct DownloadEntry' to abort.
+ */
+static void
+abort_download_ctx_menu (GtkMenuItem *item, gpointer user_data)
+{
+  struct DownloadEntry *de = user_data;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Aborting download DE=%p\n", 
+             de);
+  GNUNET_assert (de->dc != NULL);
+  GNUNET_FS_download_stop (de->dc, GNUNET_YES);
+  current_context_search_tab = NULL;
+}
+
+
+/**
+ * Copy current URI to clipboard was selected in the current context menu.
+ * 
+ * @param item the 'copy-to-clipboard' menu item
+ * @parma user_data NULL
+ */
+static void
+copy_uri_to_clipboard_ctx_menu (GtkMenuItem *item, gpointer user_data)
+{
+  GtkTreePath *path;
+  GtkTreeView *tv;
+  GtkTreeModel *tm;
+  GtkTreeIter iter;
+  struct GNUNET_FS_Uri *uri;
+  char *uris;
+  GtkClipboard *cb;
+
+  if (NULL == current_context_row_reference)
+  {
+    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"));
+  tm = gtk_tree_view_get_model (tv);
+  if (! gtk_tree_model_get_iter (tm, &iter, path))
+  {
+    GNUNET_break (0);
+    gtk_tree_path_free (path);
+    return;
+  }
+  gtk_tree_model_get (tm, &iter, 1, &uri, -1);
+  gtk_tree_path_free (path);
+  current_context_search_tab = NULL;
+  if (uri == NULL)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  uris = GNUNET_FS_uri_to_string (uri);
+  cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+  gtk_clipboard_set_text (cb, uris, -1);
+  gtk_clipboard_store (cb);
+  GNUNET_free (uris);
+}
+
+
+/**
+ * Context menu was requested for a search result list.
+ * Compute which menu items are applicable and display
+ * an appropriate menu.
+ *
+ * @param tm tree model underlying the tree view where the event happened
+ * @param tab tab where the event happened
+ * @param event_button the event
+ * @return FALSE if no menu could be popped up,
+ *         TRUE if there is now a pop-up menu
+ */
+static gboolean
+search_list_popup (GtkTreeModel *tm, 
+                  struct SearchTab *tab, 
+                  gint init_button,
+                  guint32 event_time,
+                  GtkTreeIter *iter)
+{
+  GtkMenu *menu;
+  GtkWidget *child;
+  GtkTreePath *path;
+  struct SearchResult *sr;
+  struct GNUNET_FS_Uri *uri;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Creating a menu for SR=%p, DE=%p\n", 
+             sr,
+             sr->download);
+
+  /* FIXME-UNCLEAN: move these to some menu context struct
+     (de-globalize) */
+  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 = gtk_tree_model_get_path (tm, iter);
+  current_context_row_reference = gtk_tree_row_reference_new (tm, path);
+  gtk_tree_path_free (path);
+
+  gtk_tree_model_get (tm, iter, 1, &uri, 9, &sr, -1);
+
+  menu = GTK_MENU (gtk_menu_new ());
+  if ( (NULL == sr->download) &&
+       (NULL != uri) )
+  {
+    /* only display download menus if there is a URI */
+    child = gtk_menu_item_new_with_label (_("_Download"));
+    g_signal_connect (child, "activate",
+                     G_CALLBACK (start_download_ctx_menu), NULL);
+    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);
+    
+    child = gtk_menu_item_new_with_label (_("Download _recursively"));
+    g_signal_connect (child, "activate",
+                     G_CALLBACK (start_download_recursively_ctx_menu), NULL);
+    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);
+  }
+  if (NULL != sr->download)
+  {
+    child = gtk_menu_item_new_with_label (_("_Abort download"));
+    g_signal_connect (child, "activate",
+                      G_CALLBACK (abort_download_ctx_menu), sr->download);
+    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);
+  }
+  if (NULL != uri)
+  {
+    child = gtk_menu_item_new_with_label (_("_Copy URI to Clipboard"));
+    g_signal_connect (child, "activate",
+                     G_CALLBACK (copy_uri_to_clipboard_ctx_menu), NULL);
+    gtk_label_set_use_underline (GTK_LABEL
+                                (gtk_bin_get_child (GTK_BIN (child))), TRUE);
+    gtk_widget_show (child);
+  }
+  g_signal_connect (menu, "selection-done",
+                   G_CALLBACK (search_list_popup_selection_done), NULL);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), child);
+  gtk_menu_popup (menu, NULL, NULL, NULL, NULL, init_button, event_time);
+  return TRUE;
+}
+
+
+/**
+ * We got a 'popup-menu' event, display the context menu.
+ *
+ * @param widget the tree view where the event happened
+ * @param user_data the 'struct SearchTab' of the tree view
+ * @return FALSE if no menu could be popped up,
+ *         TRUE if there is now a pop-up menu
+ */
+static gboolean
+search_list_on_popup (GtkWidget *widget, gpointer user_data)
+{
+  GtkTreeView *tv = GTK_TREE_VIEW (widget);
+  struct SearchTab *tab = user_data;
+  GtkTreeSelection *sel;
+  GtkTreeIter iter;
+  GtkTreeModel *tm;
+
+  sel = gtk_tree_view_get_selection (tv);
+  if (! gtk_tree_selection_get_selected (sel, &tm, &iter))
+    return FALSE; /* nothing selected */
+  return search_list_popup (tm, tab, 0, gtk_get_current_event_time (), &iter);
+}
+
+
+/**
+ * We got a right-click on the search result list. Display the context
+ * menu.
+ *
+ * @param widget the GtkTreeView with the search result list
+ * @param event the event, we only care about button events
+ * @param user_data the 'struct SearchTab' the widget is in
+ * @return FALSE if no menu could be popped up,
+ *         TRUE if there is now a pop-up menu
+ */
+static gboolean
+search_list_on_menu (GtkWidget * widget, 
+                    GdkEvent * event,
+                    gpointer user_data)
+{
+  GtkTreeView *tv = GTK_TREE_VIEW (widget);
+  GdkEventButton *event_button = (GdkEventButton *) event;
+  struct SearchTab *tab = user_data;
+  GtkTreeModel *tm;
+  GtkTreePath *path;
+  GtkTreeIter iter;
+
+  if ( (event->type != GDK_BUTTON_PRESS) ||
+       (event_button->button != 3) )
+    return FALSE; /* not a right-click */
+  if (! gtk_tree_view_get_path_at_pos (tv,
+                                      event_button->x, event_button->y,
+                                       &path, NULL, NULL, NULL))
+    return FALSE; /* click outside of area with values, ignore */    
+  tm = gtk_tree_view_get_model (tv);
+  if (! gtk_tree_model_get_iter (tm, &iter, path))
+    return FALSE; /* not sure how we got a path but no iter... */  
+  gtk_tree_path_free (path);
+  return search_list_popup (tm, tab, 
+                           event_button->button,
+                           event_button->time,
+                           &iter);
+}
+
+
+/**
+ * Recalculate and update the label for a search, as we have
+ * received additional search results.
+ *
+ * @param tab search tab for which we should update the label
+ */
+static void
+update_search_label (struct SearchTab *tab)
+{
+  char *label_text;
+
+  while (tab->parent != NULL)
+    tab = tab->parent->tab;
+  if (tab->num_results > 0)
+    GNUNET_asprintf (&label_text, "%.*s%s (%u)", 20, tab->query_txt,
+                     strlen (tab->query_txt) > 20 ? "..." : "",
+                     tab->num_results);
+  else
+    GNUNET_asprintf (&label_text, "%.*s%s", 20, tab->query_txt,
+                     strlen (tab->query_txt) > 20 ? "..." : "");
+  gtk_label_set_text (tab->label, label_text);
+  gtk_widget_set_tooltip_text (GTK_WIDGET (tab->label), tab->query_txt);
+  GNUNET_free (label_text);
+}
+
+
+/**
+ * Close a search tab and free associated state.  Assumes that the
+ * respective tree model has already been cleaned up (this just
+ * updates the notebook and frees the 'tab' itself).
+ *
+ * @param tab search tab to close
+ */
+static void
+close_search_tab (struct SearchTab *tab)
+{
+  GtkNotebook *notebook;
+  int index;
+  int i;
+
+  if (tab->parent != NULL)
+  {
+    /* not a top-level search (namespace update search), do not close
+       tab here! */
+    GNUNET_free (tab);
+    return;
+  }
+  notebook =
+      GTK_NOTEBOOK (GNUNET_FS_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 (search_tab_head, search_tab_tail, tab);
+  if (tab == uri_tab)
+    uri_tab = NULL;
+  GNUNET_free (tab);
+}
+
+
+/**
+ * Free a particular search result and remove the respective
+ * entries from the respective tree store.  This function
+ * is called when a search is stopped to clean up the state
+ * of the tab.
+ *
+ * @param sr the search result to clean up
+ */
+static void
+free_search_result (struct SearchResult *sr)
+{
+  GtkTreePath *tp;
+  GtkTreeModel *tm;
+  GtkTreeIter iter;
+  struct GNUNET_FS_Uri *uri;
+  struct GNUNET_CONTAINER_MetaData *meta;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Freeing a search result SR=%p\n", 
+             sr);
+  if ( (NULL == sr) ||
+       (NULL == sr->rr) ||
+       (NULL == (tm = gtk_tree_row_reference_get_model (sr->rr))) ||
+       (NULL == (tp = gtk_tree_row_reference_get_path (sr->rr))) )
+  {
+    GNUNET_break (0);
+    return;
+  }
+  if (! gtk_tree_model_get_iter (tm, &iter, tp))
+  {
+    GNUNET_break (0);
+    gtk_tree_path_free (tp);
+    return;
+  }
+  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);
+  (void) gtk_tree_store_remove (GTK_TREE_STORE (tm), &iter);
+  GNUNET_free (sr);
+}
+
+
+/**
+ * Selected row has changed in search result tree view, update preview
+ * and metadata areas.
+ *
+ * @param tv the tree view in a search tab where the selection changed
+ * @param user_data the 'struct SearchTab' that contains the tree view
+ */
+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->query_txt != NULL);
+  image =
+      GTK_IMAGE (GNUNET_FS_GTK_get_main_window_object
+                 ("GNUNET_GTK_main_window_preview_image"));
+  ms = GTK_LIST_STORE (GNUNET_FS_GTK_get_main_window_object
+                       ("GNUNET_GTK_meta_data_list_store"));
+  sel = gtk_tree_view_get_selection (tv);
+  gtk_list_store_clear (ms);
+  if (! gtk_tree_selection_get_selected (sel, &model, &iter))
+  {
+    /* nothing selected, clear preview */
+    gtk_image_clear (image);
+    return;
+  }
+  meta = NULL;
+  pixbuf = NULL;
+  gtk_tree_model_get (model, &iter, 0, &meta, 3, &pixbuf, -1);
+  if (NULL != pixbuf)
+  {
+    gtk_image_set_from_pixbuf (image, pixbuf);
+    g_object_unref (G_OBJECT (pixbuf));
+  }
+  if (NULL != meta)  
+    GNUNET_CONTAINER_meta_data_iterate (meta,
+                                        
&GNUNET_FS_GTK_add_meta_data_to_list_store,
+                                        ms);
+}
+
+
+/**
+ * Page switched in main notebook, update thumbnail and
+ * metadata views.
+ *
+ * @param dummy widget emitting the event, unused
+ * @param data master Gtk builder, unused
+ */
+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_FS_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);
+  for (tab = search_tab_head; NULL != tab; tab = tab->next)
+  {
+    if (tab->frame != w)
+      continue;
+    tv = GTK_TREE_VIEW (gtk_builder_get_object
+                       (tab->builder, "_search_result_frame"));
+    update_meta_data_views (tv, tab);
+    return;
+  }
+  /* active tab is not a search tab (likely the 'publish' tab), 
+     clear meta data and preview widgets */
+  image =
+      GTK_IMAGE (GNUNET_FS_GTK_get_main_window_object
+                 ("GNUNET_GTK_main_window_preview_image"));
+  gtk_image_clear (image);
+  ms = GTK_LIST_STORE (GNUNET_FS_GTK_get_main_window_object
+                       ("GNUNET_GTK_meta_data_list_store"));
+  gtk_list_store_clear (ms);
+}
+
+
+/**
+ * User clicked on the 'close' button for a search tab.  Tell FS to stop the 
search.
+ *
+ * @param button the 'close' button
+ * @param user_data the 'struct SearchTab' of the tab to close
+ */
+static void
+stop_search (GtkButton *button, gpointer user_data)
+{
+  struct SearchTab *tab = user_data;
+  struct GNUNET_FS_SearchContext *sc;
+
+  sc = tab->sc;
+  if (NULL == sc)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  tab->sc = NULL;
+  GNUNET_FS_search_stop (sc);
+  gtk_widget_hide (GTK_WIDGET (button));
+  gtk_widget_hide (tab->pause_button);
+  gtk_widget_hide (tab->play_button);  
+}
+
+
+/**
+ * The user clicked on the 'pause' button for a search tab.  Tell FS to pause 
the search.
+ *
+ * @param button the 'pause' button
+ * @param user_data the 'struct SearchTab' of the tab to pause
+ */
+static void
+pause_search (GtkButton *button, gpointer user_data)
+{
+  struct SearchTab *tab = user_data;
+
+  if (NULL == tab->sc)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_FS_search_pause (tab->sc);
+  gtk_widget_show (tab->play_button);
+  gtk_widget_hide (tab->pause_button);
+}
+
+
+/**
+ * The user clicked on the 'resume' button for a search tab.  Tell FS to 
resume the search.
+ *
+ * @param button the 'resume' button
+ * @param user_data the 'struct SearchTab' of the tab to resume
+ */
+static void
+continue_search (GtkButton * button, gpointer user_data)
+{
+  struct SearchTab *tab = user_data;
+
+  if (NULL == tab->sc)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_FS_search_continue (tab->sc);
+  gtk_widget_show (tab->pause_button);
+  gtk_widget_hide (tab->play_button); 
+}
+
+
+/**
+ * User clicked on the 'clean' button of a search tab.
+ * Stop completed downloads (or those that failed).  Should
+ * iterate over the underlying tree store and stop all
+ * completed entries.  Furthermore, if the resulting tree
+ * store is empty and has no search associated with it,
+ * the tab should be closed.
+ *
+ * @param button the button pressed by the user
+ * @param user_data the 'struct SearchTab' of the respective tab to clean up
+ */
+static void
+clear_downloads (GtkButton * button, gpointer user_data)
+{
+  struct SearchTab *tab = user_data;
+  struct SearchResult *sr;
+  GtkTreeModel *tm;
+  GtkTreeIter iter;
+
+  tm = GTK_TREE_MODEL (tab->ts);
+  if (TRUE != gtk_tree_model_get_iter_first (tm, &iter))
+    return;
+  /* FIXME-BUG: this is a tree, what about cleaning up
+     of the children? */
+  do
+  {
+    gtk_tree_model_get (tm, &iter, 9, &sr, -1);
+    if ( (sr->download != NULL) &&
+        (sr->download->is_done == GNUNET_YES) )
+    {
+      /* got a finished download, stop it */
+      GNUNET_FS_download_stop (sr->download->dc, GNUNET_YES);
+    }
+    if ( (NULL == sr->download) &&
+        (NULL == sr->result) )
+    {
+      /* no active download and no associated FS-API search result;
+        so this must be some left-over entry from an opened 
+        directory; clean it up */
+      free_search_result (sr);
+    }
+  }
+  while (TRUE == gtk_tree_model_iter_next (tm, &iter));
+}
+
+
+/**
+ * We received a search error message from the FS library.
+ * Present it to the user in an appropriate form.
+ *
+ * @param tab search tab affected by the error
+ * @param emsg the error message
+ */
+static void
+handle_search_error (struct SearchTab *tab, 
+                    const char *emsg)
+{
+  gtk_label_set_text (tab->label, _("Error!"));
+  gtk_widget_set_tooltip_text (GTK_WIDGET (tab->label), emsg);
+}
+
+
+/**
+ * Obtain the string we will use to describe a search result from
+ * the respective meta data.
+ *
+ * @param meta meta data to inspect
+ * @return description of the result in utf-8, never NULL
+ */
+static char *
+get_description_from_metadata (const struct GNUNET_CONTAINER_MetaData *meta)
+{
+  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_FILENAME,
+                                                     
EXTRACTOR_METATYPE_DESCRIPTION,
+                                                     
EXTRACTOR_METATYPE_SUMMARY,
+                                                     EXTRACTOR_METATYPE_ALBUM,
+                                                     
EXTRACTOR_METATYPE_COMMENT,
+                                                     
EXTRACTOR_METATYPE_SUBJECT,
+                                                     
EXTRACTOR_METATYPE_KEYWORDS,
+                                                     -1);
+  if (desc == NULL)
+    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)
+    return GNUNET_strdup (_("no description supplied"));
+  return utf8_desc;
+}
+
+
+/**
+ * Obtain the mime type (or format description) will use to describe a search 
result from
+ * the respective meta data.
+ *
+ * @param meta meta data to inspect
+ * @return mime type to use, possibly NULL
+ */
+static char *
+get_mimetype_from_metadata (const struct GNUNET_CONTAINER_MetaData *meta)
+{
+  return GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
+                                                       
EXTRACTOR_METATYPE_MIMETYPE,
+                                                       
EXTRACTOR_METATYPE_FORMAT,
+                                                       -1);
+}
+
+
+/**
+ * Some additional information about a search result has been
+ * received.  Update the view accordingly.
+ *
+ * @param sr search result that is being updated
+ * @param meta updated meta data
+ * @param availability_rank updated availability information
+ * @param availability_certainty updated availability certainty
+ * @param applicability_rank updated applicability information
+ */
+static void
+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)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Updating search result SR=%p with %d, %u, %u\n",
+             sr, availability_rank,
+             availability_certainty, applicability_rank);
+  desc = get_description_from_metadata (meta);
+  mime = get_mimetype_from_metadata (meta);
+  pixbuf = GNUNET_FS_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 (NULL != ometa)
+    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_FS_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);
+  }
+}
+
+
+/**
+ * Add a search result to the given search tab.  This function is called 
+ * not only for 'normal' search results but also for directories that
+ * are being opened and if the user manually enters a URI.
+ *
+ * @param tab search tab to extend, never NULL
+ * @param iter set to position where search result is added (OUT only)
+ * @param parent_rr reference to parent entry in search tab, NULL for normal
+ *                  search results, 
+ * @param uri uri to add, can be NULL for top-level entry of a directory 
opened from disk
+ *                        (in this case, we don't know the URI and should 
probably not
+ *                         bother to calculate it)
+ * @param meta metadata of the entry
+ * @param result associated FS search result (can be NULL if this result
+ *                        was part of a directory)
+ * @param applicability_rank how relevant is the result
+ * @return struct representing the search result (also stored in the tree
+ *                model at 'iter')
+ */
+struct SearchResult *
+GNUNET_GTK_add_search_result (struct SearchTab *tab, 
+                             GtkTreeIter *iter,
+                              GtkTreeRowReference *parent_rr,
+                              const struct GNUNET_FS_Uri *uri,
+                              const struct GNUNET_CONTAINER_MetaData *meta,
+                              struct GNUNET_FS_SearchResult *result,
+                              uint32_t applicability_rank)
+{
+  struct SearchResult *sr;
+  GtkTreePath *tp;
+  const char *status_colour;
+  char *desc;
+  char *mime;
+  char *uris;
+  GdkPixbuf *pixbuf;
+  GtkTreeIter *pitr;
+  GtkTreeIter pmem;
+  GtkTreePath *path;
+  GtkTreeModel *tm;
+  GtkTreeStore *ts;
+  uint64_t fsize;
+
+  if (NULL == uri)
+  {
+    /* opened directory file */
+    fsize = 0;
+    status_colour = "gray";
+    mime = NULL; /* FIXME-FEATURE-MAYBE: should we set mime to directory? */
+    uris = GNUNET_strdup (_("no URI"));
+  }
+  else
+  {
+    if ( (GNUNET_FS_uri_test_loc (uri)) ||
+        (GNUNET_FS_uri_test_chk (uri)) )
+    {
+      fsize = GNUNET_FS_uri_chk_get_file_size (uri);
+      mime = get_mimetype_from_metadata (meta);
+      status_colour = "white";
+    }
+    else
+    {
+      /* FIXME-FEATURE-MAYBE: create mime type for namespaces? */
+      /* FIXME-BUG-MAYBE: can we encounter ksk URIs here too? */
+      fsize = 0;
+      mime = GNUNET_strdup ("GNUnet namespace"); 
+      status_colour = "lightgreen";
+    }
+    uris = GNUNET_FS_uri_to_string (uri);
+  }
+  desc = get_description_from_metadata (meta);
+  pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta);
+
+  sr = GNUNET_malloc (sizeof (struct SearchResult));
+  sr->result = result;
+  sr->tab = tab;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Allocated a search result SR=%p\n",
+             sr);
+  if (parent_rr != NULL)
+  {
+    /* get piter from parent */
+    path = gtk_tree_row_reference_get_path (parent_rr);
+    tm = gtk_tree_row_reference_get_model (parent_rr);
+    if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (tm), &pmem, path))
+    {
+      GNUNET_break (0);
+      gtk_tree_path_free (path);
+      /* desperate measure: make top-level entry */
+      pitr = NULL;
+    }
+    else
+    {
+      pitr = &pmem;
+    }
+    ts = GTK_TREE_STORE (tm);
+  }
+  else
+  {
+    /* top-level result */
+    pitr = NULL;
+    ts = tab->ts;
+  }
+  gtk_tree_store_insert_with_values (ts, iter, pitr, G_MAXINT, 
+                                    0, GNUNET_CONTAINER_meta_data_duplicate 
(meta), 
+                                    1, (uri == NULL) ? NULL : 
GNUNET_FS_uri_dup (uri), 
+                                    2, fsize, 
+                                    3, pixbuf /* preview */ ,
+                                     4, 0 /* percent progress */ ,
+                                     5, 0 /* percent availability */ ,
+                                     6, desc /* filename/description */ ,
+                                     7, uris, 
+                                    8, status_colour, 
+                                    9, sr, 
+                                    10, mime,
+                                     11, applicability_rank, 
+                                    12, 0 /* avail-cert */ ,
+                                     13, 0, /* avail-rank */
+                                     14, (guint64) 0, /* completed */
+                                     15, NULL, /* downloaded_filename */
+                                     16, -1, /* downloaded_anonymity */
+                                     -1);
+  if (pixbuf != NULL)
+    g_object_unref (pixbuf);
+  GNUNET_free (uris);
+  GNUNET_free (desc);
+  GNUNET_free_non_null (mime);
+
+  /* remember in 'sr' where we added the result */
+  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);
+
+  /* move up to the outermost tab, in case this is an 'inner'
+     search (namespace update case) */
+  while (tab->parent != NULL)
+    tab = tab->parent->tab;
+  tab->num_results++;
+  
+  return sr;
+}
+
+
+/**
+ * We have received a search result from the FS API.  Add it to the
+ * respective search tab.  The search result can be an 'inner'
+ * search result (updated result for a namespace search) or a
+ * top-level search result.  Update the tree view and the label
+ * of the search tab accordingly.
+ *
+ * @param tab the search tab where the new result should be added
+ * @param parent parent search result (if this is a namespace update result), 
or NULL
+ * @param uri URI of the search result
+ * @param meta meta data for the result
+ * @param result FS API handle to the result
+ * @param applicability_rank how applicable is the result to the query
+ * @return struct representing the search result (also stored in the tree
+ *                model at 'iter')
+ */
+static struct SearchResult *
+process_search_result (struct SearchTab *tab, 
+                      struct SearchResult *parent,
+                       const struct GNUNET_FS_Uri *uri,
+                       const struct GNUNET_CONTAINER_MetaData *meta,
+                       struct GNUNET_FS_SearchResult *result,
+                       uint32_t applicability_rank)
+{
+  struct SearchResult *sr;
+  GtkTreeIter iter;
+
+  sr = GNUNET_GTK_add_search_result (tab, &iter,
+                                     (parent != NULL) ? parent->rr : NULL,
+                                    uri,
+                                     meta, result, applicability_rank);
+  update_search_label (tab);
+  return sr;
+}
+
+
+/**
+ * Setup a new search tab.
+ *
+ * @param sc context with FS for the search, NULL for none (open-URI/orphan 
tab)
+ * @param query the query, NULL for none (open-URI/orphan tab)
+ * @return search tab handle
+ */
+static struct SearchTab *
+setup_search_tab (struct GNUNET_FS_SearchContext *sc,
+                 const struct GNUNET_FS_Uri *query)
+{
+  struct SearchTab *tab;
+  GtkTreeView *tv;
+  GtkNotebook *notebook;
+  GtkWindow *sf;
+  gint pages;
+
+  tab = GNUNET_malloc (sizeof (struct SearchTab));
+  GNUNET_CONTAINER_DLL_insert (search_tab_head, search_tab_tail, tab);
+  tab->sc = sc;
+  if (query == NULL)
+  {
+    /* no real query, tab is for non-queries, use special label */
+    tab->query_txt = GNUNET_strdup ("*");
+  }
+  else
+  {
+    /* FS_uri functions should produce UTF-8, so let them be */
+    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 ("gnunet_fs_gtk_search_tab.glade",
+                                            tab);
+  tab->ts =
+      GTK_TREE_STORE (gtk_builder_get_object
+                      (tab->builder,
+                       "GNUNET_GTK_file_sharing_result_tree_store"));
+  /* load frame */
+  sf = GTK_WINDOW (gtk_builder_get_object
+                   (tab->builder, "_search_result_frame_window"));
+  tab->frame = gtk_bin_get_child (GTK_BIN (sf));
+  g_object_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));
+  g_object_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"));
+
+  /* FIXME-UNCLEAN: connect these signals using glade!!! */
+  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->clear_button =
+      GTK_WIDGET (gtk_builder_get_object
+                  (tab->builder, "_search_result_label_clear_button"));
+  g_signal_connect (G_OBJECT (tab->clear_button), "clicked",
+                    G_CALLBACK (clear_downloads), 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; FIXME-UNCLEAN: again, connect these with glade...  */
+  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_row_activated), 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);
+  g_signal_connect (G_OBJECT (tv), "popup-menu",
+                    G_CALLBACK (search_list_on_popup), tab);
+
+
+  /* make visible */
+  notebook =
+      GTK_NOTEBOOK (GNUNET_FS_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;
+}
+
+
+/**
+ * Setup an "inner" search, that is a subtree representing namespace
+ * 'update' results.  We use a 'struct SearchTab' to represent this
+ * sub-search.  In the GUI, the presentation is similar to search
+ * results in a directory, except that this is for a namespace search
+ * result that gave pointers to an alternative keyword to use and this
+ * is the set of the results found for this alternative keyword.
+ *
+ * All of the 'widget' elements of the returned 'search tab' reference
+ * the parent search.  The whole construction is essentially a trick
+ * to allow us to store the FS-API's 'SearchContext' somewhere and to
+ * find it when we get this kind of 'inner' search results (so that we
+ * can then place them in the tree view in the right spot).
+ *
+ * FIXME-BUG-MAYBE: don't we need a bit more information then? Like exactly 
where
+ * this 'right spot' is?  Not sure how just having 'sc' helps there,
+ * as it is not a search result (!) to hang this up on!  This might
+ * essentially boil down to an issue with the FS API, not sure...
+ *
+ * @param sc context with FS for the search
+ * @param parent parent search tab
+ * @return struct representing the search result (also stored in the tree
+ *                model at 'iter')
+ */
+static struct SearchTab *
+setup_inner_search (struct GNUNET_FS_SearchContext *sc,
+                    struct SearchResult *parent)
+{
+  struct SearchTab *ret;
+
+  ret = GNUNET_malloc (sizeof (struct SearchTab));
+  ret->parent = parent;
+  ret->sc = sc;
+  ret->query_txt = parent->tab->query_txt;
+  ret->builder = parent->tab->builder;
+  ret->frame = parent->tab->frame;
+  ret->tab_label = parent->tab->tab_label;
+  ret->close_button = parent->tab->close_button;
+  ret->clear_button = parent->tab->clear_button;
+  ret->play_button = parent->tab->play_button;
+  ret->label = parent->tab->label;
+
+  return ret;
+}
+
+
+/**
+ * Setup a new top-level entry in the URI/orphan tab.  If necessary, create
+ * the URI tab first.
+ *
+ * @param iter set to the new entry (OUT only)
+ * @param srp set to search result (can be NULL)
+ * @param meta metadata for the new entry
+ * @param uri URI for the new entry
+ * @return the 'uri_tab' the result was added to
+ */
+struct SearchTab *
+GNUNET_GTK_add_to_uri_tab (GtkTreeIter *iter, struct SearchResult **srp,
+                           const struct GNUNET_CONTAINER_MetaData *meta,
+                           const struct GNUNET_FS_Uri *uri)
+{
+  struct SearchResult *sr;
+  GtkNotebook *notebook;
+  gint page;
+
+  if (NULL == uri_tab)
+  {
+    uri_tab = setup_search_tab (NULL, NULL);
+    gtk_widget_set_visible (uri_tab->close_button, FALSE);
+    gtk_widget_set_visible (uri_tab->pause_button, FALSE);
+  }
+  /* make 'uri_tab' the current page */
+  notebook =
+    GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
+                 ("GNUNET_GTK_main_window_notebook"));
+  for (page = 0; page < gtk_notebook_get_n_pages (notebook); page++)
+    if (uri_tab->frame == gtk_notebook_get_nth_page (notebook, page))
+    {
+      gtk_notebook_set_current_page (notebook, page);
+      break;
+    }
+  sr = GNUNET_GTK_add_search_result (uri_tab, iter, NULL, uri, meta, NULL, 0);
+  if (NULL != srp)
+    *srp = sr;
+  return uri_tab;
+}
+
+
+
+/* ***************** Download event handling ****************** */
+
+
+
+/**
+ * Change the (background) color of the given download entry.
+ *
+ * @param de entry to change 
+ * @param color name of the color to use
+ */
+static void
+change_download_color (struct DownloadEntry *de, 
+                       const char *color)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
+             "Changing download DE=%p color to %s\n", 
+             de, color);
+  path = gtk_tree_row_reference_get_path (de->rr);
+  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts), &iter, path))
+  {
+    GNUNET_break (0);
+    gtk_tree_path_free (path);
+    return;
+  }
+  gtk_tree_path_free (path);
+  gtk_tree_store_set (de->ts, &iter, 8, color, -1);
+}
+
+
+/**
+ * A download operation was stopped.  Remove all state associated with
+ * it and reset the search result's background color to 'white'.
+ *
+ * @param de the download that was stopped
+ */
+static void
+stop_download (struct DownloadEntry *de)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+  GtkTreeModel *tm;
+  struct SearchResult *search_result;
+
+  tm = gtk_tree_row_reference_get_model (de->rr);
+  path = gtk_tree_row_reference_get_path (de->rr);
+  if (! gtk_tree_model_get_iter (tm, &iter, path))
+  {
+    gtk_tree_path_free (path);
+    GNUNET_break (0);
+    return;
+  }
+  gtk_tree_path_free (path);
+  gtk_tree_model_get (tm, &iter, 9, &search_result, -1);
+  GNUNET_assert (search_result->download == de); 
+  search_result->download = NULL;
+  change_download_color (de, "white");
+  gtk_tree_row_reference_free (de->rr);
+  GNUNET_FS_uri_destroy (de->uri);
+  GNUNET_CONTAINER_meta_data_destroy (de->meta);
+  GNUNET_free (de);
+}
+
+
+/**
+ * Closure for 'add_directory_entry'.
+ */
+struct AddDirectoryEntryContext
+{
+
+  /**
+   * Search tab where we need to expand the result list.
+   */
+  struct SearchTab *tab;
+
+  /**
+   * Row reference of parent (the directory).
+   */
+  GtkTreeRowReference *prr;
+
+  /**
+   * Do we need to check if the given entry already exists to
+   * avoid adding it twice?  Set to YES if 'add_directory_entry'
+   * is called upon directory completion (so we might see all
+   * entries again) and to NO if this is the initial download
+   * and we're calling during a 'PROGRESS' event.
+   */
+  int check_duplicates;
+
+};
+
+
+/**
+ * Function used to process entries in a directory.  Whenever we
+ * download a directory, this function is called on the entries in the
+ * directory to add them to the search tab.  Note that the function
+ * maybe called twice for the same entry, once during incremental
+ * processing and later once more when we have the complete directory.
+ *
+ * For the second round, the 'check_duplicates' flag will be set in
+ * the closure.  If called on an entry that already exists, the
+ * function should simply do nothing.
+ *
+ * @param cls closure, our 'struct AddDirectoryEntryContext*'
+ * @param filename name of the file in the directory
+ * @param uri URI of the file, NULL for the directory itself
+ * @param metadata metadata for the file; metadata for
+ *        the directory if everything else is NULL/zero
+ * @param length length of the available data for the file
+ *           (of type size_t since data must certainly fit
+ *            into memory; if files are larger than size_t
+ *            permits, then they will certainly not be
+ *            embedded with the directory itself).
+ * @param data data available for the file (length bytes)
+ */
+static void
+add_directory_entry (void *cls, const char *filename,
+                     const struct GNUNET_FS_Uri *uri,
+                     const struct GNUNET_CONTAINER_MetaData *meta,
+                     size_t length, const void *data)
+{
+  struct AddDirectoryEntryContext *ade = cls;
+  GtkTreeIter iter;
+  GtkTreeIter piter;
+  GtkTreePath *path;
+  GtkTreeModel *tm;
+  struct GNUNET_FS_Uri *xuri;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
+             "Adding directory entry `%s'\n", 
+             filename);
+
+  if (NULL == uri)
+  {
+    /* directory meta data itself */
+    /* FIXME-FEATURE-MAYBE: consider merging it with the meta data from
+       the original search result... */
+    return;
+  }
+  if (ade->check_duplicates == GNUNET_YES)
+  {
+    tm = gtk_tree_row_reference_get_model (ade->prr);
+    path = gtk_tree_row_reference_get_path (ade->prr);
+    if (! gtk_tree_model_get_iter (tm, &piter, path)) 
+    {
+      GNUNET_break (0);
+      gtk_tree_path_free (path);
+      return;
+    }
+    gtk_tree_path_free (path);
+    if (TRUE == gtk_tree_model_iter_children (tm, &iter, &piter))
+    {
+      do
+      {
+        gtk_tree_model_get (tm, &iter, 1, &xuri, -1);
+        if (GNUNET_YES == GNUNET_FS_uri_test_equal (xuri, uri))
+          return;               /* already present */
+      }
+      while (TRUE == gtk_tree_model_iter_next (tm, &iter));
+    }
+  }
+  GNUNET_GTK_add_search_result (ade->tab, &iter, ade->prr, uri, meta, NULL,
+                                0);
+}
+
+
+/**
+ * We got an event that some download is progressing.  Update the tree
+ * model accordingly.  If the download is a directory, try to display
+ * the contents.
+ *
+ * @param de download entry that is progressing
+ * @param size overall size of the download
+ * @param completed number of bytes we have completed
+ * @param block_data current block we've downloaded
+ * @param offset offset of block_data in the overall file
+ * @param block_size number of bytes in block_data
+ * @param depth depth of the block in the ECRS tree
+ */
+static void
+mark_download_progress (struct DownloadEntry *de, uint64_t size,
+                        uint64_t completed, const void *block_data,
+                        uint64_t offset, uint64_t block_size,
+                        unsigned int depth)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Marking download progress for DE=%p, %llu/%llu, address@hidden 
depth=%u\n",
+             de, completed, size, block_size, offset, depth);
+
+  path = gtk_tree_row_reference_get_path (de->rr);
+  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts), &iter, path))
+  {
+    GNUNET_break (0);
+    gtk_tree_path_free (path);
+    return;
+  }
+  gtk_tree_path_free (path);
+  /* FIXME-FEATURE: update availability-score here as well! */
+  gtk_tree_store_set (de->ts, &iter, 
+                     4, (guint) ((size >
+                                  0) ? (100 * completed /
+                                        size) : 100) /* progress */ ,
+                      14, completed, 
+                     -1);
+  if ( (depth == 0) &&
+       (block_size > 0) &&
+       (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (de->meta)) )
+  {
+    /* got a data block of a directory, list its contents */
+    struct AddDirectoryEntryContext ade;
+
+    ade.tab = de->tab;
+    ade.prr = de->rr;
+    ade.check_duplicates = GNUNET_NO;
+    if (GNUNET_SYSERR ==
+        GNUNET_FS_directory_list_contents ((size_t) block_size, block_data,
+                                           offset, &add_directory_entry, &ade))
+    {
+      /* Mime type was wrong, this is not a directory, update model! */
+      GNUNET_break (GNUNET_OK ==
+                   GNUNET_CONTAINER_meta_data_delete (de->meta,
+                                                      
EXTRACTOR_METATYPE_MIMETYPE, NULL, 0));
+      gtk_tree_store_set (de->ts, &iter, 
+                         10, "" /* unknown mime type */, -1);
+    }
+  }
+}
+
+
+/**
+ * FS-API encountered an error downloading a file.  Update the
+ * view accordingly.
+ *
+ * @param de download that had an error
+ * @param emsg error message to display
+ */
+static void
+mark_download_error (struct DownloadEntry *de,
+                    const char *emsg)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  change_download_color (de, "red");
+  de->is_done = GNUNET_YES;
+  path = gtk_tree_row_reference_get_path (de->rr);
+  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (de->tab->ts), &iter, path))
+  {
+    GNUNET_break (0);
+    gtk_tree_path_free (path);
+    return;
+  }
+  gtk_tree_path_free (path);
+  gtk_tree_store_set (de->tab->ts, &iter, 4, 0, 7, emsg, -1);
+}
+
+
+/**
+ * FS-API notified us that we're done with a download.  Update the
+ * view accordingly. If the download is a directory, try to display
+ * the contents.
+ *
+ * @param de download that has finished
+ * @param size overall size of the file
+ * @param filename name of the downloaded file on disk (possibly a temporary 
file)
+ */
+static void
+mark_download_completed (struct DownloadEntry *de, uint64_t size,
+                         const char *filename)
+{
+  struct AddDirectoryEntryContext ade;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Marking download completed for DE=%p, %llu-byte `%s'\n",
+             de, size, filename);
+
+  de->is_done = GNUNET_YES;
+  mark_download_progress (de, size, size, NULL, 0, 0, 0);
+  if ( (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (de->meta)) &&
+       (filename != NULL) )
+  {
+    /* download was for a directory (and we have a temp file for scanning);
+       add contents of the directory to the view */
+    ade.tab = de->tab;
+    ade.prr = de->rr;
+    ade.check_duplicates = GNUNET_YES;
+    GNUNET_FS_GTK_mmap_and_scan (filename, &add_directory_entry, &ade);
+  }
+  change_download_color (de, "green");
+}
+
+
+/**
+ * Copy all of the children of 'src_iter' from the 'src_model' to
+ * become children of 'dst_iter' in the 'dst_model'.  The models are
+ * both 'GNUNET_GTK_file_sharing_result_tree_store' models.
+ *
+ * Note that we also need to update the 'struct SearchResult'
+ * and (if it exists) the respective 'struct DownloadEntry'
+ * to refer to the new model.
+ *
+ * @param src_model source model
+ * @param src_iter parent of the nodes to move 
+ * @param dst_model destination model
+ * @param dst_iter new parent of the entries we are moving
+ */
+static void
+copy_children (GtkTreeModel * src_model, GtkTreeIter * src_iter,
+               GtkTreeModel * dst_model, GtkTreeIter * dst_iter)
+{
+  GtkTreeIter src_child;
+  GtkTreeIter dst_child;
+  GtkTreePath *path;
+  struct GNUNET_CONTAINER_MetaData *meta;
+  struct GNUNET_FS_Uri *uri;
+  guint64 filesize, completed;
+  GdkPixbuf *preview;
+  guint percent_progress;
+  guint percent_availability;
+  gchar *filename;
+  gchar *uri_as_string;
+  gchar *status_colour;
+  struct SearchResult *search_result;
+  gchar *mimetype;
+  guint applicability_rank;
+  guint availability_certainty;
+  gint availability_rank;
+  gchar *downloaded_filename;
+  gint downloaded_anonymity;
+
+  if (! gtk_tree_model_iter_children (src_model, &src_child, src_iter))
+    return;
+  do
+  {
+    gtk_tree_model_get (src_model, &src_child, 0, &meta, 1, &uri, 2,
+                       &filesize, 3, &preview, 4, &percent_progress, 5,
+                       &percent_availability, 6, &filename, 7,
+                       &uri_as_string, 8, &status_colour, 9, &search_result,
+                       10, &mimetype, 11, &applicability_rank, 12,
+                       &availability_certainty, 13, &availability_rank, 14,
+                       &completed, 15, &downloaded_filename, 16,
+                       &downloaded_anonymity, -1);
+    gtk_tree_store_insert_with_values (GTK_TREE_STORE (dst_model), &dst_child,
+                                      dst_iter, G_MAXINT, 0, meta, 1, uri, 2,
+                                      filesize, 3, preview, 4,
+                                      percent_progress, 5,
+                                      percent_availability, 6, filename, 7,
+                                      uri_as_string, 8, status_colour, 9,
+                                      search_result, 10, mimetype, 11,
+                                      applicability_rank, 12,
+                                      availability_certainty, 13,
+                                      availability_rank, 14, completed, 15,
+                                      downloaded_filename, 16,
+                                      downloaded_anonymity, -1);
+    g_free (filename);
+    g_free (downloaded_filename);
+    g_free (uri_as_string);
+    g_free (status_colour);
+    g_free (mimetype);
+    if (preview != NULL)
+      g_object_unref (preview);
+    gtk_tree_row_reference_free (search_result->rr);
+    path = gtk_tree_model_get_path (dst_model, &dst_child);
+    search_result->rr = gtk_tree_row_reference_new (dst_model, path);
+    search_result->result = NULL;
+    gtk_tree_path_free (path);
+    if (search_result->download != NULL)
+    {
+      search_result->download->ts = GTK_TREE_STORE (dst_model);
+      gtk_tree_row_reference_free (search_result->download->rr);
+      search_result->download->rr =
+       gtk_tree_row_reference_copy (search_result->rr);
+    }
+    copy_children (src_model, &src_child, dst_model, &dst_child);
+  }
+  while (TRUE == gtk_tree_model_iter_next (src_model, &src_child));
+}
+
+
+/**
+ * Delete the entire given subtree from the model.  Does not free
+ * anything inside of the respective model's fields (since they have
+ * been moved).
+ *
+ * @param model model that contains the subtree to remove
+ * @param iter root of the subtree to remove
+ */
+static void
+delete_stale_subtree (GtkTreeModel * model, GtkTreeIter * iter)
+{
+  GtkTreeIter child;
+
+  while (TRUE == gtk_tree_model_iter_children (model, &child, iter))
+    delete_stale_subtree (model, &child);
+  gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
+}
+
+
+/**
+ * Handle the case where an active download lost its
+ * search parent by moving it to the URI tab.
+ *
+ * @param de download where the parent (i.e. search) was lost
+ */
+static void
+download_lost_parent (struct DownloadEntry *de)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+  struct SearchTab *tab;
+  GtkTreeRowReference *rr_old;
+  GtkTreeModel *tm_old;
+  GtkTreeIter iter_old;
+  GtkTreeIter child;
+  GtkTreeModel *model;
+
+  /* first, move the root of the respective 'de'-tree */
+  rr_old = de->rr;
+  tab = GNUNET_GTK_add_to_uri_tab (&iter, &de->sr, de->meta, de->uri);
+  de->sr->download = de;
+  de->ts = tab->ts;
+  model = GTK_TREE_MODEL (de->ts);
+  path = gtk_tree_model_get_path (model, &iter);
+  de->rr = gtk_tree_row_reference_new (model, path);
+  gtk_tree_path_free (path);
+  tm_old = gtk_tree_row_reference_get_model (rr_old);
+  path = gtk_tree_row_reference_get_path (rr_old);
+  gtk_tree_row_reference_free (rr_old);
+  if (! gtk_tree_model_get_iter (tm_old, &iter_old, path))
+  {
+    GNUNET_break (0);
+    gtk_tree_path_free (path);
+    return;
+  }
+  gtk_tree_path_free (path);
+
+  /* finally, move all children over as well */
+  copy_children (tm_old, &iter_old, model, &iter);
+  while (gtk_tree_model_iter_children (model, &child, &iter))
+    delete_stale_subtree (model, &child);
+}
+
+
+/**
+ * Setup a new download entry.
+ *
+ * @param de existing download entry for the download, or NULL (in which case 
we create a fresh one)
+ * @param pde parent download entry, or NULL
+ * @param sr search result, or NULL
+ * @param dc download context (for stopping)
+ * @param uri the URI, must not be NULL
+ * @param filename filename on disk
+ * @param meta metadata
+ * @param size total size
+ * @param completed current progress
+ * @return download entry struct for the download (equal to 'de' if 'de' was 
not NULL)
+ */
+static struct DownloadEntry *
+setup_download (struct DownloadEntry *de, struct DownloadEntry *pde,
+                struct SearchResult *sr, struct GNUNET_FS_DownloadContext *dc,
+                const struct GNUNET_FS_Uri *uri, const char *filename,
+                const struct GNUNET_CONTAINER_MetaData *meta, uint64_t size,
+                uint64_t completed)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+  struct SearchResult *srp;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Setting up download, initially DE=%p, PDE=%p for %p & %p into 
%llu/%llu `%s'\n",
+             de, pde, sr, dc, completed, size, filename);
+  GNUNET_assert (NULL != uri);
+  srp = NULL;
+  if (NULL == de)
+  {
+    /* no existing download entry to build on, create a fresh one */
+    de = GNUNET_malloc (sizeof (struct DownloadEntry));
+    de->uri = GNUNET_FS_uri_dup (uri);
+  }
+  else
+  {
+    GNUNET_assert (GNUNET_YES == GNUNET_FS_uri_test_equal (de->uri, uri));
+  }
+  de->dc = dc;
+  de->sr = sr;
+  de->pde = pde;
+  if ( (meta != NULL) && (de->meta == NULL) )
+    de->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
+  if (NULL != sr)
+  {
+    /* got a search result; display the download in the same location as the 
search result */
+    GNUNET_assert (sr->download == NULL);
+    sr->download = de;
+    de->rr = gtk_tree_row_reference_copy (sr->rr);
+    de->ts = sr->tab->ts;
+    de->tab = sr->tab;
+    srp = sr;
+  }
+  if (NULL == de->rr)
+  {
+    /* Stand-alone download with no 'row'/search result affiliated
+       with the download so far; create a fresh entry for this
+       download in the URI tab */
+    de->tab = GNUNET_GTK_add_to_uri_tab (&iter, &srp, meta, uri);
+    de->ts = de->tab->ts;
+    path = gtk_tree_model_get_path (GTK_TREE_MODEL (de->ts), &iter);
+    de->rr = gtk_tree_row_reference_new (GTK_TREE_MODEL (de->ts), path);
+    gtk_tree_path_free (path);
+    srp->download = de;
+  }
+  path = gtk_tree_row_reference_get_path (de->rr);
+  if (! 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 */ ,
+                      6, filename /* filename/description */ ,
+                      8, "blue" /* status colour: pending */ ,
+                     9, srp,
+                     14, completed,
+                      -1);
+  return de;
+}
+
+
+
+/* ***************** Publish event handling ****************** */
+
+
+
+/**
+ * Change the (background) color of the given publish entry.
+ *
+ * @param pe entry to change 
+ * @param color name of the color to use
+ */
+static void
+change_publish_color (struct PublishEntry *pe,
+                     const char *color)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
+             "Changing publish PE=%p color to %s\n", 
+             pe, color);
+  path = gtk_tree_row_reference_get_path (pe->rr);
+  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
+  {
+    GNUNET_break (0);
+    gtk_tree_path_free (path);
+    return;
+  }
+  gtk_tree_path_free (path);
+  gtk_tree_store_set (pe->tab->ts, &iter, 2, color, -1);
+}
+
+
+/**
+ * We got an event that some publishing operation is progressing.
+ * Update the tree model accordingly.
+ *
+ * @param pe publish entry that is progressing
+ * @param size overall size of the file or directory
+ * @param completed number of bytes we have completed
+ */
+static void
+mark_publish_progress (struct PublishEntry *pe, uint64_t size,
+                       uint64_t completed)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  path = gtk_tree_row_reference_get_path (pe->rr);
+  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
+  {
+    GNUNET_break (0);
+    gtk_tree_path_free (path);
+    return;
+  }
+  gtk_tree_path_free (path);
+  gtk_tree_store_set (pe->tab->ts, &iter, 3,
+                      (guint) ((size >
+                                0) ? (100 * completed /
+                                      size) : 100) /* progress */ ,
+                      -1);
+}
+
+
+/**
+ * FS-API notified us that we're done with some publish operation.
+ * Update the view accordingly.
+ *
+ * @param pe publish operation that has finished
+ * @param uri resulting URI
+ */
+static void
+handle_publish_completed (struct PublishEntry *pe,
+                          const struct GNUNET_FS_Uri *uri)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+  char *uris;
+
+  path = gtk_tree_row_reference_get_path (pe->rr);
+  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
+  {
+    GNUNET_break (0);
+    gtk_tree_path_free (path);
+    return;
+  }
+  gtk_tree_path_free (path);
+  pe->uri = GNUNET_FS_uri_dup (uri);
+  uris = GNUNET_FS_uri_to_string (uri);
+  gtk_tree_store_set (pe->tab->ts, &iter, 
+                     5, uris,
+                      -1);
+  GNUNET_free (uris);
+  change_publish_color (pe, "green");
+}
+
+
+/**
+ * We received a publish error message from the FS library.
+ * Present it to the user in an appropriate form.
+ *
+ * @param pe publishing operation affected by the error 
+ * @param emsg the error message
+ */
+static void
+handle_publish_error (struct PublishEntry *pe,
+                     const char *emsg)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  path = gtk_tree_row_reference_get_path (pe->rr);
+  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
+  {
+    GNUNET_break (0);
+    gtk_tree_path_free (path);
+    return;
+  }
+  gtk_tree_path_free (path);
+  gtk_tree_store_set (pe->tab->ts, &iter, 
+                     5, emsg,
+                      -1);
+  change_publish_color (pe, "red");
+}
+
+
+/**
+ * A publishing operation was stopped (in FS API).  Free an entry in
+ * the publish tab and its associated state.
+ *
+ * @param pe publishing operation that was stopped
+ */
+static void
+handle_publish_stop (struct PublishEntry *pe)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  path = gtk_tree_row_reference_get_path (pe->rr);
+  /* This is a child of a directory, and we've had that directory
+     free'd already  */
+  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  (void) gtk_tree_store_remove (pe->tab->ts, &iter);
+  gtk_tree_path_free (path);
+  gtk_tree_row_reference_free (pe->rr);
+  if (pe->uri != NULL)
+  {
+    GNUNET_FS_uri_destroy (pe->uri);
+    pe->uri = NULL;
+  }
+  GNUNET_free (pe);
+}
+
+
+/**
+ * The user clicked on the "close" button of the publishing tab.
+ * Tell FS to stop all active publish operations.  Then close the tab.
+ *
+ * @param button the stop button
+ * @param user_data the 'struct PublishTab' that is being closed
+ */
+static void
+stop_publishing (GtkButton * button, gpointer user_data)
+{
+  struct PublishTab *tab = user_data;
+  struct PublishEntry *ent;
+  GtkTreeIter iter;
+  GtkTreeModel *tm;
+  GtkNotebook *notebook;
+  int index;
+  int i;
+
+  GNUNET_assert (tab == publish_tab);
+  /* stop all active operations */
+  tm = GTK_TREE_MODEL (publish_tab->ts);
+  if (gtk_tree_model_iter_children (tm, &iter, NULL))
+  {
+    do
+    {
+      gtk_tree_model_get (tm, &iter, 4, &ent, -1);
+      GNUNET_FS_publish_stop (ent->pc);
+      ent->pc = NULL;
+    }
+    while (TRUE == gtk_tree_model_iter_next (tm, &iter));
+  }
+
+  /* remove tab from notebook */
+  notebook =
+      GTK_NOTEBOOK (GNUNET_FS_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 (publish_tab->frame == gtk_notebook_get_nth_page (notebook, i))
+      index = i;
+  gtk_notebook_remove_page (notebook, index);
+
+  /* fully destroy tab */
+  g_object_unref (publish_tab->builder);
+  GNUNET_free (publish_tab);
+  publish_tab = NULL;
+}
+
+
+/**
+ * The user started a publishing operation.  Add it to the publishing
+ * tab.  If needed, create the publishing tab.
+ *
+ * @param pc the FS-API's publishing context for the operation
+ * @param fn the name of the file (or directory) that is being published
+ * @param fsize size of the file
+ * @param parent parent of this publishing operation (for recursive 
operations), NULL for top-level operations
+ * @return the publishing entry that will represent this operation
+ */
+static struct PublishEntry *
+setup_publish (struct GNUNET_FS_PublishContext *pc, const char *fn,
+               uint64_t fsize, struct PublishEntry *parent)
+{
+  struct PublishEntry *ent;
+  GtkTreeIter *pitrptr;
+  GtkTreeIter iter;
+  GtkTreeIter piter;
+  GtkTreePath *path;
+  GtkWindow *df;
+  GtkWidget *tab_label;
+  GtkWidget *close_button;
+  GtkNotebook *notebook;
+  char *size_fancy;
+  
+  if (NULL == publish_tab)
+  {
+    /* create new tab */
+    publish_tab = GNUNET_malloc (sizeof (struct PublishTab));
+    publish_tab->builder =
+      GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_publish_tab.glade",
+                                 publish_tab);
+    df = GTK_WINDOW (gtk_builder_get_object
+                    (publish_tab->builder, "_publish_frame_window"));
+    publish_tab->frame = gtk_bin_get_child (GTK_BIN (df));
+    g_object_ref (publish_tab->frame);
+    gtk_container_remove (GTK_CONTAINER (df), publish_tab->frame);
+    gtk_widget_destroy (GTK_WIDGET (df));
+    
+    /* load tab_label */
+    df = GTK_WINDOW (gtk_builder_get_object
+                    (publish_tab->builder, "_publish_label_window"));
+    tab_label = gtk_bin_get_child (GTK_BIN (df));
+    g_object_ref (tab_label);
+    gtk_container_remove (GTK_CONTAINER (df), tab_label);
+    gtk_widget_destroy (GTK_WIDGET (df));
+    
+    /* FIXME-UNCLEAN: connect these signals using GLADE!!! */
+    /* get refs to widgets */
+    close_button =
+      GTK_WIDGET (gtk_builder_get_object
+                 (publish_tab->builder, "_publish_label_close_button"));
+    g_signal_connect (G_OBJECT (close_button), "clicked",
+                     G_CALLBACK (stop_publishing), publish_tab);
+    /* make visible */
+    notebook =
+      GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
+                   ("GNUNET_GTK_main_window_notebook"));
+    gtk_notebook_insert_page (notebook, publish_tab->frame, tab_label, 0);
+    gtk_widget_show (GTK_WIDGET (notebook));
+    gtk_notebook_set_current_page (notebook, 0);
+    publish_tab->ts =
+      GTK_TREE_STORE (gtk_builder_get_object
+                     (publish_tab->builder, "_publish_frame_tree_store"));
+  }
+
+  /* decide where to insert in the tab */
+  if (NULL == parent)
+  {
+    pitrptr = NULL;
+  }
+  else
+  {
+    /* create new iter from parent */
+    path = gtk_tree_row_reference_get_path (parent->rr);
+    if (TRUE !=
+        gtk_tree_model_get_iter (GTK_TREE_MODEL (publish_tab->ts), &piter,
+                                 path))
+    {
+      GNUNET_break (0);
+      return NULL;
+    }
+    pitrptr = &piter;
+  }
+  
+  /* create entry and perform insertion */
+  ent = GNUNET_malloc (sizeof (struct PublishEntry));
+  ent->is_top = (parent == NULL) ? GNUNET_YES : GNUNET_NO;
+  ent->tab = publish_tab;
+  ent->pc = pc;
+  size_fancy = GNUNET_STRINGS_byte_size_fancy (fsize);
+  gtk_tree_store_insert_with_values (publish_tab->ts, &iter, pitrptr, G_MAXINT,
+                                     0, fn, 1, size_fancy, 2, "white", 3,
+                                     (guint) 0 /* progress */ ,
+                                     4, ent, -1);
+  GNUNET_free (size_fancy);
+  path = gtk_tree_model_get_path (GTK_TREE_MODEL (publish_tab->ts), &iter);
+  ent->rr = gtk_tree_row_reference_new (GTK_TREE_MODEL (publish_tab->ts), 
path);
+  gtk_tree_path_free (path);
+  return ent;
+}
+
+
+
+/* ***************** Master event handler ****************** */
+
+
+
+/**
+ * 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)
+{
+  void *ret;
+
+  switch (info->status)
+  {
+  case GNUNET_FS_STATUS_PUBLISH_START:
+    return setup_publish (info->value.publish.pc, info->value.publish.filename,
+                          info->value.publish.size, info->value.publish.pctx);
+  case GNUNET_FS_STATUS_PUBLISH_RESUME:
+    ret =
+        setup_publish (info->value.publish.pc, info->value.publish.filename,
+                       info->value.publish.size, info->value.publish.pctx);
+    if (ret == NULL)
+      return ret;
+    if (info->value.publish.specifics.resume.message != NULL)
+    {
+      handle_publish_error (ret,
+                           info->value.publish.specifics.resume.message);
+    }
+    else if (info->value.publish.specifics.resume.chk_uri != NULL)
+    {
+      handle_publish_completed (ret,
+                               info->value.publish.specifics.resume.chk_uri);
+    }
+    return ret;
+  case GNUNET_FS_STATUS_PUBLISH_SUSPEND:
+    handle_publish_stop (info->value.publish.cctx);
+    return NULL;
+  case GNUNET_FS_STATUS_PUBLISH_PROGRESS:
+    mark_publish_progress (info->value.publish.cctx,
+                          info->value.publish.size,
+                          info->value.publish.completed);
+    return info->value.publish.cctx;
+  case GNUNET_FS_STATUS_PUBLISH_ERROR:
+    handle_publish_error (info->value.publish.cctx,
+                         info->value.publish.specifics.error.message);
+    return info->value.publish.cctx;
+  case GNUNET_FS_STATUS_PUBLISH_COMPLETED:
+    handle_publish_completed (info->value.publish.cctx,
+                             info->value.publish.specifics.completed.chk_uri);
+    return info->value.publish.cctx;
+  case GNUNET_FS_STATUS_PUBLISH_STOPPED:
+    handle_publish_stop (info->value.publish.cctx);
+    return NULL;
+  case GNUNET_FS_STATUS_DOWNLOAD_START:
+    return setup_download (info->value.download.cctx, 
info->value.download.pctx,
+                           info->value.download.sctx, info->value.download.dc,
+                           info->value.download.uri,
+                           info->value.download.filename,
+                           info->value.download.specifics.start.meta,
+                           info->value.download.size,
+                           info->value.download.completed);
+  case GNUNET_FS_STATUS_DOWNLOAD_RESUME:
+    ret =
+        setup_download (info->value.download.cctx, info->value.download.pctx,
+                        info->value.download.sctx, info->value.download.dc,
+                        info->value.download.uri, 
info->value.download.filename,
+                        info->value.download.specifics.resume.meta,
+                        info->value.download.size,
+                        info->value.download.completed);
+    if (info->value.download.specifics.resume.message != NULL)
+      mark_download_error (ret,
+                          info->value.download.specifics.resume.message);   
+    return ret;
+  case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND:
+    stop_download (info->value.download.cctx);
+    return NULL;
+  case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
+    mark_download_progress (info->value.download.cctx,
+                           info->value.download.size,
+                           info->value.download.completed,
+                           info->value.download.specifics.progress.data,
+                           info->value.download.specifics.progress.
+                           offset,
+                           info->value.download.specifics.progress.
+                           data_len,
+                           info->value.download.specifics.progress.
+                           depth);
+    return info->value.download.cctx;
+  case GNUNET_FS_STATUS_DOWNLOAD_ERROR:
+    mark_download_error (info->value.download.cctx,
+                        info->value.download.specifics.error.message);
+    return info->value.download.cctx;
+  case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
+    mark_download_completed (info->value.download.cctx,
+                            info->value.download.size,
+                            info->value.download.filename);
+    return info->value.download.cctx;
+  case GNUNET_FS_STATUS_DOWNLOAD_STOPPED:
+    stop_download (info->value.download.cctx);
+    return NULL;
+  case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
+    change_download_color (info->value.download.cctx, "yellow");
+    return info->value.download.cctx;
+  case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
+    change_download_color (info->value.download.cctx, "blue");
+    return info->value.download.cctx;
+  case GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT:
+    download_lost_parent (info->value.download.cctx);
+    return info->value.download.cctx;
+  case GNUNET_FS_STATUS_SEARCH_START:
+    if (info->value.search.pctx != NULL)
+      return setup_inner_search (info->value.search.sc,
+                                 info->value.search.pctx);
+    return setup_search_tab (info->value.search.sc, info->value.search.query);
+  case GNUNET_FS_STATUS_SEARCH_RESUME:
+    ret = setup_search_tab (info->value.search.sc, info->value.search.query);
+    if (info->value.search.specifics.resume.message)
+      handle_search_error (ret,
+                          info->value.search.specifics.resume.message);
+    return ret;
+  case GNUNET_FS_STATUS_SEARCH_RESUME_RESULT:
+    ret =
+        process_search_result (info->value.search.cctx, 
info->value.search.pctx,
+                               info->value.search.specifics.resume_result.uri,
+                               info->value.search.specifics.resume_result.meta,
+                               info->value.search.specifics.resume_result.
+                               result,
+                               info->value.search.specifics.resume_result.
+                               applicability_rank);
+    update_search_result (ret,
+                         info->value.search.specifics.resume_result.
+                         meta,
+                         info->value.search.specifics.resume_result.
+                         applicability_rank,
+                         info->value.search.specifics.resume_result.
+                         availability_certainty,
+                         info->value.search.specifics.resume_result.
+                         availability_rank);
+    return ret;
+  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:
+    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);
+    return info->value.search.specifics.update.cctx;
+  case GNUNET_FS_STATUS_SEARCH_ERROR:
+    handle_search_error (info->value.search.cctx,
+                        info->value.search.specifics.error.message);
+    return info->value.search.cctx;
+  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_stopped.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;
+}
+
+
+/* end of gnunet-fs-gtk-event_handler.c */

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_event-handler.h (from rev 19624, 
gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.h)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_event-handler.h                             
(rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_event-handler.h     2012-02-02 13:28:32 UTC 
(rev 19629)
@@ -0,0 +1,241 @@
+/*
+     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/gnunet-fs-gtk_event-handler.h
+ * @brief Main event handler for file-sharing
+ * @author Christian Grothoff
+ */
+#include "gnunet-fs-gtk-common.h"
+
+
+/**
+ * State we keep for each (search) result entry in the
+ * tree view of a search tab.
+ */
+struct SearchResult;
+
+
+/**
+ * Context we keep for a search tab.
+ */
+struct SearchTab
+{
+  /**
+   * This is a doubly-linked list.
+   */
+  struct SearchTab *next;
+
+  /**
+   * This is a doubly-linked list.
+   */
+  struct SearchTab *prev;
+
+  /**
+   * Set in case this is an inner search, otherwise NULL.
+   */
+  struct SearchResult *parent;
+
+  /**
+   * Handle for this search with FS library.
+   */
+  struct GNUNET_FS_SearchContext *sc;
+
+  /**
+   * Text of the search query.
+   */
+  char *query_txt;
+
+  /**
+   * GtkBuilder object for the search tab.
+   */ 
+  GtkBuilder *builder;
+
+  /**
+   * Frame instance of the search tab.
+   */
+  GtkWidget *frame;
+
+  /**
+   * The widget representing this search in the tab bar (not
+   * a GtkLabel, contains the actual label and the buttons).
+   */
+  GtkWidget *tab_label;
+
+  /**
+   * Button to stop and close the search.
+   */
+  GtkWidget *close_button;
+
+  /**
+   * Button to clear all entries for downloads that have completed.
+   */
+  GtkWidget *clear_button;
+
+  /**
+   * Button to resume the search.
+   */
+  GtkWidget *play_button;
+
+  /**
+   * Button to pause the search.
+   */
+  GtkWidget *pause_button;
+
+  /**
+   * Textual label in the 'tab_label'
+   */
+  GtkLabel *label;
+
+  /**
+   * Tree store with the search results.
+   */
+  GtkTreeStore *ts;
+
+  /**
+   * Number of results we got for this search.
+   */
+  unsigned int num_results;
+
+};
+
+
+/**
+ * Information we keep for each download.
+ */
+struct DownloadEntry
+{
+
+  /**
+   * Download entry of the parent (for recursive downloads),
+   * NULL if we are either a top-level download (from URI,
+   * from opened directory, orphaned from search or direct
+   * search result).
+   */
+  struct DownloadEntry *pde;
+
+  /**
+   * Associated search result, or NULL if we don't belong
+   * to a search directly (download entry).
+   */
+  struct SearchResult *sr;
+
+  /**
+   * FS handle to control the download.
+   */
+  struct GNUNET_FS_DownloadContext *dc;
+
+  /**
+   * URI for the download.
+   */
+  struct GNUNET_FS_Uri *uri;
+
+  /**
+   * Meta data for the download.
+   */
+  struct GNUNET_CONTAINER_MetaData *meta;
+
+  /**
+   * Where in the tree view is this download being displayed.
+   */
+  GtkTreeRowReference *rr;
+
+  /**
+   * Tree store where we are stored.
+   */
+  GtkTreeStore *ts;
+
+  /**
+   * Tab where this download is currently on display.
+   */
+  struct SearchTab *tab;
+
+  /**
+   * Has the download completed (or errored)?
+   */
+  int is_done;
+
+};
+
+
+/**
+ * Setup a new top-level entry in the URI/orphan tab.  If necessary, create
+ * the URI tab first.
+ *
+ * @param iter set to the new entry (OUT only)
+ * @param srp set to search result (can be NULL)
+ * @param meta metadata for the new entry
+ * @param uri URI for the new entry
+ * @return the 'uri_tab' the result was added to
+ */
+struct SearchTab *
+GNUNET_GTK_add_to_uri_tab (GtkTreeIter * iter, struct SearchResult **sr,
+                           const struct GNUNET_CONTAINER_MetaData *meta,
+                           const struct GNUNET_FS_Uri *uri);
+
+
+/**
+ * Add a search result to the given search tab.
+ *
+ * @param tab search tab to extend, never NULL
+ * @param iter set to position where search result is added (OUT only)
+ * @param parent_rr reference to parent entry in search tab, NULL for normal
+ *                  search results, 
+ * @param uri uri to add, can be NULL for top-level entry of a directory 
opened from disk
+ *                        (in this case, we don't know the URI and should 
probably not
+ *                         bother to calculate it)
+ * @param meta metadata of the entry
+ * @param result associated FS search result (can be NULL if this result
+ *                        was part of a directory)
+ * @param applicability_rank how relevant is the result
+ * @return struct representing the search result (also stored in the tree
+ *                model at 'iter')
+ */
+struct SearchResult *
+GNUNET_GTK_add_search_result (struct SearchTab *tab, 
+                             GtkTreeIter *iter,
+                              GtkTreeRowReference *parent_rr,
+                              const struct GNUNET_FS_Uri *uri,
+                              const struct GNUNET_CONTAINER_MetaData *meta,
+                              struct GNUNET_FS_SearchResult *result,
+                              uint32_t applicability_rank);
+
+
+/**
+ * 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);
+
+
+/* end of gnunet-fs-gtk-event_handler.h */

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_publish-dialog.c (from rev 19628, 
gnunet-gtk/src/fs/gnunet-fs-gtk-main_window_file_publish.c)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_publish-dialog.c                            
(rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_publish-dialog.c    2012-02-02 13:28:32 UTC 
(rev 19629)
@@ -0,0 +1,1596 @@
+/*
+     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_publish-dialog.c
+ * @author Christian Grothoff
+ */
+#include "gnunet-fs-gtk-common.h"
+#include "gnunet-fs-gtk.h"
+#include "gnunet-fs-gtk-edit_publish_dialog.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_fs_service.h>
+
+#define MARKER_DIR_FILE_SIZE "-"
+
+#define VERBOSE_PROGRESS GNUNET_NO
+
+struct AddDirClientContext;
+
+struct MainPublishingDialogContext
+{
+  GtkBuilder *builder;
+  GtkBuilder *main_window_builder;
+  GtkTreeView *pseudonym_treeview;
+  GtkTreeSelection *pseudonym_selection;
+  GtkTreeModel *pseudonym_treemodel;
+  GtkWidget *up_button;
+  GtkWidget *down_button;
+  GtkWidget *left_button;
+  GtkWidget *right_button;
+  GtkWidget *delete_button;
+  GtkWidget *edit_button;
+  GtkWidget *execute_button;
+  GtkWidget *cancel_button;
+  GtkTreeView *file_info_treeview;
+  GtkTreeSelection *file_info_selection;
+  GtkTreeModel *file_info_treemodel;  
+  GtkWindow *master_pubdialog;
+
+  gulong open_directory_handler_id;
+  GtkBuilder *open_directory_builder;
+
+  gulong open_file_handler_id;
+  GtkBuilder *open_file_builder;
+
+  /* To keep multiple scanners running */
+  struct AddDirClientContext *adddir_head;
+  struct AddDirClientContext *adddir_tail;
+};
+
+/* One of these is kept for every directory being opened */
+struct AddDirClientContext
+{
+  struct AddDirClientContext *prev;
+  struct AddDirClientContext *next;
+
+  struct GNUNET_FS_ProcessMetadataContext *pmc;
+
+  struct MainPublishingDialogContext *ctx;
+  struct GNUNET_FS_DirScanner *ds;
+
+  struct GNUNET_FS_ShareTreeItem *directory_scan_result;
+
+  struct GNUNET_FS_BlockOptions directory_scan_bo;
+  int directory_scan_do_index;
+
+  GtkBuilder *progress_dialog_builder;
+  GtkWidget *progress_dialog;
+  GtkProgressBar *progress_dialog_bar;
+  GtkButton *progress_dialog_cancel;
+  GtkTextView *progress_dialog_textview;
+  GtkTextBuffer *progress_dialog_textbuffer;
+  GtkTextMark *progress_dialog_textmark;
+  GtkAdjustment *textview_vertial_adjustment;
+
+  unsigned int done;
+  unsigned int total;
+};
+
+
+static void
+selection_changed_cb (GtkTreeSelection * ts, struct 
MainPublishingDialogContext *ctx);
+
+
+/**
+ * Check if two GtkTreeIters refer to the same element.
+ *
+ * @param tm tree model of the iterators
+ * @param i1 first iterator
+ * @param i2 second iterator
+ * @return GNUNET_YES if they are equal
+ */
+static int
+gtk_tree_iter_equals (GtkTreeModel * tm, GtkTreeIter * i1, GtkTreeIter * i2)
+{
+  GtkTreePath *p1;
+  GtkTreePath *p2;
+  int ret;
+
+  p1 = gtk_tree_model_get_path (tm, i1);
+  p2 = gtk_tree_model_get_path (tm, i2);
+  ret = gtk_tree_path_compare (p1, p2);
+  gtk_tree_path_free (p1);
+  gtk_tree_path_free (p2);
+  return (0 == ret) ? GNUNET_YES : GNUNET_NO;
+}
+
+/* Fill out the main publishing dialog context structure */
+static void
+init_ctx (struct MainPublishingDialogContext *ctx)
+{
+  ctx->pseudonym_treeview = GTK_TREE_VIEW (gtk_builder_get_object
+      (ctx->builder, "GNUNET_GTK_master_publish_dialog_pseudonym_tree_view"));
+
+  ctx->up_button = GTK_WIDGET (gtk_builder_get_object
+      (ctx->builder, "GNUNET_GTK_master_publish_dialog_up_button"));
+  ctx->down_button = GTK_WIDGET (gtk_builder_get_object
+      (ctx->builder, "GNUNET_GTK_master_publish_dialog_down_button"));
+  ctx->left_button = GTK_WIDGET (gtk_builder_get_object
+      (ctx->builder, "GNUNET_GTK_master_publish_dialog_left_button"));
+  ctx->right_button = GTK_WIDGET (gtk_builder_get_object
+      (ctx->builder, "GNUNET_GTK_master_publish_dialog_right_button"));
+  ctx->delete_button = GTK_WIDGET (gtk_builder_get_object
+      (ctx->builder, "GNUNET_GTK_master_publish_dialog_delete_button"));
+  ctx->edit_button = GTK_WIDGET (gtk_builder_get_object
+      (ctx->builder, "GNUNET_GTK_master_publish_dialog_edit_button"));
+  ctx->execute_button = GTK_WIDGET (gtk_builder_get_object
+      (ctx->builder, "GNUNET_GTK_master_publish_dialog_execute_button"));
+  ctx->cancel_button = GTK_WIDGET (gtk_builder_get_object
+      (ctx->builder , "GNUNET_GTK_master_publish_dialog_cancel_button"));
+  ctx->file_info_treeview = GTK_TREE_VIEW (gtk_builder_get_object
+      (ctx->builder, 
"GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
+
+  ctx->master_pubdialog =
+      GTK_WINDOW (gtk_builder_get_object
+                  (ctx->builder, "GNUNET_GTK_master_publish_dialog"));
+
+  ctx->file_info_selection = gtk_tree_view_get_selection 
(ctx->file_info_treeview);
+  ctx->file_info_treemodel = gtk_tree_view_get_model (ctx->file_info_treeview);
+  ctx->pseudonym_selection = gtk_tree_view_get_selection 
(ctx->pseudonym_treeview);
+  ctx->pseudonym_treemodel = gtk_tree_view_get_model (ctx->pseudonym_treeview);
+
+  g_signal_connect (G_OBJECT (ctx->file_info_selection), "changed",
+                    G_CALLBACK (selection_changed_cb), ctx);
+  g_signal_connect (G_OBJECT (ctx->pseudonym_selection), "changed",
+                    G_CALLBACK (selection_changed_cb), ctx);
+}
+
+/**
+ * Update selectivity in the master dialog.
+ */
+static void
+update_selectivity (struct MainPublishingDialogContext *ctx)
+{
+  GtkTreeIter iter;
+  GtkTreeIter parent;
+  GtkTreeIter pred;
+  int is_dir;
+  struct GNUNET_FS_FileInformation *fip;
+  int ns_ok;
+  gchar *namespace_id;
+
+  ns_ok = GNUNET_YES;
+  if (TRUE == gtk_tree_selection_get_selected (ctx->pseudonym_selection, NULL, 
&iter))
+  {
+    gtk_tree_model_get (ctx->pseudonym_treemodel, &iter, 2, &namespace_id, -1);
+    if (namespace_id == NULL)
+      ns_ok = GNUNET_NO;
+    else
+      g_free (namespace_id);
+  }
+  /* Don't let the user close the dialog until all scanners are finished and
+   * their windows are closed
+   */
+  if ((gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &iter))
+      && (ns_ok == GNUNET_YES) && ctx->adddir_head == NULL)
+    gtk_widget_set_sensitive (ctx->execute_button, TRUE);
+  else
+    gtk_widget_set_sensitive (ctx->execute_button, FALSE);
+  if (ctx->adddir_head == NULL)
+    gtk_widget_set_sensitive (ctx->cancel_button, TRUE);
+  else
+    gtk_widget_set_sensitive (ctx->cancel_button, FALSE);
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
+  {
+    gtk_widget_set_sensitive (ctx->up_button, FALSE);
+    gtk_widget_set_sensitive (ctx->down_button, FALSE);
+    gtk_widget_set_sensitive (ctx->left_button, FALSE);
+    gtk_widget_set_sensitive (ctx->right_button, FALSE);
+    gtk_widget_set_sensitive (ctx->delete_button, FALSE);
+    gtk_widget_set_sensitive (ctx->edit_button, FALSE);
+    return;
+  }
+  gtk_widget_set_sensitive (ctx->delete_button, TRUE);
+  gtk_widget_set_sensitive (ctx->edit_button, TRUE);
+
+  /* now figure out which move operations are currently legal */
+  GNUNET_assert (TRUE == gtk_tree_selection_get_selected 
(ctx->file_info_selection, NULL, &iter));
+  if (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, &iter))
+  {
+    gtk_widget_set_sensitive (ctx->down_button, TRUE);
+  }
+  else
+  {
+    gtk_widget_set_sensitive (ctx->down_button, FALSE);
+  }
+  GNUNET_assert (TRUE == gtk_tree_selection_get_selected 
(ctx->file_info_selection, NULL, &iter));
+  if (TRUE == gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, 
&iter))
+  {
+    gtk_widget_set_sensitive (ctx->left_button, TRUE);
+    GNUNET_assert (TRUE == gtk_tree_model_iter_children 
(ctx->file_info_treemodel, &pred, &parent));
+  }
+  else
+  {
+    gtk_widget_set_sensitive (ctx->left_button, FALSE);
+    GNUNET_assert (TRUE == gtk_tree_model_get_iter_first 
(ctx->file_info_treemodel, &pred));
+  }
+  /* iterate over 'next' of pred to find out if our
+   * predecessor is a directory! */
+  is_dir = GNUNET_SYSERR;
+  while (GNUNET_YES != gtk_tree_iter_equals (ctx->file_info_treemodel, &pred, 
&iter))
+  {
+    gtk_tree_model_get (ctx->file_info_treemodel, &pred, 5, &fip, -1);
+    is_dir = GNUNET_FS_file_information_is_directory (fip);
+    GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, 
&pred));
+  }
+  if (GNUNET_YES == is_dir)
+  {
+    gtk_widget_set_sensitive (ctx->right_button, TRUE);
+  }
+  else
+  {
+    gtk_widget_set_sensitive (ctx->right_button, FALSE);
+  }
+  if (GNUNET_SYSERR != is_dir)
+  {
+    gtk_widget_set_sensitive (ctx->up_button, TRUE);
+  }
+  else
+  {
+    gtk_widget_set_sensitive (ctx->up_button, FALSE);
+  }
+}
+
+
+/**
+ * Add an empty directory to the tree model.
+ *
+ * @param name name for the directory
+ * @param bo block options
+ * @param iter parent entry, or NULL for top-level addition
+ * @param pos iterator to set to the location of the new element
+ */
+static void
+create_dir_at_iter (struct MainPublishingDialogContext *ctx, const char *name,
+                    const struct GNUNET_FS_BlockOptions *bo, GtkTreeIter * 
iter,
+                    GtkTreeIter * pos)
+{
+  struct GNUNET_FS_FileInformation *fi;
+  GtkTreeRowReference *row_reference;
+  GtkTreePath *path;
+  struct GNUNET_CONTAINER_MetaData *meta;
+
+  meta = GNUNET_CONTAINER_meta_data_create ();
+  GNUNET_FS_meta_data_make_directory (meta);
+  GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet-gtk>",
+                                     EXTRACTOR_METATYPE_FILENAME,
+                                     EXTRACTOR_METAFORMAT_UTF8, "text/plain",
+                                     name, strlen (name) + 1);
+  gtk_tree_store_insert_before (GTK_TREE_STORE (ctx->file_info_treemodel), 
pos, iter, NULL);
+  path = gtk_tree_model_get_path (ctx->file_info_treemodel, pos);
+  row_reference = gtk_tree_row_reference_new (ctx->file_info_treemodel, path);
+  gtk_tree_path_free (path);
+  fi = GNUNET_FS_file_information_create_empty_directory
+      (GNUNET_FS_GTK_get_fs_handle (), row_reference, NULL, meta, bo, name);
+  GNUNET_CONTAINER_meta_data_destroy (meta);
+  gtk_tree_store_set (GTK_TREE_STORE (ctx->file_info_treemodel), pos, 0, 
MARKER_DIR_FILE_SIZE, 1, (gboolean) GNUNET_NO,
+                      2, name, 3, (guint) bo->anonymity_level, 4,
+                      (guint) bo->content_priority, 5, fi,
+                     6, (guint64) bo->expiration_time.abs_value,
+                     7, (guint) bo->replication_level,
+                     -1);
+  update_selectivity (ctx);
+}
+
+static void
+selection_changed_cb (GtkTreeSelection * ts, struct 
MainPublishingDialogContext *ctx)
+{
+  update_selectivity (ctx);
+}
+
+static void
+remove_old_entry (GtkTreeStore * ts, GtkTreeIter * root)
+{
+  GtkTreeIter child;
+
+  while (TRUE ==
+         gtk_tree_model_iter_children (GTK_TREE_MODEL (ts), &child, root))
+    remove_old_entry (ts, &child);
+  gtk_tree_store_remove (ts, root);
+}
+
+
+/**
+ * Move an entry in the tree.
+ */
+static void
+move_entry (struct MainPublishingDialogContext *ctx, GtkTreeModel * tm, 
GtkTreeIter * old,
+            GtkTreeIter * newpos, int dsel)
+{
+  struct GNUNET_FS_FileInformation *fip;
+  gint do_index;
+  gchar *short_fn;
+  guint anonymity_level;
+  guint priority;
+  guint replication_level;
+  guint64 expiration_time_abs;
+  char *fsf;
+  GtkTreePath *path;
+  GtkTreeIter child;
+  GtkTreeIter cnewpos;
+  GtkTreeRowReference *rr;
+  GtkTreeRowReference *rr2;
+
+  gtk_tree_model_get (tm, old, 0, &fsf, 1, &do_index, 2, &short_fn, 3,
+                      &anonymity_level, 4, &priority, 5, &fip, 
+                     6, &expiration_time_abs, 7, &replication_level, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (tm), newpos, 0, fsf, 1, do_index, 2,
+                      short_fn, 3, (guint) anonymity_level, 4, (guint) 
priority,
+                      5, fip, 
+                     6, expiration_time_abs,
+                     7, replication_level, -1);
+  if (dsel == GNUNET_YES)
+  {
+    path = gtk_tree_model_get_path (tm, newpos);
+    rr = gtk_tree_row_reference_new (tm, path);
+    gtk_tree_path_free (path);
+  }
+  else
+  {
+    rr = NULL;
+  }
+  if (TRUE == gtk_tree_model_iter_children (tm, &child, old))
+  {
+    do
+    {
+      path = gtk_tree_model_get_path (tm, &child);
+      rr2 = gtk_tree_row_reference_new (tm, path);
+      gtk_tree_path_free (path);
+      gtk_tree_store_insert_before (GTK_TREE_STORE (tm), &cnewpos, newpos,
+                                    NULL);
+      move_entry (ctx, tm, &child, &cnewpos, GNUNET_NO);
+      path = gtk_tree_row_reference_get_path (rr2);
+      gtk_tree_row_reference_free (rr2);
+      GNUNET_assert (TRUE == gtk_tree_model_get_iter (tm, &child, path));
+      gtk_tree_path_free (path);
+    }
+    while (TRUE == gtk_tree_model_iter_next (tm, &child));
+  }
+  g_free (short_fn);
+  g_free (fsf);
+  if (dsel == GNUNET_YES)
+  {
+    path = gtk_tree_row_reference_get_path (rr);
+    gtk_tree_row_reference_free (rr);
+    gtk_tree_view_expand_to_path (ctx->file_info_treeview, path);
+    GNUNET_assert (TRUE == gtk_tree_model_get_iter (tm, newpos, path));
+    gtk_tree_path_free (path);
+    gtk_tree_selection_select_iter (ctx->file_info_selection, newpos);
+  }
+  update_selectivity (ctx);
+}
+
+
+/**
+ * User has changed the "current" identifier for the content in
+ * the GtkTreeView.  Update the model.
+ */
+void GNUNET_GTK_master_publish_dialog_pseudonym_updates_renderer_edited_cb
+    (GtkCellRendererText * renderer, gchar * cpath, gchar * new_text,
+     struct MainPublishingDialogContext *ctx)
+{
+  GtkTreeIter iter;
+
+  if (TRUE !=
+      gtk_tree_model_get_iter_from_string (ctx->pseudonym_treemodel, &iter, 
cpath))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  gtk_tree_store_set (GTK_TREE_STORE (ctx->pseudonym_treemodel), &iter, 5, 
new_text, -1);
+  update_selectivity (ctx);
+}
+
+
+/**
+ * User has changed the "current" identifier for the content in
+ * the GtkTreeView.  Update the model.
+ */
+void GNUNET_GTK_master_publish_dialog_pseudonym_identifier_renderer_edited_cb
+    (GtkCellRendererText * renderer, gchar * cpath, gchar * new_text,
+     struct MainPublishingDialogContext *ctx)
+{
+  GtkTreeIter iter;
+
+  if (TRUE !=
+      gtk_tree_model_get_iter_from_string (ctx->pseudonym_treemodel, &iter, 
cpath))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  gtk_tree_store_set (GTK_TREE_STORE (ctx->pseudonym_treemodel), &iter, 2, 
new_text, -1);
+  update_selectivity (ctx);
+}
+
+
+void
+GNUNET_GTK_master_publish_dialog_right_button_clicked_cb (GtkWidget * dummy,
+                                                          struct 
MainPublishingDialogContext *ctx)
+{
+  GtkTreeIter iter;
+  GtkTreeIter parent;
+  GtkTreeIter pred;
+  GtkTreeIter prev;
+  GtkTreeIter pos;
+
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  if (TRUE == gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, 
&iter))
+  {
+    GNUNET_assert (TRUE == gtk_tree_model_iter_children 
(ctx->file_info_treemodel, &pred, &parent));
+  }
+  else if (TRUE != gtk_tree_model_get_iter_first (ctx->file_info_treemodel, 
&pred))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  /* iterate over 'next' of pred to find out who our predecessor is! */
+  memset (&prev, 0, sizeof (GtkTreeIter));
+  while (GNUNET_YES != gtk_tree_iter_equals (ctx->file_info_treemodel, &pred, 
&iter))
+  {
+    prev = pred;
+    GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, 
&pred));
+  }
+  gtk_tree_store_insert_before (GTK_TREE_STORE (ctx->file_info_treemodel), 
&pos, &prev, NULL);
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
+  remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
+}
+
+
+void
+GNUNET_GTK_master_publish_dialog_left_button_clicked_cb (GtkWidget * dummy,
+                                                         struct 
MainPublishingDialogContext *ctx)
+{
+  GtkTreeIter iter;
+  GtkTreeIter parent;
+  GtkTreeIter pos;
+
+
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  if (TRUE != gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, 
&iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  gtk_tree_store_insert_after (GTK_TREE_STORE (ctx->file_info_treemodel), 
&pos, NULL, &parent);
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
+  remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
+}
+
+
+void
+GNUNET_GTK_master_publish_dialog_up_button_clicked_cb (GtkWidget * dummy,
+                                                       struct 
MainPublishingDialogContext *ctx)
+{
+  GtkTreeIter iter;
+  GtkTreeIter parent;
+  GtkTreeIter pred;
+  GtkTreeIter prev;
+  GtkTreeIter *pprev;
+  GtkTreeIter pos;
+
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  if (TRUE == gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, 
&iter))
+  {
+    GNUNET_assert (TRUE == gtk_tree_model_iter_children 
(ctx->file_info_treemodel, &pred, &parent));
+    pprev = &parent;
+  }
+  else if (TRUE == gtk_tree_model_get_iter_first (ctx->file_info_treemodel, 
&pred))
+  {
+    pprev = NULL;
+  }
+  else
+  {
+    GNUNET_break (0);
+    return;
+  }
+  /* iterate over 'next' of pred to find out who our predecessor is! */
+  while (GNUNET_YES != gtk_tree_iter_equals (ctx->file_info_treemodel, &pred, 
&iter))
+  {
+    prev = pred;
+    pprev = &prev;
+    GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, 
&pred));
+  }
+  gtk_tree_store_insert_before (GTK_TREE_STORE (ctx->file_info_treemodel), 
&pos, NULL, pprev);
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
+  remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
+}
+
+
+void
+GNUNET_GTK_master_publish_dialog_down_button_clicked_cb (GtkWidget * dummy,
+                                                         struct 
MainPublishingDialogContext *ctx)
+{
+  GtkTreeIter iter;
+  GtkTreeIter next;
+  GtkTreeIter pos;
+
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&next))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, 
&next));
+  gtk_tree_store_insert_after (GTK_TREE_STORE (ctx->file_info_treemodel), 
&pos, NULL, &next);
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
+  remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
+}
+
+
+void
+GNUNET_GTK_master_publish_dialog_new_button_clicked_cb (GtkWidget * dummy,
+                                                        struct 
MainPublishingDialogContext *ctx)
+{
+  GtkTreeIter iter;
+  GtkTreeIter pos;
+  struct GNUNET_FS_BlockOptions bo;
+
+  /* FIXME: consider opening a dialog to get
+   * anonymity, priority and expiration prior
+   * to calling this function (currently we
+   * use default values for those).
+   * Or getting these values from the configuration.
+   */
+  bo.anonymity_level = 1;
+  bo.content_priority = 1000;
+  bo.expiration_time =
+      GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS);
+  bo.replication_level = 1;
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
+  {
+    create_dir_at_iter (ctx, "unnamed/", &bo, NULL, &pos);
+    return;
+  }
+  create_dir_at_iter (ctx, "unnamed/", &bo, &iter, &pos);
+}
+
+
+static void
+insert_progress_dialog_text (struct AddDirClientContext *adcc,
+                            const char *text)
+{
+  gtk_text_buffer_insert_at_cursor (adcc->progress_dialog_textbuffer,
+                                   text, -1);
+  gtk_text_view_place_cursor_onscreen (adcc->progress_dialog_textview);
+  gtk_adjustment_set_value (adcc->textview_vertial_adjustment,
+                           gtk_adjustment_get_upper 
(adcc->textview_vertial_adjustment));
+}
+
+
+static void
+add_item (struct AddDirClientContext *adcc, GtkTreeStore *ts,
+         struct GNUNET_FS_ShareTreeItem *item, 
+         GtkTreeIter *parent, 
+         GtkTreeIter *sibling,
+         GtkTreeIter *item_iter)
+{
+  char *file_size_fancy;
+  struct GNUNET_FS_FileInformation *fi;
+  GtkTreeRowReference *row_reference;
+  GtkTreePath *path;
+  struct stat sbuf;
+  
+  if (0 != stat (item->filename,
+                &sbuf))
+  {
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "stat", item->filename);
+    return;
+  }
+
+  gtk_tree_store_insert_after (ts, item_iter, parent, sibling);
+  path = gtk_tree_model_get_path (GTK_TREE_MODEL (ts), item_iter);
+  row_reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts), path);
+  gtk_tree_path_free (path);
+
+  if (item->is_directory)
+  {
+    if (NULL != item->meta)
+      GNUNET_CONTAINER_meta_data_delete (item->meta,
+                                        EXTRACTOR_METATYPE_MIMETYPE, NULL, 0);
+    else
+      item->meta = GNUNET_CONTAINER_meta_data_create ();
+    GNUNET_FS_meta_data_make_directory (item->meta);
+    if (NULL == item->ksk_uri)
+      item->ksk_uri = GNUNET_FS_uri_ksk_create (GNUNET_FS_DIRECTORY_MIME, 
NULL);
+    else
+      GNUNET_FS_uri_ksk_add_keyword (item->ksk_uri, GNUNET_FS_DIRECTORY_MIME,
+                                    GNUNET_NO);
+    fi = GNUNET_FS_file_information_create_empty_directory (
+        GNUNET_FS_GTK_get_fs_handle (), row_reference, item->ksk_uri,
+        item->meta, &adcc->directory_scan_bo, item->filename);
+  }
+  else
+  {
+    fi = GNUNET_FS_file_information_create_from_file (
+        GNUNET_FS_GTK_get_fs_handle (), row_reference, item->filename,
+        item->ksk_uri, item->meta, adcc->directory_scan_do_index,
+        &adcc->directory_scan_bo);
+  }
+  if (item->is_directory)
+    file_size_fancy = GNUNET_strdup (MARKER_DIR_FILE_SIZE);
+  else
+    file_size_fancy = GNUNET_STRINGS_byte_size_fancy (sbuf.st_size);
+  
+  gtk_tree_store_set (ts, item_iter, 0, file_size_fancy,
+      1, (gboolean) adcc->directory_scan_do_index,
+      2, item->short_filename,
+      3, (guint) adcc->directory_scan_bo.anonymity_level,
+      4, (guint) adcc->directory_scan_bo.content_priority,
+      5, fi,
+      6, (guint64) adcc->directory_scan_bo.expiration_time.abs_value,
+      7, (guint) adcc->directory_scan_bo.replication_level, -1);
+  GNUNET_free (file_size_fancy);
+}
+
+
+/**
+ * Traverse the share tree and add it to the tree store
+ *
+ */
+static void
+add_share_items_to_treestore (struct AddDirClientContext *adcc,
+                             struct GNUNET_FS_ShareTreeItem *toplevel,
+                             GtkTreeIter *parent_iter)
+{
+  struct MainPublishingDialogContext *ctx = adcc->ctx;
+  GtkTreeStore *ts = GTK_TREE_STORE (ctx->file_info_treemodel);
+  GtkTreeIter *sibling_iter;
+  GtkTreeIter last_added;
+  struct GNUNET_FS_ShareTreeItem *item;
+
+  sibling_iter = NULL;  
+  for (item = toplevel; item != NULL; item = item->next)
+  {
+    add_item (adcc, ts, item, parent_iter, sibling_iter, &last_added);
+    sibling_iter = &last_added;
+    if (item->is_directory) 
+      add_share_items_to_treestore (adcc,
+                                   item->children_head,
+                                   sibling_iter);
+  }
+}
+
+
+static void
+close_scan (struct AddDirClientContext *adcc)
+{
+  gtk_widget_destroy (adcc->progress_dialog);
+  g_object_unref (G_OBJECT (adcc->progress_dialog_builder));  
+  GNUNET_CONTAINER_DLL_remove (adcc->ctx->adddir_head,
+                              adcc->ctx->adddir_tail, 
+                              adcc);
+  update_selectivity (adcc->ctx);
+  GNUNET_free (adcc);
+}
+
+
+static void
+directory_scan_cb (void *cls, 
+                  const char *filename, int is_directory,
+                  enum GNUNET_FS_DirScannerProgressUpdateReason reason)
+{
+  static struct GNUNET_TIME_Absolute last_pulse;
+  struct AddDirClientContext *adcc = cls;
+  char *s;
+  gdouble fraction;
+
+  switch (reason)
+  {
+  case GNUNET_FS_DIRSCANNER_FILE_START:
+    GNUNET_assert (filename != NULL);
+    if (GNUNET_TIME_absolute_get_duration (last_pulse).rel_value > 100)
+    {
+      gtk_progress_bar_pulse (adcc->progress_dialog_bar);
+      last_pulse = GNUNET_TIME_absolute_get ();
+    }
+#if VERBOSE_PROGRESS
+    if (is_directory)
+    {
+      GNUNET_asprintf (&s, _("Scanning directory `%s'.\n"), filename);
+      insert_progress_dialog_text (adcc, s);
+      GNUNET_free (s);
+    }
+    else
+      adcc->total++;
+#else
+    if (! is_directory)
+      adcc->total++;
+#endif
+    break;
+  case GNUNET_FS_DIRSCANNER_FILE_IGNORED:
+    GNUNET_assert (filename != NULL);
+    GNUNET_asprintf (&s,
+                    _("Failed to scan `%s' (access error). Skipping.\n"),
+                    filename);
+#if ! VERBOSE_PROGRESS
+    gtk_widget_show (GTK_WIDGET (gtk_builder_get_object 
(adcc->progress_dialog_builder,
+                                                        
"GNUNET_FS_GTK_progress_dialog_scrolled_window")));
+#endif
+    insert_progress_dialog_text (adcc, s);
+    GNUNET_free (s);    
+    break;
+  case GNUNET_FS_DIRSCANNER_ALL_COUNTED:
+    fraction = (adcc->total == 0) ? 1.0 : (1.0 * adcc->done) / adcc->total;
+    GNUNET_asprintf (&s, "%u/%u (%3f%%)", 
+                    adcc->done,
+                    adcc->total,
+                    100.0 * fraction);
+    gtk_progress_bar_set_text (adcc->progress_dialog_bar,
+                              s);    
+    GNUNET_free (s);
+    gtk_progress_bar_set_fraction (adcc->progress_dialog_bar,
+                                  fraction);
+    break;
+  case GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED:
+#if VERBOSE_PROGRESS
+    GNUNET_asprintf (&s, _("Processed file `%s'.\n"), filename);
+    insert_progress_dialog_text (adcc, s);
+    GNUNET_free (s);
+#endif
+    adcc->done++;
+    GNUNET_assert (adcc->done <= adcc->total);
+    fraction = (adcc->total == 0) ? 1.0 : (1.0 * adcc->done) / adcc->total;
+    GNUNET_asprintf (&s, "%u/%u (%3f%%)", 
+                    adcc->done,
+                    adcc->total,
+                    100.0 * fraction);
+    gtk_progress_bar_set_text (adcc->progress_dialog_bar,
+                              s);    
+    GNUNET_free (s);
+    gtk_progress_bar_set_fraction (adcc->progress_dialog_bar,
+                                  fraction);
+    break;
+  case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR:
+    insert_progress_dialog_text (adcc, _("Operation failed (press cancel)\n"));
+    GNUNET_FS_directory_scan_abort (adcc->ds);
+    adcc->ds = NULL;
+    break;
+  case GNUNET_FS_DIRSCANNER_FINISHED:
+    insert_progress_dialog_text (adcc, _("Scanner has finished.\n"));
+    adcc->directory_scan_result = GNUNET_FS_directory_scan_get_result 
(adcc->ds);
+    adcc->ds = NULL;
+    GNUNET_FS_share_tree_trim (adcc->directory_scan_result);
+    add_share_items_to_treestore (adcc, 
+                                 adcc->directory_scan_result,
+                                 NULL);
+    GNUNET_FS_share_tree_free (adcc->directory_scan_result);
+    adcc->directory_scan_result = NULL;
+    update_selectivity (adcc->ctx);
+    close_scan (adcc);
+    break;
+  default:
+    GNUNET_break (0);
+    break;
+  }
+}
+
+
+static void
+scan_file_or_directory (struct MainPublishingDialogContext *ctx, 
+                       gchar *filename,
+                       struct GNUNET_FS_BlockOptions *bo, 
+                       int do_index)
+{
+  struct AddDirClientContext *adcc;
+  GtkTextIter iter;
+
+  adcc = GNUNET_malloc (sizeof (struct AddDirClientContext));
+  adcc->ctx = ctx;
+  GNUNET_CONTAINER_DLL_insert_tail (ctx->adddir_head, ctx->adddir_tail, adcc);
+  adcc->ds = GNUNET_FS_directory_scan_start (filename,
+      GNUNET_NO, NULL, &directory_scan_cb, adcc);
+  adcc->directory_scan_bo = *bo;
+  adcc->directory_scan_do_index = do_index;
+
+  adcc->progress_dialog_builder = GNUNET_GTK_get_new_builder (
+      "gnunet_fs_gtk_progress_dialog.glade", adcc);
+  adcc->progress_dialog = GTK_WIDGET (gtk_builder_get_object (
+      adcc->progress_dialog_builder,
+      "GNUNET_FS_GTK_progress_dialog"));
+  adcc->progress_dialog_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (
+      adcc->progress_dialog_builder,
+      "GNUNET_FS_GTK_progress_dialog_progressbar"));
+  adcc->progress_dialog_cancel = GTK_BUTTON (gtk_builder_get_object (
+      adcc->progress_dialog_builder,
+      "GNUNET_FS_GTK_progress_dialog_cancel_button"));
+  adcc->progress_dialog_textview = GTK_TEXT_VIEW (
+      gtk_builder_get_object (adcc->progress_dialog_builder,
+      "GNUNET_FS_GTK_progress_dialog_textview"));
+  adcc->textview_vertial_adjustment  = GTK_ADJUSTMENT (
+      gtk_builder_get_object (adcc->progress_dialog_builder,
+      "GNUNET_FS_GTK_progress_dialog_textview_vertical_adjustment"));
+  adcc->progress_dialog_textbuffer = GTK_TEXT_BUFFER (
+      gtk_builder_get_object (adcc->progress_dialog_builder,
+      "GNUNET_FS_GTK_progress_dialog_textbuffer"));
+  gtk_text_buffer_get_end_iter (adcc->progress_dialog_textbuffer,
+      &iter);
+  adcc->progress_dialog_textmark = gtk_text_buffer_create_mark (
+      adcc->progress_dialog_textbuffer, "scroll",
+      &iter, FALSE);
+#if VERBOSE_PROGRESS
+  gtk_widget_show (GTK_WIDGET (gtk_builder_get_object 
(adcc->progress_dialog_builder,
+                                                      
"GNUNET_FS_GTK_progress_dialog_scrolled_window")));
+#endif
+
+  gtk_window_set_transient_for (GTK_WINDOW (adcc->progress_dialog), 
adcc->ctx->master_pubdialog);
+  gtk_window_set_title (GTK_WINDOW (adcc->progress_dialog), filename);
+  gtk_window_present (GTK_WINDOW (adcc->progress_dialog));
+
+  update_selectivity (ctx);
+}
+
+
+static void
+publish_directory_dialog_response_cb (GtkDialog * dialog,
+                                     gint response_id,
+                                     struct MainPublishingDialogContext *ctx)
+{
+  char *filename;
+  int do_index;
+  GtkSpinButton *sb;
+  struct GNUNET_FS_BlockOptions bo;
+  GtkWidget *ad;
+
+  if (g_signal_handler_is_connected (G_OBJECT (dialog), 
ctx->open_directory_handler_id))
+    g_signal_handler_disconnect (G_OBJECT (dialog), 
ctx->open_directory_handler_id);
+  ctx->open_directory_handler_id = 0;
+
+  ad = GTK_WIDGET (gtk_builder_get_object
+                   (ctx->open_directory_builder, 
"GNUNET_GTK_publish_directory_dialog"));
+  if (response_id == -5)
+  {
+    filename = GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER 
(ad));
+    sb = GTK_SPIN_BUTTON (gtk_builder_get_object
+                          (ctx->open_directory_builder,
+                           
"GNUNET_GTK_publish_directory_dialog_expiration_year_spin_button"));
+    if (!GNUNET_GTK_get_selected_anonymity_level
+        (ctx->open_directory_builder, 
"GNUNET_GTK_publish_directory_dialog_anonymity_combobox",
+         &bo.anonymity_level))
+      bo.anonymity_level = 1;
+    bo.content_priority =
+      gtk_spin_button_get_value (GTK_SPIN_BUTTON
+                                   (gtk_builder_get_object
+                                    (ctx->open_directory_builder,
+                                     
"GNUNET_GTK_publish_directory_dialog_priority_spin_button")));
+    bo.replication_level = 
+      gtk_spin_button_get_value (GTK_SPIN_BUTTON
+                                (gtk_builder_get_object
+                                 (ctx->open_directory_builder,
+                                  
"GNUNET_GTK_publish_directory_dialog_replication_spin_button")));
+    bo.expiration_time = GNUNET_FS_GTK_get_expiration_time (sb);
+    do_index =
+        gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
+                                      (gtk_builder_get_object
+                                       (ctx->open_directory_builder,
+                                        
"GNUNET_GTK_publish_directory_dialog_do_index_checkbutton")));
+
+    scan_file_or_directory (ctx, filename, &bo, do_index);
+    g_free (filename);
+  }
+  gtk_widget_destroy (ad);
+  g_object_unref (G_OBJECT (ctx->open_directory_builder));
+}
+
+
+static void
+publish_file_dialog_response_cb (GtkDialog * dialog,
+                                gint response_id,
+                                struct MainPublishingDialogContext *ctx)
+{
+  char *filename;
+  struct GNUNET_FS_BlockOptions bo;
+  int do_index;
+  GtkSpinButton *sb;
+  GtkWidget *ad;
+
+  if (g_signal_handler_is_connected (G_OBJECT (dialog), 
ctx->open_file_handler_id))
+    g_signal_handler_disconnect (G_OBJECT (dialog), ctx->open_file_handler_id);
+  ctx->open_file_handler_id = 0;
+
+  ad = GTK_WIDGET (gtk_builder_get_object
+                   (ctx->open_file_builder, "GNUNET_GTK_publish_file_dialog"));
+
+  if (response_id == -5)
+  {
+    /* OK */
+    sb = GTK_SPIN_BUTTON (gtk_builder_get_object
+                          (ctx->open_file_builder,
+                           
"GNUNET_GTK_publish_file_dialog_expiration_year_spin_button"));
+
+    if (!GNUNET_GTK_get_selected_anonymity_level
+        (ctx->open_file_builder, 
"GNUNET_GTK_publish_file_dialog_anonymity_combobox",
+         &bo.anonymity_level))
+      bo.anonymity_level = 1;
+    bo.content_priority =
+        gtk_spin_button_get_value (GTK_SPIN_BUTTON
+                                   (gtk_builder_get_object
+                                    (ctx->open_file_builder,
+                                     
"GNUNET_GTK_publish_file_dialog_priority_spin_button")));
+    bo.expiration_time = GNUNET_FS_GTK_get_expiration_time (sb);
+    bo.replication_level =
+      gtk_spin_button_get_value (GTK_SPIN_BUTTON
+                                (gtk_builder_get_object
+                                 (ctx->open_file_builder,
+                                  
"GNUNET_GTK_publish_file_dialog_replication_spin_button")));
+    do_index =
+        gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
+                                      (gtk_builder_get_object
+                                       (ctx->open_file_builder,
+                                        
"GNUNET_GTK_publish_file_dialog_do_index_checkbutton")));
+
+    filename = GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER 
(ad));
+
+    scan_file_or_directory (ctx, filename, &bo, do_index);
+
+    g_free (filename);
+  }
+  else
+  {
+    /* Cancel/Escape/close/etc */
+  }
+  gtk_widget_destroy (ad);
+}
+
+
+void
+GNUNET_GTK_master_publish_dialog_add_button_clicked_cb (GtkWidget * dummy,
+                                                        struct 
MainPublishingDialogContext *ctx)
+{
+  GtkWidget *ad;
+
+  GtkComboBox *combo;
+  GtkTreeModel *anon_treemodel;
+
+  ctx->open_file_builder = GNUNET_GTK_get_new_builder 
("gnunet_fs_gtk_publish_file_dialog.glade", ctx);
+  GNUNET_FS_GTK_setup_expiration_year_adjustment (ctx->open_file_builder);
+  ad = GTK_WIDGET (gtk_builder_get_object
+                   (ctx->open_file_builder, "GNUNET_GTK_publish_file_dialog"));
+
+  /* FIXME: Use some kind of adjustable defaults instead of 1000, 0 and TRUE */
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
+      ctx->open_file_builder,
+      "GNUNET_GTK_publish_file_dialog_priority_spin_button")), 1000);
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
+      ctx->open_file_builder,
+      "GNUNET_GTK_publish_file_dialog_replication_spin_button")), 0);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (
+      ctx->open_file_builder,
+      "GNUNET_GTK_publish_file_dialog_do_index_checkbutton")), TRUE);
+
+  ctx->open_file_handler_id = g_signal_connect (G_OBJECT (ad), "response", 
G_CALLBACK (publish_file_dialog_response_cb), ctx);
+
+  anon_treemodel = GTK_TREE_MODEL (gtk_builder_get_object 
(ctx->main_window_builder,
+      "main_window_search_anonymity_liststore"));
+  combo = GTK_COMBO_BOX (gtk_builder_get_object (ctx->open_file_builder,
+      "GNUNET_GTK_publish_file_dialog_anonymity_combobox"));
+  gtk_combo_box_set_model (combo, anon_treemodel);
+
+  gtk_window_set_transient_for (GTK_WINDOW (ad), ctx->master_pubdialog);
+
+  gtk_window_present (GTK_WINDOW (ad));
+}
+
+
+struct EditPublishContext
+{
+  struct GNUNET_FS_FileInformation *fip;
+
+  GtkTreeModel *tm;
+
+  GtkTreeIter iter;
+};
+
+
+/**
+ * Update tree view based on the information from the
+ * GNUNET_FS_FileInformation publish-structure.
+ *
+ * @param cls closure, a 'struct EditPublishContext *'
+ * @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_OK to continue, GNUNET_NO to remove
+ *         this entry from the directory, GNUNET_SYSERR
+ *         to abort the iteration
+ */
+static int
+update_treeview_after_edit (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 EditPublishContext *epc = cls;
+  
+  gtk_tree_store_set (GTK_TREE_STORE (epc->tm), &epc->iter, 
+                     1, *do_index,
+                     3, (guint) bo->anonymity_level, 
+                     4, (guint) bo->content_priority, 
+                     6, (guint64) bo->expiration_time.abs_value,
+                     7, (guint) bo->replication_level,                 
+                     -1); 
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Function called when the edit publish dialog has been closed.
+ *
+ * @param cls closure
+ * @param ret GTK_RESPONSE_OK if the dialog was closed with "OK"
+ * @param root unused (namespace root name)
+ */
+static void
+master_publish_edit_publish_dialog_cb (gpointer cls,
+                                      gint ret,
+                                       const char *root)
+{
+  struct EditPublishContext *cbargs = cls;
+
+  if (ret == GTK_RESPONSE_OK)
+    GNUNET_FS_file_information_inspect (cbargs->fip, 
&update_treeview_after_edit, cbargs);
+  GNUNET_free (cbargs);
+}
+
+
+void
+GNUNET_GTK_master_publish_dialog_edit_button_clicked_cb (GtkWidget * dummy,
+                                                         struct 
MainPublishingDialogContext *ctx)
+{
+  struct EditPublishContext *cbargs;
+  GtkListStore *anon_liststore;
+
+  anon_liststore = GTK_LIST_STORE (gtk_builder_get_object 
(ctx->main_window_builder, 
+                                                          
"main_window_search_anonymity_liststore"));
+  cbargs = GNUNET_malloc (sizeof (struct EditPublishContext));
+  cbargs->tm = ctx->file_info_treemodel;
+  if (! gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&cbargs->iter))
+  {
+    GNUNET_break (0);
+    GNUNET_free (cbargs);
+    return;
+  }
+  gtk_tree_model_get (ctx->file_info_treemodel, &cbargs->iter,
+                     5, &cbargs->fip, 
+                     -1);
+  /* FIXME: can we just give our anon_liststore out like this? What about
+     (unintended) sharing of state? */
+  GNUNET_FS_GTK_edit_publish_dialog (ctx->master_pubdialog, 
+                                     cbargs->fip, 
+                                    GNUNET_YES, 
+                                    anon_liststore,
+                                     &master_publish_edit_publish_dialog_cb,
+                                     cbargs);
+}
+
+
+/**
+ * Free row reference stored in the file information's
+ * client-info pointer.
+ */
+static int
+free_fi_row_reference (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)
+{
+  GtkTreeRowReference *row = *client_info;
+
+  if (row == NULL)
+  {
+    GNUNET_break (0);
+    return GNUNET_OK;
+  }
+  gtk_tree_row_reference_free (row);
+  return GNUNET_OK;
+}
+
+
+void
+GNUNET_GTK_master_publish_dialog_delete_button_clicked_cb (GtkWidget * dummy,
+                                                           struct 
MainPublishingDialogContext *ctx)
+{
+  GtkTreeIter iter;
+  struct GNUNET_FS_FileInformation *fip;
+
+  if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, 
&iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  gtk_tree_model_get (ctx->file_info_treemodel, &iter, 5, &fip, -1);
+  GNUNET_FS_file_information_destroy (fip, &free_fi_row_reference, NULL);
+  gtk_tree_store_remove (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
+  update_selectivity (ctx);
+}
+
+
+void
+GNUNET_FS_GTK_progress_dialog_cancel_button_clicked_cb (GtkButton *button,
+                                                       void *cls)
+{
+  struct AddDirClientContext *adcc = cls;
+
+  if (adcc->ds != NULL)
+  {
+    /* Still scanning - signal the scanner to finish */
+    GNUNET_FS_directory_scan_abort (adcc->ds);
+    adcc->ds = NULL;
+  }
+  close_scan (adcc);
+}
+
+
+gboolean
+GNUNET_FS_GTK_progress_dialog_delete_event_cb (GtkWidget *widget,
+                                              GdkEvent * event,
+                                              void *cls)
+{
+  /* Don't allow GTK to kill the window, until the scan is finished */
+  return GNUNET_NO;
+}
+
+
+void
+GNUNET_GTK_master_publish_dialog_open_button_clicked_cb (GtkWidget * dummy,
+                                                         struct 
MainPublishingDialogContext *ctx)
+{
+  GtkWidget *ad;
+
+  GtkComboBox *combo;
+  GtkTreeModel *anon_treemodel;
+
+  ctx->open_directory_builder = GNUNET_GTK_get_new_builder 
("gnunet_fs_gtk_publish_directory_dialog.glade", ctx);
+  GNUNET_FS_GTK_setup_expiration_year_adjustment (ctx->open_directory_builder);
+
+  /* FIXME: Use some kind of adjustable defaults instead of 1000, 0 and TRUE */
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
+      ctx->open_directory_builder,
+      "GNUNET_GTK_publish_directory_dialog_priority_spin_button")), 1000);
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
+      ctx->open_directory_builder,
+      "GNUNET_GTK_publish_directory_dialog_replication_spin_button")), 0);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (
+      ctx->open_directory_builder,
+      "GNUNET_GTK_publish_directory_dialog_do_index_checkbutton")), TRUE);
+
+  ad = GTK_WIDGET (gtk_builder_get_object
+                   (ctx->open_directory_builder, 
"GNUNET_GTK_publish_directory_dialog"));
+
+  ctx->open_directory_handler_id = g_signal_connect (G_OBJECT (ad), 
"response", G_CALLBACK (publish_directory_dialog_response_cb), ctx);
+
+  anon_treemodel = GTK_TREE_MODEL (gtk_builder_get_object 
(ctx->main_window_builder,
+      "main_window_search_anonymity_liststore"));
+  combo = GTK_COMBO_BOX (gtk_builder_get_object (ctx->open_directory_builder,
+      "GNUNET_GTK_publish_directory_dialog_anonymity_combobox"));
+  gtk_combo_box_set_model (combo, anon_treemodel);
+
+  gtk_window_set_transient_for (GTK_WINDOW (ad), ctx->master_pubdialog);
+
+  gtk_window_present (GTK_WINDOW (ad));
+}
+
+
+/**
+ * Get the file information struct corresponding to the
+ * given iter in the publish dialog tree model.  Recursively
+ * builds the file information struct from the subtree.
+ *
+ * @param tm model to grab fi from
+ * @param iter position to grab fi from
+ * @return file information from the given position (never NULL)
+ */
+static struct GNUNET_FS_FileInformation *
+get_file_information (GtkTreeModel * tm, GtkTreeIter * iter)
+{
+  struct GNUNET_FS_FileInformation *fi;
+  struct GNUNET_FS_FileInformation *fic;
+  GtkTreeIter child;
+
+  gtk_tree_model_get (tm, iter, 5, &fi, -1);
+  gtk_tree_store_set (GTK_TREE_STORE (tm), iter, 5, NULL, -1);
+  GNUNET_assert (fi != NULL);
+  if (gtk_tree_model_iter_children (tm, &child, iter))
+  {
+    GNUNET_break (GNUNET_YES == GNUNET_FS_file_information_is_directory (fi));
+    do
+    {
+      fic = get_file_information (tm, &child);
+      GNUNET_break (GNUNET_OK == GNUNET_FS_file_information_add (fi, fic));
+    }
+    while (gtk_tree_model_iter_next (tm, &child));
+  }
+  return fi;
+}
+
+
+/**
+ * Closure for 'add_updateable_to_ts'.
+ */
+struct UpdateableContext
+{
+  /**
+   * Parent of current insertion.
+   */
+  GtkTreeIter *parent;
+
+  /**
+   * Tree store we are modifying.
+   */
+  GtkTreeStore *ts;
+
+  /**
+   * Name of the namespace.
+   */
+  const char *namespace_name;
+
+  /**
+   * Handle to the namespace.
+   */
+  struct GNUNET_FS_Namespace *ns;
+
+  /**
+   * Hash codes of identifiers already added to tree store.
+   */
+  struct GNUNET_CONTAINER_MultiHashMap *seen;
+
+  /**
+   * Did the iterator get called?
+   */
+  int update_called;
+};
+
+
+/**
+ * Add updateable entries to the tree view.
+ *
+ * @param cls closure
+ * @param last_id ID to add
+ * @param last_uri associated URI
+ * @param last_meta associate meta data
+ * @param next_id ID for future updates
+ */
+static void
+add_updateable_to_ts (void *cls, const char *last_id,
+                      const struct GNUNET_FS_Uri *last_uri,
+                      const struct GNUNET_CONTAINER_MetaData *last_meta,
+                      const char *next_id)
+{
+  struct UpdateableContext *uc = cls;
+  struct UpdateableContext sc;
+  GtkTreeIter iter;
+  GtkTreeIter titer;
+  char *desc;
+  GNUNET_HashCode hc;
+
+  uc->update_called = GNUNET_YES;
+  GNUNET_CRYPTO_hash (last_id, strlen (last_id), &hc);
+  if (NULL != GNUNET_CONTAINER_multihashmap_get (uc->seen, &hc))
+    return;
+  GNUNET_CONTAINER_multihashmap_put (uc->seen, &hc, "dummy",
+                                     
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+  /* FIXME: what if this put fails?  Not convinced it cannot... */
+  desc =
+      GNUNET_CONTAINER_meta_data_get_first_by_types (last_meta,
+                                                     
EXTRACTOR_METATYPE_DESCRIPTION,
+                                                     EXTRACTOR_METATYPE_TITLE,
+                                                     
EXTRACTOR_METATYPE_BOOK_TITLE,
+                                                     
EXTRACTOR_METATYPE_FILENAME,
+                                                     
EXTRACTOR_METATYPE_SUMMARY,
+                                                     EXTRACTOR_METATYPE_ALBUM,
+                                                     
EXTRACTOR_METATYPE_COMMENT,
+                                                     
EXTRACTOR_METATYPE_SUBJECT,
+                                                     -1);
+  if (desc == NULL)
+    desc = GNUNET_strdup (_("no description supplied"));
+  else
+  {
+    char *utf8_desc = NULL;
+
+    utf8_desc =
+        GNUNET_FS_GTK_dubious_meta_to_utf8 (EXTRACTOR_METAFORMAT_UTF8, desc,
+                                            strlen (desc) + 1);
+    GNUNET_free (desc);
+    if (utf8_desc != NULL)
+      desc = utf8_desc;
+    else
+      desc = NULL;
+  }
+  gtk_tree_store_insert_with_values (uc->ts, &iter, uc->parent, G_MAXINT, 0,
+                                     uc->namespace_name, 1, uc->ns, 2, last_id,
+                                     3, GNUNET_FS_uri_dup (last_uri), 4,
+                                     GNUNET_CONTAINER_meta_data_duplicate
+                                     (last_meta), 5, "", 6, desc, 7,
+                                     TRUE /* update editable (always) */ ,
+                                     8, FALSE
+                                     /* current not editable (only for 
top-level) */
+                                     , -1);
+  GNUNET_free_non_null (desc);
+  sc.parent = &iter;
+  sc.ts = uc->ts;
+  sc.namespace_name = uc->namespace_name;
+  sc.ns = uc->ns;
+  sc.seen = uc->seen;
+  sc.update_called = GNUNET_NO;
+  GNUNET_FS_namespace_list_updateable (uc->ns, next_id, &add_updateable_to_ts,
+                                       &sc);
+  if ((sc.update_called == GNUNET_NO) && (next_id != NULL) &&
+      (strlen (next_id) > 0))
+  {
+    /* add leaf */
+    gtk_tree_store_insert_with_values (uc->ts, &titer, &iter, G_MAXINT, 0,
+                                       uc->namespace_name, 1, uc->ns, 2,
+                                       next_id, 3, NULL, 4, NULL, 5, "", 6, "",
+                                       7, TRUE /* update editable (always) */ ,
+                                       8, FALSE
+                                       /* current not editable (only for 
top-level) */
+                                       , -1);
+  }
+}
+
+
+/**
+ * Add all updateable entries of the current namespace to the
+ * tree store.
+ *
+ * @param cls the 'GtkTreeStore' to update
+ * @param name name of the namespace to add
+ * @param id identity of the namespace to add
+ */
+static void
+add_namespace_to_ts (void *cls, const char *name, const GNUNET_HashCode * id)
+{
+  GtkTreeStore *ts = cls;
+  struct UpdateableContext uc;
+  GtkTreeIter iter;
+
+  uc.parent = &iter;
+  uc.namespace_name = name;
+  uc.ts = ts;
+  uc.ns = GNUNET_FS_namespace_create (GNUNET_FS_GTK_get_fs_handle (), name);
+  uc.update_called = GNUNET_NO;
+  gtk_tree_store_insert_with_values (ts, &iter, NULL, G_MAXINT, 0, name, 1,
+                                     uc.ns, 2, NULL /* last-id */ ,
+                                     3, NULL /* last-uri (as string!) */ ,
+                                     4, NULL /* meta */ ,
+                                     5, NULL /* next-ID */ ,
+                                     6, NULL /* last-description */ ,
+                                     7, TRUE /* update editable */ ,
+                                     8, TRUE /* current editable */ ,
+                                     -1);
+  uc.seen = GNUNET_CONTAINER_multihashmap_create (128);
+  GNUNET_FS_namespace_list_updateable (uc.ns, NULL, &add_updateable_to_ts, 
&uc);
+  GNUNET_CONTAINER_multihashmap_destroy (uc.seen);
+}
+
+
+static void
+free_pseudonym_tree_store (GtkTreeModel * tm, GtkTreeIter * iter)
+{
+  struct GNUNET_CONTAINER_MetaData *meta;
+  struct GNUNET_FS_Namespace *ns;
+  GtkTreeIter child;
+
+  gtk_tree_model_get (tm, iter, 1, &ns, 4, &meta, -1);
+  if (meta != NULL)
+    GNUNET_CONTAINER_meta_data_destroy (meta);
+  if (ns != NULL)
+  {
+    // FIXME: delete ns?
+    // GNUNET_FS_namespace_delete (nso, GNUNET_NO);
+  }
+  if (TRUE == gtk_tree_model_iter_children (tm, &child, iter))
+  {
+    do
+    {
+      free_pseudonym_tree_store (tm, &child);
+    }
+    while (TRUE == gtk_tree_model_iter_next (tm, &child));
+  }
+}
+
+
+static void
+free_file_information_tree_store (GtkTreeModel * tm, GtkTreeIter * iter)
+{
+  GtkTreeIter child;
+  struct GNUNET_FS_FileInformation *fip;
+
+  gtk_tree_model_get (tm, iter, 5, &fip, -1);
+  if (fip != NULL)
+    GNUNET_FS_file_information_destroy (fip, NULL, NULL);
+  if (TRUE == gtk_tree_model_iter_children (tm, &child, iter))
+  {
+    do
+    {
+      free_file_information_tree_store (tm, &child);
+    }
+    while (TRUE == gtk_tree_model_iter_next (tm, &child));
+  }
+}
+
+static int
+hide_master_publish_dialog (struct MainPublishingDialogContext *ctx, gint ret)
+{
+  GtkTreeIter iter;
+  gpointer namespace;
+  gchar *namespace_id;
+  gchar *namespace_uid;
+  struct GNUNET_FS_FileInformation *fi;
+
+  /* Don't close until all scanners are finished */
+  if (ctx->adddir_head != NULL)
+    return GNUNET_NO;
+
+  if (ret == GTK_RESPONSE_OK)
+  {
+    if (TRUE == gtk_tree_selection_get_selected (ctx->pseudonym_selection, 
NULL, &iter))
+    {
+      gtk_tree_model_get (ctx->pseudonym_treemodel, &iter, 1, &namespace, 2, 
&namespace_id, 5,
+                          &namespace_uid, -1);
+    }
+    else
+    {
+      namespace = NULL;
+      namespace_id = NULL;
+      namespace_uid = NULL;
+    }
+    if (gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &iter))
+      do
+      {
+        fi = get_file_information (ctx->file_info_treemodel, &iter);
+        /* FIXME: should we convert namespace id and uid from UTF8? */
+        GNUNET_FS_publish_start (GNUNET_FS_GTK_get_fs_handle (), fi, namespace,
+                                 namespace_id, namespace_uid,
+                                 GNUNET_FS_PUBLISH_OPTION_NONE);
+      }
+      while (gtk_tree_model_iter_next (ctx->file_info_treemodel, &iter));
+    g_free (namespace_id);
+    g_free (namespace_uid);
+  }
+
+  /* free state from 'ptm' */
+  if (TRUE == gtk_tree_model_get_iter_first (ctx->pseudonym_treemodel, &iter))
+    do
+    {
+      free_pseudonym_tree_store (ctx->pseudonym_treemodel, &iter);
+    }
+    while (TRUE == gtk_tree_model_iter_next (ctx->pseudonym_treemodel, &iter));
+  gtk_tree_store_clear (GTK_TREE_STORE (ctx->pseudonym_treemodel));
+
+  /* free state from 'tm' */
+  if (TRUE == gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &iter))
+    do
+    {
+      free_file_information_tree_store (ctx->file_info_treemodel, &iter);
+    }
+    while (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, &iter));
+  gtk_tree_store_clear (GTK_TREE_STORE (ctx->file_info_treemodel));
+  gtk_widget_destroy (GTK_WIDGET (ctx->master_pubdialog));
+  g_object_unref (G_OBJECT (ctx->builder));
+  GNUNET_free (ctx);
+  return GNUNET_YES;
+}
+
+
+void
+GNUNET_GTK_master_publish_dialog_execute_button_clicked_cb (GtkButton * button,
+                                                            struct 
MainPublishingDialogContext *ctx)
+{
+  hide_master_publish_dialog (ctx, GTK_RESPONSE_OK);
+}
+
+
+void
+GNUNET_GTK_master_publish_dialog_cancel_button_clicked_cb (GtkButton * button,
+                                                           struct 
MainPublishingDialogContext *ctx)
+{
+  hide_master_publish_dialog (ctx, GTK_RESPONSE_CANCEL);
+}
+
+
+gboolean
+GNUNET_GTK_master_publish_dialog_delete_event_cb (GtkWidget * widget,
+                                                  GdkEvent * event,
+                                                  struct 
MainPublishingDialogContext *ctx)
+{
+  if (GNUNET_NO == hide_master_publish_dialog (ctx, GTK_RESPONSE_CANCEL))
+    return TRUE;
+  return FALSE;
+}
+
+
+/**
+ */
+void
+GNUNET_GTK_main_menu_file_publish_activate_cb (GtkWidget * dummy, gpointer 
user_data)
+{
+  struct MainPublishingDialogContext *ctx;
+
+  ctx = GNUNET_malloc (sizeof (struct MainPublishingDialogContext));
+  ctx->builder = GNUNET_GTK_get_new_builder 
("gnunet_fs_gtk_publish_dialog.glade", ctx);
+
+  if (ctx->builder == NULL)
+  {
+    GNUNET_free (ctx);
+    return;
+  }
+
+  init_ctx (ctx);
+  ctx->main_window_builder = GTK_BUILDER (user_data);
+  GNUNET_FS_namespace_list (GNUNET_FS_GTK_get_fs_handle (),
+                            &add_namespace_to_ts, GTK_TREE_STORE 
(ctx->pseudonym_treemodel));
+  gtk_window_present (GTK_WINDOW (ctx->master_pubdialog));
+}
+
+
+/* end of gnunet-fs-gtk-main_window_file_publish.c */

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_publish-edit-dialog.c (from rev 19628, 
gnunet-gtk/src/fs/gnunet-fs-gtk-edit_publish_dialog.c)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_publish-edit-dialog.c                       
        (rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_publish-edit-dialog.c       2012-02-02 
13:28:32 UTC (rev 19629)
@@ -0,0 +1,1163 @@
+/*
+     This file is part of GNUnet
+     (C) 2005, 2006, 2010, 2012 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_publish-edit-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 <gnunet/gnunet_util_lib.h>
+
+#include "metatypes.c"
+
+
+/**
+ * Internal state kept for each "edit" dialog where the user can edit
+ * publishing information for a file.
+ */
+struct EditPublicationDialogContext
+{
+  /**
+   * Builder for the dialog.
+   */
+  GtkBuilder *builder;
+
+  /**
+   * The 'window' object for the dialog.
+   */
+  GtkWindow *edit_publication_window;
+
+  /**
+   * The confirmation button which closes the dialog (only sensitive
+   * if the values entered are valid).
+   */
+  GtkWidget *confirm_button;
+
+  /**
+   * Tree view showing the meta data for the file.
+   */
+  GtkTreeView *meta_treeview;
+
+  /**
+   * Tree view showing the keywords for the file.
+   */
+  GtkTreeView *keywords_treeview;
+
+  /**
+   * Image showing the preview image for the file.
+   */
+  GtkImage *preview_image;
+
+  /**
+   * Combo box where the user can select the anonymity level.
+   */
+  GtkComboBox *anonymity_combo;
+
+  /**
+   * Liststore of possible publication types.
+   */
+  GtkListStore *pubtypes_liststore;
+
+  /**
+   * Liststore of all possible meta types the user can choose from.
+   * (updated to based on the selected publication type).
+   */
+  GtkListStore *metatypes_liststore;
+
+  /**
+   * Liststore showing the meta data of the file (associated with
+   * the 'meta_treeview'.
+   */
+  GtkListStore *meta_liststore;
+
+  /**
+   * Liststore with the keywords of the file (associated with the
+   * 'keywords_treeview'.
+   */
+  GtkListStore *keywords_liststore;
+
+  /**
+   * Spin button to select content priority level for the file.
+   */
+  GtkSpinButton *priority_spin;
+
+  /**
+   * Spin button to select the expiration year.
+   */
+  GtkSpinButton *expiration_year_spin;
+
+  /**
+   * Spin button to select the replication level.
+   */
+  GtkSpinButton *replication_spin;
+
+  /**
+   * Entry line for adding additional keywords.
+   */
+  GtkEntry *keyword_entry;
+
+  /**
+   * Entry line for setting a namespace root (possibly invisible).
+   */
+  GtkEntry *root_entry;
+
+  /**
+   * Entry line to check indexing vs. inserting (possibly invisible)
+   */
+  GtkToggleButton *index_checkbutton;
+
+  /**
+   * Type ID of the last selected item in the GtkCellRendererCombo
+   * of the meta data tree view.
+   */
+  gint meta_combo_selected_type_id;
+
+  /**
+   * Continuation to call once the dialog has been closed
+   */
+  GNUNET_FS_GTK_EditPublishDialogCallback cb;
+
+  /**
+   * Closure for 'cb'.
+   */
+  void *cb_cls;
+
+  /**
+   * Briefly used temporary meta data set.
+   */
+  struct GNUNET_CONTAINER_MetaData *md;
+
+  /**
+   * Information about the file being published as seen by the FS-API.
+   * This is what we are primarily editing.
+   */
+  struct GNUNET_FS_FileInformation *fip;
+
+  /**
+   * Flag to track if we changed the preview and thus should keep/discard
+   * binary metadata.
+   */
+  int preview_changed;
+
+  /**
+   * Is this operation for a directory?
+   */
+  int is_directory;
+
+  /**
+   * Is it allowed for the user to supply keywords in this dialog?
+   */
+  int allow_no_keywords;
+
+};
+
+
+/**
+ * Free resources associated with the edit publication dialog.
+ *
+ * @param ctx the context of the dialog to release resources of
+ */
+static void
+free_edit_dialog_context (struct EditPublicationDialogContext *ctx)
+{
+  gtk_widget_destroy (GTK_WIDGET (ctx->edit_publication_window));
+  // FIXME-LEAK: destroy builder!
+  GNUNET_free (ctx);
+}
+
+
+
+/* ****************** metadata editing ******************** */
+
+
+
+/**
+ * Update the set of metatypes listed in the dialog based on the
+ * given code.
+ *
+ * @param ctx main dialog context
+ * @param code which set of metatypes is desired?
+ */
+static void
+change_metatypes (struct EditPublicationDialogContext *ctx, gint code)
+{
+  gint pubtype_count;
+  gint max_type;
+  gint i;
+  GtkTreeIter iter;
+
+  /* double-check that 'code' is valid */
+  for (pubtype_count = 0; NULL != types[pubtype_count]; pubtype_count++) ;
+  GNUNET_assert (code < pubtype_count);
+  
+  /* clear existing selection of metatypes */
+  gtk_list_store_clear (ctx->metatypes_liststore);
+  max_type = EXTRACTOR_metatype_get_max ();
+  /* add new types based on selection */
+  for (i = 0; types[code][i] != EXTRACTOR_METATYPE_RESERVED; i++)  
+    if ( (types[code][i] < max_type) && (types[code][i] > 0) )
+      gtk_list_store_insert_with_values (ctx->metatypes_liststore, 
+                                        &iter, G_MAXINT, 
+                                        0, types[code][i], 
+                                        1, EXTRACTOR_METAFORMAT_UTF8, 
+                                        2, EXTRACTOR_metatype_to_string (types 
[code][i]), 
+                                        3, EXTRACTOR_metatype_to_description 
(types[code][i]), 
+                                        -1);  
+}
+
+
+/**
+ * The user has selected a different publication type.
+ * Update the meta type selection.
+ *
+ * @param widget the publication type combo box widget
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+void
+GNUNET_GTK_edit_publication_type_combo_changed_cb (GtkComboBox * widget,
+                                                   gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+  GtkTreeIter iter;
+  gint code;
+
+  if (! gtk_combo_box_get_active_iter (widget, &iter))
+    return;
+  gtk_tree_model_get (GTK_TREE_MODEL (ctx->pubtypes_liststore), &iter, 0, 
&code, -1);
+  change_metatypes (ctx, code);
+}
+
+
+/**
+ * The user has changed the selection in the meta data tree view.
+ * Update the sensitivity of the 'delete' button.
+ *
+ * @param ts the tree selection object
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+/* FIXME-UNCLEAN: connect this signal via glade (modern versions of Glade 
support this) */
+static void
+metadata_selection_changed_cb (GtkTreeSelection *ts,
+                              gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+
+  gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object
+                                       (ctx->builder, 
+                                        
"GNUNET_GTK_edit_publication_delete_button")),
+                            gtk_tree_selection_get_selected (ts, NULL, NULL));
+}
+
+
+/**
+ * The user changed (and confirmed the change) the type of a
+ * meta-data item in the meta data tree view.  Update the type and
+ * text in the list store accordingly.
+ *
+ * @param renderer widget where the change happened
+ * @param path which item was changed in the tree view
+ * @param new_text new value for the item
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+void 
+GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer_edited_cb 
(GtkCellRendererText *renderer, 
+                                                                       gchar * 
path, 
+                                                                       gchar * 
new_text,
+                                                                       
gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+  GtkTreeIter iter;
+  gint type_id;
+
+  if (! gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL 
(ctx->meta_liststore), 
+                                            &iter, 
+                                            path))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  if (-1 == ctx->meta_combo_selected_type_id)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  type_id = ctx->meta_combo_selected_type_id;
+  ctx->meta_combo_selected_type_id = -1;
+  gtk_list_store_set (ctx->meta_liststore, &iter, 
+                     0, type_id, 
+                     1, EXTRACTOR_METAFORMAT_UTF8, 
+                     2, EXTRACTOR_metatype_to_string (type_id),
+                     4, EXTRACTOR_metatype_to_description (type_id),
+                      -1);
+}
+
+
+/**
+ * The user changed the type of a meta-data item in the meta data
+ * tree view.  Obtain the selected type_id and store it in
+ * the 'meta_combo_selected_type_id' field for use by
+ * 'GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer_edited_cb'.
+ *
+ * @param combo combo box that was dropped down
+ * @param path which item was changed in the tree view
+ * @param new_iter item that is now selected in the drop-down combo box
+ * @param user_data the 'struct EditPublicationDialogContext' 
+ */
+void 
+GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer_changed_cb 
(GtkCellRendererCombo * combo, 
+                                                                        gchar 
* path_string,
+                                                                        
GtkTreeIter * new_iter,
+                                                                        
gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+  GtkTreeModel *combo_model;
+  gint type_id;
+
+  g_object_get (combo,
+               "model", &combo_model, NULL);
+  gtk_tree_model_get (combo_model, new_iter,
+                     0, &type_id,
+                     -1);
+  ctx->meta_combo_selected_type_id = type_id;
+}
+
+
+/**
+ * The user changed (and confirmed the change) the value of a
+ * meta-data item in the meta data tree view.  Update the value
+ * in the list store accordingly.
+ *
+ * @param renderer widget where the change happened
+ * @param path which item was changed in the tree view
+ * @param new_text new value for the item
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+void 
+GNUNET_GTK_edit_publication_metadata_tree_view_value_renderer_edited_cb 
(GtkCellRendererText * renderer,
+                                                                        gchar 
* path,
+                                                                        gchar 
* new_text,
+                                                                        
gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+  GtkTreeIter iter;
+  gint metatype;
+  char *avalue;
+  const char *ivalue;
+  size_t slen;
+  char *pos;
+
+  if (! gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL 
(ctx->meta_liststore),
+                                            &iter, 
+                                            path))
+  {
+    GNUNET_break (0);
+    return;
+  }
+
+  gtk_tree_model_get (GTK_TREE_MODEL (ctx->meta_liststore), &iter, 
+                     0, &metatype, -1);
+  if (metatype == EXTRACTOR_METATYPE_FILENAME) 
+  {
+    /* apply filename rules */
+    /* First, use UNIX-style separators */
+    avalue = GNUNET_strdup (new_text);
+    while (NULL != (pos = strstr (avalue, "\\")))
+      *pos = '/';
+
+    /* if user put '/' at the end, remove it' */
+    slen = strlen (avalue);
+    while ( (slen > 1) && (avalue[slen - 1] == '\\'))
+    {
+      avalue[slen - 1] = '\0';
+      slen--;
+    }
+
+    /* However, directories must end with '/', so add it */
+    if ( (new_text[strlen (new_text) - 1] != '/') && 
+        ctx->is_directory )
+    {
+      char * tmp;
+      
+      GNUNET_asprintf (&tmp, "%s/", avalue);
+      GNUNET_free (avalue);
+      avalue = tmp;
+    }
+    
+    /* Also, replace '../' everywhere with "___" */
+    while (NULL != (pos = strstr (avalue, "../")))
+      memset (pos, '_', 3);
+
+    ivalue = avalue;
+  }
+  else
+  {
+    ivalue = new_text;
+    avalue = NULL;
+  }
+  gtk_list_store_set (ctx->meta_liststore, &iter, 
+                     3, ivalue, 
+                     -1);
+  GNUNET_free_non_null (avalue);
+}
+
+
+/**
+ * The user has pushed the 'add' button for metadata.  Add a 'dummy' value
+ * to our meta data store (to be edited by the user).
+ *
+ * @param button the 'add' button
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+void
+GNUNET_GTK_edit_publication_add_button_clicked_cb (GtkButton * button,
+                                                   gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+  GtkTreeIter iter;
+
+  gtk_list_store_insert_with_values (ctx->meta_liststore,
+                                    &iter, 0,
+                                    0, 0,
+                                    1, EXTRACTOR_METAFORMAT_UTF8, 
+                                    2, _("Select a type"), 
+                                    3, _("Specify a value"), 
+                                    4, NULL, 
+                                    -1);
+}
+
+
+/**
+ * The user has pushed the 'del' button for metadata.
+ * If there is a metadata selected, remove it from the list store.
+ *
+ * @param widget the button
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+void
+GNUNET_GTK_edit_publication_delete_button_clicked_cb (GtkButton * button,
+                                                      gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+  GtkTreeIter iter;
+  GtkTreeSelection *meta_selection;
+
+  meta_selection = gtk_tree_view_get_selection (ctx->meta_treeview);
+  if (! gtk_tree_selection_get_selected (meta_selection, NULL, &iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  if (gtk_list_store_remove (ctx->meta_liststore, &iter))
+    gtk_tree_selection_select_iter (meta_selection, &iter);
+}
+
+
+/**
+ * The user has selected another preview image file.  Update the
+ * preview image.
+ *
+ * @param widget the file chooser dialog that completed
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+void
+GNUNET_GTK_edit_publication_metadata_preview_file_chooser_button_file_set_cb 
(GtkFileChooserButton * widget, 
+                                                                             
gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+  gchar *fn;
+
+  fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+  gtk_image_set_from_file (ctx->preview_image, fn);
+  g_free (fn);
+  ctx->preview_changed = GNUNET_YES;
+}
+
+
+/* ****************** keyword list editing ******************** */
+
+
+
+/**
+ * The user has changed the selection in the keyword tree view.
+ * Update the sensitivity of the 'delete' button.
+ *
+ * @param ts the tree selection object
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+/* FIXME-UNCLEAN: connect this signal via glade (modern versions of Glade 
support this) */
+static void
+keywords_selection_changed_cb (GtkTreeSelection *ts,
+                              gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+
+  gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object
+                                       (ctx->builder,
+                                        
"GNUNET_GTK_edit_publication_keyword_list_del_button")),
+                            gtk_tree_selection_get_selected (ts, NULL, NULL));
+}
+
+
+/**
+ * The user has edited the keyword entry line.  Update the
+ * sensitivity of the 'add' button.
+ *
+ * @param editable the entry line for keywords
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+void
+GNUNET_GTK_edit_publication_keyword_entry_changed_cb (GtkEditable * editable,
+                                                      gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+  const char *keyword;
+
+  keyword = gtk_entry_get_text (ctx->keyword_entry);
+  gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (ctx->builder,
+                                                               
"GNUNET_GTK_edit_publication_keyword_list_add_button")), 
+                           (strlen (keyword) > 0) ? TRUE : FALSE);
+}
+
+
+/**
+ * The user has pushed the 'del' button for the keyword.
+ * If there is a keyword selected, remove it from the list store.
+ *
+ * @param widget the button
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+void
+GNUNET_GTK_edit_publication_keyword_list_del_button_clicked_cb (GtkButton *
+                                                                button,
+                                                                gpointer 
user_data)
+{ 
+  struct EditPublicationDialogContext *ctx = user_data;
+  GtkTreeIter iter;
+  GtkTreeSelection *keywords_selection;
+
+  keywords_selection = gtk_tree_view_get_selection (ctx->keywords_treeview);
+  if (! gtk_tree_selection_get_selected (keywords_selection, NULL, &iter))
+  {
+    GNUNET_break (0);
+    return;
+  }
+  if (gtk_list_store_remove (GTK_LIST_STORE (ctx->keywords_liststore), &iter))
+    gtk_tree_selection_select_iter (keywords_selection, &iter);
+
+  /* disable confirm button if keywords are required and we have no more 
keywords */
+  if ( (! ctx->allow_no_keywords) && 
+       (! gtk_tree_model_get_iter_first (GTK_TREE_MODEL 
(ctx->keywords_liststore),
+                                        &iter)) )
+    gtk_widget_set_sensitive (ctx->confirm_button, FALSE);
+}
+
+
+/**
+ * The user has pushed the 'add' button for the keyword (or pressed RETURN).
+ * If there is a keyword in the line, add it to the list store.
+ *
+ * @param widget the entry line, or NULL (if we are called from 'RETURN')
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+void
+GNUNET_GTK_edit_publication_keyword_list_add_button_clicked_cb (GtkButton *
+                                                                button,
+                                                                gpointer 
user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+  const char *keyword;
+  GtkTreeIter iter;
+
+  keyword = gtk_entry_get_text (ctx->keyword_entry);
+  if (strlen (keyword) == 0)
+    return;
+  gtk_list_store_insert_with_values (ctx->keywords_liststore, 
+                                    &iter, G_MAXINT,
+                                    0, keyword,
+                                    1, TRUE,
+                                    -1);
+  gtk_widget_set_sensitive (ctx->confirm_button, TRUE);
+  gtk_entry_set_text (ctx->keyword_entry, "");
+}
+
+
+/**
+ * The user has pushed a button in the entry line.  Check if it was 'RETURN'
+ * and if so consider executing the 'add' action.
+ *
+ * @param widget the entry line
+ * @param event the event information
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+gboolean
+GNUNET_GTK_edit_publication_keyword_entry_key_press_event_cb (GtkWidget *
+                                                              widget,
+                                                              GdkEventKey *
+                                                              event,
+                                                              gpointer 
user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+
+  if (event->keyval != GDK_KEY_Return)
+    return FALSE;
+  GNUNET_GTK_edit_publication_keyword_list_add_button_clicked_cb (NULL, ctx);
+  return TRUE;
+}
+
+
+
+/* ****************** handlers for closing the dialog ******************** */
+
+
+/**
+ * The user clicked the 'cancel' button.  Abort the operation.
+ *
+ * @param button the cancel button
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+void
+GNUNET_GTK_edit_publication_cancel_button_clicked_cb (GtkButton * button,
+                                                      gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+
+  ctx->cb (ctx->cb_cls, GTK_RESPONSE_CANCEL, NULL);
+  free_edit_dialog_context (ctx);
+}
+
+
+/**
+ * The user closed the window.  Abort the operation.
+ *
+ * @param widget the window
+ * @param event the event that caused the window to close
+ * @param user_data the 'struct EditPublicationDialogContext'
+ * @return TRUE (always)
+ */
+gboolean
+GNUNET_GTK_edit_publication_window_delete_event_cb (GtkWidget * widget,
+                                                    GdkEvent * event,
+                                                    gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+
+  ctx->cb (ctx->cb_cls, GTK_RESPONSE_CANCEL, NULL);
+  free_edit_dialog_context (ctx);
+  return TRUE;
+}
+
+
+/**
+ * Copy binary meta data from to the new container and also preserve
+ * all entries that were not changed.  In particular, all binary meta
+ * data is removed if the preview was changed, otherwise it is all
+ * kept.  Similarly, if values are still in the liststore, they are
+ * fully kept (including plugin name and original format).  "Keeping"
+ * a value means that it is added to the 'md' meta data in the dialog
+ * context.
+ *
+ * @param cls closure, a 'struct FileInformationUpdateContext';
+ *        contains the 'new' meta data to construct in the 'md'
+ *        field and the liststore to check the current value
+ *        against in 'meta_liststore'.
+ * @param plugin_name name of the plugin that produced this value;
+ *        special values can be used (i.e. '<zlib>' 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 EditPublicationDialogContext *ctx = cls;
+  GtkTreeIter iter;
+  gchar *value;
+  guint ntype;
+  guint nformat;
+  int keep;
+
+  keep = GNUNET_NO;
+  switch (format)
+  {
+  case EXTRACTOR_METAFORMAT_UTF8:
+  case EXTRACTOR_METAFORMAT_C_STRING:
+    if (TRUE == gtk_tree_model_get_iter_first (GTK_TREE_MODEL 
(ctx->meta_liststore), &iter))
+    {
+      do
+      {
+        gtk_tree_model_get (GTK_TREE_MODEL (ctx->meta_liststore), &iter, 0, 
&ntype, 1, &nformat, 3, &value, -1);
+        if ((ntype == type) && (nformat == format) &&
+            (0 == strcmp (value, data)))
+        {
+          gtk_list_store_remove (ctx->meta_liststore, &iter);
+          keep = GNUNET_YES;
+          g_free (value);
+          break;
+        }
+        g_free (value);
+      }
+      while (TRUE == gtk_tree_model_iter_next (GTK_TREE_MODEL 
(ctx->meta_liststore), &iter));
+    }
+    break;
+  case EXTRACTOR_METAFORMAT_UNKNOWN:
+    break;
+  case EXTRACTOR_METAFORMAT_BINARY:
+    if (ctx->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 (ctx->md, plugin_name, 
type,
+                                                     format, data_mime_type,
+                                                     data, data_len));
+  return 0;
+}
+
+
+/**
+ * Function called to update the information in FI based on the changes made in
+ * the edit dialog.
+ *
+ * @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 EditPublicationDialogContext *ctx = cls;
+  GtkTreeIter iter;
+  gint year;
+
+  /* gather publishing options  */
+  *do_index = gtk_toggle_button_get_active (ctx->index_checkbutton);
+  GNUNET_break (GNUNET_GTK_get_selected_anonymity_combo_level 
(ctx->anonymity_combo,
+                                                              
&bo->anonymity_level));
+  bo->content_priority = gtk_spin_button_get_value (ctx->priority_spin);
+  bo->replication_level = gtk_spin_button_get_value (ctx->replication_spin);
+  year = gtk_spin_button_get_value (ctx->expiration_year_spin);
+  bo->expiration_time = GNUNET_FS_year_to_time (year);
+
+  /* update keyword-URI */
+  if (NULL != (*uri))
+    GNUNET_FS_uri_destroy (*uri);
+  *uri = NULL;
+  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ctx->keywords_liststore), 
&iter))
+  {
+    do
+    {
+      gchar *value;
+
+      gtk_tree_model_get (GTK_TREE_MODEL (ctx->keywords_liststore), &iter, 0, 
&value, -1);
+      if (NULL == *uri)
+       *uri = GNUNET_FS_uri_ksk_create_from_args (1, (const char **) &value);
+      else
+       GNUNET_FS_uri_ksk_add_keyword (*uri, value, GNUNET_NO);
+      g_free (value);
+    }
+    while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ctx->keywords_liststore), 
&iter));
+  }
+
+  /* update meta data; first, we copy the unchanged values from the original 
meta data */
+  ctx->md = GNUNET_CONTAINER_meta_data_create ();
+  GNUNET_CONTAINER_meta_data_iterate (meta, 
+                                     &preserve_meta_items, 
+                                     ctx);
+  /* clear original meta data */
+  GNUNET_CONTAINER_meta_data_clear (meta);
+  /* add all of the 'preserved' values */
+  GNUNET_CONTAINER_meta_data_merge (meta, ctx->md);
+  GNUNET_CONTAINER_meta_data_destroy (ctx->md);
+  ctx->md = NULL;
+  /* now add all of the values from the model; adding will simply do 
+     nothing for values that are already in the set because they were 
preserved */
+  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ctx->meta_liststore), 
&iter))
+  {
+    do
+    {
+      guint ntype;
+      guint nformat;
+      gchar *value;
+
+      gtk_tree_model_get (GTK_TREE_MODEL (ctx->meta_liststore), &iter, 0, 
&ntype, 1, &nformat, 3, &value, -1);
+      if (ntype > 0)
+        GNUNET_CONTAINER_meta_data_insert (ctx->md, "<user>", ntype, nformat,
+                                           "text/plain", value,
+                                           strlen (value) + 1);
+      g_free (value);
+    }
+    while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ctx->meta_liststore), 
&iter));
+  }
+  
+  /* finally, if we got a new preview, add it as well */
+  if (ctx->preview_changed == GNUNET_YES)
+  {
+    gchar *fn;
+    char *data;
+    gsize data_size;
+    const char *mime;
+    GFile *f;
+    GFileInfo *finfo;
+
+    fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER
+                                        (gtk_builder_get_object
+                                         (ctx->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 (! 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, "<user>",
+                                         EXTRACTOR_METATYPE_THUMBNAIL,
+                                         EXTRACTOR_METAFORMAT_BINARY, mime,
+                                         data, data_size);
+    }
+    g_object_unref (finfo);
+    g_object_unref (f);
+    g_free (fn);
+  }
+  return GNUNET_SYSERR;         /* only visit top-level item */
+}
+
+
+/**
+ * The user clicked the 'confirm' button.  Push the edits back into the
+ * FileInformation structure and given it and the options back to the 
+ * callback.  Then clean up the dialog.
+ *
+ * @param button the cancel button
+ * @param user_data the 'struct EditPublicationDialogContext'
+ */
+void
+GNUNET_GTK_edit_publication_confirm_button_clicked_cb (GtkButton * button,
+                                                       gpointer user_data)
+{
+  struct EditPublicationDialogContext *ctx = user_data;
+
+  /* push back changes to file-information */
+  GNUNET_FS_file_information_inspect (ctx->fip, 
+                                     &file_information_update,
+                                     ctx);
+  /* call our continuation */
+  ctx->cb (ctx->cb_cls, 
+          GTK_RESPONSE_OK,
+          gtk_entry_get_text (ctx->root_entry));
+  /* free resources from the edit dialog */
+  free_edit_dialog_context (ctx);
+}
+
+
+
+/* ****************** code for initialization of the dialog 
******************** */
+
+
+
+/**
+ * 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 to populate the edit 
dialog.
+ *
+ * @param cls the 'struct EditPublicationDialogContext'
+ * @param fi the entry in the publish-structure (unused)
+ * @param length length of the file or directory (unused)
+ * @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_import (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 EditPublicationDialogContext *ctx = cls;
+  GdkPixbuf *pixbuf;
+  char *short_fn;
+  int year;
+
+  /* import options */
+  year = (int) GNUNET_FS_time_to_year (bo->expiration_time);
+  gtk_spin_button_set_value (ctx->expiration_year_spin, year);
+  GNUNET_GTK_select_anonymity_combo_level (ctx->anonymity_combo,
+                                          bo->anonymity_level);
+  gtk_spin_button_set_value (ctx->priority_spin, bo->content_priority);
+  gtk_spin_button_set_value (ctx->replication_spin, bo->replication_level);
+  gtk_toggle_button_set_active (ctx->index_checkbutton, *do_index);
+
+
+  /* import keywords */
+  if (NULL != *uri)
+    GNUNET_FS_uri_ksk_get_keywords (*uri, &add_keyword, 
ctx->keywords_liststore);
+
+  /* import meta data */
+  if (NULL != meta)
+  {
+    GNUNET_CONTAINER_meta_data_iterate (meta,
+                                        
&GNUNET_FS_GTK_add_meta_data_to_list_store,
+                                        ctx->meta_liststore);
+    pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta);
+    if (pixbuf != NULL)
+    {
+      gtk_image_set_from_pixbuf (ctx->preview_image, pixbuf);
+    }
+  }
+  
+  /* Also update window title based on filename */
+  short_fn = GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
+                                                           
EXTRACTOR_METATYPE_FILENAME,
+                                                           -1);
+  if (NULL == short_fn)
+  {
+    gtk_window_set_title (ctx->edit_publication_window, _("<unnamed>"));
+  }
+  else
+  {
+    /* FIXME-BUG-MAYBE: ensure that short_fn is UTF-8 encoded */
+    gtk_window_set_title (ctx->edit_publication_window, short_fn);
+    GNUNET_free (short_fn);
+  }
+  return GNUNET_SYSERR;         /* only visit top-level item */
+}
+
+
+/**
+ * Open the dialog to edit file information data.
+ *
+ * @param parent parent window of the dialog
+ * @param fip information about the file information that is to be edited
+ * @param allow_no_keywords is it OK to close the dialog without any keywords?
+ *                          also used to indicate that this is a namespace 
operation
+ *                          (FIXME-UNCLEAN: overloaded/badly-named argument)
+ * @param anon_liststore liststore with anonymity options (FIXME-UNCLEAN: bad 
sharing)
+ * @param cb function to call when the dialog is closed
+ * @param cb_cls closure for 'cb'
+ */
+void
+GNUNET_FS_GTK_edit_publish_dialog (GtkWindow * parent,
+                                   struct GNUNET_FS_FileInformation *fip,
+                                   int allow_no_keywords,
+                                   GtkListStore *anon_liststore,
+                                   GNUNET_FS_GTK_EditPublishDialogCallback cb,
+                                   gpointer cb_cls)
+{
+  GtkTreeIter iter;
+  gint code;
+  GtkComboBox *pubtypes_combo;
+  GtkLabel *index_label;
+  GtkLabel *root_label;
+  struct EditPublicationDialogContext *ctx;
+  GtkTreeSelection *meta_selection;
+  GtkTreeSelection *keywords_selection;
+
+  ctx = GNUNET_malloc (sizeof (struct EditPublicationDialogContext));
+  ctx->fip = fip;
+  ctx->preview_changed = GNUNET_NO;
+  ctx->allow_no_keywords = allow_no_keywords;
+  ctx->is_directory = GNUNET_FS_file_information_is_directory (fip);
+  ctx->cb = cb;
+  ctx->cb_cls = cb_cls;
+  ctx->meta_combo_selected_type_id = -1;
+  ctx->builder = GNUNET_GTK_get_new_builder 
("gnunet_fs_gtk_edit_publication.glade", ctx);
+
+  if (ctx->builder == NULL)
+  {
+    GNUNET_free (ctx);
+    return;
+  }
+
+  /* obtain various widgets for use later */
+  ctx->pubtypes_liststore =
+      GTK_LIST_STORE (gtk_builder_get_object
+                      (ctx->builder, 
"GNUNET_GTK_publication_types_liststore"));
+  ctx->metatypes_liststore =
+      GTK_LIST_STORE (gtk_builder_get_object
+                      (ctx->builder,
+                       "GNUNET_GTK_publication_metadata_types_liststore"));
+  ctx->meta_treeview = GTK_TREE_VIEW (gtk_builder_get_object
+                      (ctx->builder,
+                       "GNUNET_GTK_edit_publication_metadata_tree_view"));
+  ctx->keywords_treeview = GTK_TREE_VIEW (gtk_builder_get_object
+                      (ctx->builder,
+                       "GNUNET_GTK_edit_publication_keyword_list_tree_view"));
+  ctx->edit_publication_window =
+    GTK_WINDOW (gtk_builder_get_object (ctx->builder, 
+                                       "GNUNET_GTK_edit_publication_window"));
+  ctx->keywords_liststore = GTK_LIST_STORE (gtk_builder_get_object
+                       (ctx->builder, 
"GNUNET_GTK_publication_keywords_liststore"));
+  ctx->keyword_entry =
+      GTK_ENTRY (gtk_builder_get_object
+                 (ctx->builder, "GNUNET_GTK_edit_publication_keyword_entry"));
+  ctx->confirm_button = GTK_WIDGET (gtk_builder_get_object
+                     (ctx->builder, 
"GNUNET_GTK_edit_publication_confirm_button"));
+  ctx->preview_image =
+      GTK_IMAGE (gtk_builder_get_object
+                 (ctx->builder,
+                  "GNUNET_GTK_edit_publication_metadata_preview_image"));
+  ctx->meta_liststore = GTK_LIST_STORE (gtk_builder_get_object
+                         (ctx->builder,
+                          "GNUNET_GTK_publication_metadata_liststore"));
+  ctx->root_entry = GTK_ENTRY (gtk_builder_get_object
+                    (ctx->builder, "GNUNET_GTK_edit_publication_root_entry"));
+  ctx->expiration_year_spin = GTK_SPIN_BUTTON
+                             (gtk_builder_get_object
+                              (ctx->builder,
+                               
"GNUNET_GTK_edit_publication_expiration_year_spin_button"));
+  ctx->priority_spin = GTK_SPIN_BUTTON
+                             (gtk_builder_get_object
+                              (ctx->builder,
+                               
"GNUNET_GTK_edit_publication_priority_spin_button"));
+  ctx->replication_spin = GTK_SPIN_BUTTON
+                             (gtk_builder_get_object
+                              (ctx->builder,
+                               
"GNUNET_GTK_edit_publication_replication_spin_button"));
+  ctx->index_checkbutton = GTK_TOGGLE_BUTTON
+                                (gtk_builder_get_object
+                                 (ctx->builder,
+                                  
"GNUNET_GTK_edit_publication_index_checkbutton"));
+  ctx->anonymity_combo = GTK_COMBO_BOX (gtk_builder_get_object (ctx->builder,
+                                                               
"GNUNET_GTK_edit_publication_anonymity_combobox"));
+
+  /* Basic initialization of widgets models and visibility */
+  gtk_combo_box_set_model (ctx->anonymity_combo, 
+                          GTK_TREE_MODEL (anon_liststore));
+  GNUNET_FS_GTK_setup_expiration_year_adjustment (ctx->builder);
+
+  /* FIXME-UNCLEAN: are the following three even required anymore? */
+  gtk_list_store_clear (ctx->keywords_liststore);
+  gtk_list_store_clear (ctx->meta_liststore);
+  gtk_entry_set_text (ctx->keyword_entry, "");
+
+  pubtypes_combo =
+      GTK_COMBO_BOX (gtk_builder_get_object
+                     (ctx->builder, "GNUNET_GTK_edit_publication_type_combo"));
+  if (gtk_combo_box_get_active_iter (pubtypes_combo, &iter))
+  {
+    gtk_tree_model_get (GTK_TREE_MODEL (ctx->pubtypes_liststore), &iter, 0, 
&code, -1);
+    change_metatypes (ctx, 0);
+  }
+  else
+    gtk_combo_box_set_active (pubtypes_combo, 0);
+
+  /* indexing does not apply to directories */
+  gtk_widget_set_visible (GTK_WIDGET (ctx->index_checkbutton),
+                         ! ctx->is_directory);
+  index_label = GTK_LABEL (gtk_builder_get_object
+                          (ctx->builder,
+                           "GNUNET_GTK_edit_publication_index_label"));
+  gtk_widget_set_visible (GTK_WIDGET (index_label),
+                         ! ctx->is_directory);
+
+  /* show root label only if we must have keywords, which is also only the
+     case for namespaces (FIXME-UNCLEAN: overloaded use of the argument) */
+  gtk_widget_set_visible (GTK_WIDGET (ctx->root_entry),
+                         !allow_no_keywords);
+  root_label = GTK_LABEL (gtk_builder_get_object
+                         (ctx->builder, 
"GNUNET_GTK_edit_publication_root_label"));
+  gtk_widget_set_visible (GTK_WIDGET (root_label),
+                         !allow_no_keywords);
+  
+  /* FIXME-UNCLEAN: what if we already have keywords? Again, does not really
+     apply to namespace-case, but this seems a bit ugly */
+  gtk_widget_set_sensitive (ctx->confirm_button, allow_no_keywords ? TRUE : 
FALSE);
+
+
+  /* FIXME-UNCLEAN: these signal handlers can be set by (modern) versions of 
Glade */
+  keywords_selection = gtk_tree_view_get_selection (ctx->keywords_treeview);
+  g_signal_connect (G_OBJECT (keywords_selection), "changed",
+                    G_CALLBACK (keywords_selection_changed_cb), ctx);
+  meta_selection = gtk_tree_view_get_selection (ctx->meta_treeview);
+  g_signal_connect (G_OBJECT (meta_selection), "changed",
+                    G_CALLBACK (metadata_selection_changed_cb), ctx);
+
+  /* import meta data and options */
+  GNUNET_FS_file_information_inspect (fip, &file_information_import, ctx);
+
+
+  /* Finally, display window */
+  gtk_window_set_transient_for (ctx->edit_publication_window, parent);
+  gtk_window_present (ctx->edit_publication_window);
+}
+
+
+/* end of gnunet-fs-gtk-edit_publish_dialog.c */

Copied: gnunet-gtk/src/fs/gnunet-fs-gtk_publish-edit-dialog.h (from rev 19628, 
gnunet-gtk/src/fs/gnunet-fs-gtk-edit_publish_dialog.h)
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk_publish-edit-dialog.h                       
        (rev 0)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk_publish-edit-dialog.h       2012-02-02 
13:28:32 UTC (rev 19629)
@@ -0,0 +1,66 @@
+/*
+     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_publish-edit-dialog.h
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_FS_GTK_PUBLISH_EDIT_DIALOG_H
+#define GNUNET_FS_GTK_PUBLISH_EDIT_DIALOG_H
+
+#include "gnunet-fs-gtk-common.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_fs_service.h>
+
+
+/**
+ * Function called when the edit publish dialog has been closed.
+ *
+ * @param cls closure
+ * @param ret GTK_RESPONSE_OK if the dialog was closed with "OK"
+ * @param root namespace root, NULL for file publishing
+ */
+typedef void (*GNUNET_FS_GTK_EditPublishDialogCallback) (gpointer cls,
+                                                        int ret,
+                                                         const char *root);
+
+
+/**
+ * Open the dialog to edit file information data.
+ *
+ * @param parent parent window of the dialog
+ * @param fip information about the file information that is to be edited
+ * @param allow_no_keywords is it OK to close the dialog without any keywords?
+ *                          also used to indicate that this is a namespace 
operation
+ *                          (FIXME: overloaded/badly-named argument)
+ * @param anon_liststore liststore with anonymity options (FIXME: bad sharing)
+ * @param cb function to call when the dialog is closed
+ * @param cb_cls closure for 'cb'
+ */
+void
+GNUNET_FS_GTK_edit_publish_dialog (GtkWindow * parent,
+                                   struct GNUNET_FS_FileInformation *fip,
+                                   int allow_no_keywords, 
+                                  GtkListStore *anon_liststore,
+                                   GNUNET_FS_GTK_EditPublishDialogCallback cb,
+                                   gpointer cls);
+
+#endif
+/* end of gnunet-fs-gtk-edit_publish_dialog.h */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]