-add adv port
[oweals/gnunet.git] / src / util / pseudonym.c
index c974cc5a33ec087239499395adf238c791c54718..48852ee378f9eb1c192679a8c1768c3d1e4d697d 100644 (file)
 #include "gnunet_pseudonym_lib.h"
 #include "gnunet_bio_lib.h"
 
-/** 
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+
+/**
  * Name of the directory which stores meta data for pseudonym
  */
 #define PS_METADATA_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonyms" DIR_SEPARATOR_STR "metadata" DIR_SEPARATOR_STR
 
-/** 
+/**
  * Name of the directory which stores names for pseudonyms
  */
 #define PS_NAMES_DIR    DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonyms" DIR_SEPARATOR_STR "names"    DIR_SEPARATOR_STR
 
 
-/** 
+/**
+ * Configuration section we use.
+ */
+#define GNUNET_CLIENT_SERVICE_NAME "client"
+
+
+
+/**
  * Registered callbacks for discovery of pseudonyms.
  */
 struct DiscoveryCallback
 {
-  /** 
+  /**
    * This is a linked list.
    */
   struct DiscoveryCallback *next;
 
-  /** 
+  /**
    * Function to call each time a pseudonym is discovered.
    */
   GNUNET_PSEUDONYM_Iterator callback;
 
-  /** 
+  /**
    * Closure for callback.
    */
   void *closure;
 };
 
 
-/** 
- * Head of the linked list of functions to call when 
+/**
+ * Head of the linked list of functions to call when
  * new pseudonyms are added.
  */
 static struct DiscoveryCallback *head;
@@ -77,30 +88,32 @@ static struct DiscoveryCallback *head;
  * @param rating rating of pseudonym
  */
 static void
