Support for scanning by CQL query (not yet debugged).
[yaz-moved-to-github.git] / src / zoom-c.c
index 38846b0..7131b41 100644 (file)
@@ -1,13 +1,17 @@
 /*
- * Copyright (c) 2000-2004, Index Data
+ * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: zoom-c.c,v 1.29 2004-08-02 10:06:34 adam Exp $
- *
- * ZOOM layer for C, connections, result sets, queries.
+ * $Id: zoom-c.c,v 1.58 2005-12-20 22:24:05 mike Exp $
+ */
+/**
+ * \file zoom-c.c
+ * \brief Implements ZOOM C interface.
  */
+
 #include <assert.h>
 #include <string.h>
+#include <errno.h>
 #include "zoom-p.h"
 
 #include <yaz/yaz-util.h>
 #include <yaz/charneg.h>
 #include <yaz/ill.h>
 #include <yaz/srw.h>
+#include <yaz/cql.h>
 
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
 #if HAVE_SYS_POLL_H
 #include <sys/poll.h>
 #endif
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef WIN32
+#include <winsock.h>
+#endif
+
+static int log_api = 0;
+static int log_details = 0;
 
 typedef enum {
     zoom_pending,
@@ -32,6 +52,19 @@ typedef enum {
 
 static zoom_ret ZOOM_connection_send_init (ZOOM_connection c);
 static zoom_ret do_write_ex (ZOOM_connection c, char *buf_out, int len_out);
+static char *cql2pqf(ZOOM_connection c, const char *cql);
+
+
+static void initlog()
+{
+    static int log_level_initialized = 0;
+    if (!log_level_initialized)
+    {
+        log_api = yaz_log_module_level("zoom");
+        log_details = yaz_log_module_level("zoomdetails");
+        log_level_initialized = 1;
+    }
+}
 
 static ZOOM_Event ZOOM_Event_create (int kind)
 {
@@ -51,13 +84,13 @@ static void ZOOM_connection_put_event (ZOOM_connection c, ZOOM_Event event)
 {
     if (c->m_queue_back)
     {
-       c->m_queue_back->prev = event;
-       assert (c->m_queue_front);
+        c->m_queue_back->prev = event;
+        assert (c->m_queue_front);
     }
     else
     {
-       assert (!c->m_queue_front);
-       c->m_queue_front = event;
+        assert (!c->m_queue_front);
+        c->m_queue_front = event;
     }
     event->next = c->m_queue_back;
     event->prev = 0;
@@ -70,17 +103,17 @@ static ZOOM_Event ZOOM_connection_get_event(ZOOM_connection c)
     if (!event)
     {
         c->last_event = ZOOM_EVENT_NONE;
-       return 0;
+        return 0;
     }
     assert (c->m_queue_back);
     c->m_queue_front = event->prev;
     if (c->m_queue_front)
     {
-       assert (c->m_queue_back);
-       c->m_queue_front->next = 0;
+        assert (c->m_queue_back);
+        c->m_queue_front->next = 0;
     }
     else
-       c->m_queue_back = 0;
+        c->m_queue_back = 0;
     c->last_event = event->kind;
     return event;
 }
@@ -91,6 +124,7 @@ static void set_dset_error (ZOOM_connection c, int error,
                             const char *addinfo, const char *addinfo2)
 {
     char *cp;
+
     xfree (c->addinfo);
     c->addinfo = 0;
     c->error = error;
@@ -98,21 +132,21 @@ static void set_dset_error (ZOOM_connection c, int error,
     {
         xfree(c->diagset);
         c->diagset = xstrdup(dset);
-       /* remove integer part from SRW diagset .. */
+        /* remove integer part from SRW diagset .. */
         if ((cp = strrchr(c->diagset, '/')))
-          *cp = '\0';
+           *cp = '\0';
     }
     if (addinfo && addinfo2)
     {
-        c->addinfo = xmalloc(strlen(addinfo) + strlen(addinfo2) + 2);
+        c->addinfo = (char*) xmalloc(strlen(addinfo) + strlen(addinfo2) + 2);
         strcpy(c->addinfo, addinfo);
         strcat(c->addinfo, addinfo2);
     }
     else if (addinfo)
         c->addinfo = xstrdup(addinfo);
     if (error)
-        yaz_log(LOG_DEBUG, "Error %s %s:%d %s %s",
-                c->host_port ? c->host_port : "<>", dset, error,
+        yaz_log(log_api, "%p set_dset_error %s %s:%d %s %s",
+                c, c->host_port ? c->host_port : "<>", dset, error,
                 addinfo ? addinfo : "",
                 addinfo2 ? addinfo2 : "");
 }
@@ -126,7 +160,7 @@ static void set_HTTP_error (ZOOM_connection c, int error,
 #endif
 
 static void set_ZOOM_error (ZOOM_connection c, int error,
-                           const char *addinfo)
+                            const char *addinfo)
 {
     set_dset_error(c, error, "ZOOM", addinfo, 0);
 }
@@ -153,7 +187,7 @@ ZOOM_task ZOOM_connection_add_task (ZOOM_connection c, int which)
 {
     ZOOM_task *taskp = &c->tasks;
     while (*taskp)
-       taskp = &(*taskp)->next;
+        taskp = &(*taskp)->next;
     *taskp = (ZOOM_task) xmalloc (sizeof(**taskp));
     (*taskp)->running = 0;
     (*taskp)->which = which;
@@ -181,15 +215,15 @@ void ZOOM_connection_remove_task (ZOOM_connection c)
 
     if (task)
     {
-       c->tasks = task->next;
-       switch (task->which)
-       {
-       case ZOOM_TASK_SEARCH:
-           ZOOM_resultset_destroy (task->u.search.resultset);
-           break;
-       case ZOOM_TASK_RETRIEVE:
-           ZOOM_resultset_destroy (task->u.retrieve.resultset);
-           break;
+        c->tasks = task->next;
+        switch (task->which)
+        {
+        case ZOOM_TASK_SEARCH:
+            ZOOM_resultset_destroy (task->u.search.resultset);
+            break;
+        case ZOOM_TASK_RETRIEVE:
+            ZOOM_resultset_destroy (task->u.retrieve.resultset);
+            break;
         case ZOOM_TASK_CONNECT:
             break;
         case ZOOM_TASK_SCAN:
@@ -198,14 +232,14 @@ void ZOOM_connection_remove_task (ZOOM_connection c)
         case ZOOM_TASK_PACKAGE:
             ZOOM_package_destroy (task->u.package);
             break;
-       case ZOOM_TASK_SORT:
-           ZOOM_resultset_destroy (task->u.sort.resultset);
-           ZOOM_query_destroy(task->u.sort.q);
-           break;
-       default:
-           assert (0);
-       }
-       xfree (task);
+        case ZOOM_TASK_SORT:
+            ZOOM_resultset_destroy (task->u.sort.resultset);
+            ZOOM_query_destroy(task->u.sort.q);
+            break;
+        default:
+            assert (0);
+        }
+        xfree (task);
     }
 }
 
@@ -214,7 +248,7 @@ static int ZOOM_connection_exec_task (ZOOM_connection c);
 void ZOOM_connection_remove_tasks (ZOOM_connection c)
 {
     while (c->tasks)
-       ZOOM_connection_remove_task(c);
+        ZOOM_connection_remove_task(c);
 }
 
 static ZOOM_record record_cache_lookup (ZOOM_resultset r, int pos);
@@ -224,6 +258,10 @@ ZOOM_connection_create (ZOOM_options options)
 {
     ZOOM_connection c = (ZOOM_connection) xmalloc (sizeof(*c));
 
+    initlog();
+
+    yaz_log(log_api, "%p ZOOM_connection_create", c);
+
     c->proto = PROTO_Z3950;
     c->cs = 0;
     c->mask = 0;
@@ -269,54 +307,20 @@ static char **set_DatabaseNames (ZOOM_connection con, ZOOM_options options,
                                  int *num)
 {
     char **databaseNames;
-    const char *c;
-    int no = 2;
     const char *cp = ZOOM_options_get (options, "databaseName");
     
     if (!cp || !*cp)
     {
         if (strncmp (con->host_port, "unix:", 5) == 0)
-           cp = strchr (con->host_port+5, ':');
-       else
-           cp = strchr (con->host_port, '/');
-       if (cp)
-           cp++;
-    }
-    if (cp)
-    {
-       c = cp;
-       while ((c = strchr(c, '+')))
-       {
-           c++;
-           no++;
-       }
+            cp = strchr(con->host_port+5, ':');
+        else
+            cp = strchr(con->host_port, '/');
+        if (cp)
+            cp++;
     }
-    else
-       cp = "Default";
-    databaseNames = (char**)
-        odr_malloc (con->odr_out, no * sizeof(*databaseNames));
-    no = 0;
-    while (*cp)
-    {
-       c = strchr (cp, '+');
-       if (!c)
-           c = cp + strlen(cp);
-       else if (c == cp)
-       {
-           cp++;
-           continue;
-       }
-       /* cp ptr to first char of db name, c is char
-          following db name */
-       databaseNames[no] = (char*) odr_malloc (con->odr_out, 1+c-cp);
-       memcpy (databaseNames[no], cp, c-cp);
-       databaseNames[no++][c-cp] = '\0';
-       cp = c;
-       if (*cp)
-           cp++;
-    }
-    databaseNames[no] = NULL;
-    *num = no;
+    if (!cp)
+        cp = "Default";
+    nmem_strsplit(con->odr_out->mem, "+", cp,  &databaseNames, num);
     return databaseNames;
 }
 
@@ -336,55 +340,108 @@ ZOOM_connection_connect(ZOOM_connection c,
     const char *val;
     ZOOM_task task;
 
+    initlog();
+
+    yaz_log(log_api, "%p ZOOM_connection_connect host=%s portnum=%d",
+            c, host, portnum);
+
     if (c->cs)
     {
-        yaz_log (LOG_DEBUG, "reconnect");
+        yaz_log(log_details, "%p ZOOM_connection_connect reconnect ok", c);
         c->reconnect_ok = 1;
         return;
     }
-    yaz_log(LOG_DEBUG, "connect");
+    yaz_log(log_details, "%p ZOOM_connection_connect connect", c);
     xfree (c->proxy);
     val = ZOOM_options_get (c->options, "proxy");
     if (val && *val)
-       c->proxy = xstrdup (val);
+    {
+        yaz_log(log_details, "%p ZOOM_connection_connect proxy=%s", c, val);
+        c->proxy = xstrdup (val);
+    }
     else
-       c->proxy = 0;
+        c->proxy = 0;
 
     xfree (c->charset);
     val = ZOOM_options_get (c->options, "charset");
     if (val && *val)
-       c->charset = xstrdup (val);
+    {
+        yaz_log(log_details, "%p ZOOM_connection_connect charset=%s", c, val);
+        c->charset = xstrdup (val);
+    }
     else
-       c->charset = 0;
+        c->charset = 0;
 
     xfree (c->lang);
     val = ZOOM_options_get (c->options, "lang");
     if (val && *val)
-       c->lang = xstrdup (val);
+    {
+        yaz_log(log_details, "%p ZOOM_connection_connect lang=%s", c, val);
+        c->lang = xstrdup (val);
+    }
     else
-       c->lang = 0;
+        c->lang = 0;
 
     xfree (c->host_port);
     if (portnum)
     {
-       char hostn[128];
-       sprintf (hostn, "%.80s:%d", host, portnum);
-       c->host_port = xstrdup(hostn);
+        char hostn[128];
+        sprintf (hostn, "%.80s:%d", host, portnum);
+        c->host_port = xstrdup(hostn);
     }
     else
-       c->host_port = xstrdup(host);
+        c->host_port = xstrdup(host);
+
+    {
+        /*
+         * If the "<scheme>:" part of the host string is preceded by one
+         * or more comma-separated <name>=<value> pairs, these are taken
+         * to be options to be set on the connection object.  Among other
+         * applications, this facility can be used to embed authentication
+         * in a host string:
+         *          user=admin,password=secret,tcp:localhost:9999
+         */
+        char *remainder = c->host_port;
+        char *pcolon = strchr(remainder, ':');
+        char *pcomma;
+        char *pequals;
+        while ((pcomma = strchr(remainder, ',')) != 0 &&
+               (pcolon == 0 || pcomma < pcolon)) {
+            *pcomma = '\0';
+            if ((pequals = strchr(remainder, '=')) != 0) {
+                *pequals = '\0';
+                /*printf("# setting '%s'='%s'\n", remainder, pequals+1);*/
+                ZOOM_connection_option_set(c, remainder, pequals+1);
+            }
+            remainder = pcomma+1;
+        }
+
+        if (remainder != c->host_port) {
+            xfree(c->host_port);
+            c->host_port = xstrdup(remainder);
+            /*printf("# reset hp='%s'\n", remainder);*/
+        }
+    }
 
     ZOOM_options_set(c->options, "host", c->host_port);
 
     val = ZOOM_options_get (c->options, "cookie");
     if (val && *val)
+    { 
+        yaz_log(log_details, "%p ZOOM_connection_connect cookie=%s", c, val);
         c->cookie_out = xstrdup (val);
+    }
 
     val = ZOOM_options_get (c->options, "clientIP");
     if (val && *val)
+    {
+        yaz_log(log_details, "%p ZOOM_connection_connect clientIP=%s",
+                c, val);
         c->client_IP = xstrdup (val);
+    }
 
     c->async = ZOOM_options_get_bool (c->options, "async", 0);
+    yaz_log(log_details, "%p ZOOM_connection_connect async=%d", c, c->async);
  
     set_ZOOM_error(c, ZOOM_ERROR_NONE, 0);
 
@@ -392,8 +449,8 @@ ZOOM_connection_connect(ZOOM_connection c,
 
     if (!c->async)
     {
-       while (ZOOM_event (1, &c))
-           ;
+        while (ZOOM_event (1, &c))
+            ;
     }
 }
 
@@ -402,6 +459,7 @@ ZOOM_query_create(void)
 {
     ZOOM_query s = (ZOOM_query) xmalloc (sizeof(*s));
 
+    yaz_log(log_details, "%p ZOOM_query_create", s);
     s->refcount = 1;
     s->z_query = 0;
     s->sort_spec = 0;
@@ -415,14 +473,14 @@ ZOOM_API(void)
 ZOOM_query_destroy(ZOOM_query s)
 {
     if (!s)
-       return;
+        return;
 
     (s->refcount)--;
-    yaz_log (LOG_DEBUG, "ZOOM_query_destroy count=%d", s->refcount);
+    yaz_log(log_details, "%p ZOOM_query_destroy count=%d", s, s->refcount);
     if (s->refcount == 0)
     {
-       odr_destroy (s->odr);
-       xfree (s);
+        odr_destroy (s->odr);
+        xfree (s);
     }
 }
 
@@ -435,9 +493,11 @@ ZOOM_query_prefix(ZOOM_query s, const char *str)
     s->z_query->u.type_1 =  p_query_rpn(s->odr, PROTO_Z3950, str);
     if (!s->z_query->u.type_1)
     {
-       s->z_query = 0;
-       return -1;
+        yaz_log(log_details, "%p ZOOM_query_prefix str=%s failed", s, str);
+        s->z_query = 0;
+        return -1;
     }
+    yaz_log(log_details, "%p ZOOM_query_prefix str=%s", s, str);
     return 0;
 }
 
@@ -459,6 +519,8 @@ ZOOM_query_cql(ZOOM_query s, const char *str)
     s->z_query->which = Z_Query_type_104;
     s->z_query->u.type_104 =  ext;
 
+    yaz_log(log_details, "%p ZOOM_query_cql str=%s", s, str);
+
     return 0;
 }
 
@@ -467,7 +529,12 @@ ZOOM_query_sortby(ZOOM_query s, const char *criteria)
 {
     s->sort_spec = yaz_sort_spec (s->odr, criteria);
     if (!s->sort_spec)
-       return -1;
+    {
+        yaz_log(log_details, "%p ZOOM_query_sortby criteria=%s failed",
+                s, criteria);
+        return -1;
+    }
+    yaz_log(log_details, "%p ZOOM_query_sortby criteria=%s", s, criteria);
     return 0;
 }
 
@@ -478,11 +545,12 @@ ZOOM_connection_destroy(ZOOM_connection c)
 {
     ZOOM_resultset r;
     if (!c)
-       return;
+        return;
+    yaz_log(log_api, "%p ZOOM_connection_destroy", c);
     if (c->cs)
-       cs_close (c->cs);
+        cs_close (c->cs);
     for (r = c->resultsets; r; r = r->next)
-       r->connection = 0;
+        r->connection = 0;
 
     xfree (c->buf_in);
     xfree (c->addinfo);
@@ -506,9 +574,9 @@ void ZOOM_resultset_addref (ZOOM_resultset r)
 {
     if (r)
     {
-       (r->refcount)++;
-        yaz_log (LOG_DEBUG, "ZOOM_resultset_addref r=%p count=%d",
-                 r, r->refcount);
+        (r->refcount)++;
+        yaz_log(log_details, "%p ZOOM_resultset_addref count=%d",
+                r, r->refcount);
     }
 }
 
@@ -516,7 +584,9 @@ ZOOM_resultset ZOOM_resultset_create ()
 {
     ZOOM_resultset r = (ZOOM_resultset) xmalloc (sizeof(*r));
 
-    yaz_log (LOG_DEBUG, "ZOOM_resultset_create r = %p", r);
+    initlog();
+
+    yaz_log(log_details, "%p ZOOM_resultset_create", r);
     r->refcount = 1;
     r->size = 0;
     r->odr = odr_createmem (ODR_ENCODE);
@@ -554,6 +624,7 @@ ZOOM_connection_search(ZOOM_connection c, ZOOM_query q)
     ZOOM_task task;
     const char *cp;
 
+    yaz_log(log_api, "%p ZOOM_connection_search set %p query %p", c, r, q);
     r->r_sort_spec = q->sort_spec;
     r->query = q;
 
@@ -562,10 +633,10 @@ ZOOM_connection_search(ZOOM_connection c, ZOOM_query q)
     r->start = ZOOM_options_get_int(r->options, "start", 0);
     r->count = ZOOM_options_get_int(r->options, "count", 0);
     {
-       /* If "presentChunk" is defined use that; otherwise "step" */
-       const char *cp = ZOOM_options_get (r->options, "presentChunk");
-       r->step = ZOOM_options_get_int(r->options,
-                                      (cp != 0 ? "presentChunk": "step"), 0);
+        /* If "presentChunk" is defined use that; otherwise "step" */
+        const char *cp = ZOOM_options_get (r->options, "presentChunk");
+        r->step = ZOOM_options_get_int(r->options,
+                                       (cp != 0 ? "presentChunk": "step"), 0);
     }
     r->piggyback = ZOOM_options_get_bool (r->options, "piggyback", 1);
     cp = ZOOM_options_get (r->options, "setname");
@@ -584,12 +655,12 @@ ZOOM_connection_search(ZOOM_connection c, ZOOM_query q)
     {
         if (!c->cs)
         {
-            yaz_log(LOG_DEBUG, "NO COMSTACK");
+            yaz_log(log_details, "ZOOM_connection_search: no comstack");
             ZOOM_connection_add_task(c, ZOOM_TASK_CONNECT);
         }
         else
         {
-            yaz_log(LOG_DEBUG, "PREPARE FOR RECONNECT");
+            yaz_log(log_details, "ZOOM_connection_search: reconnect");
             c->reconnect_ok = 1;
         }
     }
@@ -602,32 +673,52 @@ ZOOM_connection_search(ZOOM_connection c, ZOOM_query q)
 
     if (!c->async)
     {
-       while (ZOOM_event (1, &c))
-           ;
+        while (ZOOM_event (1, &c))
+            ;
     }
     return r;
 }
 
+/*
+ * This is the old result-set sorting API, which is maintained only
+ * for the sake of binary compatibility.  There is no reason ever to
+ * use this rather than ZOOM_resultset_sort1().
+ */
 ZOOM_API(void)
-    ZOOM_resultset_sort(ZOOM_resultset r,
-                       const char *sort_type, const char *sort_spec)
+ZOOM_resultset_sort(ZOOM_resultset r,
+                    const char *sort_type, const char *sort_spec)
+{
+    (void) ZOOM_resultset_sort1(r, sort_type, sort_spec);
+}
+
+ZOOM_API(int)
+ZOOM_resultset_sort1(ZOOM_resultset r,
+                     const char *sort_type, const char *sort_spec)
 {
     ZOOM_connection c = r->connection;
     ZOOM_task task;
+    ZOOM_query newq;
 
+    newq = ZOOM_query_create();
+    if (ZOOM_query_sortby(newq, sort_spec) < 0)
+        return -1;
+
+    yaz_log(log_api, "%p ZOOM_resultset_sort r=%p sort_type=%s sort_spec=%s",
+            r, r, sort_type, sort_spec);
     if (!c)
-       return;
+        return 0;
 
     if (c->host_port && c->proto == PROTO_HTTP)
     {
         if (!c->cs)
         {
-            yaz_log(LOG_DEBUG, "NO COMSTACK");
+            yaz_log(log_details, "%p ZOOM_resultset_sort: no comstack", r);
             ZOOM_connection_add_task(c, ZOOM_TASK_CONNECT);
         }
         else
         {
-            yaz_log(LOG_DEBUG, "PREPARE FOR RECONNECT");
+            yaz_log(log_details, "%p ZOOM_resultset_sort: prepare reconnect",
+                    r);
             c->reconnect_ok = 1;
         }
     }
@@ -635,16 +726,17 @@ ZOOM_API(void)
     ZOOM_resultset_cache_reset(r);
     task = ZOOM_connection_add_task (c, ZOOM_TASK_SORT);
     task->u.sort.resultset = r;
-    task->u.sort.q = ZOOM_query_create();
-    ZOOM_query_sortby(task->u.sort.q, sort_spec);
+    task->u.sort.q = newq;
 
     ZOOM_resultset_addref (r);  
 
     if (!c->async)
     {
-       while (ZOOM_event (1, &c))
-           ;
+        while (ZOOM_event (1, &c))
+            ;
     }
+
+    return 0;
 }
 
 ZOOM_API(void)
@@ -654,12 +746,12 @@ ZOOM_API(void)
     
     for (rc = r->record_cache; rc; rc = rc->next)
     {
-       if (rc->rec.wrbuf_marc)
-           wrbuf_free (rc->rec.wrbuf_marc, 1);
-       if (rc->rec.wrbuf_iconv)
-           wrbuf_free (rc->rec.wrbuf_iconv, 1);
-       if (rc->rec.wrbuf_opac)
-           wrbuf_free (rc->rec.wrbuf_opac, 1);
+        if (rc->rec.wrbuf_marc)
+            wrbuf_free (rc->rec.wrbuf_marc, 1);
+        if (rc->rec.wrbuf_iconv)
+            wrbuf_free (rc->rec.wrbuf_iconv, 1);
+        if (rc->rec.wrbuf_opac)
+            wrbuf_free (rc->rec.wrbuf_opac, 1);
     }
     r->record_cache = 0;
 }
@@ -670,33 +762,33 @@ ZOOM_resultset_destroy(ZOOM_resultset r)
     if (!r)
         return;
     (r->refcount)--;
-    yaz_log (LOG_DEBUG, "ZOOM_resultset_destroy r = %p count=%d",
-             r, r->refcount);
+    yaz_log(log_details, "%p ZOOM_resultset_destroy r=%p count=%d",
+            r, r, r->refcount);
     if (r->refcount == 0)
     {
-       ZOOM_resultset_cache_reset(r);
-
-       if (r->connection)
-       {
-           /* remove ourselves from the resultsets in connection */
-           ZOOM_resultset *rp = &r->connection->resultsets;
-           while (1)
-           {
-               assert (*rp);   /* we must be in this list!! */
-               if (*rp == r)
-               {   /* OK, we're here - take us out of it */
-                   *rp = (*rp)->next;
-                   break;
-               }
-               rp = &(*rp)->next;
-           }
-       }
-       ZOOM_query_destroy (r->query);
-       ZOOM_options_destroy (r->options);
-       odr_destroy (r->odr);
+        ZOOM_resultset_cache_reset(r);
+
+        if (r->connection)
+        {
+            /* remove ourselves from the resultsets in connection */
+            ZOOM_resultset *rp = &r->connection->resultsets;
+            while (1)
+            {
+                assert (*rp);   /* we must be in this list!! */
+                if (*rp == r)
+                {   /* OK, we're here - take us out of it */
+                    *rp = (*rp)->next;
+                    break;
+                }
+                rp = &(*rp)->next;
+            }
+        }
+        ZOOM_query_destroy (r->query);
+        ZOOM_options_destroy (r->options);
+        odr_destroy (r->odr);
         xfree (r->setname);
         xfree (r->schema);
-       xfree (r);
+        xfree (r);
     }
 }
 
@@ -709,7 +801,7 @@ ZOOM_resultset_size (ZOOM_resultset r)
 static void do_close (ZOOM_connection c)
 {
     if (c->cs)
-       cs_close(c->cs);
+        cs_close(c->cs);
     c->cs = 0;
     c->mask = 0;
     c->state = STATE_IDLE;
@@ -723,21 +815,24 @@ static void ZOOM_resultset_retrieve (ZOOM_resultset r,
     const char *cp;
 
     if (!r)
-       return;
+        return;
+    yaz_log(log_details, "%p ZOOM_resultset_retrieve force_sync=%d start=%d"
+            " count=%d", r, force_sync, start, count);
     c = r->connection;
     if (!c)
-       return;
+        return;
 
     if (c->host_port && c->proto == PROTO_HTTP)
     {
         if (!c->cs)
         {
-            yaz_log(LOG_DEBUG, "NO COMSTACK");
+            yaz_log(log_details, "%p ZOOM_resultset_retrieve: no comstack", r);
             ZOOM_connection_add_task(c, ZOOM_TASK_CONNECT);
         }
         else
         {
-            yaz_log(LOG_DEBUG, "PREPARE FOR RECONNECT");
+            yaz_log(log_details, "%p ZOOM_resultset_retrieve: prepare "
+                    "reconnect", r);
             c->reconnect_ok = 1;
         }
     }
@@ -759,8 +854,8 @@ static void ZOOM_resultset_retrieve (ZOOM_resultset r,
     ZOOM_resultset_addref (r);
 
     if (!r->connection->async || force_sync)
-       while (r->connection && ZOOM_event (1, &r->connection))
-           ;
+        while (r->connection && ZOOM_event (1, &r->connection))
+            ;
 }
 
 ZOOM_API(void)
@@ -770,7 +865,9 @@ ZOOM_resultset_records (ZOOM_resultset r, ZOOM_record *recs,
     int force_present = 0;
 
     if (!r)
-       return ;
+        return ;
+    yaz_log(log_api, "%p ZOOM_resultset_records r=%p start=%d count=%d",
+            r, r, start, count);
     if (count && recs)
         force_present = 1;
     ZOOM_resultset_retrieve (r, force_present, start, count);
@@ -790,8 +887,8 @@ static void get_cert(ZOOM_connection c)
     if (cs_get_peer_certificate_x509(c->cs, &cert_buf, &cert_len))
     {
         ZOOM_connection_option_setl(c, "sslPeerCert",
-                                   cert_buf, cert_len);
-       xfree(cert_buf);
+                                    cert_buf, cert_len);
+        xfree(cert_buf);
     }
 }
 
@@ -801,14 +898,14 @@ static zoom_ret do_connect (ZOOM_connection c)
     const char *effective_host;
 
     if (c->proxy)
-       effective_host = c->proxy;
+        effective_host = c->proxy;
     else
-       effective_host = c->host_port;
+        effective_host = c->host_port;
 
-    yaz_log (LOG_DEBUG, "do_connect host=%s", effective_host);
+    yaz_log(log_details, "%p do_connect effective_host=%s", c, effective_host);
 
     if (c->cs)
-       cs_close(c->cs);
+        cs_close(c->cs);
     c->cs = cs_create_host (effective_host, 0, &add);
 
     if (c->cs && c->cs->protocol == PROTO_HTTP)
@@ -819,7 +916,7 @@ static zoom_ret do_connect (ZOOM_connection c)
         c->proto = PROTO_HTTP;
         cs_get_host_args(c->host_port, &path);
         xfree(c->path);
-        c->path = xmalloc(strlen(path)+2);
+        c->path = (char*) xmalloc(strlen(path)+2);
         c->path[0] = '/';
         strcpy (c->path+1, path);
 #else
@@ -835,7 +932,7 @@ static zoom_ret do_connect (ZOOM_connection c)
         {
             ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_CONNECT);
             ZOOM_connection_put_event(c, event);
-           get_cert(c);
+            get_cert(c);
             if (c->proto == PROTO_Z3950)
                 ZOOM_connection_send_init(c);
             else
@@ -861,21 +958,21 @@ static zoom_ret do_connect (ZOOM_connection c)
         }
     }
     c->state = STATE_IDLE;
-    set_ZOOM_error(c, ZOOM_ERROR_CONNECT, effective_host);
+    set_ZOOM_error(c, ZOOM_ERROR_CONNECT, c->host_port);
     return zoom_complete;
 }
 
 int z3950_connection_socket(ZOOM_connection c)
 {
     if (c->cs)
-       return cs_fileno(c->cs);
+        return cs_fileno(c->cs);
     return -1;
 }
 
 int z3950_connection_mask(ZOOM_connection c)
 {
     if (c->cs)
-       return c->mask;
+        return c->mask;
     return 0;
 }
 
@@ -885,7 +982,7 @@ static void otherInfo_attach (ZOOM_connection c, Z_APDU *a, ODR out)
     for (i = 0; i<200; i++)
     {
         size_t len;
-       Z_OtherInformation **oi;
+        Z_OtherInformation **oi;
         char buf[80];
         const char *val;
         const char *cp;
@@ -895,7 +992,7 @@ static void otherInfo_attach (ZOOM_connection c, Z_APDU *a, ODR out)
         val = ZOOM_options_get (c->options, buf);
         if (!val)
             break;
-        cp = strchr (val, ':');
+        cp = strchr(val, ':');
         if (!cp)
             continue;
         len = cp - val;
@@ -907,8 +1004,8 @@ static void otherInfo_attach (ZOOM_connection c, Z_APDU *a, ODR out)
         if (oidval == VAL_NONE)
             continue;
         
-       yaz_oi_APDU(a, &oi);
-       yaz_oi_set_string_oidval(oi, out, oidval, 1, cp+1);
+        yaz_oi_APDU(a, &oi);
+        yaz_oi_set_string_oidval(oi, out, oidval, 1, cp+1);
     }
 }
 
@@ -917,34 +1014,34 @@ static int encode_APDU(ZOOM_connection c, Z_APDU *a, ODR out)
     assert (a);
     if (c->cookie_out)
     {
-       Z_OtherInformation **oi;
-       yaz_oi_APDU(a, &oi);
-       yaz_oi_set_string_oidval(oi, out, VAL_COOKIE, 1, c->cookie_out);
+        Z_OtherInformation **oi;
+        yaz_oi_APDU(a, &oi);
+        yaz_oi_set_string_oidval(oi, out, VAL_COOKIE, 1, c->cookie_out);
     }
     if (c->client_IP)
     {
-       Z_OtherInformation **oi;
-       yaz_oi_APDU(a, &oi);
-       yaz_oi_set_string_oidval(oi, out, VAL_CLIENT_IP, 1, c->client_IP);
+        Z_OtherInformation **oi;
+        yaz_oi_APDU(a, &oi);
+        yaz_oi_set_string_oidval(oi, out, VAL_CLIENT_IP, 1, c->client_IP);
     }
     otherInfo_attach (c, a, out);
     if (!z_APDU(out, &a, 0, 0))
     {
-       FILE *outf = fopen("/tmp/apdu.txt", "a");
-       if (a && outf)
-       {
-           ODR odr_pr = odr_createmem(ODR_PRINT);
-           fprintf (outf, "a=%p\n", a);
-           odr_setprint(odr_pr, outf);
-           z_APDU(odr_pr, &a, 0, 0);
-           odr_destroy(odr_pr);
-       }
-        yaz_log (LOG_DEBUG, "encoding failed");
+        FILE *outf = fopen("/tmp/apdu.txt", "a");
+        if (a && outf)
+        {
+            ODR odr_pr = odr_createmem(ODR_PRINT);
+            fprintf (outf, "a=%p\n", a);
+            odr_setprint(odr_pr, outf);
+            z_APDU(odr_pr, &a, 0, 0);
+            odr_destroy(odr_pr);
+        }
+        yaz_log(log_api, "%p encoding_APDU: encoding failed", c);
         set_ZOOM_error(c, ZOOM_ERROR_ENCODE, 0);
-       odr_reset(out);
-       return -1;
+        odr_reset(out);
+        return -1;
     }
-    
+    yaz_log(log_details, "%p encoding_APDU encoding OK", c);
     return 0;
 }
 
@@ -953,8 +1050,8 @@ static zoom_ret send_APDU (ZOOM_connection c, Z_APDU *a)
     ZOOM_Event event;
     assert (a);
     if (encode_APDU(c, a, c->odr_out))
-       return zoom_complete;
-    yaz_log(LOG_DEBUG, "send APDU type=%d", a->which);
+        return zoom_complete;
+    yaz_log(log_details, "%p send APDU type=%d", c, a->which);
     c->buf_out = odr_getbuf(c->odr_out, &c->len_out, 0);
     event = ZOOM_Event_create (ZOOM_EVENT_SEND_APDU);
     ZOOM_connection_put_event (c, event);
@@ -979,8 +1076,8 @@ static zoom_ret ZOOM_connection_send_init (ZOOM_connection c)
 
     /* support the pass for backwards compatibility */
     if (!auth_password)
-       auth_password = ZOOM_options_get (c->options, "pass");
-       
+        auth_password = ZOOM_options_get (c->options, "pass");
+        
     ODR_MASK_SET(ireq->options, Z_Options_search);
     ODR_MASK_SET(ireq->options, Z_Options_present);
     ODR_MASK_SET(ireq->options, Z_Options_scan);
@@ -994,89 +1091,101 @@ static zoom_ret ZOOM_connection_send_init (ZOOM_connection c)
 
     /* Index Data's Z39.50 Implementor Id is 81 */
     ireq->implementationId = odr_prepend(c->odr_out,
-       ZOOM_options_get(c->options, "implementationId"),
-       odr_prepend(c->odr_out, "81", ireq->implementationId));
+        ZOOM_options_get(c->options, "implementationId"),
+        odr_prepend(c->odr_out, "81", ireq->implementationId));
 
     ireq->implementationName = odr_prepend(c->odr_out,
-       ZOOM_options_get(c->options, "implementationName"),
-       odr_prepend(c->odr_out, "ZOOM-C", ireq->implementationName));
+        ZOOM_options_get(c->options, "implementationName"),
+        odr_prepend(c->odr_out, "ZOOM-C", ireq->implementationName));
 
