gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r6745 - in GNUnet: . src/applications/fs/ecrs src/applicati


From: gnunet
Subject: [GNUnet-SVN] r6745 - in GNUnet: . src/applications/fs/ecrs src/applications/fs/fsui src/applications/fs/gap src/applications/fs/uritrack src/applications/tbench src/applications/testing src/include
Date: Wed, 23 Apr 2008 23:49:31 -0600 (MDT)

Author: grothoff
Date: 2008-04-23 23:49:31 -0600 (Wed, 23 Apr 2008)
New Revision: 6745

Modified:
   GNUnet/ChangeLog
   GNUnet/src/applications/fs/ecrs/ecrs.h
   GNUnet/src/applications/fs/ecrs/ecrstest.c
   GNUnet/src/applications/fs/ecrs/helper.c
   GNUnet/src/applications/fs/ecrs/keyspace.c
   GNUnet/src/applications/fs/ecrs/namespace.c
   GNUnet/src/applications/fs/ecrs/namespacetest.c
   GNUnet/src/applications/fs/ecrs/parser.c
   GNUnet/src/applications/fs/ecrs/search.c
   GNUnet/src/applications/fs/ecrs/searchtest.c
   GNUnet/src/applications/fs/ecrs/uri.c
   GNUnet/src/applications/fs/ecrs/uritest.c
   GNUnet/src/applications/fs/fsui/deserialize.c
   GNUnet/src/applications/fs/fsui/downloadtest.c
   GNUnet/src/applications/fs/fsui/fsui.c
   GNUnet/src/applications/fs/fsui/fsui.h
   GNUnet/src/applications/fs/fsui/fsuitest.c
   GNUnet/src/applications/fs/fsui/recursivetest.c
   GNUnet/src/applications/fs/fsui/search.c
   GNUnet/src/applications/fs/fsui/searchtest.c
   GNUnet/src/applications/fs/fsui/serialize.c
   GNUnet/src/applications/fs/fsui/serializetest.c
   GNUnet/src/applications/fs/fsui/serializetest2.c
   GNUnet/src/applications/fs/fsui/serializetest3.c
   GNUnet/src/applications/fs/fsui/serializetest4.c
   GNUnet/src/applications/fs/gap/ondemand.c
   GNUnet/src/applications/fs/gap/test_linear_topology.c
   GNUnet/src/applications/fs/gap/test_loopback.c
   GNUnet/src/applications/fs/gap/test_multi_results.c
   GNUnet/src/applications/fs/uritrack/tracktest.c
   GNUnet/src/applications/tbench/tbenchtest.c
   GNUnet/src/applications/testing/testing.c
   GNUnet/src/include/gnunet_ecrs_lib.h
   GNUnet/src/include/gnunet_fsui_lib.h
   GNUnet/todo
Log:
big FSUI change towards ranked search results