-internal_notify (const GNUNET_HashCode * id,
+internal_notify (const struct GNUNET_HashCode * id,
                  const struct GNUNET_CONTAINER_MetaData *md, int rating)
 {
   struct DiscoveryCallback *pos;
 
   pos = head;
   while (pos != NULL)
-    {
-      pos->callback (pos->closure, id, md, rating);
-      pos = pos->next;
-    }
+  {
+    pos->callback (pos->closure, id, NULL, NULL, md, rating);
+    pos = pos->next;
+  }
 }
 
 /**
  * Register callback to be invoked whenever we discover
  * a new pseudonym.
+ * Will immediately call provided iterator callback for all
+ * already discovered pseudonyms.
+ *
  * @param cfg configuration to use
  * @param iterator iterator over pseudonym
  * @param closure point to a closure
  */
 int
 GNUNET_PSEUDONYM_discovery_callback_register (const struct
-                                              GNUNET_CONFIGURATION_Handle
-                                              *cfg,
+                                              GNUNET_CONFIGURATION_Handle *cfg,
                                               GNUNET_PSEUDONYM_Iterator
                                               iterator, void *closure)
 {
@@ -131,10 +144,10 @@ GNUNET_PSEUDONYM_discovery_callback_unregister (GNUNET_PSEUDONYM_Iterator
   pos = head;
   while ((pos != NULL) &&
          ((pos->callback != iterator) || (pos->closure != closure)))
-    {
-      prev = pos;
-      pos = pos->next;
-    }
+  {
+    prev = pos;
+    pos = pos->next;
+  }
   if (pos == NULL)
     return GNUNET_SYSERR;
   if (prev == NULL)
@@ -155,16 +168,14 @@ GNUNET_PSEUDONYM_discovery_callback_unregister (GNUNET_PSEUDONYM_Iterator
  * @return filename of the pseudonym (if psid != NULL) or directory with the data (if psid == NULL)
  */
 static char *
-get_data_filename (const struct GNUNET_CONFIGURATION_Handle
-                   *cfg, const char *prefix, const GNUNET_HashCode * psid)
+get_data_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                   const char *prefix, const struct GNUNET_HashCode * psid)
 {
   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
 
   if (psid != NULL)
     GNUNET_CRYPTO_hash_to_enc (psid, &enc);
-  return GNUNET_DISK_get_home_filename (cfg,
-                                        GNUNET_CLIENT_SERVICE_NAME,
-                                        prefix,
+  return GNUNET_DISK_get_home_filename (cfg, GNUNET_CLIENT_SERVICE_NAME, prefix,
                                         (psid ==
                                          NULL) ? NULL : (const char *) &enc,
                                         NULL);
@@ -177,11 +188,11 @@ get_data_filename (const struct GNUNET_CONFIGURATION_Handle
  * @param nsid hash code of a pseudonym
  * @param meta meta data to be written into a file
  * @param ranking ranking of a pseudonym
- * @param ns_name name of a pseudonym
+ * @param ns_name non-unique name of a pseudonym
  */
 static void
 write_pseudonym_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                      const GNUNET_HashCode * nsid,
+                      const struct GNUNET_HashCode * nsid,
                       const struct GNUNET_CONTAINER_MetaData *meta,
                       int32_t ranking, const char *ns_name)
 {
@@ -190,30 +201,30 @@ write_pseudonym_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
   fn = get_data_filename (cfg, PS_METADATA_DIR, nsid);
   GNUNET_assert (fn != NULL);
-  fileW = GNUNET_BIO_write_open(fn);
-  if (NULL != fileW) 
+  fileW = GNUNET_BIO_write_open (fn);
+  if (NULL != fileW)
+  {
+    if ((GNUNET_OK != GNUNET_BIO_write_int32 (fileW, ranking)) ||
+        (GNUNET_OK != GNUNET_BIO_write_string (fileW, ns_name)) ||
+        (GNUNET_OK != GNUNET_BIO_write_meta_data (fileW, meta)))
     {
-      if ( (GNUNET_OK != GNUNET_BIO_write_int32(fileW, ranking)) ||
-          (GNUNET_OK != GNUNET_BIO_write_string(fileW, ns_name)) ||
-          (GNUNET_OK != GNUNET_BIO_write_meta_data(fileW, meta)) )
-       {
-         (void) GNUNET_BIO_write_close(fileW);
-         GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
-         GNUNET_free (fn);
-         return;
-       }
-      if (GNUNET_OK != GNUNET_BIO_write_close(fileW))
-       {
-         GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
-         GNUNET_free (fn);
-         return;
-       }
+      (void) GNUNET_BIO_write_close (fileW);
+      GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
+      GNUNET_free (fn);
+      return;
+    }
+    if (GNUNET_OK != GNUNET_BIO_write_close (fileW))
+    {
+      GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
+      GNUNET_free (fn);
+      return;
     }
+  }
   GNUNET_free (fn);
   /* create entry for pseudonym name in names */
-  /* FIXME: 90% of what this call does is not needed
-     here => refactor code to only create the entry! */
-  GNUNET_free_non_null (GNUNET_PSEUDONYM_id_to_name (cfg, nsid));
+  if (ns_name != NULL)
+    GNUNET_free_non_null (GNUNET_PSEUDONYM_name_uniquify (cfg, nsid, ns_name,
+        NULL));
 }
 
 
@@ -227,9 +238,9 @@ write_pseudonym_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
  */
 static int
 read_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
-           const GNUNET_HashCode * nsid,
-           struct GNUNET_CONTAINER_MetaData **meta,
-           int32_t * ranking, char **ns_name)
+           const struct GNUNET_HashCode * nsid,
+           struct GNUNET_CONTAINER_MetaData **meta, int32_t * ranking,
+           char **ns_name)
 {
   char *fn;
   char *emsg;
@@ -237,180 +248,258 @@ read_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
   fn = get_data_filename (cfg, PS_METADATA_DIR, nsid);
   GNUNET_assert (fn != NULL);
-  fileR = GNUNET_BIO_read_open(fn);
+  fileR = GNUNET_BIO_read_open (fn);
   if (fileR == NULL)
-    {
-      GNUNET_free (fn);
-      return GNUNET_SYSERR;
-    }
-  if ( (GNUNET_OK != GNUNET_BIO_read_int32__(fileR, "Read int32 error!", ranking)) ||
-       (GNUNET_OK != GNUNET_BIO_read_string(fileR, "Read string error!", ns_name, 200)) ||
-       (GNUNET_OK != GNUNET_BIO_read_meta_data(fileR, "Read meta data error!", meta)) )
-    {
-      GNUNET_BIO_read_close(fileR, &emsg);
-      GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
-      GNUNET_free (fn);
-      return GNUNET_SYSERR;
-    }
+  {
+    GNUNET_free (fn);
+    return GNUNET_SYSERR;
+  }
   emsg = NULL;
-  if (GNUNET_OK != GNUNET_BIO_read_close(fileR, &emsg))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                 _("Failed to parse metadata about pseudonym from file `%s': %s\n"),
-                 fn,
-                 emsg);
-      GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
-      GNUNET_free_non_null (emsg);
-      GNUNET_free (fn);
-      return GNUNET_SYSERR;
-    }
+  *ns_name = NULL;
+  if ((GNUNET_OK != GNUNET_BIO_read_int32 (fileR, ranking)) ||
+      (GNUNET_OK !=
+       GNUNET_BIO_read_string (fileR, "Read string error!", ns_name, 200)) ||
+      (GNUNET_OK !=
+       GNUNET_BIO_read_meta_data (fileR, "Read meta data error!", meta)))
+  {
+    (void) GNUNET_BIO_read_close (fileR, &emsg);
+    GNUNET_free_non_null (emsg);
+    GNUNET_free_non_null (*ns_name);
+    *ns_name = NULL;
+    GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
+    GNUNET_free (fn);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK != GNUNET_BIO_read_close (fileR, &emsg))
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("Failed to parse metadata about pseudonym from file `%s': %s\n"), fn,
+         emsg);
+    GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
+    GNUNET_CONTAINER_meta_data_destroy (*meta);
+    *meta = NULL;
+    GNUNET_free_non_null (*ns_name);
+    *ns_name = NULL;
+    GNUNET_free_non_null (emsg);
+    GNUNET_free (fn);
+    return GNUNET_SYSERR;
+  }
   GNUNET_free (fn);
   return GNUNET_OK;
 }
 
 