-    version = odr_strdup(c->odr_out, "$Revision: 1.29 $");
-    if (strlen(version) > 10)  /* check for unexpanded CVS strings */
-       version[strlen(version)-2] = '\0';
+    version = odr_strdup(c->odr_out, "$Revision: 1.58 $");
+    if (strlen(version) > 10)   /* check for unexpanded CVS strings */
+        version[strlen(version)-2] = '\0';
     ireq->implementationVersion = odr_prepend(c->odr_out,
-       ZOOM_options_get(c->options, "implementationVersion"),
-       odr_prepend(c->odr_out, &version[11], ireq->implementationVersion));
+        ZOOM_options_get(c->options, "implementationVersion"),
+        odr_prepend(c->odr_out, &version[11], ireq->implementationVersion));
 
     *ireq->maximumRecordSize =
-       ZOOM_options_get_int (c->options, "maximumRecordSize", 1024*1024);
+        ZOOM_options_get_int (c->options, "maximumRecordSize", 1024*1024);
     *ireq->preferredMessageSize =
-       ZOOM_options_get_int (c->options, "preferredMessageSize", 1024*1024);
+        ZOOM_options_get_int (c->options, "preferredMessageSize", 1024*1024);
     
     if (auth_groupId || auth_password)
     {
-       Z_IdPass *pass = (Z_IdPass *) odr_malloc(c->odr_out, sizeof(*pass));
-       int i = 0;
-       pass->groupId = 0;
-       if (auth_groupId && *auth_groupId)
-       {
-           pass->groupId = (char *)
+        Z_IdPass *pass = (Z_IdPass *) odr_malloc(c->odr_out, sizeof(*pass));
+        int i = 0;
+        pass->groupId = 0;
+        if (auth_groupId && *auth_groupId)
+        {
+            pass->groupId = (char *)
                 odr_malloc(c->odr_out, strlen(auth_groupId)+1);
-           strcpy(pass->groupId, auth_groupId);
-           i++;
-       }
-       pass->userId = 0;
-       if (auth_userId && *auth_userId)
-       {
-           pass->userId = (char *)
+            strcpy(pass->groupId, auth_groupId);
+            i++;
+        }
+        pass->userId = 0;
+        if (auth_userId && *auth_userId)
+        {
+            pass->userId = (char *)
                 odr_malloc(c->odr_out, strlen(auth_userId)+1);
-           strcpy(pass->userId, auth_userId);
-           i++;
-       }
-       pass->password = 0;
-       if (auth_password && *auth_password)
-       {
-           pass->password = (char *)
+            strcpy(pass->userId, auth_userId);
+            i++;
+        }
+        pass->password = 0;
+        if (auth_password && *auth_password)
+        {
+            pass->password = (char *)
                 odr_malloc(c->odr_out, strlen(auth_password)+1);
-           strcpy(pass->password, auth_password);
-           i++;
-       }
-       if (i)
-       {
-           auth->which = Z_IdAuthentication_idPass;
-           auth->u.idPass = pass;
-           ireq->idAuthentication = auth;
-       }
+            strcpy(pass->password, auth_password);
+            i++;
+        }
+        if (i)
+        {
+            auth->which = Z_IdAuthentication_idPass;
+            auth->u.idPass = pass;
+            ireq->idAuthentication = auth;
+        }
     }
     else if (auth_userId)
     {
-       auth->which = Z_IdAuthentication_open;
-       auth->u.open = (char *)
+        auth->which = Z_IdAuthentication_open;
+        auth->u.open = (char *)
             odr_malloc(c->odr_out, strlen(auth_userId)+1);
-       strcpy(auth->u.open, auth_userId);
-       ireq->idAuthentication = auth;
+        strcpy(auth->u.open, auth_userId);
+        ireq->idAuthentication = auth;
     }
     if (c->proxy)