Modified: GNUnet/ChangeLog
===================================================================
--- GNUnet/ChangeLog    2008-04-24 04:01:46 UTC (rev 6744)
+++ GNUnet/ChangeLog    2008-04-24 05:49:31 UTC (rev 6745)
@@ -1,3 +1,11 @@
+Mon Apr 21 21:05:20 MDT 2008
+       Adding buffered IO for FSUI's serialize and
+       deserialize code.
+
+Sun Apr 20 20:01:20 MDT 2008
+       Fixed bug in HTTP transport causing lonely messages
+       (responses to GET) not to be delivered.
+
 Mon Mar 24 21:15:36 MDT 2008
        Fixed various problems with downloading locally
        indexed large files (downloading large files from

Modified: GNUnet/src/applications/fs/ecrs/ecrs.h
===================================================================
--- GNUnet/src/applications/fs/ecrs/ecrs.h      2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/ecrs/ecrs.h      2008-04-24 05:49:31 UTC (rev 
6745)
@@ -81,7 +81,19 @@
   {
     struct
     {
-      char **keywords;
+      /**
+       * Keywords start with a '+' if they are
+       * mandatory (in which case the '+' is NOT
+       * part of the keyword) and with a
+       * simple space if they are optional
+       * (in which case the space is ALSO not
+       * part of the actual keyword).
+       *
+       * Double-quotes to protect spaces and
+       * %-encoding are NOT used internally
+       * (only in URI-strings).
+       */
+      char ** keywords;      
       unsigned int keywordCount;
     } ksk;
     struct

Modified: GNUnet/src/applications/fs/ecrs/ecrstest.c
===================================================================
--- GNUnet/src/applications/fs/ecrs/ecrstest.c  2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/ecrs/ecrstest.c  2008-04-24 05:49:31 UTC (rev 
6745)
@@ -97,13 +97,9 @@
     {
       struct GNUNET_ECRS_MetaData *meta;
       struct GNUNET_ECRS_URI *key;
-      const char *keywords[2];
 
-      keywords[0] = name;
-      keywords[1] = NULL;
-
       meta = GNUNET_ECRS_meta_data_create ();
-      key = GNUNET_ECRS_keyword_strings_to_uri (keywords);
+      key = GNUNET_ECRS_keyword_string_to_uri (NULL, name);
       ret = GNUNET_ECRS_publish_under_keyword (NULL, cfg, key, 0, 0, 
GNUNET_get_time () + 10 * GNUNET_CRON_MINUTES,     /* expire */
                                                uri, meta);
       GNUNET_ECRS_meta_data_destroy (meta);

Modified: GNUnet/src/applications/fs/ecrs/helper.c
===================================================================
--- GNUnet/src/applications/fs/ecrs/helper.c    2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/ecrs/helper.c    2008-04-24 05:49:31 UTC (rev 
6745)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other 
contributing authors)
+     (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 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
@@ -27,14 +27,22 @@
 
 #include "platform.h"
 #include "gnunet_ecrs_lib.h"
+#include "ecrs.h"
 
 /**
  * Create an ECRS URI from a single user-supplied string of keywords.
- * The string may contain the reserved word 'AND' to create a boolean
- * search over multiple keywords.
+ * The string is broken up at spaces into individual keywords.
+ * Keywords that start with "+" are mandatory.  Double-quotes can
+ * be used to prevent breaking up strings at spaces (and also
+ * to specify non-mandatory keywords starting with "+").
  *
+ * Keywords must contain a balanced number of double quotes and
+ * double quotes can not be used in the actual keywords (for
+ * example, the string '""foo bar""' will be turned into two
+ * "OR"ed keywords 'foo' and 'bar', not into '"foo bar"'.
+ * 
  * @return an ECRS URI for the given keywords, NULL
- *  if keywords is not legal (i.e. empty).
+ *  if keywords is not legal (i.e. empty). 
  */
 struct GNUNET_ECRS_URI *
 GNUNET_ECRS_keyword_string_to_uri (struct GNUNET_GE_Context *ectx,
@@ -43,9 +51,10 @@
   char **keywords;
   unsigned int num_Words;
   int inWord;
-  char *c;
+  char *pos;
   struct GNUNET_ECRS_URI *uri;
   char *searchString;
+  int saw_quote;
 
   if (input == NULL)
     {
@@ -54,42 +63,63 @@
     }
   searchString = GNUNET_strdup (input);
   num_Words = 0;
-  for (inWord = 0, c = searchString; *c != '\0'; ++c)
+  inWord = 0;
+  saw_quote = 0;
+  pos = searchString;
+  while ('\0' != *pos)
     {
-      if (isspace (*c))
+      if ( (saw_quote ==0) &&
+          (isspace (*pos)) )
         {
           inWord = 0;
         }
-      else if (!inWord)
-        {
-          inWord = 1;
-          ++num_Words;
-        }
+      else
+       if (0 == inWord)
+         {
+           inWord = 1;
+           ++num_Words;
+         }
+      if ('"' == *pos)
+       saw_quote = (saw_quote + 1) % 2;     
+      pos++;
     }
-
   if (num_Words == 0)
     {
-      GNUNET_free_non_null (searchString);
+      GNUNET_free (searchString);
       GNUNET_GE_LOG (ectx,
                      GNUNET_GE_ERROR | GNUNET_GE_IMMEDIATE | GNUNET_GE_USER,
                      _("No keywords specified!\n"));
       return NULL;
     }
+  if (saw_quote != 0)
+    {
+      GNUNET_free (searchString);
+      GNUNET_GE_LOG (ectx,
+                     GNUNET_GE_ERROR | GNUNET_GE_IMMEDIATE | GNUNET_GE_USER,
+                     _("Number of double-quotes not balanced!\n"));
+      return NULL;
+    }
   keywords = GNUNET_malloc (num_Words * sizeof (char *));
   num_Words = 0;
-  for (inWord = 0, c = searchString; *c != '\0'; ++c)
+  inWord = 0;
+  pos = searchString;  
+  while ('\0' != *pos) 
     {
-      if (isspace (*c))
+      if ( (saw_quote == 0) &&
+          (isspace (*pos)) )
         {
           inWord = 0;
-          *c = '\0';
+          *pos = '\0';
         }
-      else if (!inWord)
+      else if (0 == inWord)
         {
-          keywords[num_Words] = c;
+          keywords[num_Words] = pos;
           inWord = 1;
           ++num_Words;
         }
+      if ('"' == *pos)
+       saw_quote = (saw_quote + 1) % 2;     
+      pos++;
     }
   uri =
     GNUNET_ECRS_keyword_command_line_to_uri (ectx, num_Words,
@@ -99,11 +129,21 @@
   return uri;
 }
 
+
 /**
  * Create an ECRS URI from a user-supplied command line of keywords.
- * The command line may contain the reserved word 'AND' to create a
- * boolean search over multiple keywords.
+ * Arguments should start with "+" to indicate mandatory
+ * keywords.  
  *
+ * @param argc number of keywords
+ * @param argv keywords (double quotes are not required for
+ *             keywords containing spaces; however, double
+ *             quotes are required for keywords starting with
+ *             "+"); there is no mechanism for having double
+ *             quotes in the actual keywords (if the user
+ *             did specifically specify double quotes, the
+ *             caller should convert each double quote
+ *             into two single quotes).
  * @return an ECRS URI for the given keywords, NULL
  *  if keywords is not legal (i.e. empty).
  */
@@ -113,93 +153,42 @@
                                          const char **keywords)
 {
   unsigned int i;
-  unsigned int uriLen;
-  char *uriString;
-  unsigned int uriSize;
   struct GNUNET_ECRS_URI *uri;
+  const char * keyword;
+  char * val;
+  const char * r;
+  char * w;
 
-  uriString = NULL;
-  uriSize = 0;
-  GNUNET_array_grow (uriString, uriSize, 4096);
-  strcpy (uriString, GNUNET_ECRS_URI_PREFIX);
-  strcat (uriString, GNUNET_ECRS_SEARCH_INFIX);
-  uriLen =
-    1 + strlen (GNUNET_ECRS_URI_PREFIX) + strlen (GNUNET_ECRS_SEARCH_INFIX);
-
-
+  uri = GNUNET_malloc (sizeof (URI));
+  uri->type = ksk;
+  uri->data.ksk.keywordCount = num_keywords;
+  uri->data.ksk.keywords = GNUNET_malloc (num_keywords * sizeof (char *));
   for (i = 0; i < num_keywords; i++)
     {
-      if (uriSize < uriLen + strlen (_("AND")) + 1 + strlen (keywords[i]))
-        GNUNET_array_grow (uriString, uriSize,
-                           uriSize + 4096 + strlen (keywords[i]));
-      if ((i > 0) && (0 == strcmp (keywords[i], _("AND"))))
-        {
-          strcat (uriString, "+");
-          if (i == num_keywords - 1)
-            strcat (uriString, _("AND"));       /* last keyword 'AND'? keep 
it! */
-          uriLen += 1;
-        }
+      keyword = keywords[i];
+      if (keyword[0] == '+')
+       {
+         val = GNUNET_strdup(keyword);
+       }
       else
-        {
-          if ((i > 0) && (0 != strcmp (keywords[i - 1], _("AND"))))
-            {
-              strcat (uriString, " ");
-              uriLen += 1;
-            }
-          strcat (uriString, keywords[i]);
-          uriLen += strlen (keywords[i]);
-        }
+       {
+         val = GNUNET_malloc(strlen(keyword) + 2);
+         strcpy(val, " ");
+         strcat(val, keyword);
+       }
+      r = val;
+      w = val;
+      while ('\0' != *r)
+       {
+         if ('"' == *r)
+           r++;
+         else
+           *(w++) = *(r++);
+       }
+      uri->data.ksk.keywords[i] = GNUNET_strdup(val);
+      GNUNET_free(val);
     }
-  uri = GNUNET_ECRS_string_to_uri (ectx, uriString);
-  GNUNET_array_grow (uriString, uriSize, 0);
   return uri;
 }
 
-/**
- * Create an ECRS URI from a user-supplied list of keywords.
- * The keywords are NOT separated by AND but already
- * given individually.
- *
- * @return an ECRS URI for the given keywords, NULL
- *  if keywords is not legal (i.e. empty).
- */
-struct GNUNET_ECRS_URI *
-GNUNET_ECRS_keyword_list_to_uri (struct GNUNET_GE_Context *ectx,
-                                 unsigned int num_keywords,
-                                 const char **keywords)
-{
-  unsigned int i;
-  unsigned int uriLen;
-  char *uriString;
-  unsigned int uriSize;
-  struct GNUNET_ECRS_URI *uri;
-
-  uriString = NULL;
-  uriSize = 0;
-  GNUNET_array_grow (uriString, uriSize, 4096);
-  strcpy (uriString, GNUNET_ECRS_URI_PREFIX);
-  strcat (uriString, GNUNET_ECRS_SEARCH_INFIX);
-  uriLen =
-    1 + strlen (GNUNET_ECRS_URI_PREFIX) + strlen (GNUNET_ECRS_SEARCH_INFIX);
-
-
-  for (i = 0; i < num_keywords; i++)
-    {
-      if (uriSize < uriLen + 1 + strlen (keywords[i]))
-        GNUNET_array_grow (uriString, uriSize,
-                           uriSize + 4096 + strlen (keywords[i]));
-      if (i > 0)
-        {
-          strcat (uriString, "+");
-          uriLen++;
-        }
-      strcat (uriString, keywords[i]);
-      uriLen += strlen (keywords[i]);
-    }
-  uri = GNUNET_ECRS_string_to_uri (ectx, uriString);
-  GNUNET_array_grow (uriString, uriSize, 0);
-  return uri;
-}
-
-
 /* end of helper.c */

Modified: GNUnet/src/applications/fs/ecrs/keyspace.c
===================================================================
--- GNUnet/src/applications/fs/ecrs/keyspace.c  2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/ecrs/keyspace.c  2008-04-24 05:49:31 UTC (rev 
6745)
@@ -137,6 +137,7 @@
   char *dstURI;
   GNUNET_EC_KBlock *kb;
   char **keywords;
+  const char * keyword;
   unsigned int keywordCount;
   int i;
 #if DEBUG_KEYSPACE
@@ -149,7 +150,7 @@
   char *cpy;                    /* copy of the encrypted portion */
   struct GNUNET_ECRS_URI *xuri;
 
-  if (!GNUNET_ECRS_uri_test_ksk (uri))
+  if (!GNUNET_ECRS_uri_test_ksk (uri)) 
     {
       GNUNET_GE_BREAK (ectx, 0);
       return GNUNET_SYSERR;
@@ -220,7 +221,10 @@
   for (i = 0; i < keywordCount; i++)
     {
       memcpy (&kb[1], cpy, mdsize + strlen (dstURI) + 1);
-      GNUNET_hash (keywords[i], strlen (keywords[i]), &key);
+      keyword = keywords[i];
+      /* first character of keyword indicates if it is
+        mandatory or not -- ignore for hashing */
+      GNUNET_hash (&keyword[1], strlen (&keyword[1]), &key);
 #if DEBUG_KEYSPACE
       IF_GELOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
                 GNUNET_hash_to_enc (&key, &enc));

Modified: GNUnet/src/applications/fs/ecrs/namespace.c
===================================================================
--- GNUnet/src/applications/fs/ecrs/namespace.c 2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/ecrs/namespace.c 2008-04-24 05:49:31 UTC (rev 
6745)
@@ -139,6 +139,7 @@
   GNUNET_EC_NBlock *nb;
   GNUNET_EC_KNBlock *knb;
   char **keywords;
+  const char * keyword;
   unsigned int keywordCount;
   int i;
   char *cpy;
@@ -262,7 +263,10 @@
               size - sizeof (GNUNET_EC_KBlock) - sizeof (unsigned int));
       for (i = 0; i < keywordCount; i++)
         {
-          GNUNET_hash (keywords[i], strlen (keywords[i]), &hc);
+         keyword = keywords[i];
+         /* first character of keyword indicates
+            mandatory or not -- ignore for hashing! */
+          GNUNET_hash (&keyword[1], strlen (&keyword[1]), &hc);
           pk = GNUNET_RSA_create_key_from_hash (&hc);
           GNUNET_RSA_get_public_key (pk, &knb->kblock.keyspace);
           GNUNET_GE_ASSERT (ectx,

Modified: GNUnet/src/applications/fs/ecrs/namespacetest.c
===================================================================
--- GNUnet/src/applications/fs/ecrs/namespacetest.c     2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/ecrs/namespacetest.c     2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -73,15 +73,10 @@
   struct GNUNET_ECRS_URI *advURI;
   struct GNUNET_ECRS_URI *rootURI;
   struct GNUNET_ECRS_MetaData *meta;
-  const char *keys[] = {
-    "testNamespace",
-    NULL,
-  };
 
-
   GNUNET_ECRS_namespace_delete (NULL, cfg, CHECKNAME);  /* make sure old one 
is deleted */
   meta = GNUNET_ECRS_meta_data_create ();
-  adv = GNUNET_ECRS_keyword_strings_to_uri (keys);
+  adv = GNUNET_ECRS_keyword_string_to_uri (NULL, "testNamespace");
   GNUNET_hash ("root", 4, &root);
   rootURI =
     GNUNET_ECRS_namespace_create (NULL,

Modified: GNUnet/src/applications/fs/ecrs/parser.c
===================================================================
--- GNUnet/src/applications/fs/ecrs/parser.c    2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/ecrs/parser.c    2008-04-24 05:49:31 UTC (rev 
6745)
@@ -39,6 +39,8 @@
 {
   struct GNUNET_ECRS_URI **uri = scls;
   struct GNUNET_ECRS_URI *u = *uri;
+  char * val;
+  size_t slen;
 
   if (u == NULL)
     {
@@ -52,9 +54,57 @@
     {
       GNUNET_GE_ASSERT (NULL, u->type == ksk);
     }
+  slen = strlen(value);
+  if (slen == 0)
+    return GNUNET_SYSERR; /* cannot be empty */
+  if (value[0] == '+')
+    {
+      /* simply preserve the "mandatory" flag */
+      if (slen < 2)
+       return GNUNET_SYSERR; /* empty keywords not allowed */
+      if ( (value[1] == '"') &&
+          (slen > 3) &&
+          (value[slen-1] == '"') ) 
+       {
+         /* remove the quotes, keep the '+' */
+         val = GNUNET_malloc(slen-1);
+         val[0] = '+';
+         memcpy(&val[1],
+                &value[2],
+                slen-3);
+         val[slen-2] = '\0';
+       }
+      else
+       {     
+         /* no quotes, just keep the '+' */
+         val = GNUNET_strdup (value);
+       }
+    }
+  else
+    {
+      if ( (value[0] == '"') &&
+          (slen > 2) &&
+          (value[slen-1] == '"') ) 
+       {
+         /* remove the quotes, add a space */
+         val = GNUNET_malloc(slen);
+         val[0] = ' ';
+         memcpy(&val[1],
+                &value[1],
+                slen-2);
+         val[slen-1] = '\0';
+       }
+      else
+       {
+         /* add a space to indicate "not mandatory" */
+         val = GNUNET_malloc(slen+2);
+         strcpy(val, " ");
+         strcat(val, value);
+       }
+    }
   GNUNET_array_grow (u->data.ksk.keywords,
                      u->data.ksk.keywordCount, u->data.ksk.keywordCount + 1);
-  u->data.ksk.keywords[u->data.ksk.keywordCount - 1] = GNUNET_strdup (value);
+  u->data.ksk.keywords[u->data.ksk.keywordCount - 1] = val;
   return GNUNET_OK;
 }
 

Modified: GNUnet/src/applications/fs/ecrs/search.c
===================================================================
--- GNUnet/src/applications/fs/ecrs/search.c    2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/ecrs/search.c    2008-04-24 05:49:31 UTC (rev 
6745)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other 
contributing authors)
+     (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 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
@@ -34,8 +34,8 @@
 #define DEBUG_SEARCH GNUNET_NO
 
 /**
- * This struct is followed by keyCount keys of
- * type "GNUNET_HashCode".
+ * Context for an individual search.  Followed
+ *  by keyCount keys of type GNUNET_HashCode.
  */
 struct PendingSearch
 {
@@ -48,16 +48,13 @@
    */
   GNUNET_HashCode decryptKey;
 
+  unsigned int keyCount;
+
   /**
    * What type of query is it?
    */
   unsigned int type;
 
-  /**
-   * How many keys are there?
-   */
-  unsigned int keyCount;
-
 };
 
 /**
@@ -176,6 +173,7 @@
         struct GNUNET_RSA_PrivateKey *pk;
         GNUNET_RSA_PublicKey pub;
         int i;
+       const char * keyword;
 
 #if DEBUG_SEARCH
         GNUNET_GE_LOG (ectx,
@@ -184,8 +182,12 @@
 #endif
         for (i = 0; i < uri->data.ksk.keywordCount; i++)
           {
-            GNUNET_hash (uri->data.ksk.keywords[i],
-                         strlen (uri->data.ksk.keywords[i]), &hc);
+           keyword = uri->data.ksk.keywords[i];
+           /* first character of the keyword is 
+              "+" or " " to indicate mandatory or
+              not -- ignore for hashing! */
+           GNUNET_hash (&keyword[1],
+                         strlen (&keyword[1]), &hc);
             pk = GNUNET_RSA_create_key_from_hash (&hc);
             GNUNET_RSA_get_public_key (pk, &pub);
             GNUNET_hash (&pub, sizeof (GNUNET_RSA_PublicKey), &query);
@@ -565,6 +567,16 @@
 {
   struct GNUNET_ECRS_SearchContext *ctx;
 
+  if (GNUNET_YES == GNUNET_ECRS_uri_test_ksk(uri))
+    {
+      if (1 != GNUNET_ECRS_uri_get_keyword_count_from_ksk(uri))
+       return NULL;
+    }
+  else
+    {
+      if (GNUNET_YES != GNUNET_ECRS_uri_test_sks(uri)) 
+       return NULL;
+    }
   ctx = GNUNET_malloc (sizeof (struct GNUNET_ECRS_SearchContext));
   ctx->start = GNUNET_get_time ();
   ctx->anonymityLevel = anonymityLevel;
@@ -576,6 +588,12 @@
   ctx->aborted = GNUNET_NO;
   ctx->lock = GNUNET_mutex_create (GNUNET_YES);
   ctx->sctx = GNUNET_FS_create_search_context (ectx, cfg, ctx->lock);
+  if (ctx->sctx == NULL) 
+    {
+      GNUNET_mutex_destroy(ctx->lock);
+      GNUNET_free(ctx);
+      return NULL;
+    }
   add_search_for_uri (uri, ctx);
   return ctx;
 }
@@ -622,6 +640,8 @@
   ctx =
     GNUNET_ECRS_search_start (ectx, cfg, uri, anonymityLevel, spcb,
                               spcbClosure);
+  if (ctx == NULL)
+    return GNUNET_SYSERR;
   while (((NULL == tt) || (GNUNET_OK == tt (ttClosure)))
          && (GNUNET_NO == GNUNET_shutdown_test ())
          && (ctx->aborted == GNUNET_NO))

Modified: GNUnet/src/applications/fs/ecrs/searchtest.c
===================================================================
--- GNUnet/src/applications/fs/ecrs/searchtest.c        2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/ecrs/searchtest.c        2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2004, 2005, 2006 Christian Grothoff (and other contributing authors)
+     (C) 2004, 2005, 2006, 2008 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
@@ -44,11 +44,11 @@
           const GNUNET_HashCode * key, int isRoot, void *closure)
 {
   int *cnt = closure;
-#if 1
+#if 0
   char *st;
 
   st = GNUNET_ECRS_uri_to_string (fi->uri);
-  printf ("Got result `%s'\n", st);
+  printf ("Got result `%.*s...'\n", 40, st);
   GNUNET_free (st);
 #endif
   (*cnt)--;
@@ -81,9 +81,7 @@
   struct GNUNET_ECRS_URI *uri;
   struct GNUNET_ECRS_MetaData *meta;
   struct GNUNET_ECRS_URI *key;
-  const char *keywords[6];
 
-
   cfg = GNUNET_GC_create ();
   if (-1 == GNUNET_GC_parse_configuration (cfg, "check.conf"))
     {
@@ -102,35 +100,26 @@
   CHECK (sock != NULL);
   /* ACTUAL TEST CODE */
   /* first, simple insertion => one result */
-#if 1
+#if 0
   printf ("Testing search for 'XXtest' with one result.\n");
 #endif
   uri = GNUNET_ECRS_string_to_uri (NULL,
                                    
"gnunet://ecrs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test");
   meta = GNUNET_ECRS_meta_data_create ();
-  keywords[0] = "XXtest";
-  keywords[1] = NULL;
 
-  key = GNUNET_ECRS_keyword_strings_to_uri (keywords);
+  key = GNUNET_ECRS_keyword_string_to_uri (NULL, "XXtest");
   CHECK (GNUNET_OK == GNUNET_ECRS_publish_under_keyword (NULL, cfg, key, 0, 0, 
GNUNET_get_time () + 10 * GNUNET_CRON_MINUTES,   /* expire */
                                                          uri, meta));
   CHECK (GNUNET_OK == searchFile (key, 1));
   GNUNET_ECRS_uri_destroy (key);
   GNUNET_ECRS_uri_destroy (uri);
 
-  /* inserting another URI under the 'XXtest' keyword and under 'binary'
-     should give both URIs since ECRS knows nothing about 'AND'ing: */
-#if 1
-  printf ("Testing search for 'XXtest AND binary' with two results.\n");
-#endif
   uri = GNUNET_ECRS_string_to_uri (NULL,
                                    
"gnunet://ecrs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test-different");
-  keywords[1] = "binary";
-  keywords[2] = NULL;
-  key = GNUNET_ECRS_keyword_strings_to_uri (keywords);
+  key = GNUNET_ECRS_keyword_string_to_uri (NULL, "+binary");
   CHECK (GNUNET_OK == GNUNET_ECRS_publish_under_keyword (NULL, cfg, key, 0, 0, 
GNUNET_get_time () + 10 * GNUNET_CRON_MINUTES,   /* expire */
                                                          uri, meta));
-  CHECK (GNUNET_OK == searchFile (key, 2));
+  CHECK (GNUNET_OK == searchFile (key, 1));
   GNUNET_ECRS_uri_destroy (key);
   GNUNET_ECRS_uri_destroy (uri);
   GNUNET_ECRS_meta_data_destroy (meta);
@@ -139,8 +128,7 @@
 #if 0
   printf ("Testing search for 'XXtest' with two results.\n");
 #endif
-  keywords[1] = NULL;
-  key = GNUNET_ECRS_keyword_strings_to_uri (keywords);
+  key = GNUNET_ECRS_keyword_string_to_uri (NULL, "XXtest");
   CHECK (GNUNET_OK == searchFile (key, 2));
   GNUNET_ECRS_uri_destroy (key);
 

Modified: GNUnet/src/applications/fs/ecrs/uri.c
===================================================================
--- GNUnet/src/applications/fs/ecrs/uri.c       2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/ecrs/uri.c       2008-04-24 05:49:31 UTC (rev 
6745)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2003, 2004, 2005, 2006, 2007 Christian Grothoff (and other 
contributing authors)
+     (C) 2003, 2004, 2005, 2006, 2007, 2008 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
@@ -75,7 +75,7 @@
  * </li></ul>
  *
  * The encoding for hexadecimal values is defined in the hashing.c
- * module (GNUNET_EncName) in the gnunet-util library and discussed there.
+ * module (GNUNET_EncName) in the gnunetutil library and discussed there.
  * <p>
  */
 
@@ -85,6 +85,18 @@
 #include "gnunet_ecrs_lib.h"
 
 /**
+ * In URI-encoding, does the given character
+ * need to be encoded using %-encoding?
+ */
+static int needs_percent(char c) {
+  return (! ( (isalnum(c)) ||
+                 (c == '-') ||
+                 (c == '_') ||
+                 (c == '.') ||
+             (c == '~') ) );
+}
+
+/**
  * Generate a keyword URI.
  * @return NULL on error (i.e. keywordCount == 0)
  */
@@ -94,20 +106,56 @@
   size_t n;
   char *ret;
   unsigned int i;
+  unsigned int j;
+  unsigned int wpos;
+  size_t slen;
+  const char * keyword;
 
   n =
     keywordCount + strlen (GNUNET_ECRS_URI_PREFIX) +
     strlen (GNUNET_ECRS_SEARCH_INFIX) + 1;
   for (i = 0; i < keywordCount; i++)
-    n += strlen (keywords[i]);
+    {
+      keyword = keywords[i];
+      slen = strlen(keyword);
+      n += slen;
+      for (j = 0; j < slen; j++)
+       {
+         if ( (j == 0) &&
+              (keyword[j] == ' ') )
+           {
+             n--;
+             continue; /* skip leading space */
+           }
+         if (needs_percent(keyword[j]))
+           n += 2; /* will use %-encoding */       
+       }
+    }
   ret = GNUNET_malloc (n);
   strcpy (ret, GNUNET_ECRS_URI_PREFIX);
   strcat (ret, GNUNET_ECRS_SEARCH_INFIX);
+  wpos = strlen(ret);
   for (i = 0; i < keywordCount; i++)
     {
-      strcat (ret, keywords[i]);
+      keyword = keywords[i];
+      slen = strlen(keyword);
+      for (j = 0; j < slen; j++)
+       {
+         if ( (j == 0) &&
+              (keyword[j] == ' ') )
+           continue; /* skip leading space */      
+         if (needs_percent(keyword[j]))
+           {
+             sprintf(&ret[wpos], "%%%02X", keyword[j]);
+             wpos += 3;
+           }
+         else
+           {
+             ret[wpos++] = keyword[j];
+           }
+       }           
       if (i != keywordCount - 1)
-        strcat (ret, "+");
+       ret[wpos++] = '+';
     }
   return ret;
 }
@@ -230,7 +278,58 @@
 }
 
 /**
- * Parses an AFS search URI.
+ * Given a keyword with %-encoding (and possibly quotes to protect
+ * spaces), return a copy of the keyword without %-encoding and
+ * without double-quotes (%22).  Also, add a space at the beginning
+ * if there is not a '+'.
+ */
+static char *
+percent_decode_keyword(const char * in) {
+  char * out;
+  char * ret;
+  unsigned int rpos;  
+  unsigned int wpos;
+  unsigned int hx;
+
+  out = GNUNET_strdup(in);
+  rpos = 0;
+  wpos = 0;
+  while (out[rpos] != '\0')
+    {
+      if (out[rpos] == '%')
+       {
+         if (1 != sscanf(&out[rpos+1], "%2X", &hx))
+           {
+             GNUNET_free(out);
+             return NULL;
+           }
+         rpos += 3;
+         if (hx == '"')
+           continue; /* skip double quote */
+         out[wpos++] = (char) hx;          
+       }
+      else
+       {
+         out[wpos++] = out[rpos++];
+       }      
+    }
+  if (out[0] == '+')
+    {
+      ret = GNUNET_strdup(out);
+    }
+  else
+    {
+      /* need to prefix with space */
+      ret = GNUNET_malloc(strlen(out)+2);
+      strcpy(ret, " ");
+      strcat(ret, out);
+    }
+  GNUNET_free(out);
+  return ret;
+}
+
+/**
+ * Parses an ECRS search URI.
  *
  * @param uri an uri string
  * @param keyword will be set to an array with the keywords
@@ -247,6 +346,7 @@
   int i;
   size_t slen;
   char *dup;
+  int saw_quote;
 
   GNUNET_GE_ASSERT (ectx, uri != NULL);
 
@@ -270,30 +370,61 @@
     return GNUNET_SYSERR;       /* no keywords / malformed */
 
   ret = 1;
+  saw_quote = 0;
   for (i = pos; i < slen; i++)
     {
-      if (uri[i] == '+')
+      if ( (uri[i] == '%') &&
+          (&uri[i] == strstr(&uri[i], "%22")) )
+       {
+         saw_quote = (saw_quote + 1) % 2;
+         i += 3;
+         continue;
+       }
+       if ( (uri[i] == '+') &&
+            (saw_quote == 0) )
         {
           ret++;
           if (uri[i - 1] == '+')
             return GNUNET_SYSERR;       /* "++" not allowed */
         }
     }
+  if (saw_quote == 1)
+    return GNUNET_SYSERR; /* quotes not balanced */
   iret = ret;
   dup = GNUNET_strdup (uri);
   (*keywords) = GNUNET_malloc (ret * sizeof (char *));
+  for (i = 0; i < ret; i++)
+    (*keywords)[i] = NULL;
   for (i = slen - 1; i >= pos; i--)
     {
-      if (dup[i] == '+')
+      if ( (uri[i] == '%') &&
+          (&uri[i] == strstr(&uri[i], "%22")) )
+       {
+         saw_quote = (saw_quote + 1) % 2;
+         i += 3;
+         continue;
+       } 
+      if ( (dup[i] == '+') &&
+          (saw_quote == 0) )
         {
-          (*keywords)[--ret] = GNUNET_strdup (&dup[i + 1]);
+          (*keywords)[--ret] = percent_decode_keyword (&dup[i + 1]);
+         if (NULL == (*keywords)[ret])
+           goto CLEANUP;
           dup[i] = '\0';
         }
     }
-  (*keywords)[--ret] = GNUNET_strdup (&dup[pos]);
+  (*keywords)[--ret] = percent_decode_keyword (&dup[pos]);
+  if (NULL == (*keywords)[ret])
+    goto CLEANUP;
   GNUNET_GE_ASSERT (ectx, ret == 0);
   GNUNET_free (dup);
   return iret;
+ CLEANUP:
+  for (i = 0; i < ret; i++)
+    GNUNET_free_non_null((*keywords)[i]);
+  GNUNET_free(*keywords);
+  *keywords = NULL;
+  return GNUNET_SYSERR; 
 }
 
 /**
@@ -653,19 +784,24 @@
                                        GNUNET_ECRS_KeywordIterator iterator,
                                        void *cls)
 {
-  int i;
+  unsigned int i;
+  char * keyword;
+
   if (uri->type != ksk)
+    return -1;
+  if (iterator == NULL)
+    return uri->data.ksk.keywordCount;
+  for (i = 0; i < uri->data.ksk.keywordCount; i++)
     {
-      return -1;
+      keyword = uri->data.ksk.keywords[i];
+      /* first character of keyword indicates
+        if it is mandator or not */
+      if (GNUNET_OK != iterator (&keyword[1],
+                                keyword[0] == '+',
+                                cls))
+       return i;
     }
-  else
-    {
-      for (i = 0; i < uri->data.ksk.keywordCount; i++)
-        if (iterator != NULL)
-          if (GNUNET_OK != iterator (uri->data.ksk.keywords[i], cls))
-            return i;
-      return i;
-    }
+  return i;
 }
 
 
@@ -803,6 +939,8 @@
   int j;
   int havePreview;
   int add;
+  const char * kword;
+  char * nkword;
 
   if (md == NULL)
     return NULL;
@@ -852,8 +990,12 @@
           if (add == 1)
             {
               GNUNET_GE_ASSERT (NULL, md->items[i].data != NULL);
-              ret->data.ksk.keywords[i - havePreview]
-                = GNUNET_strdup (md->items[i].data);
+             kword = md->items[i].data;
+             nkword = GNUNET_malloc(strlen(kword)+2);
+             strcpy(nkword, " "); /* not mandatory */
+             strcat(nkword, kword);
+              ret->data.ksk.keywords[i - havePreview] 
+                = nkword;
             }
         }
     }
@@ -861,34 +1003,6 @@
 }
 
 /**
- * Convert a NULL-terminated array of keywords
- * to an ECRS URI.
- */
-struct GNUNET_ECRS_URI *
-GNUNET_ECRS_keyword_strings_to_uri (const char *keyword[])
-{
-  unsigned int count;
-  URI *ret;
-  unsigned int i;
-
-  count = 0;
-  while (keyword[count] != NULL)
-    count++;
-
-  ret = GNUNET_malloc (sizeof (URI));
-  ret->type = ksk;
-  ret->data.ksk.keywordCount = 0;
-  ret->data.ksk.keywords = NULL;
-  GNUNET_array_grow (ret->data.ksk.keywords, ret->data.ksk.keywordCount,
-                     count);
-  for (i = 0; i < count; i++)
-    ret->data.ksk.keywords[i] = GNUNET_strdup (keyword[i]);
-  return ret;
-}
-
-
-
-/**
  * Are these two URIs equal?
  */
 int