-
 /**
- * Return the unique, human readable name for the given namespace.
+ * Return unique variant of the namespace name.
+ * Use it after GNUNET_PSEUDONYM_get_info() to make sure
+ * that name is unique.
  *
- * @param cfg configuration 
+ * @param cfg configuration
  * @param nsid cryptographic ID of the namespace
- * @return NULL on failure (should never happen)
+ * @param name name to uniquify
+ * @param suffix if not NULL, filled with the suffix value
+ * @return NULL on failure (should never happen), name on success.
+ *         Free the name with GNUNET_free().
  */
 char *
-GNUNET_PSEUDONYM_id_to_name (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                             const GNUNET_HashCode * nsid)
+GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg,
+    const struct GNUNET_HashCode * nsid, const char *name, unsigned int *suffix)
 {
-  struct GNUNET_CONTAINER_MetaData *meta;
-  char *name;
-  GNUNET_HashCode nh;
-  char *fn;
+  struct GNUNET_HashCode nh;
   uint64_t len;
+  char *fn;
   struct GNUNET_DISK_FileHandle *fh;
   unsigned int i;
   unsigned int idx;
   char *ret;
   struct stat sbuf;
-  int32_t temp = 0;
-  int32_t *rank = &temp;
 
-  meta = NULL;
-  name = NULL;
-  if (GNUNET_OK == read_info (cfg, nsid, &meta, rank, &name))
-    {
-      if ((meta != NULL) && (name == NULL))
-        name = GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
-                                                              EXTRACTOR_TITLE,
-                                                              EXTRACTOR_FILENAME,
-                                                              EXTRACTOR_DESCRIPTION,
-                                                              EXTRACTOR_SUBJECT,
-                                                              EXTRACTOR_PUBLISHER,
-                                                              EXTRACTOR_AUTHOR,
-                                                              EXTRACTOR_COMMENT,
-                                                              EXTRACTOR_SUMMARY,
-                                                              EXTRACTOR_OWNER,
-                                                              -1);
-      if (meta != NULL)
-        {
-          GNUNET_CONTAINER_meta_data_destroy (meta);
-          meta = NULL;
-        }
-    }
-  if (name == NULL)
-    name = GNUNET_strdup (_("no-name"));
   GNUNET_CRYPTO_hash (name, strlen (name), &nh);
   fn = get_data_filename (cfg, PS_NAMES_DIR, &nh);
   GNUNET_assert (fn != NULL);
 
   len = 0;
   if (0 == STAT (fn, &sbuf))