-       yaz_oi_set_string_oidval(&ireq->otherInfo, c->odr_out,
-                                VAL_PROXY, 1, c->host_port);
-    if (c->charset||c->lang)
-    {
-       Z_OtherInformation **oi;
-       Z_OtherInformationUnit *oi_unit;
-       
-       yaz_oi_APDU(apdu, &oi);
-       
-       if ((oi_unit = yaz_oi_update(oi, c->odr_out, NULL, 0, 0)))
-       {
+        yaz_oi_set_string_oidval(&ireq->otherInfo, c->odr_out,
+                                 VAL_PROXY, 1, c->host_port);
+    if (c->charset || c->lang)
+    {
+        Z_OtherInformation **oi;
+        Z_OtherInformationUnit *oi_unit;
+        
+        yaz_oi_APDU(apdu, &oi);
+        
+        if ((oi_unit = yaz_oi_update(oi, c->odr_out, NULL, 0, 0)))
+        {
+            char **charsets_addresses = 0;
+            char **langs_addresses = 0;
+            int charsets_count = 0;
+            int langs_count = 0;
+           
+            if (c->charset)
+                nmem_strsplit_blank(c->odr_out->mem, c->charset,
+                                    &charsets_addresses, &charsets_count);
+            if (c->lang)
+                nmem_strsplit_blank(c->odr_out->mem, c->lang,
+                                    &langs_addresses, &langs_count);
             ODR_MASK_SET(ireq->options, Z_Options_negotiationModel);
-            
             oi_unit->which = Z_OtherInfo_externallyDefinedInfo;
             oi_unit->information.externallyDefinedInfo =
-                yaz_set_proposal_charneg
-                (c->odr_out,
-                 (const char **)&c->charset, (c->charset) ? 1:0,
-                 (const char **)&c->lang, (c->lang) ? 1:0, 1);
-       }
+                yaz_set_proposal_charneg(c->odr_out,
+                                         (const char **) charsets_addresses,
+                                         charsets_count,
+                                         (const char **) langs_addresses,
+                                         langs_count, 
+                                         1);
+        }
     }
     assert (apdu);
     return send_APDU (c, apdu);
@@ -1092,7 +1201,7 @@ static zoom_ret send_srw (ZOOM_connection c, Z_SRW_PDU *sr)
     };
     ODR o = odr_createmem(ODR_ENCODE);
     int ret;
-    Z_SOAP *p = odr_malloc(o, sizeof(*p));
+    Z_SOAP *p = (Z_SOAP*) odr_malloc(o, sizeof(*p));
     Z_GDU *gdu;
     ZOOM_Event event;
 
@@ -1114,7 +1223,7 @@ static zoom_ret send_srw (ZOOM_connection c, Z_SRW_PDU *sr)
 
         if (cp0 && cp1)
         {
-            char *h = odr_malloc(c->odr_out, cp1 - cp0 + 1);
+            char *h = (char*) odr_malloc(c->odr_out, cp1 - cp0 + 1);
             memcpy (h, cp0, cp1 - cp0);
             h[cp1-cp0] = '\0';
             z_HTTP_header_add(c->odr_out, &gdu->u.HTTP_Request->headers,
@@ -1133,7 +1242,7 @@ static zoom_ret send_srw (ZOOM_connection c, Z_SRW_PDU *sr)
     z_HTTP_header_add(c->odr_out, &gdu->u.HTTP_Request->headers,
                       "SOAPAction", "\"\"");
     p->which = Z_SOAP_generic;
-    p->u.generic = odr_malloc(o, sizeof(*p->u.generic));
+    p->u.generic = (Z_SOAP_Generic *) odr_malloc(o, sizeof(*p->u.generic));
     p->u.generic->no = 0;
     p->u.generic->ns = 0;
     p->u.generic->p = sr;
@@ -1166,7 +1275,7 @@ static zoom_ret ZOOM_connection_srw_send_search(ZOOM_connection c)
     const char *recordPacking = 0;
 
     if (c->error)                  /* don't continue on error */
-       return zoom_complete;
+        return zoom_complete;
     assert (c->tasks);
     if (c->tasks->which == ZOOM_TASK_SEARCH)
     {
@@ -1253,18 +1362,20 @@ static zoom_ret ZOOM_connection_send_search (ZOOM_connection c)
 
     r = c->tasks->u.search.resultset;
 
+    yaz_log(log_details, "%p ZOOM_connection_send_search set=%p", c, r);
+
     elementSetName =
-       ZOOM_options_get (r->options, "elementSetName");
+        ZOOM_options_get (r->options, "elementSetName");
     smallSetElementSetName  =
-       ZOOM_options_get (r->options, "smallSetElementSetName");
+        ZOOM_options_get (r->options, "smallSetElementSetName");
     mediumSetElementSetName =
-       ZOOM_options_get (r->options, "mediumSetElementSetName");
+        ZOOM_options_get (r->options, "mediumSetElementSetName");
 
     if (!smallSetElementSetName)
-       smallSetElementSetName = elementSetName;
+        smallSetElementSetName = elementSetName;
 
     if (!mediumSetElementSetName)
-       mediumSetElementSetName = elementSetName;
+        mediumSetElementSetName = elementSetName;
 
     assert (r);
     assert (r->query);
@@ -1274,11 +1385,11 @@ static zoom_ret ZOOM_connection_send_search (ZOOM_connection c)
     if (!search_req->query)
     {
         set_ZOOM_error(c, ZOOM_ERROR_INVALID_QUERY, 0);
-       return zoom_complete;
+        return zoom_complete;
     }
 
     search_req->databaseNames =
-       set_DatabaseNames (c, r->options, &search_req->num_databaseNames);
+        set_DatabaseNames (c, r->options, &search_req->num_databaseNames);
 
     /* get syntax (no need to provide unless piggyback is in effect) */
     syntax = ZOOM_options_get (r->options, "preferredRecordSyntax");
@@ -1288,47 +1399,47 @@ static zoom_ret ZOOM_connection_send_search (ZOOM_connection c)
     mspn = ZOOM_options_get_int (r->options, "mediumSetPresentNumber", -1);
     if (lslb != -1 && ssub != -1 && mspn != -1)
     {
-       /* So're a Z39.50 expert? Let's hope you don't do sort */
-       *search_req->largeSetLowerBound = lslb;
-       *search_req->smallSetUpperBound = ssub;
-       *search_req->mediumSetPresentNumber = mspn;
+        /* So're a Z39.50 expert? Let's hope you don't do sort */
+        *search_req->largeSetLowerBound = lslb;
+        *search_req->smallSetUpperBound = ssub;
+        *search_req->mediumSetPresentNumber = mspn;
     }
     else if (r->start == 0 && r->count > 0
-            && r->piggyback && !r->r_sort_spec && !r->schema)
+             && r->piggyback && !r->r_sort_spec && !r->schema)
     {
-       /* Regular piggyback - do it unless we're going to do sort */
-       *search_req->largeSetLowerBound = 2000000000;
-       *search_req->smallSetUpperBound = 1;
-       *search_req->mediumSetPresentNumber = r->step>0 ? r->step : r->count;
+        /* Regular piggyback - do it unless we're going to do sort */
+        *search_req->largeSetLowerBound = 2000000000;
+        *search_req->smallSetUpperBound = 1;
+        *search_req->mediumSetPresentNumber = r->step>0 ? r->step : r->count;
     }
     else
     {
-       /* non-piggyback. Need not provide elementsets or syntaxes .. */
-       smallSetElementSetName = 0;
-       mediumSetElementSetName = 0;
-       syntax = 0;
+        /* non-piggyback. Need not provide elementsets or syntaxes .. */
+        smallSetElementSetName = 0;
+        mediumSetElementSetName = 0;
+        syntax = 0;
     }
     if (smallSetElementSetName && *smallSetElementSetName)
     {
-       Z_ElementSetNames *esn = (Z_ElementSetNames *)
+        Z_ElementSetNames *esn = (Z_ElementSetNames *)
             odr_malloc (c->odr_out, sizeof(*esn));
-       
-       esn->which = Z_ElementSetNames_generic;
-       esn->u.generic = odr_strdup (c->odr_out, smallSetElementSetName);
-       search_req->smallSetElementSetNames = esn;
+        
+        esn->which = Z_ElementSetNames_generic;
+        esn->u.generic = odr_strdup (c->odr_out, smallSetElementSetName);
+        search_req->smallSetElementSetNames = esn;
     }
     if (mediumSetElementSetName && *mediumSetElementSetName)
     {
-       Z_ElementSetNames *esn = (Z_ElementSetNames *)
+        Z_ElementSetNames *esn = (Z_ElementSetNames *)
             odr_malloc (c->odr_out, sizeof(*esn));
-       
-       esn->which = Z_ElementSetNames_generic;
-       esn->u.generic = odr_strdup (c->odr_out, mediumSetElementSetName);
-       search_req->mediumSetElementSetNames = esn;
+        
+        esn->which = Z_ElementSetNames_generic;
+        esn->u.generic = odr_strdup (c->odr_out, mediumSetElementSetName);
+        search_req->mediumSetElementSetNames = esn;
     }
     if (syntax)
-       search_req->preferredRecordSyntax =
-           yaz_str_to_z3950oid (c->odr_out, CLASS_RECSYN, syntax);
+        search_req->preferredRecordSyntax =
+            yaz_str_to_z3950oid (c->odr_out, CLASS_RECSYN, syntax);
     
     if (!r->setname)
     {
@@ -1349,45 +1460,50 @@ static zoom_ret ZOOM_connection_send_search (ZOOM_connection c)
                     break;
             }
             r->setname = xstrdup (setname);
-            yaz_log (LOG_DEBUG, "allocating set %s", r->setname);
+            yaz_log(log_details, "%p ZOOM_connection_send_search: allocating "
+                    "set %s", c, r->setname);
         }
         else
+        {
+            yaz_log(log_details, "%p ZOOM_connection_send_search: using "
+                    "default set", c);
             r->setname = xstrdup ("default");
+        }
         ZOOM_options_set (r->options, "setname", r->setname);
     }
     search_req->resultSetName = odr_strdup(c->odr_out, r->setname);
-    /* send search request */
     return send_APDU (c, apdu);
 }
 
-static void response_diag (ZOOM_connection c, Z_DiagRec *p)
+static void response_default_diag(ZOOM_connection c, Z_DefaultDiagFormat *r)
 {
     int oclass;
-    Z_DefaultDiagFormat *r;
     char *addinfo = 0;
-    
-    xfree (c->addinfo);
-    c->addinfo = 0;
-    if (p->which != Z_DiagRec_defaultFormat)
-    {
-        set_ZOOM_error(c, ZOOM_ERROR_DECODE, 0);
-       return;
-    }
-    r = p->u.defaultFormat;
+
     switch (r->which)
     {
     case Z_DefaultDiagFormat_v2Addinfo:
-       addinfo = r->u.v2Addinfo;
-       break;
+        addinfo = r->u.v2Addinfo;
+        break;
     case Z_DefaultDiagFormat_v3Addinfo:
-       addinfo = r->u.v3Addinfo;
-       break;
+        addinfo = r->u.v3Addinfo;
+        break;
     }
+    xfree (c->addinfo);
+    c->addinfo = 0;
     set_dset_error(c, *r->condition,
                    yaz_z3950oid_to_str(r->diagnosticSetId, &oclass),
                    addinfo, 0);
 }
 