Modified: GNUnet/src/applications/fs/ecrs/uritest.c
===================================================================
--- GNUnet/src/applications/fs/ecrs/uritest.c   2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/ecrs/uritest.c   2008-04-24 05:49:31 UTC (rev 
6745)
@@ -48,8 +48,8 @@
       ABORT ();
     }
   if ((2 != ret->data.ksk.keywordCount) ||
-      (0 != strcmp ("foo", ret->data.ksk.keywords[0])) ||
-      (0 != strcmp ("bar", ret->data.ksk.keywords[1])))
+      (0 != strcmp (" foo", ret->data.ksk.keywords[0])) ||
+      (0 != strcmp (" bar", ret->data.ksk.keywords[1])))
     {
       GNUNET_ECRS_uri_destroy (ret);
       ABORT ();

Modified: GNUnet/src/applications/fs/fsui/deserialize.c
===================================================================
--- GNUnet/src/applications/fs/fsui/deserialize.c       2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/fsui/deserialize.c       2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other 
contributing authors)
+     (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 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
@@ -31,45 +31,110 @@
 #include "gnunet_directories.h"
 #include "fsui.h"
 
+typedef struct {
+  int fd;
+  unsigned int have;
+  unsigned int size;
+  unsigned int pos;
+  char * buffer;
+} ReadBuffer;
 
 static int
-read_int (int fd, int *val)
+read_buffered(ReadBuffer * rb,
+             void * d,
+             unsigned int size) {
+  char * dst = d;
+  unsigned int min;
+  unsigned int pos;
+  int ret;
+
+  if (rb->fd == -1)
+    return -1;
+  pos = 0;
+  do 
+    {
+      /* first, use buffer */
+      min = rb->have - rb->pos;
+      if (min > 0) 
+       {
+         if (min > size)
+           min = size;
+         memcpy(&dst[pos],
+                &rb->buffer[rb->pos],
+                min);
+         rb->pos += min;
+         pos += min;
+       }
+      if (pos == size)
+       return pos; /* done! */
+      GNUNET_GE_ASSERT(NULL, rb->have == rb->pos);  
+      /* fill buffer */
+      ret = READ(rb->fd, rb->buffer, rb->size);
+      if (ret == -1)
+       {
+         CLOSE(rb->fd);
+         rb->fd = -1;
+         return -1;
+       }
+      if (ret == 0)
+       return 0;
+      rb->pos = 0;
+      rb->have = ret;
+    }
+  while (pos < size); /* should always be true */
+  return pos;
+}
+
+
+static int
+read_int (ReadBuffer * rb, int *val)
 {
   int big;
 
-  if (sizeof (int) != READ (fd, &big, sizeof (int)))
+  if (sizeof (int) != read_buffered (rb, &big, sizeof (int)))
     return GNUNET_SYSERR;
   *val = ntohl (big);
   return GNUNET_OK;
 }
 
-#define READINT(a) if (GNUNET_OK != read_int(fd, (int*) &a)) return 
GNUNET_SYSERR;
+static unsigned int
+read_uint (ReadBuffer * rb, unsigned int *val)
+{
+  unsigned int big;
 
+  if (sizeof (unsigned int) != read_buffered (rb, &big, sizeof (unsigned int)))
+    return GNUNET_SYSERR;
+  *val = ntohl (big);
+  return GNUNET_OK;
+}
+
+#define READINT(a) if (GNUNET_OK != read_int(rb, (int*) &a)) return 
GNUNET_SYSERR;
+
 static int
-read_long (int fd, long long *val)
+read_long (ReadBuffer * rb, long long *val)
 {
   long long big;
 
-  if (sizeof (long long) != READ (fd, &big, sizeof (long long)))
+  if (sizeof (long long) != read_buffered (rb, &big, sizeof (long long)))
     return GNUNET_SYSERR;
   *val = GNUNET_ntohll (big);
   return GNUNET_OK;
 }
 
-#define READLONG(a) if (GNUNET_OK != read_long(fd, (long long*) &a)) return 
GNUNET_SYSERR;
+#define READLONG(a) if (GNUNET_OK != read_long(rb, (long long*) &a)) return 
GNUNET_SYSERR;
 
 static struct GNUNET_ECRS_URI *
-read_uri (struct GNUNET_GE_Context *ectx, int fd)
+read_uri (struct GNUNET_GE_Context *ectx, ReadBuffer * rb)
 {
   char *buf;
   struct GNUNET_ECRS_URI *ret;
   unsigned int size;
 
-  if (GNUNET_OK != read_int (fd, (int *) &size))
+  if (GNUNET_OK != read_uint (rb, &size))
     return NULL;
   buf = GNUNET_malloc (size + 1);
   buf[size] = '\0';
-  if (size != READ (fd, buf, size))
+  if (size != read_buffered (rb, buf, size))
     {
       GNUNET_free (buf);
       return NULL;
@@ -80,21 +145,21 @@
   return ret;
 }
 
-#define READURI(u) if (NULL == (u = read_uri(ectx, fd))) return GNUNET_SYSERR;
+#define READURI(u) if (NULL == (u = read_uri(ectx, rb))) return GNUNET_SYSERR;
 
 static char *
-read_string (int fd, unsigned int maxLen)
+read_string (ReadBuffer * rb, unsigned int maxLen)
 {
   char *buf;
   unsigned int big;
 
-  if (GNUNET_OK != read_int (fd, (int *) &big))
+  if (GNUNET_OK != read_uint (rb, &big))
     return NULL;
   if (big > maxLen)
     return NULL;
   buf = GNUNET_malloc (big + 1);
   buf[big] = '\0';
-  if (big != READ (fd, buf, big))
+  if (big != read_buffered (rb, buf, big))
     {
       GNUNET_free (buf);
       return NULL;
@@ -102,7 +167,7 @@
   return buf;
 }
 
-#define READSTRING(c, max) if (NULL == (c = read_string(fd, max))) return 
GNUNET_SYSERR;
+#define READSTRING(c, max) if (NULL == (c = read_string(rb, max))) return 
GNUNET_SYSERR;
 
 static void
 fixState (GNUNET_FSUI_State * state)
@@ -139,13 +204,13 @@
  * @return GNUNET_OK on success, GNUNET_SYSERR on error
  */
 static struct GNUNET_ECRS_MetaData *
-read_meta (struct GNUNET_GE_Context *ectx, int fd)
+read_meta (struct GNUNET_GE_Context *ectx, ReadBuffer * rb)
 {
   unsigned int size;
   char *buf;
   struct GNUNET_ECRS_MetaData *meta;
 
-  if (read_int (fd, (int *) &size) != GNUNET_OK)
+  if (read_uint (rb, &size) != GNUNET_OK)
     {
       GNUNET_GE_BREAK (ectx, 0);
       return NULL;
@@ -156,7 +221,7 @@
       return NULL;
     }
   buf = GNUNET_malloc (size);
-  if (size != READ (fd, buf, size))
+  if (size != read_buffered (rb, buf, size))
     {
       GNUNET_free (buf);
       GNUNET_GE_BREAK (ectx, 0);
@@ -179,10 +244,10 @@
  * @return GNUNET_OK on success, GNUNET_SYSERR on error
  */
 static int
-readFileInfo (struct GNUNET_GE_Context *ectx, int fd,
+readFileInfo (struct GNUNET_GE_Context *ectx, ReadBuffer * rb,
               GNUNET_ECRS_FileInfo * fi)
 {
-  fi->meta = read_meta (ectx, fd);
+  fi->meta = read_meta (ectx, rb);
   if (fi->meta == NULL)
     {
       GNUNET_GE_BREAK (ectx, 0);
@@ -190,7 +255,7 @@
     }
   fi->uri = NULL;
 
-  fi->uri = read_uri (ectx, fd);
+  fi->uri = read_uri (ectx, rb);
   if (fi->uri == NULL)
     {
       GNUNET_ECRS_meta_data_destroy (fi->meta);
@@ -212,7 +277,7 @@
  */
 static GNUNET_FSUI_DownloadList *
 readDownloadList (struct GNUNET_GE_Context *ectx,
-                  int fd, GNUNET_FSUI_Context * ctx,
+                  ReadBuffer * rb, GNUNET_FSUI_Context * ctx,
                   GNUNET_FSUI_DownloadList * parent)
 {
   GNUNET_FSUI_DownloadList *ret;
@@ -223,21 +288,21 @@
   int soff;
 
   GNUNET_GE_ASSERT (ectx, ctx != NULL);
-  if ((GNUNET_OK != read_int (fd, (int *) &big)) || (big == 0))
+  if ((GNUNET_OK != read_uint (rb, &big)) || (big == 0))
     return NULL;
   ret = GNUNET_malloc (sizeof (GNUNET_FSUI_DownloadList));
   memset (ret, 0, sizeof (GNUNET_FSUI_DownloadList));
   ret->ctx = ctx;
-  if ((GNUNET_OK != read_int (fd, (int *) &soff)) ||
-      (GNUNET_OK != read_int (fd, (int *) &ret->state)) ||
-      (GNUNET_OK != read_int (fd, (int *) &ret->is_recursive)) ||
-      (GNUNET_OK != read_int (fd, (int *) &ret->is_directory)) ||
-      (GNUNET_OK != read_int (fd, (int *) &ret->anonymityLevel)) ||
-      (GNUNET_OK != read_int (fd, (int *) &ret->completedDownloadsCount)) ||
-      (GNUNET_OK != read_long (fd, (long long *) &ret->total)) ||
-      (GNUNET_OK != read_long (fd, (long long *) &ret->completed)) ||
-      (GNUNET_OK != read_long (fd, (long long *) &ret->runTime)) ||
-      (GNUNET_OK != read_int (fd, (int *) &big)) || (big > 1024 * 1024))
+  if ((GNUNET_OK != read_int (rb, &soff)) ||
+      (GNUNET_OK != read_int (rb, (int*) &ret->state)) ||
+      (GNUNET_OK != read_int (rb, &ret->is_recursive)) ||
+      (GNUNET_OK != read_int (rb, &ret->is_directory)) ||
+      (GNUNET_OK != read_uint (rb, &ret->anonymityLevel)) ||
+      (GNUNET_OK != read_uint (rb, &ret->completedDownloadsCount)) ||
+      (GNUNET_OK != read_long (rb, (long long *) &ret->total)) ||
+      (GNUNET_OK != read_long (rb, (long long *) &ret->completed)) ||
+      (GNUNET_OK != read_long (rb, (long long *) &ret->runTime)) ||
+      (GNUNET_OK != read_uint (rb, &big)) || (big > 1024 * 1024))
     {
       GNUNET_GE_BREAK (NULL, 0);
       GNUNET_free (ret);
@@ -246,14 +311,14 @@
   fixState (&ret->state);
   ret->filename = GNUNET_malloc (big + 1);
   ret->filename[big] = '\0';
-  if (big != READ (fd, ret->filename, big))
+  if (big != read_buffered (rb, ret->filename, big))
     {
       GNUNET_GE_BREAK (ectx, 0);
       GNUNET_free (ret->filename);
       GNUNET_free (ret);
       return NULL;
     }
-  if (GNUNET_OK != readFileInfo (ectx, fd, &ret->fi))
+  if (GNUNET_OK != readFileInfo (ectx, rb, &ret->fi))
     {
       GNUNET_GE_BREAK (NULL, 0);
       GNUNET_free (ret->filename);
@@ -268,7 +333,7 @@
   ok = GNUNET_YES;
   for (i = 0; i < ret->completedDownloadsCount; i++)
     {
-      ret->completedDownloads[i] = read_uri (ectx, fd);
+      ret->completedDownloads[i] = read_uri (ectx, rb);
       if (ret->completedDownloads[i] == NULL)
         {
           GNUNET_GE_BREAK (NULL, 0);
@@ -316,8 +381,8 @@
           pos->my_downloads[pos->my_downloads_size - 1] = ret;
         }
     }
-  ret->next = readDownloadList (ectx, fd, ctx, parent);
-  ret->child = readDownloadList (ectx, fd, ctx, ret);
+  ret->next = readDownloadList (ectx, rb, ctx, parent);
+  ret->child = readDownloadList (ectx, rb, ctx, ret);
 #if DEBUG_PERSISTENCE
   GNUNET_GE_LOG (ectx,
                  GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
@@ -328,16 +393,16 @@
 }
 
 static int
-checkMagic (int fd)
+checkMagic (ReadBuffer * rb)
 {
   char magic[8];
 
-  if (8 != READ (fd, magic, 8))
+  if (8 != read_buffered (rb, magic, 8))
     {
       GNUNET_GE_BREAK (NULL, 0);
       return GNUNET_SYSERR;
     }
-  if (0 != memcmp (magic, "FSUI02\n\0", 8))
+  if (0 != memcmp (magic, "FSUI03\n\0", 8))
     {
       GNUNET_GE_BREAK (NULL, 0);
       return GNUNET_SYSERR;
@@ -346,7 +411,7 @@
 }
 
 static int
-readCollection (int fd, struct GNUNET_FSUI_Context *ctx)
+readCollection (ReadBuffer * rb, struct GNUNET_FSUI_Context *ctx)
 {
   int big;
 
@@ -364,7 +429,7 @@
     }
   ctx->collectionDataSize = big;
   ctx->collectionData = GNUNET_malloc (big);
-  if (big != READ (fd, ctx->collectionData, big))
+  if (big != read_buffered (rb, ctx->collectionData, big))
     {
       GNUNET_free (ctx->collectionData);
       ctx->collectionData = NULL;
@@ -375,16 +440,153 @@
   return GNUNET_OK;
 }
 
+/**
+ * Read in information about the individual ECRS searches
+ * that we are performing.
+ */
+struct SearchRecordList *
+read_search_record_list(struct GNUNET_GE_Context * ectx,
+                       ReadBuffer *rb) 
+{
+  unsigned int is_required;
+  GNUNET_HashCode key;
+  struct GNUNET_ECRS_URI * uri;
+  struct SearchRecordList * ret;
+  struct SearchRecordList * head;
+  struct SearchRecordList * tail;
+
+  ret = NULL;
+  head = NULL;
+  tail = NULL;
+  while (1) 
+    {
+      if (GNUNET_OK != read_uint(rb, &is_required))
+       break;
+      if (is_required == -1)
+       break; /* end of list marker */
+      if (sizeof(GNUNET_HashCode) 
+         != read_buffered(rb, &key, sizeof(GNUNET_HashCode)))
+       break;
+      uri = read_uri(ectx, rb);
+      if (uri == NULL)
+       break; /* error */      
+      ret = GNUNET_malloc(sizeof(struct SearchRecordList));
+      ret->key = key;
+      ret->uri = uri;
+      ret->search = NULL;
+      ret->is_required = is_required;
+      ret->next = NULL;
+      if (head == NULL)
+       head = ret;
+      if (tail != NULL)
+       tail->next = ret;
+      tail = ret;
+    }     
+  return head;
+}
+
+/**
+ * Read all of the results received so far
+ * for this search.
+ *
+ * @param search_count length of search_list
+ * @param search_list list of ECRS search requests 
+ */
+struct SearchResultList *
+read_result_list(struct GNUNET_GE_Context * ectx,
+                ReadBuffer *rb,
+                unsigned int search_count,
+                struct SearchRecordList ** search_list) 
+{
+  unsigned int matching;
+  unsigned int remaining;
+  unsigned int probeSucc;
+  unsigned int probeFail;
+  struct SearchResultList * ret;
+  struct SearchResultList * head;
+  struct SearchResultList * tail;
+  unsigned int i;
+  unsigned int idx;
+
+  ret = NULL;
+  head = NULL;
+  tail = NULL;
+  while (1) 
+    { 
+      if (GNUNET_OK != read_uint(rb, &matching)) 
+       break;
+      if (matching == -1)
+       break; /* end of list marker */
+      if ( (GNUNET_OK != read_uint(rb, &remaining)) ||
+          (GNUNET_OK != read_uint(rb, &probeSucc)) ||
+          (GNUNET_OK != read_uint(rb, &probeFail)) )      
+       break;
+      ret = GNUNET_malloc(sizeof(struct SearchResultList));
+      if (GNUNET_OK != readFileInfo(ectx, rb, &ret->fi))
+       {
+         GNUNET_free(ret);
+         break;
+       }
+      ret->matchingSearchCount = matching;
+      ret->mandatoryMatchesRemaining = remaining;
+      ret->probeSuccess = probeSucc;
+      ret->probeFailure = probeFail;
+      ret->test_download = NULL;
+      ret->next = NULL;
+      ret->matchingSearches = NULL;
+      i = 0;
+      GNUNET_array_grow(ret->matchingSearches,
+                       i,
+                       ret->matchingSearchCount);
+      while (i-- > 0)
+       {
+         if ( (GNUNET_OK != read_uint(rb, &idx)) ||
+              (idx > search_count) )
+           {
+             GNUNET_GE_BREAK(NULL, 0);
+             GNUNET_array_grow(ret->matchingSearches,
+                               ret->matchingSearchCount,
+                               0);
+             GNUNET_free(ret);
+             return head;      
+           }
+         if (idx == 0)
+           {
+             GNUNET_GE_BREAK(NULL, 0);
+             ret->matchingSearches[i] = NULL;
+           }
+         else      
+           {
+             GNUNET_GE_BREAK(NULL, search_list[idx - 1] != NULL);
+             ret->matchingSearches[i] = search_list[idx - 1];
+           }
+       }
+      if (head == NULL)
+       head = ret;
+      if (tail != NULL)
+       tail->next = ret;
+      tail = ret;
+    }     
+  return head;
+}
+
+/**
+ * Read in all of the FSUI-searches that we are
+ * performing.
+ */
 static int
-readSearches (int fd, struct GNUNET_FSUI_Context *ctx)
+readSearches (ReadBuffer * rb, struct GNUNET_FSUI_Context *ctx)
 {
   int big;
   GNUNET_FSUI_SearchList *list;
   GNUNET_FSUI_SearchList *last;
-  int i;
-  ResultPending *rp;
+  struct SearchResultList *srp;
+  struct SearchRecordList *srl;
+  struct SearchRecordList **srla;
   char *buf;
   GNUNET_CronTime stime;
+  unsigned int total_searches;
+  unsigned int i;
 
   while (1)
     {
@@ -393,15 +595,13 @@
         return GNUNET_OK;
       list = GNUNET_malloc (sizeof (GNUNET_FSUI_SearchList));
       memset (list, 0, sizeof (GNUNET_FSUI_SearchList));
-      if ((GNUNET_OK != read_int (fd, (int *) &list->state)) ||
-          (GNUNET_OK != read_long (fd, (long long *) &list->start_time)) ||
-          (GNUNET_OK != read_long (fd, (long long *) &stime)) ||
-          (GNUNET_OK != read_int (fd, (int *) &list->anonymityLevel)) ||
-          (GNUNET_OK != read_int (fd, (int *) &list->sizeResultsReceived)) ||
-          (GNUNET_OK !=
-           read_int (fd, (int *) &list->sizeUnmatchedResultsReceived))
-          || (list->sizeResultsReceived > 1024 * 1024)
-          || (list->sizeUnmatchedResultsReceived > 1024 * 1024))
+      list->lock = GNUNET_mutex_create(GNUNET_NO);
+      list->ctx = ctx;
+      if ((GNUNET_OK != read_int (rb, (int *) &list->state)) ||
+          (GNUNET_OK != read_long (rb, (long long *) &list->start_time)) ||
+          (GNUNET_OK != read_long (rb, (long long *) &stime)) ||
+          (GNUNET_OK != read_uint (rb, &list->anonymityLevel)) ||
+          (GNUNET_OK != read_uint (rb, &list->mandatory_keyword_count)) )
         {
           GNUNET_GE_BREAK (NULL, 0);
           break;
@@ -410,7 +610,7 @@
       if (stime > GNUNET_get_time ())
         stime = GNUNET_get_time ();
       list->start_time += GNUNET_get_time () - stime;
-      buf = read_string (fd, 1024 * 1024);
+      buf = read_string (rb, 1024 * 1024);
       if (buf == NULL)
         {
           GNUNET_GE_BREAK (NULL, 0);
@@ -430,72 +630,32 @@
           GNUNET_GE_BREAK (NULL, 0);
           break;
         }
-      list->numberOfURIKeys =
-        GNUNET_ECRS_uri_get_keyword_count_from_ksk (list->uri);
-      if (list->sizeResultsReceived > 0)
-        {
-          list->resultsReceived
-            =
-            GNUNET_malloc (list->sizeResultsReceived *
-                           sizeof (GNUNET_ECRS_FileInfo));
-          memset (list->resultsReceived, 0,
-                  list->sizeResultsReceived * sizeof (GNUNET_ECRS_FileInfo));
-        }
-      if (list->sizeUnmatchedResultsReceived > 0)
-        {
-          list->unmatchedResultsReceived
-            = GNUNET_malloc (list->sizeUnmatchedResultsReceived *
-                             sizeof (ResultPending));
-          memset (list->unmatchedResultsReceived,
-                  0,
-                  list->sizeUnmatchedResultsReceived *
-                  sizeof (ResultPending));
-        }
-      for (i = 0; i < list->sizeResultsReceived; i++)
-        if (GNUNET_OK !=
-            readFileInfo (ctx->ectx, fd, &list->resultsReceived[i]))
-          {
-            GNUNET_GE_BREAK (NULL, 0);
-            goto ERR;
-          }
-      for (i = 0; i < list->sizeUnmatchedResultsReceived; i++)
-        {
-          rp = &list->unmatchedResultsReceived[i];
-          if (GNUNET_OK != readFileInfo (ctx->ectx, fd, &rp->fi))
-            {
-              GNUNET_GE_BREAK (NULL, 0);
-              goto ERR;
-            }
-          if (GNUNET_OK != read_int (fd, (int *) &rp->matchingKeyCount))
-            {
-              GNUNET_GE_BREAK (NULL, 0);
-              goto ERR;
-            }
-          if ((rp->matchingKeyCount > 1024) ||
-              (rp->matchingKeyCount >= list->numberOfURIKeys))
-            {
-              GNUNET_GE_BREAK (NULL, 0);
-              goto ERR;
-            }
-          if (rp->matchingKeyCount > 0)
-            {
-              rp->matchingKeys
-                =
-                GNUNET_malloc (sizeof (GNUNET_HashCode) *
-                               rp->matchingKeyCount);
-              if (sizeof (GNUNET_HashCode) * rp->matchingKeyCount !=
-                  READ (fd, rp->matchingKeys,
-                        sizeof (GNUNET_HashCode) * rp->matchingKeyCount))
-                {
-                  GNUNET_GE_BREAK (NULL, 0);
-                  goto ERR;
-                }
-            }
-        }
+      list->searches = read_search_record_list(ctx->ectx, rb);
+      if (list->searches == NULL)
+       goto ERR; /* can never be empty in practice */
+      srl = list->searches;
+      total_searches = 0;
+      while (srl != NULL)
+       {
+         total_searches++;
+         srl = srl->next;
+       }
+      srla = GNUNET_malloc(total_searches * sizeof(struct SearchRecordList*));
+      srl = list->searches;
+      i = total_searches;
+      while (srl != NULL)
+       {
+         srla[--i] = srl;
+         srl = srl->next;
+       }
+      list->resultsReceived = read_result_list(ctx->ectx, rb,
+                                              total_searches,
+                                              srla);
+      GNUNET_free(srla);
       list->ctx = ctx;
       list->next = NULL;
+
       /* finally: append (!) to list */
-
       if (ctx->activeSearches == NULL)
         {
           ctx->activeSearches = list;
@@ -510,50 +670,40 @@
     }                           /* end OUTER: 'while(1)' */
 ERR:
   /* error - deallocate 'list' */
-  if (list->resultsReceived != NULL)
+  while (list->resultsReceived != NULL)
     {
-      for (i = 0; i < list->sizeResultsReceived; i++)
-        {
-          if (list->resultsReceived[i].uri != NULL)
-            GNUNET_ECRS_uri_destroy (list->resultsReceived[i].uri);
-          if (list->resultsReceived[i].meta != NULL)
-            GNUNET_ECRS_meta_data_destroy (list->resultsReceived[i].meta);
-        }
-      GNUNET_array_grow (list->resultsReceived, list->sizeResultsReceived, 0);
+      srp = list->resultsReceived;
+      list->resultsReceived = srp->next;
+      GNUNET_free(srp);
     }
-  if (list->unmatchedResultsReceived != NULL)
+  while (list->searches != NULL)
     {
-      for (i = 0; i < list->sizeUnmatchedResultsReceived; i++)
-        {
-          rp = &list->unmatchedResultsReceived[i];
-
-          if (rp->fi.uri != NULL)
-            GNUNET_ECRS_uri_destroy (rp->fi.uri);
-          if (rp->fi.meta != NULL)
-            GNUNET_ECRS_meta_data_destroy (rp->fi.meta);
-          GNUNET_free_non_null (rp->matchingKeys);
-        }
-      GNUNET_array_grow (list->resultsReceived, list->sizeResultsReceived, 0);
+      srl = list->searches;
+      list->searches = srl->next;      
+      if (srl->uri != NULL)
+       GNUNET_ECRS_uri_destroy(srl->uri);
+      GNUNET_free(srl);
     }
   if (list->uri != NULL)
     GNUNET_ECRS_uri_destroy (list->uri);
+  GNUNET_mutex_destroy(list->lock);
   GNUNET_free (list);
   return GNUNET_SYSERR;
 }
 
 static int
-readDownloads (int fd, struct GNUNET_FSUI_Context *ctx)
+readDownloads (ReadBuffer * rb, struct GNUNET_FSUI_Context *ctx)
 {
   memset (&ctx->activeDownloads, 0, sizeof (GNUNET_FSUI_DownloadList));
   ctx->activeDownloads.child
-    = readDownloadList (ctx->ectx, fd, ctx, &ctx->activeDownloads);
+    = readDownloadList (ctx->ectx, rb, ctx, &ctx->activeDownloads);
   return GNUNET_OK;
 }
 
 static int
 readUploadList (struct GNUNET_FSUI_Context *ctx,
                 struct GNUNET_FSUI_UploadList *parent,
-                int fd, struct GNUNET_FSUI_UploadShared *shared, int top)
+                ReadBuffer * rb, struct GNUNET_FSUI_UploadShared *shared, int 
top)
 {
   struct GNUNET_FSUI_UploadList *list;
   struct GNUNET_FSUI_UploadList l;
@@ -598,7 +748,7 @@
         READURI (l.uri);
       if ((big & 4) == 4)
         {
-          l.keywords = read_uri (ctx->ectx, fd);
+          l.keywords = read_uri (ctx->ectx, rb);
           if (l.keywords == NULL)
             {
               if (l.uri != NULL)
@@ -609,7 +759,7 @@
         }
       if ((big & 8) == 8)
         {
-          l.meta = read_meta (ctx->ectx, fd);
+          l.meta = read_meta (ctx->ectx, rb);
           if (l.meta == NULL)
             {
               if (l.uri != NULL)
@@ -620,7 +770,7 @@
               break;
             }
         }
-      l.filename = read_string (fd, 1024 * 1024);
+      l.filename = read_string (rb, 1024 * 1024);
       if (l.filename == NULL)
         {
           if (l.uri != NULL)
@@ -636,7 +786,7 @@
       memcpy (list, &l, sizeof (struct GNUNET_FSUI_UploadList));
       list->shared = shared;
       list->parent = parent;
-      if (GNUNET_OK != readUploadList (ctx, list, fd, shared, GNUNET_NO))
+      if (GNUNET_OK != readUploadList (ctx, list, rb, shared, GNUNET_NO))
         {
           if (l.uri != NULL)
             GNUNET_ECRS_uri_destroy (l.uri);
@@ -655,7 +805,7 @@
 
 
 static int
-readUploads (int fd, struct GNUNET_FSUI_Context *ctx)
+readUploads (ReadBuffer * rb, struct GNUNET_FSUI_Context *ctx)
 {
   int big;
   int bag;
@@ -690,7 +840,7 @@
       READSTRING (sshared.top_filename, 1024 * 1024);
       if ((big & 4) == 4)
         {
-          sshared.global_keywords = read_uri (ctx->ectx, fd);
+          sshared.global_keywords = read_uri (ctx->ectx, rb);
           if (sshared.global_keywords == NULL)
             {
               GNUNET_free_non_null (sshared.extractor_config);
@@ -702,7 +852,7 @@
       memcpy (shared, &sshared, sizeof (GNUNET_FSUI_UploadShared));
       shared->ctx = ctx;
       if (GNUNET_OK !=
-          readUploadList (ctx, &ctx->activeUploads, fd, shared, GNUNET_YES))
+          readUploadList (ctx, &ctx->activeUploads, rb, shared, GNUNET_YES))
         {
           GNUNET_GE_BREAK (NULL, 0);
 #if 0
@@ -723,7 +873,7 @@
 }
 
 static int
-readUnindex (int fd, struct GNUNET_FSUI_Context *ctx)
+readUnindex (ReadBuffer * rb, struct GNUNET_FSUI_Context *ctx)
 {
   int big;
   char *name;
@@ -750,29 +900,35 @@
 void
 GNUNET_FSUI_deserialize (struct GNUNET_FSUI_Context *ctx)
 {
-  int fd;
+  ReadBuffer rb;
 
-  fd = -1;
+  rb.fd = -1;
   if (0 != ACCESS (ctx->name, R_OK))
     return;
-  fd = GNUNET_disk_file_open (ctx->ectx, ctx->name, O_RDONLY);
-  if (fd == -1)
+  rb.fd = GNUNET_disk_file_open (ctx->ectx, ctx->name, O_RDONLY);
+  if (rb.fd == -1)
     return;
-
-  if ((GNUNET_OK != checkMagic (fd)) ||
-      (GNUNET_OK != readCollection (fd, ctx)) ||
-      (GNUNET_OK != readSearches (fd, ctx)) ||
-      (GNUNET_OK != readDownloads (fd, ctx)) ||
-      (GNUNET_OK != readUnindex (fd, ctx))
-      || (GNUNET_OK != readUploads (fd, ctx)))
+  rb.pos = 0;
+  rb.size = 64 * 1024;
+  rb.have = 0;
+  rb.buffer = GNUNET_malloc(rb.size);
+  if ((GNUNET_OK != checkMagic (&rb)) ||
+      (GNUNET_OK != readCollection (&rb, ctx)) ||
+      (GNUNET_OK != readSearches (&rb, ctx)) ||
+      (GNUNET_OK != readDownloads (&rb, ctx)) ||
+      (GNUNET_OK != readUnindex (&rb, ctx))
+      || (GNUNET_OK != readUploads (&rb, ctx)))
     {
       GNUNET_GE_BREAK (ctx->ectx, 0);
       GNUNET_GE_LOG (ctx->ectx,
                      GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
                      _
                      ("FSUI state file `%s' had syntax error at offset %u.\n"),
-                     ctx->name, LSEEK (fd, 0, SEEK_CUR));
+                     ctx->name, LSEEK (rb.fd, 0, SEEK_CUR));
     }
-  CLOSE (fd);
+  CLOSE (rb.fd);
   UNLINK (ctx->name);
+  GNUNET_free(rb.buffer);
 }
+
+/* end of deserialize.c */

Modified: GNUnet/src/applications/fs/fsui/downloadtest.c
===================================================================
--- GNUnet/src/applications/fs/fsui/downloadtest.c      2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/fsui/downloadtest.c      2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -211,7 +211,6 @@
   char *keywords[] = {
     "down_foo",
     "down_bar",
-    NULL,
   };
   char keyword[40];
   int prog;
@@ -250,7 +249,7 @@
   GNUNET_disk_file_write (ectx, fn, buf, FILESIZE, "600");
   GNUNET_free (buf);
   meta = GNUNET_ECRS_meta_data_create ();
-  kuri = GNUNET_ECRS_keyword_list_to_uri (ectx, 2, (const char **) keywords);
+  kuri = GNUNET_ECRS_keyword_command_line_to_uri (ectx, 2, (const char **) 
keywords);
   waitForEvent = GNUNET_FSUI_upload_completed;
   upload = GNUNET_FSUI_upload_start (ctx,
                                      fn,
@@ -273,7 +272,7 @@
         break;
     }
   GNUNET_FSUI_upload_stop (ctx, upload);
-  GNUNET_snprintf (keyword, 40, "%s %s %s", keywords[0], _("AND"),
+  GNUNET_snprintf (keyword, 40, "+%s +%s", keywords[0],
                    keywords[1]);
   uri = GNUNET_ECRS_keyword_string_to_uri (ectx, keyword);
   waitForEvent = GNUNET_FSUI_download_completed;

Modified: GNUnet/src/applications/fs/fsui/fsui.c
===================================================================
--- GNUnet/src/applications/fs/fsui/fsui.c      2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/fsui/fsui.c      2008-04-24 05:49:31 UTC (rev 
6745)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other 
contributing authors)
+     (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 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
@@ -196,6 +196,11 @@
   GNUNET_FSUI_Context *ret;
   GNUNET_FSUI_SearchList *list;
   GNUNET_FSUI_UnindexList *xlist;
+  struct SearchResultList * pos;
+  struct SearchRecordList * rec;
+  unsigned int valid;
+  unsigned int i;
+  GNUNET_ECRS_FileInfo * fis;
   char *fn;
   char *gh;
   unsigned long long size;
@@ -257,15 +262,37 @@
   list = ret->activeSearches;
   while (list != NULL)
     {
+      valid = 0;
+      pos = list->resultsReceived;
+      while (pos != NULL)
+       {
+         if (pos->mandatoryMatchesRemaining == 0)
+           valid++;
+         pos = pos->next;
+       }
+      fis = NULL;
+      if (valid > 0)
+       {
+         fis = GNUNET_malloc(sizeof(GNUNET_ECRS_FileInfo) * valid);
+         pos = list->resultsReceived;
+         i = 0;
+         while (pos != NULL)
+           {
+             if (pos->mandatoryMatchesRemaining == 0)
+               fis[i++] = pos->fi;
+             pos = pos->next;
+           } 
+       }
       event.type = GNUNET_FSUI_search_resumed;
       event.data.SearchResumed.sc.pos = list;
       event.data.SearchResumed.sc.cctx = NULL;
-      event.data.SearchResumed.fis = list->resultsReceived;
-      event.data.SearchResumed.fisSize = list->sizeResultsReceived;
+      event.data.SearchResumed.fis = fis;
+      event.data.SearchResumed.fisSize = valid;
       event.data.SearchResumed.anonymityLevel = list->anonymityLevel;
       event.data.SearchResumed.searchURI = list->uri;
       event.data.SearchResumed.state = list->state;
       list->cctx = cb (closure, &event);
+      GNUNET_free_non_null(fis);
       list = list->next;
     }
   /* 2c) signal upload restarts */
@@ -322,20 +349,39 @@
       if (list->state == GNUNET_FSUI_PENDING)
         {
           list->state = GNUNET_FSUI_ACTIVE;
-          list->handle = GNUNET_ECRS_search_start (list->ctx->ectx,
-                                                   list->ctx->cfg,
-                                                   list->uri,
-                                                   list->anonymityLevel,
-                                                   
&GNUNET_FSUI_search_progress_callback,
-                                                   list);
-          if (list->handle == NULL)
-            {
-              GNUNET_GE_LOG (ectx,
-                             GNUNET_GE_FATAL | GNUNET_GE_ADMIN |
-                             GNUNET_GE_IMMEDIATE,
-                             "Failed to resume search\n");
-              list->state = GNUNET_FSUI_PENDING;
-            }
+         rec = list->searches;
+         while (rec != NULL)
+           {
+             rec->search = GNUNET_ECRS_search_start (list->ctx->ectx,
+                                                     list->ctx->cfg,
+                                                     rec->uri,
+                                                     list->anonymityLevel,
+                                                     
&GNUNET_FSUI_search_progress_callback,
+                                                     list);
+             if (rec->search == NULL)
+               {
+                 GNUNET_GE_LOG (ectx,
+                                GNUNET_GE_FATAL | GNUNET_GE_ADMIN |
+                                GNUNET_GE_IMMEDIATE,
+                                "Failed to resume search\n");
+                 list->state = GNUNET_FSUI_PENDING;
+               }
+             rec = rec->next;
+           }
+         if (list->state != GNUNET_FSUI_ACTIVE)
+           {
+             /* stop searches, we failed... */
+             rec = list->searches;
+             while (rec != NULL)
+               {
+                 if (rec->search != NULL)
+                   {
+                     GNUNET_ECRS_search_stop(rec->search);
+                     rec->search = NULL;
+                   }
+                 rec = rec->next;
+               }
+           }
         }
       list = list->next;
     }
@@ -464,9 +510,10 @@
   GNUNET_FSUI_DownloadList *dpos;
   GNUNET_FSUI_UnindexList *xpos;
   GNUNET_FSUI_UploadList *upos;
+  struct SearchRecordList * rec;
+  struct SearchResultList * res;
   GNUNET_FSUI_Event event;
   void *unused;
-  int i;
 
   ectx = ctx->ectx;
   if (ctx->ipc != NULL)
@@ -499,8 +546,23 @@
         {
           if (spos->state == GNUNET_FSUI_ACTIVE)
             spos->state = GNUNET_FSUI_PENDING;
-          GNUNET_ECRS_search_stop (spos->handle);
-          spos->handle = NULL;
+         rec = spos->searches;
+         while (rec != NULL)
+           {
+             GNUNET_ECRS_search_stop (rec->search);
+             rec->search = NULL;
+             rec = rec->next;
+           }
+         res = spos->resultsReceived;
+         while (res != NULL)
+           {
+             if (res->test_download != NULL)
+               {
+                 GNUNET_ECRS_file_download_partial_stop(res->test_download);
+                 res->test_download = NULL;
+               }
+             res = res->next;
+           }
           if (spos->state != GNUNET_FSUI_PENDING)
             spos->state++;      /* _JOINED */
         }
@@ -582,25 +644,22 @@
       spos = ctx->activeSearches;
       ctx->activeSearches = spos->next;
       GNUNET_ECRS_uri_destroy (spos->uri);
-      for (i = spos->sizeResultsReceived - 1; i >= 0; i--)
-        {
-          GNUNET_ECRS_FileInfo *fi;
-          fi = &spos->resultsReceived[i];
-          GNUNET_ECRS_meta_data_destroy (fi->meta);
-          GNUNET_ECRS_uri_destroy (fi->uri);
-        }
-      GNUNET_array_grow (spos->resultsReceived, spos->sizeResultsReceived, 0);
-      for (i = spos->sizeUnmatchedResultsReceived - 1; i >= 0; i--)
-        {
-          ResultPending *rp;
-
-          rp = &spos->unmatchedResultsReceived[i];
-          GNUNET_array_grow (rp->matchingKeys, rp->matchingKeyCount, 0);
-          GNUNET_ECRS_meta_data_destroy (rp->fi.meta);
-          GNUNET_ECRS_uri_destroy (rp->fi.uri);
-        }
-      GNUNET_array_grow (spos->unmatchedResultsReceived,
-                         spos->sizeUnmatchedResultsReceived, 0);
+      while (spos->searches != NULL)
+       {
+         rec = spos->searches;
+         spos->searches = rec->next;
+         GNUNET_ECRS_uri_destroy(rec->uri);
+         GNUNET_free(rec);
+       }
+      while (spos->resultsReceived != NULL)
+       {
+         res = spos->resultsReceived;
+         spos->resultsReceived = res->next;      
+          GNUNET_ECRS_meta_data_destroy (res->fi.meta);
+          GNUNET_ECRS_uri_destroy (res->fi.uri);
+         GNUNET_free(res->matchingSearches);     
+         GNUNET_free(res);
+       }
       GNUNET_free (spos);
     }
   /* 4b) free unindex memory */

Modified: GNUnet/src/applications/fs/fsui/fsui.h
===================================================================
--- GNUnet/src/applications/fs/fsui/fsui.h      2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/fsui/fsui.h      2008-04-24 05:49:31 UTC (rev 
6745)
@@ -33,28 +33,89 @@
 /**
  * Track record for a given result.
  */
-typedef struct
+struct SearchResultList
 {
 
+  struct SearchResultList * next;
+
   /**
-   * What are these keys?
+   * Test download (if any).
    */
-  GNUNET_HashCode *matchingKeys;
+  struct GNUNET_ECRS_DownloadContext *test_download;
 
   /**
+   * Which individual searches does this result match?
+   * (do NOT free the search records that this array
+   * points to when freeing this result!).
+   */
+  struct SearchRecordList ** matchingSearches;
+
+  /**
    * What info do we have about this result?
    */
   GNUNET_ECRS_FileInfo fi;
 
   /**
-   * For how many keys (GNUNET_hash of keyword) did we
-   * get this result?
+   * For how many searches did we get this result?
+   * (size of the matchingSearches array).
    */
-  unsigned int matchingKeyCount;
+  unsigned int matchingSearchCount;
 
-} ResultPending;
+  /**
+   * How many more searches that are mandatory do
+   * we need to match against before displaying?
+   * (once this value reaches zero, we can display
+   * the result).
+   */
+  unsigned int mandatoryMatchesRemaining;
 
+  /**
+   * How often did a test download succeed?
+   */
+  unsigned int probeSuccess;
+
+  /**
+   * How often did a test download fail?
+   */
+  unsigned int probeFailure;
+
+};
+
 /**
+ * Track record for the ECRS search requests.
+ */
+struct SearchRecordList
+{
+  
+  struct SearchRecordList * next;
+
+  /**
+   * Handles to the ECRS SearchContexts.
+   */
+  struct GNUNET_ECRS_SearchContext * search;
+
+  /**
+   * Which keyword are we searching? (this is
+   * the exact URI given to ECRS which should
+   * contain only a single keyword).
+   */
+  struct GNUNET_ECRS_URI *uri;
+
+  /**
+   * Key for the search.
+   */
+  GNUNET_HashCode key;
+
+  /**
+   * Do we have to have a match in this search
+   * for displaying the result (did the keyword
+   * that was specified start with a "+"?).
+   */
+  unsigned int is_required;
+
+};
+
+/**
  * @brief list of active searches
  */
 typedef struct GNUNET_FSUI_SearchList
@@ -66,6 +127,11 @@
   GNUNET_CronTime start_time;
 
   /**
+   * Lock for the search.
+   */ 
+  struct GNUNET_Mutex * lock;
+
+  /**
    * Searches are kept in a simple linked list.
    */
   struct GNUNET_FSUI_SearchList *next;
@@ -76,9 +142,9 @@
   struct GNUNET_FSUI_Context *ctx;
 
   /**
-   * Handle to the thread which performs the search.
+   * Handles to the ECRS SearchContexts.
    */
-  struct GNUNET_ECRS_SearchContext *handle;
+  struct SearchRecordList * searches;
 
   /**
    * Which URI are we searching?
@@ -86,17 +152,18 @@
   struct GNUNET_ECRS_URI *uri;
 
   /**
-   * What downloads belong to this search?
+   * What downloads belong to this search (full downloads).
    */
   struct GNUNET_FSUI_DownloadList **my_downloads;
 
   /**
    * List of all results found so far.
    */
-  GNUNET_ECRS_FileInfo *resultsReceived;
+  struct SearchResultList *resultsReceived;
 
-  ResultPending *unmatchedResultsReceived;
-
+  /**
+   * Client context for the search.
+   */
   void *cctx;
 
   /**
@@ -105,28 +172,18 @@
   unsigned int anonymityLevel;
 
   /**
-   * Of how many individual queries does the
-   * boolean query consist (1 for non-boolean queries).
+   * Number of mandatory keywords in our URI.
    */
-  unsigned int numberOfURIKeys;
+  unsigned int mandatory_keyword_count;
 
   /**
-   * Size of the resultsReceived array
-   */
-  unsigned int sizeResultsReceived;
-
-  /**
    * Number of downloads associated with this search.
    */
   unsigned int my_downloads_size;
 
   /**
-   * Size of the queue of results that matched at least
-   * one of the queries in the boolean query, but not
-   * yet all of them.
+   * FSUI state of this search.
    */
-  unsigned int sizeUnmatchedResultsReceived;
-
   GNUNET_FSUI_State state;
 
 } GNUNET_FSUI_SearchList;

Modified: GNUnet/src/applications/fs/fsui/fsuitest.c
===================================================================
--- GNUnet/src/applications/fs/fsui/fsuitest.c  2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/fsui/fsuitest.c  2008-04-24 05:49:31 UTC (rev 
6745)
@@ -113,7 +113,6 @@
   char *keywords[] = {
     "fsui_foo",
     "fsui_bar",
-    NULL,
   };
   char keyword[40];
   int prog;
@@ -150,7 +149,7 @@
                           filename,
                           "foo bar test!", strlen ("foo bar test!"), "600");
   meta = GNUNET_ECRS_meta_data_create ();
-  kuri = GNUNET_ECRS_keyword_list_to_uri (NULL, 2, (const char **) keywords);
+  kuri = GNUNET_ECRS_keyword_command_line_to_uri (NULL, 2, (const char **) 
keywords);
   upload = GNUNET_FSUI_upload_start (ctx, filename, 
(GNUNET_FSUI_DirectoryScanCallback) & GNUNET_disk_directory_scan, NULL, 0,  /* 
anonymity */
                                      0, /* priority */
                                      GNUNET_YES,

Modified: GNUnet/src/applications/fs/fsui/recursivetest.c
===================================================================
--- GNUnet/src/applications/fs/fsui/recursivetest.c     2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/fsui/recursivetest.c     2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -29,7 +29,7 @@
 #include "gnunet_util.h"
 #include "gnunet_fsui_lib.h"
 
-#define DEBUG_VERBOSE GNUNET_YES
+#define DEBUG_VERBOSE GNUNET_NO
 
 #define CHECK(a) if (!(a)) { ok = GNUNET_NO; GNUNET_GE_BREAK(ectx, 0); goto 
FAILURE; }
 
@@ -292,7 +292,6 @@
   char *keywords[] = {
     "down_foo",
     "down_bar",
-    NULL,
   };
   char keyword[40];
   int prog;
@@ -325,7 +324,7 @@
   CHECK (ctx != NULL);
   fn = makeHierarchy(42, DIRECTORY_TREE_SPEC);
   meta = GNUNET_ECRS_meta_data_create ();
-  kuri = GNUNET_ECRS_keyword_list_to_uri (ectx, 2, (const char **) keywords);
+  kuri = GNUNET_ECRS_keyword_command_line_to_uri (ectx, 2, (const char **) 
keywords);
   waitForEvent = GNUNET_FSUI_upload_completed;
   upload = GNUNET_FSUI_upload_start (ctx,
                                      fn,
@@ -348,7 +347,7 @@
         break;
     }
   GNUNET_FSUI_upload_stop (ctx, upload);
-  GNUNET_snprintf (keyword, 40, "%s %s %s", keywords[0], _("AND"),
+  GNUNET_snprintf (keyword, 40, "+%s +%s", keywords[0],
                    keywords[1]);
   uri = GNUNET_ECRS_keyword_string_to_uri (ectx, keyword);
   waitForEvent = GNUNET_FSUI_download_completed;

Modified: GNUnet/src/applications/fs/fsui/search.c
===================================================================
--- GNUnet/src/applications/fs/fsui/search.c    2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/fsui/search.c    2008-04-24 05:49:31 UTC (rev 
6745)
@@ -22,7 +22,8 @@
  * @file applications/fs/fsui/search.c
  * @brief Helper functions for searching.  FSUI search performs the
  *   filtering of duplicate results as well as adding boolean search
- *   (ANDing).
+ *   (ANDing and ORing) and confirming if files are present in the
+ *   network.
  * @author Christian Grothoff
  */
 
@@ -37,29 +38,25 @@
 
 #define DEBUG_SEARCH GNUNET_NO
 
+void bug() {}
+
 /**
  * Pass the result to the client and note it as shown.
  */
 static void
-processResult (const GNUNET_ECRS_FileInfo * fi, GNUNET_FSUI_SearchList * pos)
+processResult (struct GNUNET_FSUI_SearchList * ctx,
+              struct SearchResultList * pos)
 {
   GNUNET_FSUI_Event event;
 
-  GNUNET_array_grow (pos->resultsReceived,
-                     pos->sizeResultsReceived, pos->sizeResultsReceived + 1);
-  pos->resultsReceived[pos->sizeResultsReceived - 1].uri
-    = GNUNET_ECRS_uri_duplicate (fi->uri);
-  pos->resultsReceived[pos->sizeResultsReceived - 1].meta
-    = GNUNET_ECRS_meta_data_duplicate (fi->meta);
-
   event.type = GNUNET_FSUI_search_result;
-  event.data.SearchResult.sc.pos = pos;
-  event.data.SearchResult.sc.cctx = pos->cctx;
-  event.data.SearchResult.fi = *fi;
-  event.data.SearchResult.searchURI = pos->uri;
-  pos->ctx->ecb (pos->ctx->ecbClosure, &event);
-  GNUNET_URITRACK_add_state (pos->ctx->ectx,
-                             pos->ctx->cfg, pos->uri,
+  event.data.SearchResult.sc.pos = ctx;
+  event.data.SearchResult.sc.cctx = ctx->cctx;
+  event.data.SearchResult.fi = pos->fi;
+  event.data.SearchResult.searchURI = ctx->uri;
+  ctx->ctx->ecb (ctx->ctx->ecbClosure, &event);
+  GNUNET_URITRACK_add_state (ctx->ctx->ectx,
+                             ctx->ctx->cfg, pos->fi.uri,
                              GNUNET_URITRACK_SEARCH_RESULT);
 }
 
@@ -69,17 +66,17 @@
  */
 int
 GNUNET_FSUI_search_progress_callback (const GNUNET_ECRS_FileInfo * fi,
-                                      const GNUNET_HashCode * key, int isRoot,
+                                      const GNUNET_HashCode * key, 
+                                     int isRoot,
                                       void *cls)
 {
   GNUNET_FSUI_SearchList *pos = cls;
   unsigned int i;
-  unsigned int j;
-  ResultPending *rp;
   struct GNUNET_GE_Context *ectx;
+  struct SearchResultList * srl;
+  struct SearchRecordList * rec;
 
   ectx = pos->ctx->ectx;
-
   GNUNET_URITRACK_track (ectx, pos->ctx->cfg, fi);
   if (isRoot)
     {
@@ -88,101 +85,146 @@
                                            fi->meta);
       return GNUNET_OK;
     }
-  for (i = 0; i < pos->sizeResultsReceived; i++)
-    if (GNUNET_ECRS_uri_test_equal (fi->uri, pos->resultsReceived[i].uri))
-      {
-#if DEBUG_SEARCH
-        GNUNET_GE_LOG (ectx,
-                       GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
-                       "Received search result that I have seen before.\n");
-#endif
-        return GNUNET_OK;       /* seen before */
-      }
-  if (pos->numberOfURIKeys == 1)
+  GNUNET_mutex_lock (pos->lock);
+  srl = pos->resultsReceived;
+  while (srl != NULL)
     {
+      if (GNUNET_ECRS_uri_test_equal (fi->uri, 
+                                     srl->fi.uri))
+       {
+         for (i=0;i<srl->matchingSearchCount;i++)
+           {
+             if ( (GNUNET_ECRS_uri_test_sks(pos->uri)) ||
+                  (0 == memcmp(key,
+                               &srl->matchingSearches[i]->key,
+                               sizeof(GNUNET_HashCode))) )
+               {
 #if DEBUG_SEARCH
-      GNUNET_GE_LOG (ectx,
-                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
-                     "Received search result (showing client)!\n");
+                 GNUNET_GE_LOG (ectx,
+                                GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | 
GNUNET_GE_USER,
+                                "Received search result that I have seen 
before.\n");
 #endif
-      processResult (fi, pos);
-      return GNUNET_OK;
+                 GNUNET_mutex_unlock (pos->lock);
+                 return GNUNET_OK;       /* seen before */
+               }             
+           }
+         /* not seen before, find corresponding search! */
+         rec = pos->searches;
+         while ( (rec != NULL) &&
+                 (0 != memcmp(key,
+                              &rec->key,
+                              sizeof(GNUNET_HashCode))) )
+           rec = rec->next;
+         if (rec == NULL)
+           {
+             GNUNET_GE_BREAK(NULL, 0);
+             GNUNET_mutex_unlock (pos->lock);
+             return GNUNET_OK; /* should have matching search */
+           }
+         GNUNET_array_append(srl->matchingSearches,
+                             srl->matchingSearchCount,
+                             rec);
+         if (rec->is_required)
+           {
+             if (srl->mandatoryMatchesRemaining > 0)
+               srl->mandatoryMatchesRemaining--;
+             else
+               {
+                 bug();
+                 GNUNET_GE_BREAK(NULL, 0);
+               }
+           }     
+         if (srl->mandatoryMatchesRemaining == 0)
+           processResult(pos, srl);
+         GNUNET_mutex_unlock (pos->lock);
+         return GNUNET_OK;
+       }
+      srl = srl->next;
     }
-  if (key == NULL)
+  /* new result */
+  rec = pos->searches;
+  while ( (rec != NULL) &&
+         (! GNUNET_ECRS_uri_test_sks(pos->uri)) &&
+         (0 != memcmp(key,
+                      &rec->key,
+                      sizeof(GNUNET_HashCode))) )
+    rec = rec->next;
+  if (rec == NULL)
     {
-      GNUNET_GE_BREAK (ectx, 0);
-#if DEBUG_SEARCH
-      GNUNET_GE_LOG (ectx,
-                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
-                     "Received search result without key to decrypt.\n");
-#endif
-      return GNUNET_SYSERR;
+      GNUNET_GE_BREAK(NULL, 0);
+      GNUNET_mutex_unlock (pos->lock);
+      return GNUNET_OK; /* should have matching search */
     }
-  for (i = 0; i < pos->sizeUnmatchedResultsReceived; i++)
+  srl = GNUNET_malloc(sizeof(struct SearchResultList));
+  memset(srl, 
+        0,
+        sizeof(struct SearchResultList));
+  GNUNET_array_append(srl->matchingSearches,
+                     srl->matchingSearchCount,
+                     rec);
+  srl->fi.meta = GNUNET_ECRS_meta_data_duplicate (fi->meta);
+  srl->fi.uri = GNUNET_ECRS_uri_duplicate (fi->uri);
+  srl->mandatoryMatchesRemaining = pos->mandatory_keyword_count;
+  if (rec->is_required)
     {
-      rp = &pos->unmatchedResultsReceived[i];
-      if (!GNUNET_ECRS_uri_test_equal (fi->uri, rp->fi.uri))
-        continue;
-      for (j = 0; j < rp->matchingKeyCount; j++)
-        if (0 == memcmp (key, &rp->matchingKeys[j], sizeof (GNUNET_HashCode)))
-          {
-#if DEBUG_SEARCH
-            GNUNET_GE_LOG (ectx,
-                           GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
-                           GNUNET_GE_USER,
-                           "Received search result that I have seen before 
(missing keyword to show client).\n");
-#endif
-            return GNUNET_OK;
-          }
-      if (rp->matchingKeyCount + 1 == pos->numberOfURIKeys)
-        {
-#if DEBUG_SEARCH
-          GNUNET_GE_LOG (ectx,
-                         GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
-                         GNUNET_GE_USER,
-                         "Received search result (showing client)!\n");
-#endif
-          GNUNET_array_grow (rp->matchingKeys, rp->matchingKeyCount, 0);
-          processResult (&rp->fi, pos);
-          GNUNET_ECRS_uri_destroy (rp->fi.uri);
-          GNUNET_ECRS_meta_data_destroy (rp->fi.meta);
-          pos->unmatchedResultsReceived[i]
-            =
-            pos->unmatchedResultsReceived[pos->
-                                          sizeUnmatchedResultsReceived - 1];
-          GNUNET_array_grow (pos->unmatchedResultsReceived,
-                             pos->sizeUnmatchedResultsReceived,
-                             pos->sizeUnmatchedResultsReceived - 1);
-          return GNUNET_OK;
-        }
-      GNUNET_array_grow (rp->matchingKeys,
-                         rp->matchingKeyCount, rp->matchingKeyCount + 1);
-      rp->matchingKeys[rp->matchingKeyCount - 1] = *key;
-#if DEBUG_SEARCH
-      GNUNET_GE_LOG (ectx,
-                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
-                     GNUNET_GE_USER,
-                     "Received search result (waiting for more %u keys before 
showing client).\n",
-                     pos->numberOfURIKeys - rp->matchingKeyCount);
-#endif
-      return GNUNET_OK;
+      if (srl->mandatoryMatchesRemaining > 0)
+       srl->mandatoryMatchesRemaining--;
+      else
+       {
+         bug();
+         GNUNET_GE_BREAK(NULL, 0);
+       }
+   }
+  srl->next = pos->resultsReceived;
+  pos->resultsReceived = srl;
+  if (srl->mandatoryMatchesRemaining == 0)
+    processResult(pos, srl);
+  GNUNET_mutex_unlock (pos->lock);
+  return GNUNET_OK;
+}
+
+/**
+ * This function is called on each keyword in the
+ * search list.  Start the corresponding ECRS search.
+ * 
+ * @param closure our GNUNET_FSUI_SearchList.
+ */
+static int
+create_ecrs_search(const char * keyword,
+                  int is_mandatory,
+                  void * closure)
+{
+  struct GNUNET_FSUI_SearchList * pos = closure;
+  struct SearchRecordList * srl;
+
+  srl = GNUNET_malloc(sizeof(struct SearchRecordList));
+  memset(srl, 0, sizeof(struct SearchRecordList));
+  srl->uri = GNUNET_ECRS_keyword_command_line_to_uri(pos->ctx->ectx,
+                                                    1,
+                                                    &keyword);  
+  GNUNET_hash(keyword,
+             strlen(keyword),
+             &srl->key);
+  srl->is_required = is_mandatory;
+  if (is_mandatory)
+    pos->mandatory_keyword_count++;
+  srl->next = pos->searches;
+  pos->searches = srl;
+  srl->search = 
+    GNUNET_ECRS_search_start (pos->ctx->ectx,
+                             pos->ctx->cfg,
+                             srl->uri,
+                             pos->anonymityLevel,
+                             &GNUNET_FSUI_search_progress_callback,
+                             pos);
+  if (srl->search == NULL)
+    {
+      GNUNET_ECRS_uri_destroy(srl->uri);
+      pos->searches = srl->next;
+      GNUNET_free(srl);
+      pos->start_time = 0; /* flag to indicate error */
+      return GNUNET_SYSERR;
     }
-  GNUNET_array_grow (pos->unmatchedResultsReceived,
-                     pos->sizeUnmatchedResultsReceived,
-                     pos->sizeUnmatchedResultsReceived + 1);
-  rp = &pos->unmatchedResultsReceived[pos->sizeUnmatchedResultsReceived - 1];
-  rp->fi.meta = GNUNET_ECRS_meta_data_duplicate (fi->meta);
-  rp->fi.uri = GNUNET_ECRS_uri_duplicate (fi->uri);
-  rp->matchingKeys = NULL;
-  rp->matchingKeyCount = 0;
-  GNUNET_array_grow (rp->matchingKeys, rp->matchingKeyCount, 1);
-  rp->matchingKeys[0] = *key;
-#if DEBUG_SEARCH
-  GNUNET_GE_LOG (ectx,
-                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
-                 "Received search result (waiting for %u more keys before 
showing client).\n",
-                 pos->numberOfURIKeys - rp->matchingKeyCount);
-#endif
   return GNUNET_OK;
 }
 
@@ -197,39 +239,89 @@
   GNUNET_FSUI_SearchList *pos;
   struct GNUNET_GE_Context *ectx;
   GNUNET_FSUI_Event event;
+  struct SearchRecordList * srl;
 
+  if (! (GNUNET_ECRS_uri_test_ksk(uri) ||
+        GNUNET_ECRS_uri_test_sks(uri) ) )
+    {
+      GNUNET_GE_BREAK(NULL, 0);
+      return NULL;
+    }      
   ectx = ctx->ectx;
-  GNUNET_mutex_lock (ctx->lock);
   pos = GNUNET_malloc (sizeof (GNUNET_FSUI_SearchList));
+  memset(pos,
+        0,
+        sizeof (GNUNET_FSUI_SearchList));
   pos->state = GNUNET_FSUI_ACTIVE;
-  pos->uri = GNUNET_ECRS_uri_duplicate (uri);
-  pos->numberOfURIKeys = GNUNET_ECRS_uri_get_keyword_count_from_ksk (uri);
-  pos->sizeResultsReceived = 0;
-  pos->resultsReceived = NULL;
-  pos->sizeUnmatchedResultsReceived = 0;
-  pos->unmatchedResultsReceived = 0;
   pos->anonymityLevel = anonymityLevel;
   pos->ctx = ctx;
   pos->start_time = GNUNET_get_time ();
+  pos->uri = GNUNET_ECRS_uri_duplicate (uri);
+  pos->lock = GNUNET_mutex_create(GNUNET_NO);
   event.type = GNUNET_FSUI_search_started;
   event.data.SearchStarted.sc.pos = pos;
   event.data.SearchStarted.sc.cctx = NULL;
   event.data.SearchStarted.searchURI = pos->uri;
   event.data.SearchStarted.anonymityLevel = pos->anonymityLevel;
   pos->cctx = pos->ctx->ecb (pos->ctx->ecbClosure, &event);
-  pos->handle = GNUNET_ECRS_search_start (pos->ctx->ectx,
-                                          pos->ctx->cfg,
-                                          pos->uri,
-                                          pos->anonymityLevel,
-                                          
&GNUNET_FSUI_search_progress_callback,
-                                          pos);
-  if (pos->handle == NULL)
+  GNUNET_mutex_lock(pos->lock);
+  if (GNUNET_ECRS_uri_test_ksk(uri))
     {
+      /* (possibly boolean) keyword search */
+      GNUNET_ECRS_uri_get_keywords_from_ksk(uri,
+                                           &create_ecrs_search,
+                                           pos);
+      if (pos->start_time == 0)
+       {
+         /* failed to start ECRS searches */
+         while (pos->searches != NULL)
+           {
+             srl = pos->searches;
+             pos->searches = srl->next;
+             GNUNET_ECRS_search_stop(srl->search);
+             GNUNET_ECRS_uri_destroy (srl->uri);
+             GNUNET_free(srl);
+           }
+       }
+    }
+  else
+    {
+      /* Namespace search, only one ECRS search */
+      srl = GNUNET_malloc(sizeof(struct SearchRecordList));
+      memset(srl, 0, sizeof(struct SearchRecordList));
+      srl->uri = GNUNET_ECRS_uri_duplicate (uri);
+      srl->search = GNUNET_ECRS_search_start (pos->ctx->ectx,
+                                             pos->ctx->cfg,
+                                             pos->uri,
+                                             pos->anonymityLevel,
+                                             
&GNUNET_FSUI_search_progress_callback,
+                                             pos);
+      if (srl->search == NULL)
+       {
+         GNUNET_ECRS_uri_destroy (srl->uri);
+         GNUNET_free (srl);
+       }
+      else
+       {
+         pos->searches = srl;
+       }
+    }
+  if (pos->searches == NULL)
+    {
+      /* failed to initiate searches */
+      event.type = GNUNET_FSUI_search_stopped;
+      event.data.SearchStopped.sc.pos = pos;
+      event.data.SearchStopped.sc.cctx = NULL;
+      pos->cctx = pos->ctx->ecb (pos->ctx->ecbClosure, &event);        
       GNUNET_ECRS_uri_destroy (pos->uri);
+      GNUNET_mutex_unlock(pos->lock);
+      GNUNET_mutex_destroy(pos->lock);  
       GNUNET_free (pos);
-      GNUNET_mutex_unlock (ctx->lock);
       return NULL;
-    }
+    }     
+  GNUNET_mutex_unlock(pos->lock);
+  /* success, add to FSUI state */
+  GNUNET_mutex_lock (ctx->lock);
   pos->next = ctx->activeSearches;
   ctx->activeSearches = pos;
   GNUNET_mutex_unlock (ctx->lock);
@@ -244,6 +336,8 @@
                           struct GNUNET_FSUI_SearchList *sl)
 {
   GNUNET_FSUI_Event event;
+  struct SearchRecordList * rec;
+  struct SearchResultList * srl;
 
   GNUNET_mutex_lock (ctx->lock);
   if (sl->state == GNUNET_FSUI_PENDING)
@@ -257,9 +351,33 @@
       GNUNET_mutex_unlock (ctx->lock);
       return GNUNET_SYSERR;
     }
-  GNUNET_ECRS_search_stop (sl->handle);
   sl->state = GNUNET_FSUI_ABORTED_JOINED;
-  sl->handle = NULL;
+  GNUNET_mutex_unlock (ctx->lock);
+  /* must not hold lock while stopping ECRS searches! */
+  while (sl->searches != NULL)
+    {
+      rec = sl->searches;
+      sl->searches = rec->next;
+      GNUNET_ECRS_search_stop(rec->search);
+      GNUNET_ECRS_uri_destroy (rec->uri);
+      GNUNET_free(rec);
+    }
+  /* clean up a bit more: we don't need matchingSearches
+     anymore, and the pointers are now invalid! */     
+  GNUNET_mutex_lock (ctx->lock);
+  srl = sl->resultsReceived;
+  while (srl != NULL)
+    {
+      GNUNET_array_grow(srl->matchingSearches,
+                       srl->matchingSearchCount,
+                       0);
+      if (srl->test_download != NULL)
+       {
+         GNUNET_ECRS_file_download_partial_stop(srl->test_download);
+         srl->test_download = NULL;
+       }
+      srl = srl->next;
+    }
   event.type = GNUNET_FSUI_search_aborted;
   event.data.SearchAborted.sc.pos = sl;
   event.data.SearchAborted.sc.cctx = sl->cctx;
@@ -276,6 +394,8 @@
                           struct GNUNET_FSUI_SearchList *sl)
 {
   GNUNET_FSUI_Event event;
+  struct SearchRecordList * rec;
+  struct SearchResultList * srl;
 
   GNUNET_mutex_lock (ctx->lock);
   if (sl->state != GNUNET_FSUI_ACTIVE)
@@ -283,9 +403,28 @@
       GNUNET_mutex_unlock (ctx->lock);
       return GNUNET_SYSERR;
     }
-  GNUNET_ECRS_search_stop (sl->handle);
-  sl->handle = NULL;
   sl->state = GNUNET_FSUI_PAUSED;
+  GNUNET_mutex_unlock (ctx->lock);
+  /* must not hold lock while stopping ECRS searches */
+  rec = sl->searches;
+  while (rec != NULL)
+    {
+      if (rec->search != NULL)
+       GNUNET_ECRS_search_stop(rec->search);
+      rec->search = NULL;
+      rec = rec->next;
+    }
+  GNUNET_mutex_lock (ctx->lock);
+  srl = sl->resultsReceived;
+  while (srl != NULL)
+    {
+      if (srl->test_download != NULL)
+       {
+         GNUNET_ECRS_file_download_partial_stop(srl->test_download);
+         srl->test_download = NULL;
+       }
+      srl = srl->next;
+    }
   event.type = GNUNET_FSUI_search_paused;
   event.data.SearchPaused.sc.pos = sl;
   event.data.SearchPaused.sc.cctx = sl->cctx;
@@ -302,6 +441,7 @@
                             struct GNUNET_FSUI_SearchList *pos)
 {
   GNUNET_FSUI_Event event;
+  struct SearchRecordList * rec;
 
   GNUNET_mutex_lock (ctx->lock);
   pos->state = GNUNET_FSUI_ACTIVE;
@@ -309,15 +449,23 @@
   event.data.SearchStarted.sc.pos = pos;
   event.data.SearchStarted.sc.cctx = pos->cctx;
   pos->ctx->ecb (pos->ctx->ecbClosure, &event);
-  pos->handle = GNUNET_ECRS_search_start (pos->ctx->ectx,
-                                          pos->ctx->cfg,
-                                          pos->uri,
-                                          pos->anonymityLevel,
-                                          
&GNUNET_FSUI_search_progress_callback,
-                                          pos);
-  if (pos->handle == NULL)
+  rec = pos->searches;
+  while (rec != NULL)
     {
-      pos->state = GNUNET_FSUI_PAUSED;
+      rec->search = GNUNET_ECRS_search_start (pos->ctx->ectx,
+                                             pos->ctx->cfg,
+                                             rec->uri,
+                                             pos->anonymityLevel,
+                                             
&GNUNET_FSUI_search_progress_callback,
+                                             pos);
+      if (rec->search == NULL)
+       break;
+      rec = rec->next;
+    }
+  if (rec != NULL)
+    {
+      /* failed to restart, auto-pause again */
+      GNUNET_FSUI_search_pause(ctx, pos);
       GNUNET_mutex_unlock (ctx->lock);
       return GNUNET_SYSERR;
     }
@@ -336,6 +484,8 @@
   GNUNET_FSUI_SearchList *pos;
   GNUNET_FSUI_SearchList *prev;
   int i;
+  struct SearchRecordList * rec;
+  struct SearchResultList * srl;
 
   GNUNET_mutex_lock (ctx->lock);
   if (sl->state == GNUNET_FSUI_ACTIVE)
@@ -361,29 +511,38 @@
   GNUNET_array_grow (sl->my_downloads, sl->my_downloads_size, 0);
   GNUNET_mutex_unlock (ctx->lock);
   pos->next = NULL;
-  GNUNET_GE_ASSERT (ctx->ectx, pos->handle == NULL);
+  while (sl->searches != NULL)
+    {
+      rec = sl->searches;
+      sl->searches = rec->next;
+      if (rec->search != NULL)
+       {
+         GNUNET_GE_BREAK (ctx->ectx, 0);
+         GNUNET_ECRS_search_stop(rec->search);
+         rec->search = NULL;
+       }
+      GNUNET_ECRS_uri_destroy (rec->uri);
+      GNUNET_free(rec);
+    }
   event.type = GNUNET_FSUI_search_stopped;
   event.data.SearchStopped.sc.pos = pos;
   event.data.SearchStopped.sc.cctx = pos->cctx;
   pos->ctx->ecb (pos->ctx->ecbClosure, &event);
   GNUNET_ECRS_uri_destroy (pos->uri);
-  for (i = 0; i < pos->sizeResultsReceived; i++)
+  while (sl->resultsReceived != NULL)
     {
-      GNUNET_ECRS_uri_destroy (pos->resultsReceived[i].uri);
-      GNUNET_ECRS_meta_data_destroy (pos->resultsReceived[i].meta);
+      srl = sl->resultsReceived;
+      sl->resultsReceived = srl->next;
+      GNUNET_array_grow(srl->matchingSearches,
+                       srl->matchingSearchCount,
+                       0);
+      GNUNET_ECRS_uri_destroy (srl->fi.uri);
+      GNUNET_ECRS_meta_data_destroy (srl->fi.meta);
+      if (srl->test_download != NULL)
+       GNUNET_ECRS_file_download_partial_stop(srl->test_download);
+      GNUNET_free(srl);
     }
-  GNUNET_array_grow (pos->resultsReceived, pos->sizeResultsReceived, 0);
-  for (i = 0; i < pos->sizeUnmatchedResultsReceived; i++)
-    {
-      GNUNET_ECRS_uri_destroy (pos->unmatchedResultsReceived[i].fi.uri);
-      GNUNET_ECRS_meta_data_destroy (pos->unmatchedResultsReceived[i].fi.
-                                     meta);
-      GNUNET_array_grow (pos->unmatchedResultsReceived[i].matchingKeys,
-                         pos->unmatchedResultsReceived[i].matchingKeyCount,
-                         0);
-    }
-  GNUNET_array_grow (pos->unmatchedResultsReceived,
-                     pos->sizeUnmatchedResultsReceived, 0);
+  GNUNET_mutex_destroy(pos->lock);
   GNUNET_free (pos);
   return GNUNET_OK;
 }

Modified: GNUnet/src/applications/fs/fsui/searchtest.c
===================================================================
--- GNUnet/src/applications/fs/fsui/searchtest.c        2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/fsui/searchtest.c        2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -131,7 +131,6 @@
   char *keywords[] = {
     "search_foo",
     "search_bar",
-    NULL,
   };
   char keyword[40];
   int prog;
@@ -165,8 +164,7 @@
                            cfg, "fsuisearchtest", 32, GNUNET_YES,
                            &eventCallback, NULL);
   CHECK (ctx != NULL);
-  GNUNET_snprintf (keyword, 40, "%s %s %s", keywords[0], _("AND"),
-                   keywords[1]);
+  GNUNET_snprintf (keyword, 40, "+%s +%s", keywords[0], keywords[1]);
   luri = GNUNET_ECRS_keyword_string_to_uri (NULL, keyword);
   uri = NULL;
   search = GNUNET_FSUI_search_start (ctx, 0, luri);
@@ -190,7 +188,7 @@
                           fn, "foo bar test!", strlen ("foo bar test!"),
                           "600");
   meta = GNUNET_ECRS_meta_data_create ();
-  kuri = GNUNET_ECRS_keyword_list_to_uri (NULL, 2, (const char **) keywords);
+  kuri = GNUNET_ECRS_keyword_command_line_to_uri (NULL, 2, (const char **) 
keywords);
   waitForEvent = GNUNET_FSUI_upload_completed;
   upload =
     GNUNET_FSUI_upload_start (ctx,

Modified: GNUnet/src/applications/fs/fsui/serialize.c
===================================================================
--- GNUnet/src/applications/fs/fsui/serialize.c 2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/fsui/serialize.c 2008-04-24 05:49:31 UTC (rev 
6745)
@@ -31,46 +31,95 @@
 #include "gnunet_directories.h"
 #include "fsui.h"
 
+
+typedef struct {
+  int fd;
+  unsigned int have;
+  unsigned int size;
+  char * buffer;
+} WriteBuffer;
+
 static void
-WRITEINT (int fd, int val)
+write_buffered(WriteBuffer * wb,
+              const void * s,
+              unsigned int size) {
+  const char * src = s;
+  unsigned int min;
+  unsigned int pos;
+  int ret;
+
+  if (wb->fd == -1)
+    return;
+  pos = 0;
+  do 
+    {
+      /* first, just use buffer */
+      min = wb->size - wb->have;
+      if (min > size)
+       min = size;
+      memcpy(&wb->buffer[wb->have],
+            &src[pos],
+            min);
+      pos += min;
+      wb->have += min;
+      if (pos == size)
+       return; /* done */
+      GNUNET_GE_ASSERT(NULL, wb->have == wb->size);
+      ret = WRITE(wb->fd,
+                 wb->buffer,
+                 wb->size);
+      if (ret != wb->size)
+       {
+         CLOSE(wb->fd);
+         wb->fd = -1;
+         return; /* error */
+       }
+      wb->have = 0;
+    }
+  while (pos < size); /* should always be true */
+}
+
+
+static void
+WRITEINT (WriteBuffer * wb, int val)
 {
   int big;
   big = htonl (val);
-  WRITE (fd, &big, sizeof (int));
+  write_buffered (wb, &big, sizeof (int));
 }
 
 static void
-WRITELONG (int fd, long long val)
+WRITELONG (WriteBuffer * wb, long long val)
 {
   long long big;
   big = GNUNET_htonll (val);
-  WRITE (fd, &big, sizeof (long long));
+  write_buffered (wb, &big, sizeof (long long));
 }
 
 static void
-writeURI (int fd, const struct GNUNET_ECRS_URI *uri)
+writeURI (WriteBuffer * wb, const struct GNUNET_ECRS_URI *uri)
 {
   char *buf;
   unsigned int size;
 
   buf = GNUNET_ECRS_uri_to_string (uri);
   size = strlen (buf);
-  WRITEINT (fd, size);
-  WRITE (fd, buf, size);
+  WRITEINT (wb, size);
+  write_buffered (wb, buf, size);
   GNUNET_free (buf);
 }
 
 static void
-WRITESTRING (int fd, const char *name)
+WRITESTRING (WriteBuffer * wb, const char *name)
 {
   GNUNET_GE_BREAK (NULL, name != NULL);
-  WRITEINT (fd, strlen (name));
-  WRITE (fd, name, strlen (name));
+  WRITEINT (wb, strlen (name));
+  write_buffered (wb, name, strlen (name));
 }
 
 static void
 writeMetaData (struct GNUNET_GE_Context *ectx,
-               int fd, const struct GNUNET_ECRS_MetaData *meta)
+               WriteBuffer * wb, const struct GNUNET_ECRS_MetaData *meta)
 {
   unsigned int size;
   char *buf;
@@ -88,18 +137,18 @@
                                    size,
                                    GNUNET_ECRS_SERIALIZE_PART |
                                    GNUNET_ECRS_SERIALIZE_NO_COMPRESS);
-  WRITEINT (fd, size);
-  WRITE (fd, buf, size);
+  WRITEINT (wb, size);
+  write_buffered (wb, buf, size);
   GNUNET_free (buf);
 }
 
 
 static void
-writeFileInfo (struct GNUNET_GE_Context *ectx, int fd,
+writeFileInfo (struct GNUNET_GE_Context *ectx, WriteBuffer * wb,
                const GNUNET_ECRS_FileInfo * fi)
 {
-  writeMetaData (ectx, fd, fi->meta);
-  writeURI (fd, fi->uri);
+  writeMetaData (ectx, wb, fi->meta);
+  writeURI (wb, fi->uri);
 }
 
 
@@ -108,7 +157,7 @@
  */
 static void
 writeDownloadList (struct GNUNET_GE_Context *ectx,
-                   int fd, GNUNET_FSUI_Context * ctx,
+                   WriteBuffer * wb, GNUNET_FSUI_Context * ctx,
                    GNUNET_FSUI_DownloadList * list)
 {
   int i;
@@ -116,7 +165,7 @@
 
   if (list == NULL)
     {
-      WRITEINT (fd, 0);
+      WRITEINT (wb, 0);
       return;
     }
 #if DEBUG_PERSISTENCE
@@ -125,10 +174,10 @@
                  "Serializing download state of download `%s': (%llu, %llu)\n",
                  list->filename, list->completed, list->total);
 #endif
-  WRITEINT (fd, 1);
+  WRITEINT (wb, 1);
   if (list->search == NULL)
     {
-      WRITEINT (fd, 0);
+      WRITEINT (wb, 0);
     }
   else
     {
@@ -136,9 +185,6 @@
       pos = ctx->activeSearches;
       while (pos != list->search)
         {
-          if ((pos->sizeResultsReceived <= 1024 * 1024) &&
-              (pos->sizeUnmatchedResultsReceived <= 1024 * 1024))
-            i++;
           pos = pos->next;
           if (pos == NULL)
             {
@@ -146,98 +192,141 @@
               i = 0;
               break;
             }
+         i++;
         }
-      if ((pos != NULL) &&
-          ((pos->sizeResultsReceived < 1024 * 1024) ||
-           (pos->sizeUnmatchedResultsReceived < 1024 * 1024)))
+      if (pos == NULL) 
         i = 0;
-      WRITEINT (fd, i);
+      WRITEINT (wb, i);
     }
-  WRITEINT (fd, list->state);
-  WRITEINT (fd, list->is_recursive);
-  WRITEINT (fd, list->is_directory);
-  WRITEINT (fd, list->anonymityLevel);
-  WRITEINT (fd, list->completedDownloadsCount);
-  WRITELONG (fd, list->total);
-  WRITELONG (fd, list->completed);
-  WRITELONG (fd, GNUNET_get_time () - list->startTime);
+  WRITEINT (wb, list->state);
+  WRITEINT (wb, list->is_recursive);
+  WRITEINT (wb, list->is_directory);
+  WRITEINT (wb, list->anonymityLevel);
+  WRITEINT (wb, list->completedDownloadsCount);
+  WRITELONG (wb, list->total);
+  WRITELONG (wb, list->completed);
+  WRITELONG (wb, GNUNET_get_time () - list->startTime);
 
-  WRITESTRING (fd, list->filename);
-  writeFileInfo (ectx, fd, &list->fi);
+  WRITESTRING (wb, list->filename);
+  writeFileInfo (ectx, wb, &list->fi);
   for (i = 0; i < list->completedDownloadsCount; i++)
-    writeURI (fd, list->completedDownloads[i]);
-  writeDownloadList (ectx, fd, ctx, list->next);
-  writeDownloadList (ectx, fd, ctx, list->child);
+    writeURI (wb, list->completedDownloads[i]);
+  writeDownloadList (ectx, wb, ctx, list->next);
+  writeDownloadList (ectx, wb, ctx, list->child);
 }
 
 static void
-writeCollection (int fd, struct GNUNET_FSUI_Context *ctx)
+writeCollection (WriteBuffer * wb, struct GNUNET_FSUI_Context *ctx)
 {
   if ((ctx->collectionData == NULL) ||
       (ctx->collectionDataSize > 16 * 1024 * 1024))
     {
-      WRITEINT (fd, 0);
+      WRITEINT (wb, 0);
       return;
     }
   /* serialize collection data */
-  WRITEINT (fd, ctx->collectionDataSize);
-  WRITE (fd, ctx->collectionData, ctx->collectionDataSize);
+  WRITEINT (wb, ctx->collectionDataSize);
+  write_buffered (wb, ctx->collectionData, ctx->collectionDataSize);
 }
 
+
+/**
+ * Write information about the individual ECRS searches
+ * that we are performing.
+ */
 static void
-writeSearches (int fd, struct GNUNET_FSUI_Context *ctx)
+write_search_record_list(struct GNUNET_GE_Context * ectx,
+                        WriteBuffer *wb,
+                        struct SearchRecordList * pos) 
 {
+  while (pos != NULL) 
+    {
+      WRITEINT(wb, pos->is_required);
+      write_buffered(wb, &pos->key, sizeof(GNUNET_HashCode));
+      writeURI(wb, pos->uri);
+      pos = pos->next;
+    }     
+  WRITEINT(wb, -1);
+}
+
+/**
+ * Write all of the results received so far
+ * for this search.
+ *
+ * @param search_count length of search_list
+ * @param search_list list of ECRS search requests 
+ * @param pos results to write
+ */
+void
+write_result_list(struct GNUNET_GE_Context * ectx,
+                 WriteBuffer *wb,
+                 struct SearchRecordList * search_list,
+                 struct SearchResultList * pos) 
+{
+  unsigned int i;
+  unsigned int idx;
+  struct SearchRecordList * spos;
+
+  while (pos != NULL) 
+    { 
+      WRITEINT(wb, pos->matchingSearchCount);
+      WRITEINT(wb, pos->mandatoryMatchesRemaining);
+      WRITEINT(wb, pos->probeSuccess);
+      WRITEINT(wb, pos->probeFailure);
+      writeFileInfo(ectx, wb, &pos->fi);
+      i = pos->matchingSearchCount;
+      while (i-- > 0)
+       {
+         idx = 1;
+         spos = search_list;
+         while ( (spos != NULL) &&
+                 (spos != pos->matchingSearches[i]) )
+           {
+             idx++;
+             spos = spos->next;
+           }
+         if (spos == NULL)
+           idx = 0;
+         WRITEINT(wb, idx);      
+       }
+      pos = pos->next;
+    }     
+  WRITEINT(wb, -1);
+}
+
+
+static void
+writeSearches (WriteBuffer * wb, struct GNUNET_FSUI_Context *ctx)
+{
   GNUNET_FSUI_SearchList *spos;
-  int i;
 
   spos = ctx->activeSearches;
   while (spos != NULL)
     {
-      if ((spos->sizeResultsReceived > 1024 * 1024) ||
-          (spos->sizeUnmatchedResultsReceived > 1024 * 1024))
-        {
-          /* too large to serialize - skip! */
-          spos = spos->next;
-          continue;
-        }
       GNUNET_GE_ASSERT (ctx->ectx,
                         GNUNET_ECRS_uri_test_ksk (spos->uri) ||
                         GNUNET_ECRS_uri_test_sks (spos->uri));
-      WRITEINT (fd, 1);
-      WRITEINT (fd, spos->state);
-      WRITELONG (fd, spos->start_time);
-      WRITELONG (fd, GNUNET_get_time ());
-      WRITEINT (fd, spos->anonymityLevel);
-      WRITEINT (fd, spos->sizeResultsReceived);
-      WRITEINT (fd, spos->sizeUnmatchedResultsReceived);
-      writeURI (fd, spos->uri);
-      for (i = 0; i < spos->sizeResultsReceived; i++)
-        writeFileInfo (ctx->ectx, fd, &spos->resultsReceived[i]);
-      for (i = 0; i < spos->sizeUnmatchedResultsReceived; i++)
-        {
-          ResultPending *rp;
-
-          rp = &spos->unmatchedResultsReceived[i];
-          writeFileInfo (ctx->ectx, fd, &rp->fi);
-          GNUNET_GE_ASSERT (ctx->ectx,
-                            rp->matchingKeyCount < spos->numberOfURIKeys);
-          if (rp->matchingKeyCount > 1024)
-            {
-              WRITEINT (fd, 0); /* too large to serialize */
-              continue;
-            }
-          WRITEINT (fd, rp->matchingKeyCount);
-          WRITE (fd,
-                 rp->matchingKeys,
-                 sizeof (GNUNET_HashCode) * rp->matchingKeyCount);
-        }
+      WRITEINT (wb, 1);
+      WRITEINT (wb, spos->state);
+      WRITELONG (wb, spos->start_time);
+      WRITELONG (wb, GNUNET_get_time ());
+      WRITEINT (wb, spos->anonymityLevel);
+      WRITEINT (wb, spos->mandatory_keyword_count);
+      writeURI (wb, spos->uri);
+      write_search_record_list(ctx->ectx,
+                              wb,
+                              spos->searches);
+      write_result_list(ctx->ectx,
+                       wb,
+                       spos->searches,
+                       spos->resultsReceived);
       spos = spos->next;
     }
-  WRITEINT (fd, 0);
+  WRITEINT (wb, 0);
 }
 
 static void
-writeUnindexing (int fd, struct GNUNET_FSUI_Context *ctx)
+writeUnindexing (WriteBuffer * wb, struct GNUNET_FSUI_Context *ctx)
 {
   GNUNET_FSUI_UnindexList *xpos;
 
@@ -245,17 +334,17 @@
   xpos = ctx->unindexOperations;
   while (xpos != NULL)
     {
-      WRITEINT (fd, 1);
-      WRITEINT (fd, xpos->state);
-      WRITESTRING (fd, xpos->filename);
+      WRITEINT (wb, 1);
+      WRITEINT (wb, xpos->state);
+      WRITESTRING (wb, xpos->filename);
       xpos = xpos->next;
     }
   /* unindex list terminator */
-  WRITEINT (fd, 0);
+  WRITEINT (wb, 0);
 }
 
 static void
-writeUploadList (int fd,
+writeUploadList (WriteBuffer * wb,
                  struct GNUNET_FSUI_Context *ctx,
                  struct GNUNET_FSUI_UploadList *upos, int top)
 {
@@ -270,30 +359,30 @@
         bits |= 4;
       if (upos->meta != NULL)
         bits |= 8;
-      WRITEINT (fd, bits);
-      WRITEINT (fd, 0x34D1F023);
-      WRITEINT (fd, upos->state);
-      WRITELONG (fd, upos->completed);
-      WRITELONG (fd, upos->total);
-      WRITELONG (fd, GNUNET_get_time ());
-      WRITELONG (fd, upos->start_time);
+      WRITEINT (wb, bits);
+      WRITEINT (wb, 0x34D1F023);
+      WRITEINT (wb, upos->state);
+      WRITELONG (wb, upos->completed);
+      WRITELONG (wb, upos->total);
+      WRITELONG (wb, GNUNET_get_time ());
+      WRITELONG (wb, upos->start_time);
       if (upos->uri != NULL)
-        writeURI (fd, upos->uri);
+        writeURI (wb, upos->uri);
       if (upos->keywords != NULL)
-        writeURI (fd, upos->keywords);
+        writeURI (wb, upos->keywords);
       if (upos->meta != NULL)
-        writeMetaData (ctx->ectx, fd, upos->meta);
-      WRITESTRING (fd, upos->filename);
-      writeUploadList (fd, ctx, upos->child, GNUNET_NO);
+        writeMetaData (ctx->ectx, wb, upos->meta);
+      WRITESTRING (wb, upos->filename);
+      writeUploadList (wb, ctx, upos->child, GNUNET_NO);
       if (top == GNUNET_YES)
         break;
       upos = upos->next;
     }
-  WRITEINT (fd, 0);
+  WRITEINT (wb, 0);
 }
 
 static void
-writeUploads (int fd, struct GNUNET_FSUI_Context *ctx,
+writeUploads (WriteBuffer * wb, struct GNUNET_FSUI_Context *ctx,
               struct GNUNET_FSUI_UploadList *upos)
 {
   struct GNUNET_FSUI_UploadShared *shared;
@@ -307,42 +396,49 @@
         bits |= 2;
       if (shared->global_keywords != NULL)
         bits |= 4;
-      WRITEINT (fd, bits);
-      WRITEINT (fd, 0x44D1F024);
-      WRITEINT (fd, shared->doIndex);
-      WRITEINT (fd, shared->anonymityLevel);
-      WRITEINT (fd, shared->priority);
-      WRITEINT (fd, shared->individualKeywords);
-      WRITELONG (fd, shared->expiration);
+      WRITEINT (wb, bits);
+      WRITEINT (wb, 0x44D1F024);
+      WRITEINT (wb, shared->doIndex);
+      WRITEINT (wb, shared->anonymityLevel);
+      WRITEINT (wb, shared->priority);
+      WRITEINT (wb, shared->individualKeywords);
+      WRITELONG (wb, shared->expiration);
       if (shared->extractor_config != NULL)
-        WRITESTRING (fd, shared->extractor_config);
-      WRITESTRING (fd, shared->top_filename);
+        WRITESTRING (wb, shared->extractor_config);
+      WRITESTRING (wb, shared->top_filename);
       if (shared->global_keywords != NULL)
-        writeURI (fd, shared->global_keywords);
-      writeUploadList (fd, ctx, upos, GNUNET_YES);
+        writeURI (wb, shared->global_keywords);
+      writeUploadList (wb, ctx, upos, GNUNET_YES);
       upos = upos->next;
     }
-  WRITEINT (fd, 0);
+  WRITEINT (wb, 0);
 }
 
 void
 GNUNET_FSUI_serialize (struct GNUNET_FSUI_Context *ctx)
 {
-  int fd;
+  WriteBuffer wb;
 
-  fd = GNUNET_disk_file_open (ctx->ectx,
-                              ctx->name,
-                              O_CREAT | O_TRUNC | O_WRONLY,
-                              S_IRUSR | S_IWUSR);
-  if (fd == -1)
+  wb.fd = GNUNET_disk_file_open (ctx->ectx,
+                                ctx->name,
+                                O_CREAT | O_TRUNC | O_WRONLY,
+                                S_IRUSR | S_IWUSR);
+  if (wb.fd == -1)
     return;
-  WRITE (fd, "FSUI02\n\0", 8);  /* magic */
-  writeCollection (fd, ctx);
-  writeSearches (fd, ctx);
-  writeDownloadList (ctx->ectx, fd, ctx, ctx->activeDownloads.child);
-  writeUnindexing (fd, ctx);
-  writeUploads (fd, ctx, ctx->activeUploads.child);
-  CLOSE (fd);
+  wb.have = 0;
+  wb.size = 64 * 1024;
+  wb.buffer = GNUNET_malloc(wb.size);
+  write_buffered (&wb, "FSUI03\n\0", 8);  /* magic */
+  writeCollection (&wb, ctx);
+  writeSearches (&wb, ctx);
+  writeDownloadList (ctx->ectx, &wb, ctx, ctx->activeDownloads.child);
+  writeUnindexing (&wb, ctx);
+  writeUploads (&wb, ctx, ctx->activeUploads.child);
+  WRITE(wb.fd,
+       wb.buffer,
+       wb.have);  
+  CLOSE (wb.fd);
+  GNUNET_free(wb.buffer);
 }
 
-/* end of serializer */
+/* end of serialize.c */

Modified: GNUnet/src/applications/fs/fsui/serializetest.c
===================================================================
--- GNUnet/src/applications/fs/fsui/serializetest.c     2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/fsui/serializetest.c     2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -155,7 +155,6 @@
   char *keywords[] = {
     "down_foo",
     "down_bar",
-    NULL,
   };
   int prog;
   char *buf;
@@ -190,7 +189,7 @@
   GNUNET_disk_file_write (ectx, fn, buf, FILESIZE, "600");
   GNUNET_free (buf);
   meta = GNUNET_ECRS_meta_data_create ();
-  kuri = GNUNET_ECRS_keyword_list_to_uri (ectx, 2, (const char **) keywords);
+  kuri = GNUNET_ECRS_keyword_command_line_to_uri (ectx, 2, (const char **) 
keywords);
   waitForEvent = GNUNET_FSUI_upload_completed;
   upload = GNUNET_FSUI_upload_start (ctx,
                                      fn,

Modified: GNUnet/src/applications/fs/fsui/serializetest2.c
===================================================================
--- GNUnet/src/applications/fs/fsui/serializetest2.c    2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/fsui/serializetest2.c    2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -323,7 +323,6 @@
   char *keywords[] = {
     "down_foo",
     "down_bar",
-    NULL,
   };
   char keyword[40];
   int prog;
@@ -367,7 +366,7 @@
       GNUNET_free (fn);
     }
   meta = GNUNET_ECRS_meta_data_create ();
-  kuri = GNUNET_ECRS_keyword_list_to_uri (ectx, 2, (const char **) keywords);
+  kuri = GNUNET_ECRS_keyword_command_line_to_uri (ectx, 2, (const char **) 
keywords);
   GNUNET_ECRS_meta_data_insert (meta, EXTRACTOR_MIMETYPE,
                                 GNUNET_DIRECTORY_MIME);
   upload =
@@ -382,8 +381,7 @@
   kuri = NULL;
   GNUNET_FSUI_upload_stop (ctx, upload);
   CHECK (upURI != NULL);
-  GNUNET_snprintf (keyword, 40, "%s %s %s", keywords[0], _("AND"),
-                   keywords[1]);
+  GNUNET_snprintf (keyword, 40, "+%s +%s", keywords[0], keywords[1]);
   uri = GNUNET_ECRS_keyword_string_to_uri (ectx, keyword);
   search = GNUNET_FSUI_search_start (ctx, 0, uri);
   CHECK (search != NULL);

Modified: GNUnet/src/applications/fs/fsui/serializetest3.c
===================================================================
--- GNUnet/src/applications/fs/fsui/serializetest3.c    2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/fsui/serializetest3.c    2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -130,7 +130,6 @@
   char *keywords[] = {
     "down_foo",
     "down_bar",
-    NULL,
   };
   char keyword[40];
   int prog;
@@ -158,7 +157,7 @@
                            cfg, "serializetest3", 32, GNUNET_YES,
                            &eventCallback, NULL);
   CHECK (ctx != NULL);
-  GNUNET_snprintf (keyword, 40, "%s %s %s", keywords[0], _("AND"),
+  GNUNET_snprintf (keyword, 40, "+%s +%s", keywords[0], 
                    keywords[1]);
   uri = GNUNET_ECRS_keyword_string_to_uri (ectx, keyword);
   search = GNUNET_FSUI_search_start (ctx, 0, uri);

Modified: GNUnet/src/applications/fs/fsui/serializetest4.c
===================================================================
--- GNUnet/src/applications/fs/fsui/serializetest4.c    2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/fsui/serializetest4.c    2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -296,7 +296,6 @@
   char *keywords[] = {
     "down_foo",
     "down_bar",
-    NULL,
   };
   char keyword[40];
   int prog;
@@ -340,7 +339,7 @@
       GNUNET_free (fn);
     }
   meta = GNUNET_ECRS_meta_data_create ();
-  kuri = GNUNET_ECRS_keyword_list_to_uri (ectx, 2, (const char **) keywords);
+  kuri = GNUNET_ECRS_keyword_command_line_to_uri (ectx, 2, (const char **) 
keywords);
   GNUNET_ECRS_meta_data_insert (meta, EXTRACTOR_MIMETYPE,
                                 GNUNET_DIRECTORY_MIME);
   upload =
@@ -355,7 +354,7 @@
   kuri = NULL;
   GNUNET_FSUI_upload_stop (ctx, upload);
   CHECK (upURI != NULL);
-  GNUNET_snprintf (keyword, 40, "%s %s %s", keywords[0], _("AND"),
+  GNUNET_snprintf (keyword, 40, "+%s +%s", keywords[0], 
                    keywords[1]);
   uri = GNUNET_ECRS_keyword_string_to_uri (ectx, keyword);
   download = GNUNET_FSUI_download_start (ctx,

Modified: GNUnet/src/applications/fs/gap/ondemand.c
===================================================================
--- GNUnet/src/applications/fs/gap/ondemand.c   2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/fs/gap/ondemand.c   2008-04-24 05:49:31 UTC (rev 
6745)
@@ -167,7 +167,7 @@
   if (ret != -1)
     {
       GNUNET_GE_LOG (coreAPI->ectx,
-                     GNUNET_GE_ERROR | GNUNET_GE_BULK |
+                     GNUNET_GE_WARNING | GNUNET_GE_BULK |
                      GNUNET_GE_USER,
                      _
                      ("Because the file `%s' has been unavailable for 3 days"

Modified: GNUnet/src/applications/fs/gap/test_linear_topology.c
===================================================================
--- GNUnet/src/applications/fs/gap/test_linear_topology.c       2008-04-24 
04:01:46 UTC (rev 6744)
+++ GNUnet/src/applications/fs/gap/test_linear_topology.c       2008-04-24 
05:49:31 UTC (rev 6745)
@@ -112,13 +112,9 @@
     {
       struct GNUNET_ECRS_MetaData *meta;
       struct GNUNET_ECRS_URI *key;
-      const char *keywords[2];
 
-      keywords[0] = name;
-      keywords[1] = NULL;
-
       meta = GNUNET_ECRS_meta_data_create ();
-      key = GNUNET_ECRS_keyword_strings_to_uri (keywords);
+      key = GNUNET_ECRS_keyword_string_to_uri (NULL, name);
       ret = GNUNET_ECRS_publish_under_keyword (ectx, cfg, key, 0, 0, 
GNUNET_get_time () + 100 * GNUNET_CRON_MINUTES,    /* expire */
                                                uri, meta);
       GNUNET_ECRS_meta_data_destroy (meta);

Modified: GNUnet/src/applications/fs/gap/test_loopback.c
===================================================================
--- GNUnet/src/applications/fs/gap/test_loopback.c      2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/gap/test_loopback.c      2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -107,13 +107,9 @@
     {
       struct GNUNET_ECRS_MetaData *meta;
       struct GNUNET_ECRS_URI *key;
-      const char *keywords[2];
 
-      keywords[0] = name;
-      keywords[1] = NULL;
-
       meta = GNUNET_ECRS_meta_data_create ();
-      key = GNUNET_ECRS_keyword_strings_to_uri (keywords);
+      key = GNUNET_ECRS_keyword_string_to_uri (NULL, name);
       ret = GNUNET_ECRS_publish_under_keyword (ectx, cfg, key, 0, 0, 
GNUNET_get_time () + 10 * GNUNET_CRON_MINUTES,     /* expire */
                                                uri, meta);
       GNUNET_ECRS_meta_data_destroy (meta);

Modified: GNUnet/src/applications/fs/gap/test_multi_results.c
===================================================================
--- GNUnet/src/applications/fs/gap/test_multi_results.c 2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/gap/test_multi_results.c 2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -149,10 +149,6 @@
   int ret;
   int i;
   char buf[128];
-  const char *keywords[] = {
-    "multi-test",
-    NULL,
-  };
 
   ret = 0;
   cfg = GNUNET_GC_create ();
@@ -184,7 +180,7 @@
           return -1;
         }
     }
-  key = GNUNET_ECRS_keyword_strings_to_uri (keywords);
+  key = GNUNET_ECRS_keyword_string_to_uri (NULL, "multi-test");
   fprintf (stderr, "Uploading...");
   for (i = 0; i < TOTAL; i++)
     {

Modified: GNUnet/src/applications/fs/uritrack/tracktest.c
===================================================================
--- GNUnet/src/applications/fs/uritrack/tracktest.c     2008-04-24 04:01:46 UTC 
(rev 6744)
+++ GNUnet/src/applications/fs/uritrack/tracktest.c     2008-04-24 05:49:31 UTC 
(rev 6745)
@@ -98,18 +98,10 @@
 static int
 testTracking ()
 {
-  static const char *k1[] = {
-    "foo",
-    NULL,
-  };
-  static const char *k2[] = {
-    "foot",
-    NULL,
-  };
-  fi1.uri = GNUNET_ECRS_keyword_strings_to_uri (k1);
+  fi1.uri = GNUNET_ECRS_keyword_string_to_uri (NULL, "foo");
   fi1.meta = GNUNET_ECRS_meta_data_create ();
   GNUNET_ECRS_meta_data_insert (fi1.meta, EXTRACTOR_MIMETYPE, "foo/bar");
-  fi2.uri = GNUNET_ECRS_keyword_strings_to_uri (k2);
+  fi2.uri = GNUNET_ECRS_keyword_string_to_uri (NULL, "foot");
   fi2.meta = GNUNET_ECRS_meta_data_create ();
   GNUNET_ECRS_meta_data_insert (fi2.meta, EXTRACTOR_MIMETYPE, "foo/bar");
 

Modified: GNUnet/src/applications/tbench/tbenchtest.c
===================================================================
--- GNUnet/src/applications/tbench/tbenchtest.c 2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/tbench/tbenchtest.c 2008-04-24 05:49:31 UTC (rev 
6745)
@@ -157,14 +157,17 @@
   /* 'blast' pass: hit bandwidth limits! */
   for (i = 8; i < 60000; i *= 2)
     {
+      if (GNUNET_shutdown_test() == GNUNET_YES)
+       break;
       if (ret == 0)
         ret =
           test (sock, i, 1 + 1024 / i, 4, 10 * GNUNET_CRON_MILLISECONDS, 2,
                 2 * GNUNET_CRON_SECONDS);
     }
-  ret =
-    test (sock, 32768, 10, 10, 500 * GNUNET_CRON_MILLISECONDS, 1,
-          10 * GNUNET_CRON_SECONDS);
+  if (GNUNET_shutdown_test() != GNUNET_YES)
+    ret =
+      test (sock, 32768, 10, 10, 500 * GNUNET_CRON_MILLISECONDS, 1,
+           10 * GNUNET_CRON_SECONDS);
   GNUNET_client_connection_destroy (sock);
 #if START_PEERS
   GNUNET_TESTING_stop_daemons (peers);

Modified: GNUnet/src/applications/testing/testing.c
===================================================================
--- GNUnet/src/applications/testing/testing.c   2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/applications/testing/testing.c   2008-04-24 05:49:31 UTC (rev 
6745)
@@ -19,7 +19,7 @@
 */
 
 /**
- * @file applications/testing/testingtest.c
+ * @file applications/testing/testing.c
  * @brief testcase for testing library
  * @author Christian Grothoff
  */
@@ -110,9 +110,7 @@
     }
   GNUNET_free (dpath);
   updatePort (cfg, "TCP", tra_offset);
-  updatePort (cfg, "TCP6", tra_offset);
   updatePort (cfg, "UDP", tra_offset);
-  updatePort (cfg, "UDP6", tra_offset);
   updatePort (cfg, "HTTP", tra_offset);
   updatePort (cfg, "SMTP", tra_offset);
   GNUNET_GC_set_configuration_value_string (cfg,

Modified: GNUnet/src/include/gnunet_ecrs_lib.h
===================================================================
--- GNUnet/src/include/gnunet_ecrs_lib.h        2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/include/gnunet_ecrs_lib.h        2008-04-24 05:49:31 UTC (rev 
6745)
@@ -53,9 +53,10 @@
  * 4.0.x: with expiration, variable meta-data, kblocks
  * 4.1.x: with new error and configuration handling
  * 5.0.x: with location URIs
- * 6.x.x: who knows? :-)
+ * 6.0.0: with support for OR in KSKs
+ * 7.0.0: who knows? :-)
  */
-#define GNUNET_ECRS_VERSION "5.1.0"
+#define GNUNET_ECRS_VERSION "6.0.0"
 
 #define GNUNET_DIRECTORY_MIME  "application/gnunet-directory"
 #define GNUNET_DIRECTORY_MAGIC "\211GND\r\n\032\n"
@@ -96,9 +97,14 @@
 
 /**
  * Iterator over keywords
+ *
+ * @param keyword the keyword
+ * @param is_mandatory is the keyword mandatory (in a search)
  * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort
  */
-typedef int (*GNUNET_ECRS_KeywordIterator) (const char *data, void *closure);
+typedef int (*GNUNET_ECRS_KeywordIterator) (const char *keyword, 
+                                           int is_mandatory,
+                                           void *closure);
 
 /**
  * Create a fresh MetaData token.
@@ -294,7 +300,8 @@
                                                          *uri);
 
 /**
- * Iterate over all keywords in this keyword URI?
+ * Iterate over all keywords in this keyword URI.
+ *
  * @return -1 if this is not a keyword URI, otherwise number of
  *   keywords iterated over until iterator aborted
  */
@@ -367,19 +374,19 @@
                                                                    *uri);
 
 /**
- * Convert a NULL-terminated array of keywords
- * to an ECRS URI.
- */
-struct GNUNET_ECRS_URI *GNUNET_ECRS_keyword_strings_to_uri (const char
-                                                            *keyword[]);
-
-/**
  * Create an ECRS URI from a single user-supplied string of keywords.
- * The string may contain the reserved word 'AND' to create a boolean
- * search over multiple keywords.
+ * The string is broken up at spaces into individual keywords.
+ * Keywords that start with "+" are mandatory.  Double-quotes can
+ * be used to prevent breaking up strings at spaces (and also
+ * to specify non-mandatory keywords starting with "+").
  *
+ * Keywords must contain a balanced number of double quotes and
+ * double quotes can not be used in the actual keywords (for
+ * example, the string '""foo bar""' will be turned into two
+ * "OR"ed keywords 'foo' and 'bar', not into '"foo bar"'.
+ * 
  * @return an ECRS URI for the given keywords, NULL
- *  if keywords is not legal (i.e. empty).
+ *  if keywords is not legal (i.e. empty). 
  */
 struct GNUNET_ECRS_URI *GNUNET_ECRS_keyword_string_to_uri (struct
                                                            GNUNET_GE_Context
@@ -389,9 +396,18 @@
 
 /**
  * Create an ECRS URI from a user-supplied command line of keywords.
- * The command line may contain the reserved word 'AND' to create a
- * boolean search over multiple keywords.
+ * Arguments should start with "+" to indicate mandatory
+ * keywords.  
  *
+ * @param argc number of keywords
+ * @param argv keywords (double quotes are not required for
+ *             keywords containing spaces; however, double
+ *             quotes are required for keywords starting with
+ *             "+"); there is no mechanism for having double
+ *             quotes in the actual keywords (if the user
+ *             did specifically specify double quotes, the
+ *             caller should convert each double quote
+ *             into two single quotes).
  * @return an ECRS URI for the given keywords, NULL
  *  if keywords is not legal (i.e. empty).
  */
@@ -405,22 +421,6 @@
                                                                  /* helper.c */
 
 /**
- * Create an ECRS URI from a user-supplied list of keywords.
- * The keywords are NOT separated by AND but already
- * given individually.
- *
- * @return an ECRS URI for the given keywords, NULL
- *  if keywords is not legal (i.e. empty).
- */
-struct GNUNET_ECRS_URI *GNUNET_ECRS_keyword_list_to_uri (struct
-                                                         GNUNET_GE_Context
-                                                         *ectx,
-                                                         unsigned int
-                                                         num_keywords,
-                                                         const char
-                                                         **keywords);
-
-/**
  * Test if two URIs are equal.
  */
 int GNUNET_ECRS_uri_test_equal (const struct GNUNET_ECRS_URI *u1,
@@ -757,8 +757,9 @@
 /**
  * Start search for content (asynchronous version).
  *
- * @param uri specifies the search parameters
- * @param uri set to the URI of the uploaded file
+ * @param uri specifies the search parameters;
+ *        this must be a simple URI (with a single
+ *        keyword)
  */
 struct GNUNET_ECRS_SearchContext *
 GNUNET_ECRS_search_start (struct GNUNET_GE_Context *ectx,

Modified: GNUnet/src/include/gnunet_fsui_lib.h
===================================================================
--- GNUnet/src/include/gnunet_fsui_lib.h        2008-04-24 04:01:46 UTC (rev 
6744)
+++ GNUnet/src/include/gnunet_fsui_lib.h        2008-04-24 05:49:31 UTC (rev 
6745)
@@ -56,17 +56,18 @@
  * may want to open a window informing the user about the pending
  * shutdown operation.<p>
  *
- * Any "startXXX" operation will result in FSUI state and memory
- * being allocated until it is paired with a "stopXXX" operation.
- * Before calling "stopXXX", one of three things must happen:
+ * Any "start" operation will result in FSUI state and memory
+ * being allocated until it is paired with a "stop" operation.
+ * Before calling "stop", one of three things must happen:
  * Either, the client receives an "error" (something went wrong)
  * or "completed" (action finished) event.  Alternatively, the
- * client may call abortXXX" which will result in an "aborted"
+ * client may call "abort" which will result in an "aborted"
  * event.  In either case, the event itself will NOT result in
  * the memory being released by FSUI -- the client must still
- * call "GNUNET_FSUI_stopXXX" explicitly.  Clients that call
- * "GNUNET_FSUI_stopXXX" before an aborted, error or completed event
- * will be blocked until either of the three events happens.<p>
+ * call "stop" explicitly.  Clients that call "stop" before an 
+ * aborted, error or completed event will be blocked until
+ * an error or completion event happens (it is illegal for a
+ * client to call "abort" after calling "stop").<p>
  *
  * Using the Event mechanism, clients can associate an arbitrary
  * pointer with any operation (upload, download, search or
@@ -76,9 +77,6 @@
  * that memory when suspend or stop events are issued.  For all
  * events (other than start/resume), FSUI will track and provide
  * the client pointer as part of the event (cctx field).<p>
- *
- * Note that most of this code is completely new in GNUnet 0.7.0 and
- * thus still highly experimental.  Suggestions are welcome.<p>
  */
 
 #ifndef GNUNET_FSUI_LIB_H
@@ -134,6 +132,7 @@
   GNUNET_FSUI_search_resumed,
   GNUNET_FSUI_search_paused,
   GNUNET_FSUI_search_restarted,
+  GNUNET_FSUI_search_update,
   GNUNET_FSUI_download_started,
   GNUNET_FSUI_download_stopped,
   GNUNET_FSUI_download_progress,
@@ -394,7 +393,40 @@
     } SearchRestarted;
 
 
+    struct
+    {
 
+      GNUNET_FSUI_SearchContext sc;
+
+      /**
+       * File-Info of the data for which we have
+       * updated ranking information.
+       */
+      GNUNET_ECRS_FileInfo fi;
+
+      /**
+       * The URI of the search for which we provide
+       * the updated ranking information.
+       */
+      const struct GNUNET_ECRS_URI *searchURI;
+
+      /**
+       * Updated availability rank (negative: 
+       * unavailable, positive: available)
+       */
+      int availability_rank;
+
+      /**
+       * Updated applicability rank (the larger,
+       * the better the result fits the search
+       * criteria).
+       */
+      unsigned int applicability_rank;
+
+    } SearchUpdate;
+
+
+
     struct
     {
 

Modified: GNUnet/todo
===================================================================
--- GNUnet/todo 2008-04-24 04:01:46 UTC (rev 6744)
+++ GNUnet/todo 2008-04-24 05:49:31 UTC (rev 6745)
@@ -4,14 +4,18 @@
   RC == Release Critical
 
 0.8.0 [4'08] (aka "advanced features"):
-- document gnunet-auto-share on webpage
-- clean up VPN code
+- add code to check that [MODULES] configuration entries are
+  at least superficially valid (matching strings...)
+- document gnunet-auto-share on webpage [RC]
+- clean up and test VPN code [RC]
 - tune GAP query planning code [RC]
 - gnunet-chat (CS-only) [RC]
-- test new asynchronous ECRS API (and resulting FSUI changes);
-  make sure error handling & reporting are nice [RC]
-- test RPC code (write a small demo)
-- make it easier to get your own identity (gnunet-peer-info? gnunet-setup?)
+- test new asynchronous ECRS API (and resulting FSUI changes):
+  * make sure error handling & reporting are nice [RC]
+- make it easier to get your own identity (gnunet-peer-info? gnunet-setup?) 
[RC]
+- google-style search support:
+  * extended FSUI support (test event generation, support for probing 
downloads)
+  * gnunet-gtk and gnunet-qt support (visualization, sorting, event handling)
 
 Hostlist for network testing:
 * http://vserver1236.vserver-on.de/hostlist-074
@@ -25,6 +29,7 @@
 - HTTPS support (#1225)
 - clean up indexing with gnunet-insert (#1107)
 - power insert (#854)
+- test RPC code (write a small demo)
 
 
 1.0.0 (aka "userfriendly"):





reply via email to

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