-    GNUNET_DISK_file_size (fn, &len, GNUNET_YES);
-  fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_CREATE
-                              | GNUNET_DISK_OPEN_READWRITE,
+    GNUNET_break (GNUNET_OK == GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES));
+  fh = GNUNET_DISK_file_open (fn,
+                              GNUNET_DISK_OPEN_CREATE |
+                              GNUNET_DISK_OPEN_READWRITE,
                               GNUNET_DISK_PERM_USER_READ |
                               GNUNET_DISK_PERM_USER_WRITE);
   i = 0;
   idx = -1;
-  while ((len >= sizeof (GNUNET_HashCode)) &&
-         (sizeof (GNUNET_HashCode)
-          == GNUNET_DISK_file_read (fh, &nh, sizeof (GNUNET_HashCode))))
-    {
-      if (0 == memcmp (&nh, nsid, sizeof (GNUNET_HashCode)))
-        {
-          idx = i;
-          break;
-        }
-      i++;
-      len -= sizeof (GNUNET_HashCode);
-    }
-  if (idx == -1)
+  while ((len >= sizeof (struct GNUNET_HashCode)) &&
+         (sizeof (struct GNUNET_HashCode) ==
+          GNUNET_DISK_file_read (fh, &nh, sizeof (struct GNUNET_HashCode))))
+  {
+    if (0 == memcmp (&nh, nsid, sizeof (struct GNUNET_HashCode)))
     {
       idx = i;
-      if (sizeof (GNUNET_HashCode) !=
-          GNUNET_DISK_file_write (fh, nsid, sizeof (GNUNET_HashCode)))
-        GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn);
+      break;
     }
+    i++;
+    len -= sizeof (struct GNUNET_HashCode);
+  }
+  if (idx == -1)
+  {
+    idx = i;
+    if (sizeof (struct GNUNET_HashCode) !=
+        GNUNET_DISK_file_write (fh, nsid, sizeof (struct GNUNET_HashCode)))
+      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "write", fn);
+  }
   GNUNET_DISK_file_close (fh);
   ret = GNUNET_malloc (strlen (name) + 32);
   GNUNET_snprintf (ret, strlen (name) + 32, "%s-%u", name, idx);
-  GNUNET_free (name);
+  if (suffix != NULL)
+    *suffix = idx;
   GNUNET_free (fn);
   return ret;
 }
 