+static void response_diag(ZOOM_connection c, Z_DiagRec *p)
+{
+    if (p->which != Z_DiagRec_defaultFormat)
+        set_ZOOM_error(c, ZOOM_ERROR_DECODE, 0);
+    else
+        response_default_diag(c, p->u.defaultFormat);
+}
+
 ZOOM_API(ZOOM_record)
 ZOOM_record_clone (ZOOM_record srec)
 {
@@ -1398,7 +1514,7 @@ ZOOM_record_clone (ZOOM_record srec)
 
     odr_enc = odr_createmem(ODR_ENCODE);
     if (!z_NamePlusRecord (odr_enc, &srec->npr, 0, 0))
-       return 0;
+        return 0;
     buf = odr_getbuf (odr_enc, &size, 0);
     
     nrec = (ZOOM_record) xmalloc (sizeof(*nrec));
@@ -1436,21 +1552,21 @@ ZOOM_API(void)
 ZOOM_record_destroy (ZOOM_record rec)
 {
     if (!rec)
-       return;
+        return;
     if (rec->wrbuf_marc)
-       wrbuf_free (rec->wrbuf_marc, 1);
+        wrbuf_free (rec->wrbuf_marc, 1);
     if (rec->wrbuf_iconv)
-       wrbuf_free (rec->wrbuf_iconv, 1);
+        wrbuf_free (rec->wrbuf_iconv, 1);
     if (rec->wrbuf_opac)
-       wrbuf_free (rec->wrbuf_opac, 1);
+        wrbuf_free (rec->wrbuf_opac, 1);
     odr_destroy (rec->odr);
     xfree (rec);
 }
 
 static const char *marc_iconv_return(ZOOM_record rec, int marc_type,
-                                    int *len,
-                                    const char *buf, int sz,
-                                    const char *record_charset)
+                                     int *len,
+                                     const char *buf, int sz,
+                                     const char *record_charset)
 {
     char to[40];
     char from[40];
@@ -1461,51 +1577,51 @@ static const char *marc_iconv_return(ZOOM_record rec, int marc_type,
     strcpy(to, "UTF-8");
     if (record_charset && *record_charset)
     {
-       /* Use "from,to" or just "from" */
-       const char *cp =strchr(record_charset, ',');
-       int clen = strlen(record_charset);
-       if (cp && cp[1])
-       {
-           strncpy( to, cp+1, sizeof(to)-1);
-           to[sizeof(to)-1] = '\0';
-           clen = cp - record_charset;
-       }
-       if (clen > sizeof(from)-1)
-           clen = sizeof(from)-1;
-       
-       if (clen)
-           strncpy(from, record_charset, clen);
-       from[clen] = '\0';
+        /* Use "from,to" or just "from" */
+        const char *cp = strchr(record_charset, ',');
+        int clen = strlen(record_charset);
+        if (cp && cp[1])
+        {
+            strncpy( to, cp+1, sizeof(to)-1);
+            to[sizeof(to)-1] = '\0';
+            clen = cp - record_charset;
+        }
+        if (clen > sizeof(from)-1)
+            clen = sizeof(from)-1;
+        
+        if (clen)
+            strncpy(from, record_charset, clen);
+        from[clen] = '\0';
     }
 
     if (*from && *to)
     {
-       cd = yaz_iconv_open(to, from);
-       yaz_marc_iconv(mt, cd);
+        cd = yaz_iconv_open(to, from);
+        yaz_marc_iconv(mt, cd);
     }
 
     yaz_marc_xml(mt, marc_type);
     if (!rec->wrbuf_marc)
-       rec->wrbuf_marc = wrbuf_alloc();
+        rec->wrbuf_marc = wrbuf_alloc();
     wrbuf_rewind (rec->wrbuf_marc);
     if (yaz_marc_decode_wrbuf (mt, buf, sz, rec->wrbuf_marc) > 0)
     {
-       yaz_marc_destroy(mt);
-       if (cd)
-           yaz_iconv_close(cd);
-       if (len)
-           *len = wrbuf_len(rec->wrbuf_marc);
-       return wrbuf_buf(rec->wrbuf_marc);
+        yaz_marc_destroy(mt);
+        if (cd)
+            yaz_iconv_close(cd);
+        if (len)
+            *len = wrbuf_len(rec->wrbuf_marc);
+        return wrbuf_buf(rec->wrbuf_marc);
     }
     yaz_marc_destroy(mt);
     if (cd)
-       yaz_iconv_close(cd);
+        yaz_iconv_close(cd);
     return 0;
 }
 
 static const char *record_iconv_return(ZOOM_record rec, int *len,
-                                      const char *buf, int sz,
-                                      const char *record_charset)
+                                       const char *buf, int sz,
+                                       const char *record_charset)
 {
     char to[40];
     char from[40];
@@ -1515,56 +1631,56 @@ static const char *record_iconv_return(ZOOM_record rec, int *len,
     strcpy(to, "UTF-8");
     if (record_charset && *record_charset)
     {
-       /* Use "from,to" or just "from" */
-       const char *cp =strchr(record_charset, ',');
-       int clen = strlen(record_charset);
-       if (cp && cp[1])
-       {
-           strncpy( to, cp+1, sizeof(to)-1);
-           to[sizeof(to)-1] = '\0';
-           clen = cp - record_charset;
-       }
-       if (clen > sizeof(from)-1)
-           clen = sizeof(from)-1;
-       
-       if (clen)
-           strncpy(from, record_charset, clen);
-       from[clen] = '\0';
+        /* Use "from,to" or just "from" */
+        const char *cp = strchr(record_charset, ',');
+        int clen = strlen(record_charset);
+        if (cp && cp[1])
+        {
+            strncpy( to, cp+1, sizeof(to)-1);
+            to[sizeof(to)-1] = '\0';
+            clen = cp - record_charset;
+        }
+        if (clen > sizeof(from)-1)
+            clen = sizeof(from)-1;
+        
+        if (clen)
+            strncpy(from, record_charset, clen);
+        from[clen] = '\0';
     }
 
     if (*from && *to && (cd = yaz_iconv_open(to, from)))
     {
-       char outbuf[12];
-       size_t inbytesleft = sz;
-       const char *inp = buf;
-       
-       if (!rec->wrbuf_iconv)
-           rec->wrbuf_iconv = wrbuf_alloc();
-
-       wrbuf_rewind(rec->wrbuf_iconv);
-
-       while (inbytesleft)
-       {
-           size_t outbytesleft = sizeof(outbuf);
-           char *outp = outbuf;
-           size_t r = yaz_iconv (cd, (char**) &inp,
-                                 &inbytesleft, 
-                                 &outp, &outbytesleft);
-           if (r == (size_t) (-1))
-           {
-               int e = yaz_iconv_error(cd);
-               if (e != YAZ_ICONV_E2BIG)
-                   break;
-           }
-           wrbuf_write(rec->wrbuf_iconv, outbuf, outp - outbuf);
-       }
-       wrbuf_puts(rec->wrbuf_iconv, "");
-       buf = wrbuf_buf(rec->wrbuf_iconv);
-       sz = wrbuf_len(rec->wrbuf_iconv);
-       yaz_iconv_close(cd);
+        char outbuf[12];
+        size_t inbytesleft = sz;
+        const char *inp = buf;
+        
+        if (!rec->wrbuf_iconv)
+            rec->wrbuf_iconv = wrbuf_alloc();
+
+        wrbuf_rewind(rec->wrbuf_iconv);
+
+        while (inbytesleft)
+        {
+            size_t outbytesleft = sizeof(outbuf);
+            char *outp = outbuf;
+            size_t r = yaz_iconv (cd, (char**) &inp,
+                                  &inbytesleft, 
+                                  &outp, &outbytesleft);
+            if (r == (size_t) (-1))
+            {
+                int e = yaz_iconv_error(cd);
+                if (e != YAZ_ICONV_E2BIG)
+                    break;
+            }
+            wrbuf_write(rec->wrbuf_iconv, outbuf, outp - outbuf);
+        }
+        wrbuf_puts(rec->wrbuf_iconv, "");
+        buf = wrbuf_buf(rec->wrbuf_iconv);
+        sz = wrbuf_len(rec->wrbuf_iconv);
+        yaz_iconv_close(cd);
     }
     if (len)
-       *len = sz;
+        *len = sz;
     return buf;
 }
 
@@ -1579,75 +1695,75 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
     Z_NamePlusRecord *npr;
     
     if (len)
-       *len = 0; /* default return */
-       
+        *len = 0; /* default return */
+        
     if (!rec)
-       return 0;
+        return 0;
     npr = rec->npr;
     if (!npr)
-       return 0;
+        return 0;
 
     cp = type_spec;
     for (i = 0; cp[i] && i < sizeof(type)-1; i++)
     {
-       if (cp[i] == ';' || cp[i] == ' ')
-           break;
-       type[i] = cp[i];
+        if (cp[i] == ';' || cp[i] == ' ')
+            break;
+        type[i] = cp[i];
     }
     type[i] = '\0';
     charset[0] = '\0';
     while (type_spec[i] == ';')
     {
-       i++;
-       while (type_spec[i] == ' ')
-           i++;
-       if (!strncmp(type_spec+i, "charset=", 8))
-       {
-           int j = 0;
-           i = i + 8; /* skip charset= */
-           for (j = 0; type_spec[i]  && j < sizeof(charset)-1; i++, j++)
-           {
-               if (type_spec[i] == ';' || type_spec[i] == ' ')
-                   break;
-               charset[j] = cp[i];
-           }
-           charset[j] = '\0';
-       }
-       else if (!strncmp(type_spec+i, "xpath=", 6))
-       {
-           int j = 0; 
-           i = i + 6;
-           for (j = 0; type_spec[i] && j < sizeof(xpath)-1; i++, j++)
-               xpath[j] = cp[i];
-           xpath[j] = '\0';
-       } 
-       while (type_spec[i] == ' ')
-           i++;
+        i++;
+        while (type_spec[i] == ' ')
+            i++;
+        if (!strncmp(type_spec+i, "charset=", 8))
+        {
+            int j = 0;
+            i = i + 8; /* skip charset= */
+            for (j = 0; type_spec[i]  && j < sizeof(charset)-1; i++, j++)
+            {
+                if (type_spec[i] == ';' || type_spec[i] == ' ')
+                    break;
+                charset[j] = cp[i];
+            }
+            charset[j] = '\0';
+        }
+        else if (!strncmp(type_spec+i, "xpath=", 6))
+        {
+            int j = 0; 
+            i = i + 6;
+            for (j = 0; type_spec[i] && j < sizeof(xpath)-1; i++, j++)
+                xpath[j] = cp[i];
+            xpath[j] = '\0';
+        } 
+        while (type_spec[i] == ' ')
+            i++;
     }
     if (!strcmp (type, "database"))
     {
-       if (len)
+        if (len)
             *len = (npr->databaseName ? strlen(npr->databaseName) : 0);
-       return npr->databaseName;
+        return npr->databaseName;
     }
     else if (!strcmp (type, "syntax"))
     {
-        const char *desc = 0;  
-       if (npr->which == Z_NamePlusRecord_databaseRecord)
-       {
-           Z_External *r = (Z_External *) npr->u.databaseRecord;
-           oident *ent = oid_getentbyoid(r->direct_reference);
-           if (ent)
-               desc = ent->desc;
-       }
-       if (!desc)
+        const char *desc = 0;   
+        if (npr->which == Z_NamePlusRecord_databaseRecord)
+        {
+            Z_External *r = (Z_External *) npr->u.databaseRecord;
+            oident *ent = oid_getentbyoid(r->direct_reference);
+            if (ent)
+                desc = ent->desc;
+        }
+        if (!desc)
             desc = "none";
-       if (len)
+        if (len)
             *len = strlen(desc);
-       return desc;
+        return desc;
     }
     if (npr->which != Z_NamePlusRecord_databaseRecord)
-       return 0;
+        return 0;
 
     /* from now on - we have a database record .. */
     if (!strcmp (type, "render"))
@@ -1655,21 +1771,22 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
         Z_External *r = (Z_External *) npr->u.databaseRecord;
         oident *ent = oid_getentbyoid(r->direct_reference);
 
-       /* render bibliographic record .. */
-       if (r->which == Z_External_OPAC)
-       {
-           r = r->u.opac->bibliographicRecord;
-           if (!r)
-               return 0;
-           ent = oid_getentbyoid(r->direct_reference);
-       }
+        /* render bibliographic record .. */
+        if (r->which == Z_External_OPAC)
+        {
+            r = r->u.opac->bibliographicRecord;
+            if (!r)
+                return 0;
+            ent = oid_getentbyoid(r->direct_reference);
+        }
         if (r->which == Z_External_sutrs)
-           return record_iconv_return(rec, len,
-                                      r->u.sutrs->buf, r->u.sutrs->len,
-                                      charset);
+            return record_iconv_return(rec, len,
+                                       (char*) r->u.sutrs->buf,
+                                       r->u.sutrs->len,
+                                       charset);
         else if (r->which == Z_External_octet)
         {
-           const char *ret_buf;
+            const char *ret_buf;
             switch (ent->value)
             {
             case VAL_SOIF:
@@ -1680,18 +1797,18 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
             case VAL_APPLICATION_XML:
                 break;
             default:
-               ret_buf = marc_iconv_return(
-                   rec, YAZ_MARC_LINE, len,
-                   (const char *) r->u.octet_aligned->buf,
-                   r->u.octet_aligned->len,
-                   charset);
-               if (ret_buf)
-                   return ret_buf;
+                ret_buf = marc_iconv_return(
+                    rec, YAZ_MARC_LINE, len,
+                    (const char *) r->u.octet_aligned->buf,
+                    r->u.octet_aligned->len,
+                    charset);
+                if (ret_buf)
+                    return ret_buf;
             }
-           return record_iconv_return(rec, len,
-                                      (const char *) r->u.octet_aligned->buf,
-                                      r->u.octet_aligned->len,
-                                      charset);
+            return record_iconv_return(rec, len,
+                                       (const char *) r->u.octet_aligned->buf,
+                                       r->u.octet_aligned->len,
+                                       charset);
         }
         else if (r->which == Z_External_grs1)
         {
@@ -1699,35 +1816,35 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
                 rec->wrbuf_marc = wrbuf_alloc();
             wrbuf_rewind (rec->wrbuf_marc);
             yaz_display_grs1(rec->wrbuf_marc, r->u.grs1, 0);
-           return record_iconv_return(rec, len,
-                                      wrbuf_buf(rec->wrbuf_marc),
-                                      wrbuf_len(rec->wrbuf_marc),
-                                      charset);
+            return record_iconv_return(rec, len,
+                                       wrbuf_buf(rec->wrbuf_marc),
+                                       wrbuf_len(rec->wrbuf_marc),
+                                       charset);
         }
-       return 0;
+        return 0;
     }
     else if (!strcmp (type, "xml") || !strcmp(type, "oai"))
     {
         Z_External *r = (Z_External *) npr->u.databaseRecord;
         oident *ent = oid_getentbyoid(r->direct_reference);
 
-       /* render bibliographic record .. */
-       if (r->which == Z_External_OPAC)
-       {
-           r = r->u.opac->bibliographicRecord;
-           if (!r)
-               return 0;
-           ent = oid_getentbyoid(r->direct_reference);
-       }
+        /* render bibliographic record .. */
+        if (r->which == Z_External_OPAC)
+        {
+            r = r->u.opac->bibliographicRecord;
+            if (!r)
+                return 0;
+            ent = oid_getentbyoid(r->direct_reference);
+        }
         
         if (r->which == Z_External_sutrs)
-           return record_iconv_return(rec, len,
-                                      (const char *) r->u.sutrs->buf,
-                                      r->u.sutrs->len,
-                                      charset);
+            return record_iconv_return(rec, len,
+                                       (const char *) r->u.sutrs->buf,
+                                       r->u.sutrs->len,
+                                       charset);
         else if (r->which == Z_External_octet)
         {
-           const char *ret_buf;
+            const char *ret_buf;
             int marc_decode_type = YAZ_MARC_MARCXML;
 
             if (!strcmp(type, "oai"))
@@ -1742,67 +1859,67 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
             case VAL_APPLICATION_XML:
                 break;
             default:
-               ret_buf = marc_iconv_return(
-                   rec, marc_decode_type, len,
-                   (const char *) r->u.octet_aligned->buf,
-                   r->u.octet_aligned->len,
-                   charset);
-               if (ret_buf)
-                   return ret_buf;
+                ret_buf = marc_iconv_return(
+                    rec, marc_decode_type, len,
+                    (const char *) r->u.octet_aligned->buf,
+                    r->u.octet_aligned->len,
+                    charset);
+                if (ret_buf)
+                    return ret_buf;
             }
-           return record_iconv_return(rec, len,
-                                      (const char *) r->u.octet_aligned->buf,
-                                      r->u.octet_aligned->len,
-                                      charset);
+            return record_iconv_return(rec, len,
+                                       (const char *) r->u.octet_aligned->buf,
+                                       r->u.octet_aligned->len,
+                                       charset);
         }
         else if (r->which == Z_External_grs1)
         {
             if (len) *len = 5;
             return "GRS-1";
         }
-       return 0;
+        return 0;
     }
     else if (!strcmp (type, "raw"))
     {
-       Z_External *r = (Z_External *) npr->u.databaseRecord;
-       
-       if (r->which == Z_External_sutrs)
-       {
-           if (len) *len = r->u.sutrs->len;
-           return (const char *) r->u.sutrs->buf;
-       }
-       else if (r->which == Z_External_octet)
-       {
-           if (len) *len = r->u.octet_aligned->len;
-           return (const char *) r->u.octet_aligned->buf;
-       }
-       else /* grs-1, explain, OPAC, ... */
-       {
-           if (len) *len = -1;
-           return (const char *) npr->u.databaseRecord;
-       }
-       return 0;
+        Z_External *r = (Z_External *) npr->u.databaseRecord;
+        
+        if (r->which == Z_External_sutrs)
+        {
+            if (len) *len = r->u.sutrs->len;
+            return (const char *) r->u.sutrs->buf;
+        }
+        else if (r->which == Z_External_octet)
+        {
+            if (len) *len = r->u.octet_aligned->len;
+            return (const char *) r->u.octet_aligned->buf;
+        }
+        else /* grs-1, explain, OPAC, ... */
+        {
+            if (len) *len = -1;
+            return (const char *) npr->u.databaseRecord;
+        }
+        return 0;
     }
     else if (!strcmp (type, "ext"))
     {
-       if (len) *len = -1;
-       return (const char *) npr->u.databaseRecord;
+        if (len) *len = -1;
+        return (const char *) npr->u.databaseRecord;
     }
     else if (!strcmp (type, "opac"))
-            
-    {
-       Z_External *r = (Z_External *) npr->u.databaseRecord;
-       if (r->which == Z_External_OPAC)
-       {
-           if (!rec->wrbuf_opac)
-               rec->wrbuf_opac = wrbuf_alloc();
-           wrbuf_rewind (rec->wrbuf_opac);
-           yaz_display_OPAC(rec->wrbuf_opac, r->u.opac, 0);
-           return record_iconv_return(rec, len,
-                                      wrbuf_buf(rec->wrbuf_opac),
-                                      wrbuf_len(rec->wrbuf_opac),
-                                      charset);
-       }
+             
+    {
+        Z_External *r = (Z_External *) npr->u.databaseRecord;
+        if (r->which == Z_External_OPAC)
+        {
+            if (!rec->wrbuf_opac)
+                rec->wrbuf_opac = wrbuf_alloc();
+            wrbuf_rewind (rec->wrbuf_opac);
+            yaz_display_OPAC(rec->wrbuf_opac, r->u.opac, 0);
+            return record_iconv_return(rec, len,
+                                       wrbuf_buf(rec->wrbuf_opac),
+                                       wrbuf_len(rec->wrbuf_opac),
+                                       charset);
+        }
     }
     return 0;
 }