+/**
+ * Get namespace name, metadata and rank
+ * This is a wrapper around internal read_info() call, and ensures that
+ * returned data is not invalid (not NULL).
+ *
+ * @param cfg configuration
+ * @param nsid cryptographic ID of the namespace
+ * @param ret_meta a location to store metadata pointer. NULL, if metadata
+ *        is not needed. Destroy with GNUNET_CONTAINER_meta_data_destroy().
+ * @param ret_rank a location to store rank. NULL, if rank not needed.
+ * @param ret_name a location to store human-readable name. Name is not unique.
+ *        NULL, if name is not needed. Free with GNUNET_free().
+ * @param name_is_a_dup is set to GNUNET_YES, if ret_name was filled with
+ *        a duplicate of a "no-name" placeholder
+ * @return GNUNET_OK on success. GNUENT_SYSERR if the data was
+ *         unobtainable (in that case ret_* are filled with placeholders - 
+ *         empty metadata container, rank -1 and a "no-name" name).
+ */
+int
+GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
+    const struct GNUNET_HashCode * nsid, struct GNUNET_CONTAINER_MetaData **ret_meta,
+    int32_t *ret_rank, char **ret_name, int *name_is_a_dup)
+{
+  struct GNUNET_CONTAINER_MetaData *meta;
+  char *name;
+  int32_t rank = -1;
+
+  meta = NULL;
+  name = NULL;
+  if (GNUNET_OK == read_info (cfg, nsid, &meta, &rank, &name))
+  {
+    if ((meta != NULL) && (name == NULL))
+      name =
+          GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
+                                                         EXTRACTOR_METATYPE_TITLE,
+                                                         EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME,
+                                                         EXTRACTOR_METATYPE_FILENAME,
+                                                         EXTRACTOR_METATYPE_DESCRIPTION,
+                                                         EXTRACTOR_METATYPE_SUBJECT,
+                                                         EXTRACTOR_METATYPE_PUBLISHER,
+                                                         EXTRACTOR_METATYPE_AUTHOR_NAME,
+                                                         EXTRACTOR_METATYPE_COMMENT,
+                                                         EXTRACTOR_METATYPE_SUMMARY,
+                                                         -1);
+    if (ret_name != NULL)
+    {
+      if (name == NULL)
+      {
+        name = GNUNET_strdup (_("no-name"));
+        if (name_is_a_dup != NULL)
+          *name_is_a_dup = GNUNET_YES;
+      }
+      else if (name_is_a_dup != NULL)
+        *name_is_a_dup = GNUNET_NO;
+      *ret_name = name;
+    }
+    else if (name != NULL)
+      GNUNET_free (name);
+
+    if (ret_meta != NULL)
+    {
+      if (meta == NULL)
+        meta = GNUNET_CONTAINER_meta_data_create ();
+      *ret_meta = meta;
+    }
+    else if (meta != NULL)
+      GNUNET_CONTAINER_meta_data_destroy (meta);
+
+    if (ret_rank != NULL)
+      *ret_rank = rank;
+
+    return GNUNET_OK;
+  }
+  if (ret_name != NULL)
+    *ret_name = GNUNET_strdup (_("no-name"));
+  if (ret_meta != NULL)
+    *ret_meta = GNUNET_CONTAINER_meta_data_create ();
+  if (ret_rank != NULL)
+    *ret_rank = -1;
+  if (name_is_a_dup != NULL)
+    *name_is_a_dup = GNUNET_YES;
+  return GNUNET_SYSERR;
+}
+
 /**
  * Get the namespace ID belonging to the given namespace name.
  *
  * @param cfg configuration to use
- * @param ns_uname human-readable name for the namespace
+ * @param ns_uname unique (!) human-readable name for the namespace
  * @param nsid set to namespace ID based on 'ns_uname'
- * @return GNUNET_OK on success
+ * @return GNUNET_OK on success, GNUNET_SYSERR on failure
  */
 int
 GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                             const char *ns_uname, GNUNET_HashCode * nsid)
+    const char *ns_uname, struct GNUNET_HashCode * nsid)
 {
   size_t slen;
   uint64_t len;
   unsigned int idx;
   char *name;
-  GNUNET_HashCode nh;
+  struct GNUNET_HashCode nh;
   char *fn;
   struct GNUNET_DISK_FileHandle *fh;
 
   idx = -1;
   slen = strlen (ns_uname);
-  while ((slen > 0) && (1 != sscanf (&ns_uname[slen - 1], "-%u", &idx)))
+  while ((slen > 0) && (1 != SSCANF (&ns_uname[slen - 1], "-%u", &idx)))
     slen--;
   if (slen == 0)
     return GNUNET_SYSERR;
   name = GNUNET_strdup (ns_uname);
   name[slen - 1] = '\0';
+
   GNUNET_CRYPTO_hash (name, strlen (name), &nh);
   GNUNET_free (name);
   fn = get_data_filename (cfg, PS_NAMES_DIR, &nh);
   GNUNET_assert (fn != NULL);
 
   if ((GNUNET_OK != GNUNET_DISK_file_test (fn) ||
-       (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES))) ||
-      ((idx + 1) * sizeof (GNUNET_HashCode) > len))
-    {
-      GNUNET_free (fn);
-      return GNUNET_SYSERR;
-    }
-  fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_CREATE
-                              | GNUNET_DISK_OPEN_READWRITE,
+       (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES))) ||
+      ((idx + 1) * sizeof (struct GNUNET_HashCode) > len))
+  {
+    GNUNET_free (fn);
+    return GNUNET_SYSERR;
+  }
+  fh = GNUNET_DISK_file_open (fn,
+                              GNUNET_DISK_OPEN_CREATE |
+                              GNUNET_DISK_OPEN_READWRITE,
                               GNUNET_DISK_PERM_USER_READ |
                               GNUNET_DISK_PERM_USER_WRITE);
   GNUNET_free (fn);