@@ -1830,11 +1947,11 @@ static void record_cache_add (ZOOM_resultset r, Z_NamePlusRecord *npr,
 
     for (rc = r->record_cache; rc; rc = rc->next)
     {
-       if (pos == rc->pos)
-       {
-           if (strcmp_null(r->schema, rc->schema))
+        if (pos == rc->pos)
+        {
+            if (strcmp_null(r->schema, rc->schema))
                 continue;
-           if (strcmp_null(elementSetName,rc->elementSetName))
+            if (strcmp_null(elementSetName,rc->elementSetName))
                 continue;
             if (strcmp_null(syntax, rc->syntax))
                 continue;
@@ -1842,7 +1959,7 @@ static void record_cache_add (ZOOM_resultset r, Z_NamePlusRecord *npr,
             rc->rec.npr = npr;
             /* keeping wrbuf_marc too */
             return;
-       }
+        }
     }
     rc = (ZOOM_record_cache) odr_malloc (r->odr, sizeof(*rc));
     rc->rec.npr = npr; 
@@ -1851,19 +1968,19 @@ static void record_cache_add (ZOOM_resultset r, Z_NamePlusRecord *npr,
     rc->rec.wrbuf_iconv = 0;
     rc->rec.wrbuf_opac = 0;
     if (elementSetName)
-       rc->elementSetName = odr_strdup (r->odr, elementSetName);
+        rc->elementSetName = odr_strdup (r->odr, elementSetName);
     else
-       rc->elementSetName = 0;
+        rc->elementSetName = 0;
 
     if (syntax)
-       rc->syntax = odr_strdup (r->odr, syntax);
+        rc->syntax = odr_strdup (r->odr, syntax);
     else
-       rc->syntax = 0;
+        rc->syntax = 0;
 
     if (r->schema)
-       rc->schema = odr_strdup (r->odr, r->schema);
+        rc->schema = odr_strdup (r->odr, r->schema);
     else
-       rc->schema = 0;
+        rc->schema = 0;
 
     rc->pos = pos;
     rc->next = r->record_cache;
@@ -1880,27 +1997,27 @@ static ZOOM_record record_cache_lookup (ZOOM_resultset r, int pos)
     
     for (rc = r->record_cache; rc; rc = rc->next)
     {
-       if (pos == rc->pos)
-       {
-           if (strcmp_null(r->schema, rc->schema))
+        if (pos == rc->pos)
+        {
+            if (strcmp_null(r->schema, rc->schema))
                 continue;
-           if (strcmp_null(elementSetName,rc->elementSetName))
+            if (strcmp_null(elementSetName,rc->elementSetName))
                 continue;
             if (strcmp_null(syntax, rc->syntax))
                 continue;
             return &rc->rec;
-       }
+        }
     }
     return 0;
 }
-                                            
+                                             
 static void handle_records (ZOOM_connection c, Z_Records *sr,
-                           int present_phase)
+                            int present_phase)
 {
     ZOOM_resultset resultset;
 
     if (!c->tasks)
-       return ;
+        return ;
     switch (c->tasks->which)
     {
     case ZOOM_TASK_SEARCH:
@@ -1908,56 +2025,54 @@ static void handle_records (ZOOM_connection c, Z_Records *sr,
         break;
     case ZOOM_TASK_RETRIEVE:
         resultset = c->tasks->u.retrieve.resultset;        
-       break;
+        break;
     default:
         return;
     }
     if (sr && sr->which == Z_Records_NSD)
-    {
-       Z_DiagRec dr, *dr_p = &dr;
-       dr.which = Z_DiagRec_defaultFormat;
-       dr.u.defaultFormat = sr->u.nonSurrogateDiagnostic;
-       
-       response_diag (c, dr_p);
-    }
+        response_default_diag(c, sr->u.nonSurrogateDiagnostic);
     else if (sr && sr->which == Z_Records_multipleNSD)
     {
-       if (sr->u.multipleNonSurDiagnostics->num_diagRecs >= 1)
-           response_diag(c, sr->u.multipleNonSurDiagnostics->diagRecs[0]);
-       else
+        if (sr->u.multipleNonSurDiagnostics->num_diagRecs >= 1)
+            response_diag(c, sr->u.multipleNonSurDiagnostics->diagRecs[0]);
+        else
             set_ZOOM_error(c, ZOOM_ERROR_DECODE, 0);
     }
     else 
     {
-       if (resultset->count + resultset->start > resultset->size)
-           resultset->count = resultset->size - resultset->start;
-       if (resultset->count < 0)
-           resultset->count = 0;
-       if (sr && sr->which == Z_Records_DBOSD)
-       {
-           int i;
-           NMEM nmem = odr_extract_mem (c->odr_in);
-           Z_NamePlusRecordList *p =
-               sr->u.databaseOrSurDiagnostics;
-           for (i = 0; i<p->num_records; i++)
-           {
-               record_cache_add (resultset, p->records[i],
+        if (resultset->count + resultset->start > resultset->size)
+            resultset->count = resultset->size - resultset->start;
+        if (resultset->count < 0)
+            resultset->count = 0;
+        if (sr && sr->which == Z_Records_DBOSD)
+        {
+            int i;
+            NMEM nmem = odr_extract_mem (c->odr_in);
+            Z_NamePlusRecordList *p =
+                sr->u.databaseOrSurDiagnostics;
+            for (i = 0; i<p->num_records; i++)
+            {
+                record_cache_add (resultset, p->records[i],
                                   i+ resultset->start);
-           }
-           /* transfer our response to search_nmem .. we need it later */
-           nmem_transfer (resultset->odr->mem, nmem);
-           nmem_destroy (nmem);
-           if (present_phase && p->num_records == 0)
-           {
-               /* present response and we didn't get any records! */
-                set_ZOOM_error(c, ZOOM_ERROR_DECODE, 0);
-           }
-       }
-       else if (present_phase)
-       {
-           /* present response and we didn't get any records! */
-            set_ZOOM_error(c, ZOOM_ERROR_DECODE, 0);
-       }
+            }
+            /* transfer our response to search_nmem .. we need it later */
+            nmem_transfer (resultset->odr->mem, nmem);
+            nmem_destroy (nmem);
+            if (present_phase && p->num_records == 0)
+            {
+                /* present response and we didn't get any records! */
+                Z_NamePlusRecord *myrec = 
+                    zget_surrogateDiagRec(resultset->odr, 0, 14, 0);
+                record_cache_add(resultset, myrec, resultset->start);
+            }
+        }
+        else if (present_phase)
+        {
+            /* present response and we didn't get any records! */
+            Z_NamePlusRecord *myrec = 
+                zget_surrogateDiagRec(resultset->odr, 0, 14, 0);
+            record_cache_add(resultset, myrec, resultset->start);
+        }
     }
 }
 
@@ -1966,21 +2081,127 @@ static void handle_present_response (ZOOM_connection c, Z_PresentResponse *pr)
     handle_records (c, pr->records, 1);
 }
 
+static void handle_queryExpressionTerm(ZOOM_options opt, const char *name,
+                                       Z_Term *term)
+{
+    switch (term->which)
+    {
+    case Z_Term_general:
+        ZOOM_options_setl(opt, name,
+                          (const char *)(term->u.general->buf), 
+                          term->u.general->len);
+        break;
+    case Z_Term_characterString:
+        ZOOM_options_set(opt, name, term->u.characterString);
+        break;
+    case Z_Term_numeric:
+        ZOOM_options_set_int(opt, name, *term->u.numeric);
+        break;
+    }
+}
+
+static void handle_queryExpression(ZOOM_options opt, const char *name,
+                                   Z_QueryExpression *exp)
+{
+    char opt_name[80];
+    
+    switch (exp->which)
+    {
+    case Z_QueryExpression_term:
+        if (exp->u.term && exp->u.term->queryTerm)
+        {
+            sprintf(opt_name, "%s.term", name);
+            handle_queryExpressionTerm(opt, opt_name, exp->u.term->queryTerm);
+        }
+        break;
+    case Z_QueryExpression_query:
+        break;
+    }
+}
+
+static void handle_searchResult(ZOOM_connection c, ZOOM_resultset resultset,
+                                Z_OtherInformation *o)
+{
+    int i;
+    for (i = 0; o && i < o->num_elements; i++)
+    {
+        if (o->list[i]->which == Z_OtherInfo_externallyDefinedInfo)
+        {
+            Z_External *ext = o->list[i]->information.externallyDefinedInfo;
+            
+            if (ext->which == Z_External_searchResult1)
+            {
+                int j;
+                Z_SearchInfoReport *sr = ext->u.searchResult1;
+                
+                if (sr->num)
+                    ZOOM_options_set_int(
+                        resultset->options, "searchresult.size", sr->num);
+
+                for (j = 0; j < sr->num; j++)
+                {
+                    Z_SearchInfoReport_s *ent =
+                        ext->u.searchResult1->elements[j];
+                    char pref[80];
+                    
+                    sprintf(pref, "searchresult.%d", j);
+
+                    if (ent->subqueryId)
+                    {
+                        char opt_name[80];
+                        sprintf(opt_name, "%s.id", pref);
+                        ZOOM_options_set(resultset->options, opt_name,
+                                         ent->subqueryId);
+                    }
+                    if (ent->subqueryExpression)
+                    {
+                        char opt_name[80];
+                        sprintf(opt_name, "%s.subquery", pref);
+                        handle_queryExpression(resultset->options, opt_name,
+                                               ent->subqueryExpression);
+                    }
+                    if (ent->subqueryInterpretation)
+                    {
+                        char opt_name[80];
+                        sprintf(opt_name, "%s.interpretation", pref);
+                        handle_queryExpression(resultset->options, opt_name,
+                                               ent->subqueryInterpretation);
+                    }
+                    if (ent->subqueryRecommendation)
+                    {
+                        char opt_name[80];
+                        sprintf(opt_name, "%s.recommendation", pref);
+                        handle_queryExpression(resultset->options, opt_name,
+                                               ent->subqueryRecommendation);
+                    }
+                    if (ent->subqueryCount)
+                    {
+                        char opt_name[80];
+                        sprintf(opt_name, "%s.count", pref);
+                        ZOOM_options_set_int(resultset->options, opt_name,
+                                             *ent->subqueryCount);
+                    }                                             
+                }
+            }
+        }
+    }
+}
+
 static void handle_search_response (ZOOM_connection c, Z_SearchResponse *sr)
 {
     ZOOM_resultset resultset;
     ZOOM_Event event;
-    
-    yaz_log (LOG_DEBUG, "got search response");
-    
+
     if (!c->tasks || c->tasks->which != ZOOM_TASK_SEARCH)
-       return ;
-    
+        return ;
+
     event = ZOOM_Event_create(ZOOM_EVENT_RECV_SEARCH);
     ZOOM_connection_put_event(c, event);
 
     resultset = c->tasks->u.search.resultset;
 
+    handle_searchResult(c, resultset, sr->additionalSearchInfo);
+
     resultset->size = *sr->resultCount;
     handle_records (c, sr->records, 0);
 }
@@ -1988,7 +2209,7 @@ static void handle_search_response (ZOOM_connection c, Z_SearchResponse *sr)
 static void sort_response (ZOOM_connection c, Z_SortResponse *res)
 {
     if (res->diagnostics && res->num_diagnostics > 0)
-       response_diag (c, res->diagnostics[0]);
+        response_diag (c, res->diagnostics[0]);
 }
 
 static int scan_response (ZOOM_connection c, Z_ScanResponse *res)
@@ -2018,29 +2239,29 @@ static int scan_response (ZOOM_connection c, Z_ScanResponse *res)
 }
 
 static zoom_ret send_sort (ZOOM_connection c,
-                          ZOOM_resultset resultset)
+                           ZOOM_resultset resultset)
 {
     if (c->error)
-       resultset->r_sort_spec = 0;
+        resultset->r_sort_spec = 0;
     if (resultset->r_sort_spec)
     {
-       Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_sortRequest);
-       Z_SortRequest *req = apdu->u.sortRequest;
-       
-       req->num_inputResultSetNames = 1;
-       req->inputResultSetNames = (Z_InternationalString **)
-           odr_malloc (c->odr_out, sizeof(*req->inputResultSetNames));
-       req->inputResultSetNames[0] =
+        Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_sortRequest);
+        Z_SortRequest *req = apdu->u.sortRequest;
+        
+        req->num_inputResultSetNames = 1;
+        req->inputResultSetNames = (Z_InternationalString **)
+            odr_malloc (c->odr_out, sizeof(*req->inputResultSetNames));
+        req->inputResultSetNames[0] =
             odr_strdup (c->odr_out, resultset->setname);
-       req->sortedResultSetName = odr_strdup (c->odr_out, resultset->setname);
-       req->sortSequence = resultset->r_sort_spec;
-       resultset->r_sort_spec = 0;
-       return send_APDU (c, apdu);
+        req->sortedResultSetName = odr_strdup (c->odr_out, resultset->setname);
+        req->sortSequence = resultset->r_sort_spec;
+        resultset->r_sort_spec = 0;
+        return send_APDU (c, apdu);
     }
     return zoom_complete;
 }
 
-static zoom_ret send_present (ZOOM_connection c)
+static zoom_ret send_present(ZOOM_connection c)
 {
     Z_APDU *apdu = 0;
     Z_PresentRequest *req = 0;
@@ -2050,8 +2271,10 @@ static zoom_ret send_present (ZOOM_connection c)
     ZOOM_resultset  resultset;
 
     if (!c->tasks)
-       return zoom_complete;
-
+    {
+        yaz_log(log_details, "%p send_present no tasks", c);
+        return zoom_complete;
+    }
     switch (c->tasks->which)
     {
     case ZOOM_TASK_SEARCH:
@@ -2063,48 +2286,62 @@ static zoom_ret send_present (ZOOM_connection c)
         resultset->count = c->tasks->u.retrieve.count;
 
         if (resultset->start >= resultset->size)
+        {
+            yaz_log(log_details, "%p send_present start=%d >= size=%d",
+                    c, resultset->start, resultset->size);
             return zoom_complete;
+        }
         if (resultset->start + resultset->count > resultset->size)
             resultset->count = resultset->size - resultset->start;
-       break;
+        break;
     default:
         return zoom_complete;
     }
+    yaz_log(log_details, "%p send_present start=%d count=%d",
+            c, resultset->start, resultset->count);
 
     syntax = ZOOM_resultset_option_get (resultset, "preferredRecordSyntax");
     elementSetName = ZOOM_resultset_option_get (resultset, "elementSetName");
 
     if (c->error)                  /* don't continue on error */
-       return zoom_complete;
+        return zoom_complete;
     if (resultset->start < 0)
-       return zoom_complete;
+        return zoom_complete;
     for (i = 0; i<resultset->count; i++)
     {
-       ZOOM_record rec =
-           record_cache_lookup (resultset, i + resultset->start);
-       if (!rec)
-           break;
+        ZOOM_record rec =
+            record_cache_lookup (resultset, i + resultset->start);
+        if (!rec)
+            break;
     }
     if (i == resultset->count)
-       return zoom_complete;
+    {
+        yaz_log(log_details, "%p send_present skip=%d no more to fetch", c, i);
+        return zoom_complete;
+    }
 
     apdu = zget_APDU(c->odr_out, Z_APDU_presentRequest);
     req = apdu->u.presentRequest;
 
     resultset->start += i;
     resultset->count -= i;
+
+    if (i)
+        yaz_log(log_details, "%p send_present skip=%d", c, i);
+
     *req->resultSetStartPoint = resultset->start + 1;
     *req->numberOfRecordsRequested = resultset->step>0 ?
         resultset->step : resultset->count;
     assert (*req->numberOfRecordsRequested > 0);
 
+
     if (syntax && *syntax)
-       req->preferredRecordSyntax =
-           yaz_str_to_z3950oid (c->odr_out, CLASS_RECSYN, syntax);
+        req->preferredRecordSyntax =
+            yaz_str_to_z3950oid (c->odr_out, CLASS_RECSYN, syntax);
 
     if (resultset->schema && *resultset->schema)
     {
-       Z_RecordComposition *compo = (Z_RecordComposition *)
+        Z_RecordComposition *compo = (Z_RecordComposition *)
             odr_malloc (c->odr_out, sizeof(*compo));
 
         req->recordComposition = compo;
@@ -2147,16 +2384,16 @@ static zoom_ret send_present (ZOOM_connection c)
     }
     else if (elementSetName && *elementSetName)
     {
-       Z_ElementSetNames *esn = (Z_ElementSetNames *)
+        Z_ElementSetNames *esn = (Z_ElementSetNames *)
             odr_malloc (c->odr_out, sizeof(*esn));
-       Z_RecordComposition *compo = (Z_RecordComposition *)
+        Z_RecordComposition *compo = (Z_RecordComposition *)
             odr_malloc (c->odr_out, sizeof(*compo));
-       
-       esn->which = Z_ElementSetNames_generic;
-       esn->u.generic = odr_strdup (c->odr_out, elementSetName);
-       compo->which = Z_RecordComp_simple;
-       compo->u.simple = esn;
-       req->recordComposition = compo;
+        
+        esn->which = Z_ElementSetNames_generic;
+        esn->u.generic = odr_strdup (c->odr_out, elementSetName);
+        compo->which = Z_RecordComp_simple;
+        compo->u.simple = esn;
+        req->recordComposition = compo;
     }
     req->resultSetId = odr_strdup(c->odr_out, resultset->setname);
     return send_APDU (c, apdu);
@@ -2165,7 +2402,23 @@ static zoom_ret send_present (ZOOM_connection c)
 ZOOM_API(ZOOM_scanset)
 ZOOM_connection_scan (ZOOM_connection c, const char *start)
 {
+    ZOOM_scanset s;
+    ZOOM_query q = ZOOM_query_create();
+
+    ZOOM_query_prefix (q, start);
+
+    s = ZOOM_connection_scan1(c, q);
+    ZOOM_query_destroy (q);
+    return s;
+
+}
+
+ZOOM_API(ZOOM_scanset)
+ZOOM_connection_scan1 (ZOOM_connection c, ZOOM_query q)
+{
     ZOOM_scanset scan = (ZOOM_scanset) xmalloc (sizeof(*scan));
+    char *start;
+    char *freeme = 0;
 
     scan->connection = c;
     scan->odr = odr_createmem (ODR_DECODE);
@@ -2173,9 +2426,34 @@ ZOOM_connection_scan (ZOOM_connection c, const char *start)
     scan->refcount = 1;
     scan->scan_response = 0;
 
-    if ((scan->termListAndStartPoint =
-         p_query_scan(scan->odr, PROTO_Z3950, &scan->attributeSet,
-                      start)))
+    /*
+     * We need to check the query-type, so we can recognise CQL and
+     * compile it into a form that we can use here.  The ZOOM_query
+     * structure has no explicit `type' member, but inspection of the
+     * ZOOM_query_prefix() and ZOOM_query_cql() functions shows how
+     * the structure is set up in each case.
+     */
+
+    if (q->z_query->which == Z_Query_type_1) {
+        yaz_log(log_api, "%p ZOOM_connection_scan1 q=%p PQF '%s'",
+                c, q, q->query_string);
+        start = q->query_string;
+    } else if (q->z_query->which == Z_Query_type_104) {
+        yaz_log(log_api, "%p ZOOM_connection_scan1 q=%p CQL '%s'",
+                c, q, q->query_string);
+        start = freeme = cql2pqf(c, q->query_string);
+        if (start == 0)
+            return 0;
+    } else {
+        yaz_log(YLOG_FATAL, "%p ZOOM_connection_scan1 q=%p unknown type '%s'",
+                c, q, q->query_string);
+        abort();
+    }
+
+    scan->termListAndStartPoint =
+        p_query_scan(scan->odr, PROTO_Z3950, &scan->attributeSet, start);
+    xfree (freeme);
+    if (scan->termListAndStartPoint != 0)
     {
         ZOOM_task task = ZOOM_connection_add_task (c, ZOOM_TASK_SCAN);
         task->u.scan.scan = scan;
@@ -2208,6 +2486,8 @@ ZOOM_scanset_destroy (ZOOM_scanset scan)
 static zoom_ret send_package (ZOOM_connection c)
 {
     ZOOM_Event event;
+
+    yaz_log(log_details, "%p send_package", c);
     if (!c->tasks)
         return zoom_complete;
     assert (c->tasks->which == ZOOM_TASK_PACKAGE);
@@ -2224,6 +2504,8 @@ static zoom_ret send_scan (ZOOM_connection c)
     ZOOM_scanset scan;
     Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_scanRequest);
     Z_ScanRequest *req = apdu->u.scanRequest;
+
+    yaz_log(log_details, "%p send_scan", c);
     if (!c->tasks)
         return zoom_complete;
     assert (c->tasks->which == ZOOM_TASK_SCAN);
@@ -2259,7 +2541,7 @@ ZOOM_scanset_size (ZOOM_scanset scan)
 
 ZOOM_API(const char *)
 ZOOM_scanset_term (ZOOM_scanset scan, size_t pos,
-                  int *occ, int *len)
+                   int *occ, int *len)
 {
     const char *term = 0;
     size_t noent = ZOOM_scanset_size (scan);
@@ -2285,7 +2567,7 @@ ZOOM_scanset_term (ZOOM_scanset scan, size_t pos,
 
 ZOOM_API(const char *)
 ZOOM_scanset_display_term (ZOOM_scanset scan, size_t pos,
-                          int *occ, int *len)
+                           int *occ, int *len)
 {
     const char *term = 0;
     size_t noent = ZOOM_scanset_size (scan);
@@ -2300,11 +2582,11 @@ ZOOM_scanset_display_term (ZOOM_scanset scan, size_t pos,
         Z_TermInfo *t = res->entries->entries[pos]->u.termInfo;
 
         if (t->displayTerm)
-       {
-           term = t->displayTerm;
-           *len = strlen(term);
-       }
-       else if (t->term->which == Z_Term_general)
+        {
+            term = t->displayTerm;
+            *len = strlen(term);
+        }
+        else if (t->term->which == Z_Term_general)
         {
             term = (const char *) t->term->u.general->buf;
             *len = t->term->u.general->len;
@@ -2371,13 +2653,13 @@ static Z_External *encode_ill_request (ZOOM_package p)
     ILL_Request *req;
     Z_External *r = 0;
     struct ill_get_ctl ctl;
-       
+        
     ctl.odr = p->odr_out;
     ctl.clientData = p;
     ctl.f = ill_array_lookup;
-       
+        
     req = ill_get_ILLRequest(&ctl, "ill", 0);
-       
+        
     if (!ill_Request (out, &req, 0, 0))
     {
         int ill_request_size;
@@ -2391,17 +2673,17 @@ static Z_External *encode_ill_request (ZOOM_package p)
         oident oid;
         int illRequest_size = 0;
         char *illRequest_buf = odr_getbuf (out, &illRequest_size, 0);
-               
+                
         oid.proto = PROTO_GENERAL;
         oid.oclass = CLASS_GENERAL;
         oid.value = VAL_ISO_ILL_1;
-               
+                
         r = (Z_External *) odr_malloc (out, sizeof(*r));
         r->direct_reference = odr_oiddup(out,oid_getoidbyent(&oid)); 
         r->indirect_reference = 0;
         r->descriptor = 0;
         r->which = Z_External_single;
-               
+                
         r->u.single_ASN1_type = (Odr_oct *)
             odr_malloc (out, sizeof(*r->u.single_ASN1_type));
         r->u.single_ASN1_type->buf = (unsigned char*)
@@ -2418,35 +2700,35 @@ static Z_ItemOrder *encode_item_order(ZOOM_package p)
     Z_ItemOrder *req = (Z_ItemOrder *) odr_malloc (p->odr_out, sizeof(*req));
     const char *str;
     
-    req->which=Z_IOItemOrder_esRequest;
+    req->which = Z_IOItemOrder_esRequest;
     req->u.esRequest = (Z_IORequest *) 
         odr_malloc(p->odr_out,sizeof(Z_IORequest));
 
     /* to keep part ... */
     req->u.esRequest->toKeep = (Z_IOOriginPartToKeep *)
-       odr_malloc(p->odr_out,sizeof(Z_IOOriginPartToKeep));
+        odr_malloc(p->odr_out,sizeof(Z_IOOriginPartToKeep));
     req->u.esRequest->toKeep->supplDescription = 0;
     req->u.esRequest->toKeep->contact = (Z_IOContact *)
         odr_malloc (p->odr_out, sizeof(*req->u.esRequest->toKeep->contact));
-       
+        
     str = ZOOM_options_get(p->options, "contact-name");
     req->u.esRequest->toKeep->contact->name = str ?
         nmem_strdup (p->odr_out->mem, str) : 0;
-       
+        
     str = ZOOM_options_get(p->options, "contact-phone");
     req->u.esRequest->toKeep->contact->phone = str ?
         nmem_strdup (p->odr_out->mem, str) : 0;
-       
+        
     str = ZOOM_options_get(p->options, "contact-email");
     req->u.esRequest->toKeep->contact->email = str ?
         nmem_strdup (p->odr_out->mem, str) : 0;
-       
+        
     req->u.esRequest->toKeep->addlBilling = 0;
-       
+        
     /* not to keep part ... */
     req->u.esRequest->notToKeep = (Z_IOOriginPartNotToKeep *)
         odr_malloc(p->odr_out,sizeof(Z_IOOriginPartNotToKeep));
-       
+        
     str = ZOOM_options_get(p->options, "itemorder-setname");
     if (!str)
         str = "default";
@@ -2462,7 +2744,7 @@ static Z_ItemOrder *encode_item_order(ZOOM_package p)
            nmem_strdup (p->odr_out->mem, str);
         req->u.esRequest->notToKeep->resultSetItem->item =
             (int *) odr_malloc(p->odr_out, sizeof(int));
-       
+        
         str = ZOOM_options_get(p->options, "itemorder-item");
         *req->u.esRequest->notToKeep->resultSetItem->item =
             (str ? atoi(str) : 1);
@@ -2473,56 +2755,80 @@ static Z_ItemOrder *encode_item_order(ZOOM_package p)
 }
 
 Z_APDU *create_admin_package(ZOOM_package p, int type, 
-                            Z_ESAdminOriginPartToKeep **toKeepP,
-                            Z_ESAdminOriginPartNotToKeep **notToKeepP)
+                             Z_ESAdminOriginPartToKeep **toKeepP,
+                             Z_ESAdminOriginPartNotToKeep **notToKeepP)
 {
     Z_APDU *apdu = create_es_package (p, VAL_ADMINSERVICE);
     if (apdu)
     {
-       Z_ESAdminOriginPartToKeep  *toKeep;
-       Z_ESAdminOriginPartNotToKeep  *notToKeep;
-       Z_External *r = (Z_External *) odr_malloc (p->odr_out, sizeof(*r));
-       const char *first_db = "Default";
-       int num_db;
-       char **db = set_DatabaseNames(p->connection, p->options, &num_db);
-       if (num_db > 0)
-           first_db = db[0];
-           
-       r->direct_reference =
-           yaz_oidval_to_z3950oid(p->odr_out, CLASS_EXTSERV,
-                                  VAL_ADMINSERVICE);
-       r->descriptor = 0;
-       r->indirect_reference = 0;
-       r->which = Z_External_ESAdmin;
-       
-       r->u.adminService = (Z_Admin *)
-           odr_malloc(p->odr_out, sizeof(*r->u.adminService));
-       r->u.adminService->which = Z_Admin_esRequest;
-       r->u.adminService->u.esRequest = (Z_AdminEsRequest *)
-           odr_malloc(p->odr_out, sizeof(*r->u.adminService->u.esRequest));
-       
-       toKeep = r->u.adminService->u.esRequest->toKeep =
-           (Z_ESAdminOriginPartToKeep *) 
-           odr_malloc(p->odr_out, sizeof(*r->u.adminService->u.esRequest->toKeep));
-       toKeep->which=type;
-       toKeep->databaseName = odr_strdup(p->odr_out, first_db);
-       toKeep->u.create=odr_nullval();
-       apdu->u.extendedServicesRequest->taskSpecificParameters = r;
-       
-       r->u.adminService->u.esRequest->notToKeep = notToKeep =
-           (Z_ESAdminOriginPartNotToKeep *)
-           odr_malloc(p->odr_out,
-                      sizeof(*r->u.adminService->u.esRequest->notToKeep));
-       notToKeep->which=Z_ESAdminOriginPartNotToKeep_recordsWillFollow;
-       notToKeep->u.recordsWillFollow=odr_nullval();
-       if (toKeepP)
-           *toKeepP = toKeep;
-       if (notToKeepP)
-           *notToKeepP = notToKeep;
+        Z_ESAdminOriginPartToKeep  *toKeep;
+        Z_ESAdminOriginPartNotToKeep  *notToKeep;
+        Z_External *r = (Z_External *) odr_malloc (p->odr_out, sizeof(*r));
+        const char *first_db = "Default";
+        int num_db;
+        char **db = set_DatabaseNames(p->connection, p->options, &num_db);
+        if (num_db > 0)
+            first_db = db[0];
+            
+        r->direct_reference =
+            yaz_oidval_to_z3950oid(p->odr_out, CLASS_EXTSERV,
+                                   VAL_ADMINSERVICE);
+        r->descriptor = 0;
+        r->indirect_reference = 0;
+        r->which = Z_External_ESAdmin;
+        
+        r->u.adminService = (Z_Admin *)
+            odr_malloc(p->odr_out, sizeof(*r->u.adminService));
+        r->u.adminService->which = Z_Admin_esRequest;
+        r->u.adminService->u.esRequest = (Z_AdminEsRequest *)
+            odr_malloc(p->odr_out, sizeof(*r->u.adminService->u.esRequest));
+        
+        toKeep = r->u.adminService->u.esRequest->toKeep =
+            (Z_ESAdminOriginPartToKeep *) 
+            odr_malloc(p->odr_out, sizeof(*r->u.adminService->u.esRequest->toKeep));
+        toKeep->which = type;
+        toKeep->databaseName = odr_strdup(p->odr_out, first_db);
+        toKeep->u.create = odr_nullval();
+        apdu->u.extendedServicesRequest->taskSpecificParameters = r;
+        
+        r->u.adminService->u.esRequest->notToKeep = notToKeep =
+            (Z_ESAdminOriginPartNotToKeep *)
+            odr_malloc(p->odr_out,
+                       sizeof(*r->u.adminService->u.esRequest->notToKeep));
+        notToKeep->which = Z_ESAdminOriginPartNotToKeep_recordsWillFollow;
+        notToKeep->u.recordsWillFollow = odr_nullval();
+        if (toKeepP)
+            *toKeepP = toKeep;
+        if (notToKeepP)
+            *notToKeepP = notToKeep;
     }
     return apdu;
 }
 
+static Z_APDU *create_xmlupdate_package(ZOOM_package p)
+{
+    Z_APDU *apdu = create_es_package(p, VAL_XMLES);
+    Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
+    Z_External *ext = (Z_External *) odr_malloc(p->odr_out, sizeof(*ext));
+    const char *doc = ZOOM_options_get(p->options, "doc");
+
+    req->taskSpecificParameters = ext;
+    ext->direct_reference = req->packageType;
+    ext->descriptor = 0;
+    ext->indirect_reference = 0;
+    
+    ext->which = Z_External_octet;
+    ext->u.single_ASN1_type = (Odr_oct *)
+        odr_malloc (p->odr_out, sizeof(Odr_oct));
+
+    if (!doc)
+        doc = "";
+    ext->u.single_ASN1_type->buf = (unsigned char*)
+        odr_strdup(p->odr_out, doc);
+    ext->u.single_ASN1_type->size = ext->u.single_ASN1_type->len = strlen(doc);
+    return apdu;
+}
+
 static Z_APDU *create_update_package(ZOOM_package p)
 {
     Z_APDU *apdu = 0;
@@ -2538,98 +2844,98 @@ static Z_APDU *create_update_package(ZOOM_package p)
     int action_no = -1;
     
     if (syntax_str)
-       syntax_oid = oid_getvalbyname(syntax_str);
+        syntax_oid = oid_getvalbyname(syntax_str);
     if (!record_buf)
     {
-       record_buf = "void";
-       syntax_oid = VAL_SUTRS;
+        record_buf = "void";
+        syntax_oid = VAL_SUTRS;
     }
-    if (syntax_oid != VAL_NONE)
-       syntax_oid = VAL_TEXT_XML;
+    if (syntax_oid == VAL_NONE)
+        syntax_oid = VAL_TEXT_XML;
     
     if (num_db > 0)
-       first_db = db[0];
+        first_db = db[0];
     
     if (!action)
-       action = "specialUpdate";
+        action = "specialUpdate";
     
     if (!strcmp(action, "recordInsert"))
-       action_no = Z_IUOriginPartToKeep_recordInsert;
+        action_no = Z_IUOriginPartToKeep_recordInsert;
     else if (!strcmp(action, "recordReplace"))
-       action_no = Z_IUOriginPartToKeep_recordReplace;
+        action_no = Z_IUOriginPartToKeep_recordReplace;
     else if (!strcmp(action, "recordDelete"))
-       action_no = Z_IUOriginPartToKeep_recordDelete;
+        action_no = Z_IUOriginPartToKeep_recordDelete;
     else if (!strcmp(action, "elementUpdate"))
-       action_no = Z_IUOriginPartToKeep_elementUpdate;
+        action_no = Z_IUOriginPartToKeep_elementUpdate;
     else if (!strcmp(action, "specialUpdate"))
-       action_no = Z_IUOriginPartToKeep_specialUpdate;
+        action_no = Z_IUOriginPartToKeep_specialUpdate;
     else
-       return 0;
+        return 0;
 
     apdu = create_es_package (p, VAL_DBUPDATE);
     if (apdu)
     {
-       Z_IUOriginPartToKeep *toKeep;
-       Z_IUSuppliedRecords *notToKeep;
-       Z_External *r = (Z_External *)
-           odr_malloc (p->odr_out, sizeof(*r));
-       
-       apdu->u.extendedServicesRequest->taskSpecificParameters = r;
-       
-       r->direct_reference =
-           yaz_oidval_to_z3950oid(p->odr_out, CLASS_EXTSERV,
-                                  VAL_DBUPDATE);
-       r->descriptor = 0;
-       r->which = Z_External_update;
-       r->indirect_reference = 0;
-       r->u.update = (Z_IUUpdate *)
-           odr_malloc(p->odr_out, sizeof(*r->u.update));
-       
-       r->u.update->which = Z_IUUpdate_esRequest;
-       r->u.update->u.esRequest = (Z_IUUpdateEsRequest *)
-           odr_malloc(p->odr_out, sizeof(*r->u.update->u.esRequest));
-       toKeep = r->u.update->u.esRequest->toKeep = 
-           (Z_IUOriginPartToKeep *)
-           odr_malloc(p->odr_out, sizeof(*toKeep));
-       
-       toKeep->databaseName = odr_strdup(p->odr_out, first_db);
-       toKeep->schema = 0;
-       toKeep->elementSetName = 0;
-       toKeep->actionQualifier = 0;
-       toKeep->action = odr_intdup(p->odr_out, action_no);
-       
-       notToKeep = r->u.update->u.esRequest->notToKeep = 
-           (Z_IUSuppliedRecords *)
-           odr_malloc(p->odr_out, sizeof(*notToKeep));
-       notToKeep->num = 1;
-       notToKeep->elements = (Z_IUSuppliedRecords_elem **)
-           odr_malloc(p->odr_out, sizeof(*notToKeep->elements));
-       notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *)
-           odr_malloc(p->odr_out, sizeof(**notToKeep->elements));
-       notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque;
-       if (recordIdOpaque)
-       {
-           notToKeep->elements[0]->u.opaque = (Odr_oct *)
-               odr_malloc (p->odr_out, sizeof(Odr_oct));
-           notToKeep->elements[0]->u.opaque->size =
-               notToKeep->elements[0]->u.opaque->len = strlen(recordIdOpaque);
-           notToKeep->elements[0]->u.opaque->buf =
-               odr_strdup(p->odr_out, recordIdOpaque);
-       }
-       else if (recordIdNumber)
-       {
-           notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_number;
-           
-           notToKeep->elements[0]->u.number =
-               odr_intdup(p->odr_out, atoi(recordIdNumber));
-       }
-       else
-           notToKeep->elements[0]->u.opaque = 0;
-       notToKeep->elements[0]->supplementalId = 0;
-       notToKeep->elements[0]->correlationInfo = 0;
-       notToKeep->elements[0]->record =
-           z_ext_record(p->odr_out, syntax_oid,
-                        record_buf, strlen(record_buf));
+        Z_IUOriginPartToKeep *toKeep;
+        Z_IUSuppliedRecords *notToKeep;
+        Z_External *r = (Z_External *)
+            odr_malloc (p->odr_out, sizeof(*r));
+        
+        apdu->u.extendedServicesRequest->taskSpecificParameters = r;
+        
+        r->direct_reference =
+            yaz_oidval_to_z3950oid(p->odr_out, CLASS_EXTSERV,
+                                   VAL_DBUPDATE);
+        r->descriptor = 0;
+        r->which = Z_External_update;
+        r->indirect_reference = 0;
+        r->u.update = (Z_IUUpdate *)
+            odr_malloc(p->odr_out, sizeof(*r->u.update));
+        
+        r->u.update->which = Z_IUUpdate_esRequest;
+        r->u.update->u.esRequest = (Z_IUUpdateEsRequest *)
+            odr_malloc(p->odr_out, sizeof(*r->u.update->u.esRequest));
+        toKeep = r->u.update->u.esRequest->toKeep = 
+            (Z_IUOriginPartToKeep *)
+            odr_malloc(p->odr_out, sizeof(*toKeep));
+        
+        toKeep->databaseName = odr_strdup(p->odr_out, first_db);
+        toKeep->schema = 0;
+        toKeep->elementSetName = 0;
+        toKeep->actionQualifier = 0;
+        toKeep->action = odr_intdup(p->odr_out, action_no);
+        
+        notToKeep = r->u.update->u.esRequest->notToKeep = 
+            (Z_IUSuppliedRecords *)
+            odr_malloc(p->odr_out, sizeof(*notToKeep));
+        notToKeep->num = 1;
+        notToKeep->elements = (Z_IUSuppliedRecords_elem **)
+            odr_malloc(p->odr_out, sizeof(*notToKeep->elements));
+        notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *)
+            odr_malloc(p->odr_out, sizeof(**notToKeep->elements));
+        notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque;
+        if (recordIdOpaque)
+        {
+            notToKeep->elements[0]->u.opaque = (Odr_oct *)
+                odr_malloc (p->odr_out, sizeof(Odr_oct));
+            notToKeep->elements[0]->u.opaque->size =
+                notToKeep->elements[0]->u.opaque->len = strlen(recordIdOpaque);
+            notToKeep->elements[0]->u.opaque->buf = (unsigned char*)
+                odr_strdup(p->odr_out, recordIdOpaque);
+        }
+        else if (recordIdNumber)
+        {
+            notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_number;
+            
+            notToKeep->elements[0]->u.number =
+                odr_intdup(p->odr_out, atoi(recordIdNumber));
+        }
+        else
+            notToKeep->elements[0]->u.opaque = 0;
+        notToKeep->elements[0]->supplementalId = 0;
+        notToKeep->elements[0]->correlationInfo = 0;
+        notToKeep->elements[0]->record =
+            z_ext_record(p->odr_out, syntax_oid,
+                         record_buf, strlen(record_buf));
     }
     if (0 && apdu)
     {
@@ -2672,22 +2978,26 @@ ZOOM_API(void)
     }
     else if (!strcmp(type, "create"))  /* create database */
     {
-       apdu = create_admin_package(p, Z_ESAdminOriginPartToKeep_create,
-                                   0, 0);
-    }  
+        apdu = create_admin_package(p, Z_ESAdminOriginPartToKeep_create,
+                                    0, 0);
+    }   
     else if (!strcmp(type, "drop"))  /* drop database */
     {
-       apdu = create_admin_package(p, Z_ESAdminOriginPartToKeep_drop,
-                                   0, 0);
+        apdu = create_admin_package(p, Z_ESAdminOriginPartToKeep_drop,
+                                    0, 0);
     }
     else if (!strcmp(type, "commit"))  /* commit changes */
     {
-       apdu = create_admin_package(p, Z_ESAdminOriginPartToKeep_commit,
-                                   0, 0);
+        apdu = create_admin_package(p, Z_ESAdminOriginPartToKeep_commit,
+                                    0, 0);
     }
     else if (!strcmp(type, "update")) /* update record(s) */
     {
-       apdu = create_update_package(p);
+        apdu = create_update_package(p);
+    }
+    else if (!strcmp(type, "xmlupdate"))
+    {
+        apdu = create_xmlupdate_package(p);
     }
     if (apdu)
     {
@@ -2761,22 +3071,21 @@ static int ZOOM_connection_exec_task (ZOOM_connection c)
     zoom_ret ret = zoom_complete;
 
     if (!task)
-    {
-        yaz_log (LOG_DEBUG, "ZOOM_connection_exec_task task=<null>");
-       return 0;
-    }
-    yaz_log (LOG_DEBUG, "ZOOM_connection_exec_task type=%d run=%d",
-             task->which, task->running);
+        return 0;
+    yaz_log(log_details, "%p ZOOM_connection_exec_task type=%d run=%d",
+             c, task->which, task->running);
     if (c->error != ZOOM_ERROR_NONE)
     {
-        yaz_log (LOG_DEBUG, "remove tasks because of error = %d", c->error);
+        yaz_log(log_details, "%p ZOOM_connection_exec_task "
+                "removing tasks because of error = %d", c, c->error);
         ZOOM_connection_remove_tasks (c);
         return 0;
     }
     if (task->running)
     {
-        yaz_log (LOG_DEBUG, "task already running");
-       return 0;
+        yaz_log(log_details, "%p ZOOM_connection_exec_task "
+                 "task already running", c);
+        return 0;
     }
     task->running = 1;
     ret = zoom_complete;
@@ -2804,26 +3113,29 @@ static int ZOOM_connection_exec_task (ZOOM_connection c)
             break;
         case ZOOM_TASK_PACKAGE:
             ret = send_package(c);
-           break;
-       case ZOOM_TASK_SORT:
-           c->tasks->u.sort.resultset->r_sort_spec = 
-               c->tasks->u.sort.q->sort_spec;
-           ret = send_sort(c, c->tasks->u.sort.resultset);
+            break;
+        case ZOOM_TASK_SORT:
+            c->tasks->u.sort.resultset->r_sort_spec = 
+                c->tasks->u.sort.q->sort_spec;
+            ret = send_sort(c, c->tasks->u.sort.resultset);
             break;
         }
     }
     else
     {
-        yaz_log (LOG_DEBUG, "remove tasks because no connection exist");
+        yaz_log(log_details, "%p ZOOM_connection_exec_task "
+                "remove tasks because no connection exist", c);
         ZOOM_connection_remove_tasks (c);
     }
     if (ret == zoom_complete)
     {
-        yaz_log (LOG_DEBUG, "task removed (complete)");
+        yaz_log(log_details, "%p ZOOM_connection_exec_task "
+                 "task removed (complete)", c);
         ZOOM_connection_remove_task (c);
         return 0;
     }
-    yaz_log (LOG_DEBUG, "task pending");
+    yaz_log(log_details, "%p ZOOM_connection_exec_task "
+            "task pending", c);
     return 1;
 }
 
@@ -2832,9 +3144,9 @@ static zoom_ret send_sort_present (ZOOM_connection c)
     zoom_ret r = zoom_complete;
 
     if (c->tasks && c->tasks->which == ZOOM_TASK_SEARCH)
-       r = send_sort (c, c->tasks->u.search.resultset);
+        r = send_sort (c, c->tasks->u.search.resultset);
     if (r == zoom_complete)
-       r = send_present (c);
+        r = send_present (c);
     return r;
 }
 