-  GNUNET_DISK_file_seek (fh, idx * sizeof (GNUNET_HashCode),
-                         GNUNET_DISK_SEEK_SET);
-  if (sizeof (GNUNET_HashCode) !=
-      GNUNET_DISK_file_read (fh, nsid, sizeof (GNUNET_HashCode)))
-    {
-      GNUNET_DISK_file_close (fh);
-      return GNUNET_SYSERR;
-    }
+  if (GNUNET_SYSERR ==
+      GNUNET_DISK_file_seek (fh, idx * sizeof (struct GNUNET_HashCode),
+                            GNUNET_DISK_SEEK_SET))
+  {
+    GNUNET_DISK_file_close (fh);
+    return GNUNET_SYSERR;
+  }
+  if (sizeof (struct GNUNET_HashCode) !=
+      GNUNET_DISK_file_read (fh, nsid, sizeof (struct GNUNET_HashCode)))
+  {
+    GNUNET_DISK_file_close (fh);
+    return GNUNET_SYSERR;
+  }
   GNUNET_DISK_file_close (fh);
   return GNUNET_OK;
 }
@@ -451,28 +540,39 @@ list_pseudonym_helper (void *cls, const char *fullname)
 {
   struct ListPseudonymClosure *c = cls;
   int ret;
-  GNUNET_HashCode id;
-  int rating;
+  struct GNUNET_HashCode id;
+  int32_t rating;
   struct GNUNET_CONTAINER_MetaData *meta;
   const char *fn;
   char *str;
+  char *name_unique;
 
   if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))
     return GNUNET_OK;
-  fn =
-    &fullname[strlen (fullname) + 1 -
-              sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)];
+  fn = &fullname[strlen (fullname) + 1 -
+                 sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)];
   if (fn[-1] != DIR_SEPARATOR)
     return GNUNET_OK;
   ret = GNUNET_OK;
   if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (fn, &id))
     return GNUNET_OK;           /* invalid name */
   str = NULL;
-  if (GNUNET_OK != read_info (c->cfg, &id, &meta, &rating, &str))
-    return GNUNET_OK;           /* ignore entry */
-  GNUNET_free_non_null (str);
+  if (GNUNET_OK != GNUNET_PSEUDONYM_get_info (c->cfg, &id, &meta, &rating,
+      &str, NULL))
+  {
+    /* ignore entry. FIXME: Why? Lack of data about a pseudonym is not a reason
+     * to ignore it... So yeah, it will have placeholders instead of name,
+     * empty metadata container and a default rank == -1, so what? We know
+     * its nsid - that's all we really need. Right? */
+    GNUNET_free (str);
+    GNUNET_CONTAINER_meta_data_destroy (meta);
+    return GNUNET_OK;
+  }
+  name_unique = GNUNET_PSEUDONYM_name_uniquify (c->cfg, &id, str, NULL);
   if (c->iterator != NULL)
-    ret = c->iterator (c->closure, &id, meta, rating);
+    ret = c->iterator (c->closure, &id, str, name_unique, meta, rating);
+  GNUNET_free_non_null (str);
+  GNUNET_free_non_null (name_unique);
   GNUNET_CONTAINER_meta_data_destroy (meta);
   return ret;
 }