@@ -2855,20 +3167,56 @@ static int es_response (ZOOM_connection c,
             ZOOM_options_setl (c->tasks->u.package->options,
                                "targetReference", (char*) id->buf, id->len);
     }
+    if (res->taskPackage && 
+        res->taskPackage->which == Z_External_octet)
+    {
+        Odr_oct *doc = res->taskPackage->u.octet_aligned;
+        ZOOM_options_setl (c->tasks->u.package->options,
+                           "xmlUpdateDoc", (char*) doc->buf, doc->len);
+    }
     return 1;
 }
 
+static void interpret_init_diag(ZOOM_connection c,
+                                Z_DiagnosticFormat *diag)
+{
+    if (diag->num > 0)
+    {
+        Z_DiagnosticFormat_s *ds = diag->elements[0];
+        if (ds->which == Z_DiagnosticFormat_s_defaultDiagRec)
+            response_default_diag(c, ds->u.defaultDiagRec);
+    }
+}
+
+
+static void interpret_otherinformation_field(ZOOM_connection c,
+                                             Z_OtherInformation *ui)
+{
+    int i;
+    for (i = 0; i < ui->num_elements; i++)
+    {
+        Z_OtherInformationUnit *unit = ui->list[i];
+        if (unit->which == Z_OtherInfo_externallyDefinedInfo &&
+            unit->information.externallyDefinedInfo &&
+            unit->information.externallyDefinedInfo->which ==
+            Z_External_diag1) 
+        {
+            interpret_init_diag(c, unit->information.externallyDefinedInfo->u.diag1);
+        } 
+    }
+}
 
-static void handle_apdu (ZOOM_connection c, Z_APDU *apdu)
+static void recv_apdu (ZOOM_connection c, Z_APDU *apdu)
 {
     Z_InitResponse *initrs;
     
     c->mask = 0;
-    yaz_log (LOG_DEBUG, "recv APDU type=%d", apdu->which);
+    yaz_log(log_details, "%p recv_apdu apdu->which=%d", c, apdu->which);
     switch(apdu->which)
     {
     case Z_APDU_initResponse:
-       initrs = apdu->u.initResponse;
+        yaz_log(log_api, "%p recv_apd: Received Init response", c);
+        initrs = apdu->u.initResponse;
         ZOOM_connection_option_set(c, "serverImplementationId",
                                    initrs->implementationId ?
                                    initrs->implementationId : "");
@@ -2878,7 +3226,7 @@ static void handle_apdu (ZOOM_connection c, Z_APDU *apdu)
         ZOOM_connection_option_set(c, "serverImplementationVersion",
                                    initrs->implementationVersion ?
                                    initrs->implementationVersion : "");
-       /* Set the three old options too, for old applications */
+        /* Set the three old options too, for old applications */
         ZOOM_connection_option_set(c, "targetImplementationId",
                                    initrs->implementationId ?
                                    initrs->implementationId : "");
@@ -2888,19 +3236,24 @@ static void handle_apdu (ZOOM_connection c, Z_APDU *apdu)
         ZOOM_connection_option_set(c, "targetImplementationVersion",
                                    initrs->implementationVersion ?
                                    initrs->implementationVersion : "");
-       if (!*initrs->result)
-       {
-            set_ZOOM_error(c, ZOOM_ERROR_INIT, 0);
-       }
-       else
-       {
-           char *cookie =
-               yaz_oi_get_string_oidval (&apdu->u.initResponse->otherInfo,
-                                         VAL_COOKIE, 1, 0);
-           xfree (c->cookie_in);
-           c->cookie_in = 0;
-           if (cookie)
-               c->cookie_in = xstrdup(cookie);
+        if (!*initrs->result)
+        {
+            Z_External *uif = initrs->userInformationField;
+
+            set_ZOOM_error(c, ZOOM_ERROR_INIT, 0); /* default error */
+
+            if (uif && uif->which == Z_External_userInfo1)
+                interpret_otherinformation_field(c, uif->u.userInfo1);
+        }
+        else
+        {
+            char *cookie =
+                yaz_oi_get_string_oidval (&apdu->u.initResponse->otherInfo,
+                                          VAL_COOKIE, 1, 0);
+            xfree (c->cookie_in);
+            c->cookie_in = 0;
+            if (cookie)
+                c->cookie_in = xstrdup(cookie);
             if (ODR_MASK_GET(initrs->options, Z_Options_namedResultSets) &&
                 ODR_MASK_GET(initrs->protocolVersion, Z_ProtocolVersion_3))
                 c->support_named_resultsets = 1;
@@ -2909,22 +3262,23 @@ static void handle_apdu (ZOOM_connection c, Z_APDU *apdu)
                 assert (c->tasks->which == ZOOM_TASK_CONNECT);
                 ZOOM_connection_remove_task (c);
             }
-           ZOOM_connection_exec_task (c);
-       }
-       if (ODR_MASK_GET(initrs->options, Z_Options_negotiationModel))
-       {
+            ZOOM_connection_exec_task (c);
+        }
+        if (ODR_MASK_GET(initrs->options, Z_Options_negotiationModel))
+        {
             NMEM tmpmem = nmem_create();
             Z_CharSetandLanguageNegotiation *p =
                 yaz_get_charneg_record(initrs->otherInfo);
             
             if (p)
             {
-                char *charset=NULL, *lang=NULL;
+                char *charset = NULL, *lang = NULL;
                 int sel;
                 
                 yaz_get_response_charneg(tmpmem, p, &charset, &lang, &sel);
-                yaz_log(LOG_DEBUG, "Target accepted: charset %s, "
-                        "language %s, select %d",
+                yaz_log(log_details, "%p recv_apdu target accepted: "
+                        "charset %s, language %s, select %d",
+                        c,
                         charset ? charset : "none", lang ? lang : "none", sel);
                 if (charset)
                     ZOOM_connection_option_set (c, "negotiation-charset",
@@ -2932,34 +3286,44 @@ static void handle_apdu (ZOOM_connection c, Z_APDU *apdu)
                 if (lang)
                     ZOOM_connection_option_set (c, "negotiation-lang",
                                                 lang);
+
+                ZOOM_connection_option_set (
+                    c,  "negotiation-charset-in-effect-for-records",
+                    (sel != 0) ? "1" : "0");
                 nmem_destroy(tmpmem);
             }
-       }       
-       break;
+        }       
+        break;
     case Z_APDU_searchResponse:
-       handle_search_response (c, apdu->u.searchResponse);
-       if (send_sort_present (c) == zoom_complete)
-           ZOOM_connection_remove_task (c);
-       break;
+        yaz_log(log_api, "%p recv_apdu Search response", c);
+        handle_search_response (c, apdu->u.searchResponse);
+        if (send_sort_present (c) == zoom_complete)
+            ZOOM_connection_remove_task (c);
+        break;
     case Z_APDU_presentResponse:
-       handle_present_response (c, apdu->u.presentResponse);
-       if (send_present (c) == zoom_complete)
-           ZOOM_connection_remove_task (c);
-       break;
+        yaz_log(log_api, "%p recv_apdu Present response", c);
+        handle_present_response (c, apdu->u.presentResponse);
+        if (send_present (c) == zoom_complete)
+            ZOOM_connection_remove_task (c);
+        break;
     case Z_APDU_sortResponse:
-       sort_response (c, apdu->u.sortResponse);
-       if (send_present (c) == zoom_complete)
-           ZOOM_connection_remove_task (c);
+        yaz_log(log_api, "%p recv_apdu Sort response", c);
+        sort_response (c, apdu->u.sortResponse);
+        if (send_present (c) == zoom_complete)
+            ZOOM_connection_remove_task (c);
         break;
     case Z_APDU_scanResponse:
+        yaz_log(log_api, "%p recv_apdu Scan response", c);
         scan_response (c, apdu->u.scanResponse);
         ZOOM_connection_remove_task (c);
         break;
     case Z_APDU_extendedServicesResponse:
+        yaz_log(log_api, "%p recv_apdu Extended Services response", c);
         es_response (c, apdu->u.extendedServicesResponse);
         ZOOM_connection_remove_task (c);
         break;
     case Z_APDU_close:
+        yaz_log(log_api, "%p recv_apdu Close PDU", c);
         if (c->reconnect_ok)
         {
             do_close(c);
@@ -2968,11 +3332,12 @@ static void handle_apdu (ZOOM_connection c, Z_APDU *apdu)
         }
         else
         {
-            set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, 0);
+            set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, c->host_port);
             do_close(c);
         }
         break;
     default:
+        yaz_log(log_api, "%p Received unknown PDU", c);
         set_ZOOM_error(c, ZOOM_ERROR_DECODE, 0);
         do_close(c);
     }
@@ -2995,14 +3360,14 @@ static void handle_srw_response(ZOOM_connection c,
     else if (c->tasks->which == ZOOM_TASK_RETRIEVE)
         resultset = c->tasks->u.retrieve.resultset;
     else
-       return ;
+        return ;
 
     event = ZOOM_Event_create(ZOOM_EVENT_RECV_SEARCH);
     ZOOM_connection_put_event(c, event);
 
     resultset->size = 0;
 
-    yaz_log(LOG_DEBUG, "got SRW response OK");
+    yaz_log(log_details, "%p handle_srw_response got SRW response OK", c);
     
     if (res->numberOfRecords)
         resultset->size = *res->numberOfRecords;
@@ -3030,7 +3395,7 @@ static void handle_srw_response(ZOOM_connection c,
         npr->u.databaseRecord->which = Z_External_octet;
         npr->u.databaseRecord->u.octet_aligned = (Odr_oct *)
             odr_malloc(c->odr_in, sizeof(Odr_oct));
-        npr->u.databaseRecord->u.octet_aligned->buf = 
+        npr->u.databaseRecord->u.octet_aligned->buf = (unsigned char*)
             res->records[i].recordData_buf;
         npr->u.databaseRecord->u.octet_aligned->len = 
             npr->u.databaseRecord->u.octet_aligned->size = 
@@ -3039,16 +3404,16 @@ static void handle_srw_response(ZOOM_connection c,
     }
     if (res->num_diagnostics > 0)
     {
-       const char *uri = res->diagnostics[0].uri;
-       if (uri)
-       {
-           int code = 0;       
-           const char *cp;
-           if ((cp = strrchr(uri, '/')))
-               code = atoi(cp+1);
-           set_dset_error(c, code, uri,
-                          res->diagnostics[0].details, 0);
-       }
+        const char *uri = res->diagnostics[0].uri;
+        if (uri)
+        {
+            int code = 0;       
+            const char *cp;
+            if ((cp = strrchr(uri, '/')))
+                code = atoi(cp+1);
+            set_dset_error(c, code, uri,
+                           res->diagnostics[0].details, 0);
+        }
     }
     nmem = odr_extract_mem(c->odr_in);
     nmem_transfer(resultset->odr->mem, nmem);
@@ -3065,7 +3430,7 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres)
     const char *connection_head = z_HTTP_header_lookup(hres->headers,
                                                        "Connection");
     c->mask = 0;
-    yaz_log (LOG_DEBUG, "handle_http");
+    yaz_log(log_details, "%p handle_http", c);
 
     if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
     {
@@ -3082,7 +3447,7 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres)
         if (!ret && soap_package->which == Z_SOAP_generic &&
             soap_package->u.generic->no == 0)
         {
-            Z_SRW_PDU *sr = soap_package->u.generic->p;
+            Z_SRW_PDU *sr = (Z_SRW_PDU*) soap_package->u.generic->p;
             if (sr->which == Z_SRW_searchRetrieve_response)
                 handle_srw_response(c, sr->u.response);
             else
@@ -3132,22 +3497,22 @@ static int do_read (ZOOM_connection c)
     
     r = cs_get (c->cs, &c->buf_in, &c->len_in);
     more = cs_more(c->cs);
-    yaz_log (LOG_DEBUG, "do_read len=%d more=%d", r, more);
+    yaz_log(log_details, "%p do_read len=%d more=%d", c, r, more);
     if (r == 1)
-       return 0;
+        return 0;
     if (r <= 0)
     {
         if (c->reconnect_ok)
         {
             do_close (c);
             c->reconnect_ok = 0;
-            yaz_log (LOG_DEBUG, "reconnect read");
+            yaz_log(log_details, "%p do_read reconnect read", c);
             c->tasks->running = 0;
             ZOOM_connection_insert_task (c, ZOOM_TASK_CONNECT);
         }
         else
         {
-            set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, 0);
+            set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, c->host_port);
             do_close (c);
         }
     }
@@ -3156,31 +3521,31 @@ static int do_read (ZOOM_connection c)
         Z_GDU *gdu;
         ZOOM_Event event;
 
-       odr_reset (c->odr_in);
-       odr_setbuf (c->odr_in, c->buf_in, r, 0);
+        odr_reset (c->odr_in);
+        odr_setbuf (c->odr_in, c->buf_in, r, 0);
         event = ZOOM_Event_create (ZOOM_EVENT_RECV_APDU);
         ZOOM_connection_put_event (c, event);
 
-       if (!z_GDU (c->odr_in, &gdu, 0, 0))
-       {
-           int x;
-           int err = odr_geterrorx(c->odr_in, &x);
-           char msg[60];
-           const char *element = odr_getelement(c->odr_in);
-           sprintf (msg, "ODR code %d:%d element=%-20s",
-                    err, x, element ? element : "<unknown>");
-           set_ZOOM_error(c, ZOOM_ERROR_DECODE, msg);
-           do_close (c);
-       }
-       else if (gdu->which == Z_GDU_Z3950)
-           handle_apdu (c, gdu->u.z3950);
+        if (!z_GDU (c->odr_in, &gdu, 0, 0))
+        {
+            int x;
+            int err = odr_geterrorx(c->odr_in, &x);
+            char msg[60];
+            const char *element = odr_getelement(c->odr_in);
+            sprintf (msg, "ODR code %d:%d element=%-20s",
+                     err, x, element ? element : "<unknown>");
+            set_ZOOM_error(c, ZOOM_ERROR_DECODE, msg);
+            do_close (c);
+        }
+        else if (gdu->which == Z_GDU_Z3950)
+            recv_apdu (c, gdu->u.z3950);
         else if (gdu->which == Z_GDU_HTTP_Response)
         {
 #if HAVE_XML2
             handle_http (c, gdu->u.HTTP_Response);
 #else
             set_ZOOM_error(c, ZOOM_ERROR_DECODE, 0);
-           do_close (c);
+            do_close (c);
 #endif
         }
         c->reconnect_ok = 0;
@@ -3196,24 +3561,25 @@ static zoom_ret do_write_ex (ZOOM_connection c, char *buf_out, int len_out)
     event = ZOOM_Event_create(ZOOM_EVENT_SEND_DATA);
     ZOOM_connection_put_event (c, event);
 
-    yaz_log (LOG_DEBUG, "do_write_ex len=%d", len_out);
-    if ((r=cs_put (c->cs, buf_out, len_out)) < 0)
+    yaz_log(log_details, "%p do_write_ex len=%d", c, len_out);
+    if ((r = cs_put(c->cs, buf_out, len_out)) < 0)
     {
+        yaz_log(log_details, "%p do_write_ex write failed", c);
         if (c->reconnect_ok)
         {
             do_close (c);
             c->reconnect_ok = 0;
-            yaz_log (LOG_DEBUG, "reconnect write");
+            yaz_log(log_details, "%p do_write_ex reconnect write", c);
             c->tasks->running = 0;
             ZOOM_connection_insert_task (c, ZOOM_TASK_CONNECT);
             return zoom_pending;
         }
-       if (c->state == STATE_CONNECTING)
-           set_ZOOM_error(c, ZOOM_ERROR_CONNECT, 0);
-       else
-            set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, 0);
-       do_close (c);
-       return zoom_complete;
+        if (c->state == STATE_CONNECTING)
+            set_ZOOM_error(c, ZOOM_ERROR_CONNECT, c->host_port);
+        else
+            set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, c->host_port);
+        do_close (c);
+        return zoom_complete;
     }
     else if (r == 1)
     {    
@@ -3222,12 +3588,14 @@ static zoom_ret do_write_ex (ZOOM_connection c, char *buf_out, int len_out)
             c->mask += ZOOM_SELECT_WRITE;
         if (c->cs->io_pending & CS_WANT_READ)
             c->mask += ZOOM_SELECT_READ;
-        yaz_log (LOG_DEBUG, "do_write_ex 1 mask=%d", c->mask);
+        yaz_log(log_details, "%p do_write_ex write incomplete mask=%d",
+                c, c->mask);
     }
     else
     {
         c->mask = ZOOM_SELECT_READ|ZOOM_SELECT_EXCEPT;
-        yaz_log (LOG_DEBUG, "do_write_ex 2 mask=%d", c->mask);
+        yaz_log(log_details, "%p do_write_ex write complete mask=%d",
+                c, c->mask);
     }
     return zoom_pending;
 }
@@ -3244,16 +3612,22 @@ ZOOM_connection_option_get (ZOOM_connection c, const char *key)
     return ZOOM_options_get (c->options, key);
 }
 
+ZOOM_API(const char *)
+ZOOM_connection_option_getl (ZOOM_connection c, const char *key, int *lenp)
+{
+    return ZOOM_options_getl (c->options, key, lenp);
+}
+
 ZOOM_API(void)
 ZOOM_connection_option_set (ZOOM_connection c, const char *key,
-                           const char *val)
+                            const char *val)
 {
     ZOOM_options_set (c->options, key, val);
 }
 
 ZOOM_API(void)
 ZOOM_connection_option_setl (ZOOM_connection c, const char *key,
-                            const char *val, int len)
+                             const char *val, int len)
 {
     ZOOM_options_setl (c->options, key, val, len);
 }
@@ -3295,36 +3669,48 @@ ZOOM_connection_addinfo (ZOOM_connection c)
 }
 
 ZOOM_API(const char *)
+ZOOM_connection_diagset (ZOOM_connection c)
+{
+    const char *diagset;
+    ZOOM_connection_error_x (c, 0, 0, &diagset);
+    return diagset;
+}
+
+ZOOM_API(const char *)
 ZOOM_diag_str (int error)
 {
     switch (error)
     {
     case ZOOM_ERROR_NONE:
-       return "No error";
+        return "No error";
     case ZOOM_ERROR_CONNECT:
-       return "Connect failed";
+        return "Connect failed";
     case ZOOM_ERROR_MEMORY:
-       return "Out of memory";
+        return "Out of memory";
     case ZOOM_ERROR_ENCODE:
-       return "Encoding failed";
+        return "Encoding failed";
     case ZOOM_ERROR_DECODE:
-       return "Decoding failed";
+        return "Decoding failed";
     case ZOOM_ERROR_CONNECTION_LOST:
-       return "Connection lost";
+        return "Connection lost";
     case ZOOM_ERROR_INIT:
-       return "Init rejected";
+        return "Init rejected";
     case ZOOM_ERROR_INTERNAL:
-       return "Internal failure";
+        return "Internal failure";
     case ZOOM_ERROR_TIMEOUT:
-       return "Timeout";
+        return "Timeout";
     case ZOOM_ERROR_UNSUPPORTED_PROTOCOL:
-       return "Unsupported protocol";
+        return "Unsupported protocol";
     case ZOOM_ERROR_UNSUPPORTED_QUERY:
-       return "Unsupported query type";
+        return "Unsupported query type";
     case ZOOM_ERROR_INVALID_QUERY:
-       return "Invalid query";
+        return "Invalid query";
+    case ZOOM_ERROR_CQL_PARSE:
+        return "CQL parsing error";
+    case ZOOM_ERROR_CQL_TRANSFORM:
+        return "CQL transformation error";
     default:
-       return diagbib1_str (error);
+        return diagbib1_str (error);
     }
 }
 
@@ -3364,14 +3750,14 @@ static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
 {
     ZOOM_Event event = 0;
     int r = cs_look(c->cs);
-    yaz_log (LOG_DEBUG, "ZOOM_connection_do_io c=%p mask=%d cs_look=%d",
-            c, mask, r);
+    yaz_log(log_details, "%p ZOOM_connection_do_io mask=%d cs_look=%d",
+             c, mask, r);
     
     if (r == CS_NONE)
     {
         event = ZOOM_Event_create (ZOOM_EVENT_CONNECT);
-       set_ZOOM_error(c, ZOOM_ERROR_CONNECT, 0);
-       do_close (c);
+        set_ZOOM_error(c, ZOOM_ERROR_CONNECT, c->host_port);
+        do_close (c);
         ZOOM_connection_put_event (c, event);
     }
     else if (r == CS_CONNECT)
@@ -3380,7 +3766,8 @@ static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
         event = ZOOM_Event_create (ZOOM_EVENT_CONNECT);
 
         ret = cs_rcvconnect (c->cs);
-        yaz_log (LOG_DEBUG, "cs_rcvconnect returned %d", ret);
+        yaz_log(log_details, "%p ZOOM_connection_do_io "
+                "cs_rcvconnect returned %d", c, ret);
         if (ret == 1)
         {
             c->mask = ZOOM_SELECT_EXCEPT;
@@ -3393,7 +3780,7 @@ static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
         else if (ret == 0)
         {
             ZOOM_connection_put_event (c, event);
-           get_cert(c);
+            get_cert(c);
             if (c->proto == PROTO_Z3950)
                 ZOOM_connection_send_init(c);
             else
@@ -3408,7 +3795,7 @@ static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
         }
         else
         {
-            set_ZOOM_error(c, ZOOM_ERROR_CONNECT, 0);
+            set_ZOOM_error(c, ZOOM_ERROR_CONNECT, c->host_port);
             do_close (c);
             ZOOM_connection_put_event (c, event);
         }
@@ -3434,7 +3821,8 @@ ZOOM_connection_last_event(ZOOM_connection cs)
 ZOOM_API(int)
 ZOOM_event (int no, ZOOM_connection *cs)
 {
-    int timeout = 5000;
+    int timeout = 30;      /* default timeout in seconds */
+    int timeout_set = 0;   /* whether it was overriden at all */
 #if HAVE_SYS_POLL_H
     struct pollfd pollfds[1024];
     ZOOM_connection poll_cs[1024];
@@ -3447,12 +3835,12 @@ ZOOM_event (int no, ZOOM_connection *cs)
 
     for (i = 0; i<no; i++)
     {
-       ZOOM_connection c = cs[i];
+        ZOOM_connection c = cs[i];
         ZOOM_Event event;
-       if (c && (event = ZOOM_connection_get_event(c)))
+        if (c && (event = ZOOM_connection_get_event(c)))
         {
             ZOOM_Event_destroy (event);
-           return i+1;
+            return i+1;
         }
     }
     for (i = 0; i<no; i++)
@@ -3478,23 +3866,31 @@ ZOOM_event (int no, ZOOM_connection *cs)
     nfds = 0;
     for (i = 0; i<no; i++)
     {
-       ZOOM_connection c = cs[i];
-       int fd, mask;
+        ZOOM_connection c = cs[i];
+        int fd, mask;
         int this_timeout;
-       
-       if (!c)
-           continue;
-       fd = z3950_connection_socket(c);
-       mask = z3950_connection_mask(c);
-
-       if (fd == -1)
-           continue;
-       if (max_fd < fd)
-           max_fd = fd;
-
-        this_timeout = ZOOM_options_get_int (c->options, "timeout", -1);
-        if (this_timeout != -1 && this_timeout < timeout)
-            timeout = this_timeout;
+        
+        if (!c)
+            continue;
+        fd = z3950_connection_socket(c);
+        mask = z3950_connection_mask(c);
+
+        if (fd == -1)
+            continue;
+        if (max_fd < fd)
+            max_fd = fd;
+        
+        /* -1 is used for indefinite timeout (no timeout), so -2 here. */
+        this_timeout = ZOOM_options_get_int (c->options, "timeout", -2);
+        if (this_timeout != -2)
+        {
+            /* ensure the minimum timeout is used */
+            if (!timeout_set)
+                timeout = this_timeout;
+            else if (this_timeout != -1 && this_timeout < timeout)
+                timeout = this_timeout;
+            timeout_set = 1;
+        }               
 #if HAVE_SYS_POLL_H
         if (mask)
         {
@@ -3513,31 +3909,28 @@ ZOOM_event (int no, ZOOM_connection *cs)
             nfds++;
         }
 #else
-       if (mask & ZOOM_SELECT_READ)
-       {
-           FD_SET (fd, &input);
-           nfds++;
-       }
-       if (mask & ZOOM_SELECT_WRITE)
-       {
-           FD_SET (fd, &output);
-           nfds++;
-       }
-       if (mask & ZOOM_SELECT_EXCEPT)
-       {
-           FD_SET (fd, &except);
-           nfds++;
-       }
+        if (mask & ZOOM_SELECT_READ)
+        {
+            FD_SET (fd, &input);
+            nfds++;
+        }
+        if (mask & ZOOM_SELECT_WRITE)
+        {
+            FD_SET (fd, &output);
+            nfds++;
+        }
+        if (mask & ZOOM_SELECT_EXCEPT)
+        {
+            FD_SET (fd, &except);
+            nfds++;
+        }
 #endif
     }
-    if (timeout >= 5000)
-        timeout = 30;
-
     if (!nfds)
         return 0;
 
 #if HAVE_SYS_POLL_H
-    r = poll (pollfds, nfds, timeout * 1000);
+    r = poll (pollfds, nfds, (timeout == -1 ? -1 : timeout * 1000));
     for (i = 0; i<nfds; i++)
     {
         ZOOM_connection c = poll_cs[i];
@@ -3556,8 +3949,8 @@ ZOOM_event (int no, ZOOM_connection *cs)
         else if (r == 0 && c->mask)
         {
             ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT);
-           /* timeout and this connection was waiting */
-           set_ZOOM_error(c, ZOOM_ERROR_TIMEOUT, 0);
+            /* timeout and this connection was waiting */
+            set_ZOOM_error(c, ZOOM_ERROR_TIMEOUT, 0);
             do_close (c);
             ZOOM_connection_put_event(c, event);
         }
@@ -3565,50 +3958,123 @@ ZOOM_event (int no, ZOOM_connection *cs)
 #else
     tv.tv_sec = timeout;
     tv.tv_usec = 0;
-    yaz_log (LOG_DEBUG, "select start");
-    r = select (max_fd+1, &input, &output, &except, &tv);
-    yaz_log (LOG_DEBUG, "select stop, returned r=%d", r);
+    r = select (max_fd+1, &input, &output, &except, (timeout == -1 ? 0 : &tv));
     for (i = 0; i<no; i++)
     {
-       ZOOM_connection c = cs[i];
-       int fd, mask;
-
-       if (!c)
-           continue;
-       fd = z3950_connection_socket(c);
-       mask = 0;
-       if (r && c->mask)
-       {
-           /* no timeout and real socket */
-           if (FD_ISSET(fd, &input))
-               mask += ZOOM_SELECT_READ;
-           if (FD_ISSET(fd, &output))
-               mask += ZOOM_SELECT_WRITE;
-           if (FD_ISSET(fd, &except))
-               mask += ZOOM_SELECT_EXCEPT;
-           if (mask)
-               ZOOM_connection_do_io(c, mask);
-       }
-       if (r == 0 && c->mask)
-       {
+        ZOOM_connection c = cs[i];
+        int fd, mask;
+
+        if (!c)
+            continue;
+        fd = z3950_connection_socket(c);
+        mask = 0;
+        if (r && c->mask)
+        {
+            /* no timeout and real socket */
+            if (FD_ISSET(fd, &input))
+                mask += ZOOM_SELECT_READ;
+            if (FD_ISSET(fd, &output))
+                mask += ZOOM_SELECT_WRITE;
+            if (FD_ISSET(fd, &except))
+                mask += ZOOM_SELECT_EXCEPT;
+            if (mask)
+                ZOOM_connection_do_io(c, mask);
+        }
+        if (r == 0 && c->mask)
+        {
             ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT);
-           /* timeout and this connection was waiting */
-           set_ZOOM_error(c, ZOOM_ERROR_TIMEOUT, 0);
+            /* timeout and this connection was waiting */
+            set_ZOOM_error(c, ZOOM_ERROR_TIMEOUT, 0);
             do_close (c);
-            yaz_log (LOG_DEBUG, "timeout");
             ZOOM_connection_put_event(c, event);
-       }
+        }
     }
 #endif
     for (i = 0; i<no; i++)
     {
-       ZOOM_connection c = cs[i];
+        ZOOM_connection c = cs[i];
         ZOOM_Event event;
-       if (c && (event = ZOOM_connection_get_event(c)))
+        if (c && (event = ZOOM_connection_get_event(c)))
         {
             ZOOM_Event_destroy (event);
-           return i+1;
+            return i+1;
         }
     }
     return 0;
 }
+
+
+/*
+ * Returns an xmalloc()d string containing RPN that corresponds to the
+ * CQL passed in.  On error, sets the Connection object's error state
+ * and returns a null pointer.
+ * ### We could cache CQL parser and/or transformer in Connection.
+ */
+static char *cql2pqf(ZOOM_connection c, const char *cql)
+{
+    CQL_parser parser;
+    int error;
+    struct cql_node *node;
+    const char *cqlfile;
+    static cql_transform_t trans;
+    char pqfbuf[512];
+
+    parser = cql_parser_create();
+    printf("*** got CQL parser %p\n", parser);
+    if ((error = cql_parser_string(parser, cql)) != 0) {
+        cql_parser_destroy(parser);
+        set_ZOOM_error(c, ZOOM_ERROR_CQL_PARSE, cql);
+        return 0;
+    }
+
+    node = cql_parser_result(parser);
+    printf("*** got CQL node %p\n", node);
+    cql_parser_destroy(parser);
+    printf("*** destroyed parser\n");
+
+    cqlfile = ZOOM_connection_option_get(c, "cqlfile");
+    printf("*** cqlfile is %p\n", cqlfile);
+    if (cqlfile == 0) {
+        printf("*** cqlfile is null\n");
+        cql_node_destroy(node);
+        printf("*** destroyed node\n");
+        set_ZOOM_error(c, ZOOM_ERROR_CQL_TRANSFORM, "no CQL transform file");
+        printf("*** set ZOOM_error\n");
+        return 0;
+    }
+    printf("*** got CQL file %s\n", cqlfile);
+
+    if ((trans = cql_transform_open_fname(cqlfile)) == 0) {
+        char buf[512];        
+        cql_node_destroy(node);
+        sprintf(buf, "can't open CQL transform file '%.200s': %.200s",
+                cqlfile, strerror(errno));
+        set_ZOOM_error(c, ZOOM_ERROR_CQL_TRANSFORM, buf);
+        return 0;
+    }
+
+    error = cql_transform_buf(trans, node, pqfbuf, sizeof pqfbuf);
+    cql_node_destroy(node);
+    if (error != 0) {
+        char buf[512];
+        const char *addinfo;
+        error = cql_transform_error(trans, &addinfo);
+        cql_transform_close(trans);
+        sprintf(buf, "%.200s (addinfo=%.200s)", cql_strerror(error), addinfo);
+        set_ZOOM_error(c, ZOOM_ERROR_CQL_TRANSFORM, buf);
+        return 0;
+    }
+
+    cql_transform_close(trans);
+    return xstrdup(pqfbuf);
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+