@@ -481,7 +581,7 @@ list_pseudonym_helper (void *cls, const char *fullname)
 /**
  * List all available pseudonyms.
  *
- * @param cfg overall configuration 
+ * @param cfg overall configuration
  * @param iterator function to call for each pseudonym
  * @param closure closure for iterator
  * @return number of pseudonyms found
@@ -505,6 +605,7 @@ GNUNET_PSEUDONYM_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg,
   return ret;
 }
 
+
 /**
  * Change the ranking of a pseudonym.
  *
@@ -516,7 +617,7 @@ GNUNET_PSEUDONYM_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg,
  */
 int
 GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                       const GNUNET_HashCode * nsid, int delta)
+                       const struct GNUNET_HashCode * nsid, int delta)
 {
   struct GNUNET_CONTAINER_MetaData *meta;
   int ret;
@@ -526,10 +627,10 @@ GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg,
   name = NULL;
   ret = read_info (cfg, nsid, &meta, &ranking, &name);
   if (ret == GNUNET_SYSERR)
-    {
-      ranking = 0;
-      meta = GNUNET_CONTAINER_meta_data_create ();
-    }
+  {
+    ranking = 0;
+    meta = GNUNET_CONTAINER_meta_data_create ();
+  }
   ranking += delta;
   write_pseudonym_info (cfg, nsid, meta, ranking, name);
   GNUNET_CONTAINER_meta_data_destroy (meta);
@@ -537,23 +638,32 @@ GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg,
   return ranking;
 }
 
+
 /**
- * Insert metadata into existing MD record (passed as cls).
+ * Set the pseudonym metadata, rank and name.
  *
- * @param cls metadata to add to
- * @param type type of entry to insert
- * @param data value of entry to insert
+ * @param cfg overall configuration
+ * @param nsid id of the pseudonym
+ * @param name name to set. Must be the non-unique version of it.
+ *        May be NULL, in which case it erases pseudonym's name!
+ * @param md metadata to set
+ *        May be NULL, in which case it erases pseudonym's metadata!
+ * @param rank rank to assign
+ * @return GNUNET_OK on success, GNUNET_SYSERR on failure
  */
-static int
-merge_meta_helper (void *cls, EXTRACTOR_KeywordType type, const char *data)
+int
+GNUNET_PSEUDONYM_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
+    const struct GNUNET_HashCode * nsid, const char *name,
+    const struct GNUNET_CONTAINER_MetaData *md, int rank)
 {
-  struct GNUNET_CONTAINER_MetaData *meta = cls;
-  GNUNET_CONTAINER_meta_data_insert (meta, type, data);
+  GNUNET_assert (cfg != NULL);
+  GNUNET_assert (nsid != NULL);
+
+  write_pseudonym_info (cfg, nsid, md, rank, name);
   return GNUNET_OK;
 }
 
 
-
 /**
  * Add a pseudonym to the set of known pseudonyms.
  * For all pseudonym advertisements that we discover
@@ -565,7 +675,7 @@ merge_meta_helper (void *cls, EXTRACTOR_KeywordType type, const char *data)
  */
 void
 GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                      const GNUNET_HashCode * id,
+                      const struct GNUNET_HashCode * id,
                       const struct GNUNET_CONTAINER_MetaData *meta)
 {
   char *name;
@@ -580,22 +690,19 @@ GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
   if ((0 == STAT (fn, &sbuf)) &&
       (GNUNET_OK == read_info (cfg, id, &old, &ranking, &name)))
-    {
-      GNUNET_CONTAINER_meta_data_get_contents (meta, &merge_meta_helper, old);
-      write_pseudonym_info (cfg, id, old, ranking, name);
-      GNUNET_CONTAINER_meta_data_destroy (old);
-      GNUNET_free_non_null (name);
-    }
+  {
+    GNUNET_CONTAINER_meta_data_merge (old, meta);
+    write_pseudonym_info (cfg, id, old, ranking, name);
+    GNUNET_CONTAINER_meta_data_destroy (old);
+    GNUNET_free_non_null (name);
+  }
   else
-    {
-      write_pseudonym_info (cfg, id, meta, ranking, NULL);
-    }
+  {
+    write_pseudonym_info (cfg, id, meta, ranking, NULL);
+  }
   GNUNET_free (fn);
   internal_notify (id, meta, ranking);
 }
 
 
-
-
-
 /* end of pseudonym.c */