ZOOM C: fix un-init var for cookie buffer
[yaz-moved-to-github.git] / src / zoom-c.c
index 923e500..d6821d6 100644 (file)
@@ -1,11 +1,14 @@
 /* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2010 Index Data
+ * Copyright (C) 1995-2011 Index Data
  * See the file LICENSE for details.
  */
 /**
  * \file zoom-c.c
  * \brief Implements ZOOM C interface.
  */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include <assert.h>
 #include <string.h>
 #include <yaz/xmalloc.h>
 #include <yaz/otherinfo.h>
 #include <yaz/log.h>
-#include <yaz/pquery.h>
-#include <yaz/marcdisp.h>
 #include <yaz/diagbib1.h>
 #include <yaz/charneg.h>
-#include <yaz/ill.h>
-#include <yaz/srw.h>
-#include <yaz/cql.h>
-#include <yaz/ccl.h>
 #include <yaz/query-charset.h>
-#include <yaz/copy_types.h>
 #include <yaz/snprintf.h>
 #include <yaz/facet.h>
 
@@ -40,29 +36,11 @@ static int log_details0 = 0;
 
 static void resultset_destroy(ZOOM_resultset r);
 static zoom_ret do_write_ex(ZOOM_connection c, char *buf_out, int len_out);
-static char *cql2pqf(ZOOM_connection c, const char *cql);
-
-ZOOM_API(const char *) ZOOM_get_event_str(int event)
-{
-    static const char *ar[] = {
-        "NONE",
-        "CONNECT",
-        "SEND_DATA",
-        "RECV_DATA",
-        "TIMEOUT",
-        "UNKNOWN",
-        "SEND_APDU",
-        "RECV_APDU",
-        "RECV_RECORD",
-        "RECV_SEARCH",
-        "END"
-    };
-    return ar[event];
-}
 
 static void initlog(void)
 {
     static int log_level_initialized = 0;
+
     if (!log_level_initialized)
     {
         log_api0 = yaz_log_module_level("zoom");
@@ -71,72 +49,6 @@ static void initlog(void)
     }
 }
 
-ZOOM_Event ZOOM_Event_create(int kind)
-{
-    ZOOM_Event event = (ZOOM_Event) xmalloc(sizeof(*event));
-    event->kind = kind;
-    event->next = 0;
-    event->prev = 0;
-    return event;
-}
-
-static void ZOOM_Event_destroy(ZOOM_Event event)
-{
-    xfree(event);
-}
-
-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);
-    }
-    else
-    {
-        assert(!c->m_queue_front);
-        c->m_queue_front = event;
-    }
-    event->next = c->m_queue_back;
-    event->prev = 0;
-    c->m_queue_back = event;
-}
-
-static ZOOM_Event ZOOM_connection_get_event(ZOOM_connection c)
-{
-    ZOOM_Event event = c->m_queue_front;
-    if (!event)
-    {
-        c->last_event = ZOOM_EVENT_NONE;
-        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;
-    }
-    else
-        c->m_queue_back = 0;
-    c->last_event = event->kind;
-    return event;
-}
-
-static void ZOOM_connection_remove_events(ZOOM_connection c)
-{
-    ZOOM_Event event;
-    while ((event = ZOOM_connection_get_event(c)))
-        ZOOM_Event_destroy(event);
-}
-
-ZOOM_API(int) ZOOM_connection_peek_event(ZOOM_connection c)
-{
-    ZOOM_Event event = c->m_queue_front;
-
-    return event ? event->kind : ZOOM_EVENT_NONE;
-}
-
 void ZOOM_connection_remove_tasks(ZOOM_connection c);
 
 void ZOOM_set_dset_error(ZOOM_connection c, int error,
@@ -174,7 +86,7 @@ void ZOOM_set_dset_error(ZOOM_connection c, int error,
     }
 }
 
-static int uri_to_code(const char *uri)
+int ZOOM_uri_to_code(const char *uri)
 {
     int code = 0;       
     const char *cp;
@@ -183,21 +95,6 @@ static int uri_to_code(const char *uri)
     return code;
 }
 
-#if YAZ_HAVE_XML2
-static void set_HTTP_error(ZOOM_connection c, int error,
-                           const char *addinfo, const char *addinfo2)
-{
-    ZOOM_set_dset_error(c, error, "HTTP", addinfo, addinfo2);
-}
-
-static void set_SRU_error(ZOOM_connection c, Z_SRW_diagnostic *d)
-{
-    const char *uri = d->uri;
-    if (uri)
-        ZOOM_set_dset_error(c, uri_to_code(uri), uri, d->details, 0);
-}
-
-#endif
 
 
 void ZOOM_set_error(ZOOM_connection c, int error, const char *addinfo)
@@ -285,7 +182,6 @@ ZOOM_task ZOOM_connection_insert_task(ZOOM_connection c, int which)
 
     task->running = 0;
     task->which = which;
-    clear_error(c);
     return task;
 }
 
@@ -445,6 +341,8 @@ static zoom_sru_mode get_sru_mode_from_string(const char *s)
         return zoom_sru_get;
     else if (!yaz_matchstr(s, "post"))
         return zoom_sru_post;
+    else if (!yaz_matchstr(s, "solr"))
+        return zoom_sru_solr;
     return zoom_sru_error;
 }
 
@@ -453,7 +351,6 @@ ZOOM_API(void)
                             const char *host, int portnum)
 {
     const char *val;
-    ZOOM_task task;
 
     initlog();
 
@@ -612,7 +509,7 @@ ZOOM_API(void)
     c->async = ZOOM_options_get_bool(c->options, "async", 0);
     yaz_log(c->log_details, "%p ZOOM_connection_connect async=%d", c, c->async);
  
-    task = ZOOM_connection_add_task(c, ZOOM_TASK_CONNECT);
+    ZOOM_connection_add_task(c, ZOOM_TASK_CONNECT);
 
     if (!c->async)
     {
@@ -621,142 +518,6 @@ ZOOM_API(void)
     }
 }
 
-ZOOM_API(ZOOM_query)
-    ZOOM_query_create(void)
-{
-    ZOOM_query s = (ZOOM_query) xmalloc(sizeof(*s));
-
-    s->refcount = 1;
-    s->z_query = 0;
-    s->sort_spec = 0;
-    s->odr = odr_createmem(ODR_ENCODE);
-    s->query_string = 0;
-
-    return s;
-}
-
-ZOOM_API(void)
-    ZOOM_query_destroy(ZOOM_query s)
-{
-    if (!s)
-        return;
-
-    (s->refcount)--;
-    if (s->refcount == 0)
-    {
-        odr_destroy(s->odr);
-        xfree(s);
-    }
-}
-
-ZOOM_API(int)
-    ZOOM_query_prefix(ZOOM_query s, const char *str)
-{
-    s->query_string = odr_strdup(s->odr, str);
-    s->z_query = (Z_Query *) odr_malloc(s->odr, sizeof(*s->z_query));
-    s->z_query->which = Z_Query_type_1;
-    s->z_query->u.type_1 =  p_query_rpn(s->odr, str);
-    if (!s->z_query->u.type_1)
-    {
-        s->z_query = 0;
-        return -1;
-    }
-    return 0;
-}
-
-ZOOM_API(int)
-    ZOOM_query_cql(ZOOM_query s, const char *str)
-{
-    Z_External *ext;
-
-    s->query_string = odr_strdup(s->odr, str);
-
-    ext = (Z_External *) odr_malloc(s->odr, sizeof(*ext));
-    ext->direct_reference = odr_oiddup(s->odr, yaz_oid_userinfo_cql);
-    ext->indirect_reference = 0;
-    ext->descriptor = 0;
-    ext->which = Z_External_CQL;
-    ext->u.cql = s->query_string;
-    
-    s->z_query = (Z_Query *) odr_malloc(s->odr, sizeof(*s->z_query));
-    s->z_query->which = Z_Query_type_104;
-    s->z_query->u.type_104 =  ext;
-
-    return 0;
-}
-
-/*
- * Translate the CQL string client-side into RPN which is passed to
- * the server.  This is useful for server's that don't themselves
- * support CQL, for which ZOOM_query_cql() is useless.  `conn' is used
- * only as a place to stash diagnostics if compilation fails; if this
- * information is not needed, a null pointer may be used.
- */
-ZOOM_API(int)
-    ZOOM_query_cql2rpn(ZOOM_query s, const char *str, ZOOM_connection conn)
-{
-    char *rpn;
-    int ret;
-    ZOOM_connection freeme = 0;
-
-    if (conn == 0)
-        conn = freeme = ZOOM_connection_create(0);
-
-    rpn = cql2pqf(conn, str);
-    if (freeme != 0)
-        ZOOM_connection_destroy(freeme);
-    if (rpn == 0)
-        return -1;
-
-    ret = ZOOM_query_prefix(s, rpn);
-    xfree(rpn);
-    return ret;
-}
-
-/*
- * Analogous in every way to ZOOM_query_cql2rpn(), except that there
- * is no analogous ZOOM_query_ccl() that just sends uninterpreted CCL
- * to the server, as the YAZ GFS doesn't know how to handle this.
- */
-ZOOM_API(int)
-    ZOOM_query_ccl2rpn(ZOOM_query s, const char *str, const char *config,
-                       int *ccl_error, const char **error_string,
-                       int *error_pos)
-{
-    int ret;
-    struct ccl_rpn_node *rpn;
-    CCL_bibset bibset = ccl_qual_mk();
-
-    if (config)
-        ccl_qual_buf(bibset, config);
-
-    rpn = ccl_find_str(bibset, str, ccl_error, error_pos);
-    if (!rpn)
-    {
-        *error_string = ccl_err_msg(*ccl_error);
-        ret = -1;
-    }
-    else
-    {
-        WRBUF wr = wrbuf_alloc();
-        ccl_pquery(wr, rpn);
-        ccl_rpn_delete(rpn);
-        ret = ZOOM_query_prefix(s, wrbuf_cstr(wr));
-        wrbuf_destroy(wr);
-    }
-    ccl_qual_rm(&bibset);
-    return ret;
-}
-
-ZOOM_API(int)
-    ZOOM_query_sortby(ZOOM_query s, const char *criteria)
-{
-    s->sort_spec = yaz_sort_spec(s->odr, criteria);
-    if (!s->sort_spec)
-        return -1;
-    return 0;
-}
-
 ZOOM_API(void) ZOOM_resultset_release(ZOOM_resultset r)
 {
 #if ZOOM_RESULT_LISTS
@@ -795,7 +556,7 @@ ZOOM_API(void)
         cs_close(c->cs);
 
 #if ZOOM_RESULT_LISTS
-    // Remove the connection's usage of resultsets
+    /* Remove the connection's usage of resultsets */
     list = c->resultsets;
     while (list) {
         ZOOM_resultsets removed = list;
@@ -848,6 +609,27 @@ void ZOOM_resultset_addref(ZOOM_resultset r)
     }
 }
 
+static int g_resultsets = 0;
+static YAZ_MUTEX g_resultset_mutex = 0;
+
+/* TODO We need to initialize this before running threaded:
+ * call resultset_use(0)  */
+
+static int resultset_use(int delta) {
+    int resultset_count;
+    if (g_resultset_mutex == 0)
+        yaz_mutex_create(&g_resultset_mutex);
+    yaz_mutex_enter(g_resultset_mutex);
+    g_resultsets += delta;
+    resultset_count = g_resultsets;
+    yaz_mutex_leave(g_resultset_mutex);
+    return resultset_count;
+}
+
+int resultsets_count(void) {
+    return resultset_use(0);
+}
+
 ZOOM_resultset ZOOM_resultset_create(void)
 {
     int i;
@@ -881,6 +663,7 @@ ZOOM_resultset ZOOM_resultset_create(void)
         YAZ_SHPTR_INIT(r->record_wrbuf, w);
     }
 #endif
+    resultset_use(1);
     return r;
 }
 
@@ -910,7 +693,7 @@ ZOOM_API(ZOOM_resultset)
 #endif
 
     yaz_log(c->log_api, "%p ZOOM_connection_search set %p query %p", c, r, q);
-    r->r_sort_spec = q->sort_spec;
+    r->r_sort_spec = ZOOM_query_get_sortspec(q);
     r->query = q;
 
     r->options = ZOOM_options_create_with_parent(c->options);
@@ -975,7 +758,7 @@ ZOOM_API(ZOOM_resultset)
    
     ZOOM_resultset_addref(r);
 
-    (q->refcount)++;
+    ZOOM_query_addref(q);
 
     if (!c->async)
     {
@@ -1040,38 +823,6 @@ ZOOM_API(int)
     return 0;
 }
 
-static void ZOOM_record_release(ZOOM_record rec)
-{
-    if (!rec)
-        return;
-
-#if SHPTR
-    if (rec->record_wrbuf)
-        YAZ_SHPTR_DEC(rec->record_wrbuf, wrbuf_destroy);
-#else
-    if (rec->wrbuf)
-        wrbuf_destroy(rec->wrbuf);
-#endif
-
-    if (rec->odr)
-        odr_destroy(rec->odr);
-}
-
-ZOOM_API(void)
-    ZOOM_resultset_cache_reset(ZOOM_resultset r)
-{
-    int i;
-    for (i = 0; i<RECORD_HASH_SIZE; i++)
-    {
-        ZOOM_record_cache rc;
-        for (rc = r->record_hash[i]; rc; rc = rc->next)
-        {
-            ZOOM_record_release(&rc->rec);
-        }
-        r->record_hash[i] = 0;
-    }
-}
-
 ZOOM_API(void)
     ZOOM_resultset_destroy(ZOOM_resultset r)
 {
@@ -1102,6 +853,7 @@ static void resultset_destroy(ZOOM_resultset r)
 #if SHPTR
         YAZ_SHPTR_DEC(r->record_wrbuf, wrbuf_destroy);
 #endif
+        resultset_use(-1);
         xfree(r);
     }
     else
@@ -1274,41 +1026,35 @@ static void get_cert(ZOOM_connection c)
 }
 
 static zoom_ret do_connect_host(ZOOM_connection c,
-                                const char *effective_host,
                                 const char *logical_url);
 
 static zoom_ret do_connect(ZOOM_connection c)
 {
-    const char *effective_host;
-
-    if (c->proxy)
-        effective_host = c->proxy;
-    else
-        effective_host = c->host_port;
-    return do_connect_host(c, effective_host, c->host_port);
+    return do_connect_host(c, c->host_port);
 }
 
-static zoom_ret do_connect_host(ZOOM_connection c, const char *effective_host,
-    const char *logical_url)
+static zoom_ret do_connect_host(ZOOM_connection c, const char *logical_url)
 {
     void *add;
 
-    yaz_log(c->log_details, "%p do_connect effective_host=%s", c, effective_host);
-
     if (c->cs)
         cs_close(c->cs);
-    c->cs = cs_create_host(effective_host, 0, &add);
-
+    c->cs = cs_create_host_proxy(logical_url, 0, &add, c->proxy);
+    
     if (c->cs && c->cs->protocol == PROTO_HTTP)
     {
 #if YAZ_HAVE_XML2
-        if (logical_url)
+        c->proto = PROTO_HTTP;
+        xfree(c->path);
+        if (c->proxy)
+        {
+            c->path = xstrdup(logical_url);
+        }
+        else
         {
             const char *db = 0;
             
-            c->proto = PROTO_HTTP;
             cs_get_host_args(logical_url, &db);
-            xfree(c->path);
             
             c->path = xmalloc(strlen(db) * 3 + 2);
             yaz_encode_sru_dbpath_buf(c->path, db);
@@ -1361,184 +1107,6 @@ static zoom_ret do_connect_host(ZOOM_connection c, const char *effective_host,
    0 if PDU was not sent OK (nothing to wait for) 
 */
 
-#if YAZ_HAVE_XML2
-static zoom_ret send_srw(ZOOM_connection c, Z_SRW_PDU *sr)
-{
-    Z_GDU *gdu;
-    ZOOM_Event event;
-    const char *database =  ZOOM_options_get(c->options, "databaseName");
-    char *fdatabase = 0;
-    
-    if (database)
-        fdatabase = yaz_encode_sru_dbpath_odr(c->odr_out, database);
-    gdu = z_get_HTTP_Request_host_path(c->odr_out, c->host_port,
-                                       fdatabase ? fdatabase : c->path);
-
-    if (c->sru_mode == zoom_sru_get)
-    {
-        yaz_sru_get_encode(gdu->u.HTTP_Request, sr, c->odr_out, c->charset);
-    }
-    else if (c->sru_mode == zoom_sru_post)
-    {
-        yaz_sru_post_encode(gdu->u.HTTP_Request, sr, c->odr_out, c->charset);
-    }
-    else if (c->sru_mode == zoom_sru_soap)
-    {
-        yaz_sru_soap_encode(gdu->u.HTTP_Request, sr, c->odr_out, c->charset);
-    }
-    if (!z_GDU(c->odr_out, &gdu, 0, 0))
-        return zoom_complete;
-    if (c->odr_print)
-        z_GDU(c->odr_print, &gdu, 0, 0);
-    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);
-    odr_reset(c->odr_out);
-    return ZOOM_send_buf(c);
-}
-#endif
-
-#if YAZ_HAVE_XML2
-static Z_SRW_PDU *ZOOM_srw_get_pdu(ZOOM_connection c, int type)
-{
-    Z_SRW_PDU *sr = yaz_srw_get_pdu(c->odr_out, type, c->sru_version);
-    sr->username = c->user;
-    sr->password = c->password;
-    return sr;
-}
-#endif
-
-#if YAZ_HAVE_XML2
-static zoom_ret ZOOM_connection_srw_send_search(ZOOM_connection c)
-{
-    int i;
-    int *start, *count;
-    ZOOM_resultset resultset = 0;
-    Z_SRW_PDU *sr = 0;
-    const char *option_val = 0;
-
-    if (c->error)                  /* don't continue on error */
-        return zoom_complete;
-    assert(c->tasks);
-    switch(c->tasks->which)
-    {
-    case ZOOM_TASK_SEARCH:
-        resultset = c->tasks->u.search.resultset;
-        if (!resultset->setname)
-            resultset->setname = xstrdup("default");
-        ZOOM_options_set(resultset->options, "setname", resultset->setname);
-        start = &c->tasks->u.search.start;
-        count = &c->tasks->u.search.count;
-        break;
-    case ZOOM_TASK_RETRIEVE:
-        resultset = c->tasks->u.retrieve.resultset;
-
-        start = &c->tasks->u.retrieve.start;
-        count = &c->tasks->u.retrieve.count;
-
-        if (*start >= resultset->size)
-            return zoom_complete;
-        if (*start + *count > resultset->size)
-            *count = resultset->size - *start;
-
-        for (i = 0; i < *count; i++)
-        {
-            ZOOM_record rec =
-                ZOOM_record_cache_lookup(resultset, i + *start,
-                                         c->tasks->u.retrieve.syntax,
-                                         c->tasks->u.retrieve.elementSetName);
-            if (!rec)
-                break;
-            else
-            {
-                ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_RECV_RECORD);
-                ZOOM_connection_put_event(c, event);
-            }
-        }
-        *start += i;
-        *count -= i;
-
-        if (*count == 0)
-            return zoom_complete;
-        break;
-    default:
-        return zoom_complete;
-    }
-    assert(resultset->query);
-        
-    sr = ZOOM_srw_get_pdu(c, Z_SRW_searchRetrieve_request);
-    if (resultset->query->z_query->which == Z_Query_type_104
-        && resultset->query->z_query->u.type_104->which == Z_External_CQL)
-    {
-        sr->u.request->query_type = Z_SRW_query_type_cql;
-        sr->u.request->query.cql =resultset->query->z_query->u.type_104->u.cql;
-    }
-    else if (resultset->query->z_query->which == Z_Query_type_1 &&
-             resultset->query->z_query->u.type_1)
-    {
-        sr->u.request->query_type = Z_SRW_query_type_pqf;
-        sr->u.request->query.pqf = resultset->query->query_string;
-    }
-    else
-    {
-        ZOOM_set_error(c, ZOOM_ERROR_UNSUPPORTED_QUERY, 0);
-        return zoom_complete;
-    }
-    sr->u.request->startRecord = odr_intdup(c->odr_out, *start + 1);
-    sr->u.request->maximumRecords = odr_intdup(
-        c->odr_out, (resultset->step > 0 && resultset->step < *count) ? 
-        resultset->step : *count);
-    sr->u.request->recordSchema = resultset->schema;
-    
-    option_val = ZOOM_resultset_option_get(resultset, "recordPacking");
-    if (option_val)
-        sr->u.request->recordPacking = odr_strdup(c->odr_out, option_val);
-
-    option_val = ZOOM_resultset_option_get(resultset, "extraArgs");
-    yaz_encode_sru_extra(sr, c->odr_out, option_val);
-    return send_srw(c, sr);
-}
-#else
-static zoom_ret ZOOM_connection_srw_send_search(ZOOM_connection c)
-{
-    return zoom_complete;
-}
-#endif
-
-ZOOM_API(ZOOM_record)
-    ZOOM_record_clone(ZOOM_record srec)
-{
-    char *buf;
-    int size;
-    ODR odr_enc;
-    ZOOM_record nrec;
-
-    odr_enc = odr_createmem(ODR_ENCODE);
-    if (!z_NamePlusRecord(odr_enc, &srec->npr, 0, 0))
-        return 0;
-    buf = odr_getbuf(odr_enc, &size, 0);
-    
-    nrec = (ZOOM_record) xmalloc(sizeof(*nrec));
-    yaz_log(log_details0, "ZOOM_record create");
-    nrec->odr = odr_createmem(ODR_DECODE);
-#if SHPTR
-    nrec->record_wrbuf = 0;
-#else
-    nrec->wrbuf = 0;
-#endif
-    odr_setbuf(nrec->odr, buf, size, 0);
-    z_NamePlusRecord(nrec->odr, &nrec->npr, 0, 0);
-    
-    nrec->schema = odr_strdup_null(nrec->odr, srec->schema);
-    nrec->diag_uri = odr_strdup_null(nrec->odr, srec->diag_uri);
-    nrec->diag_message = odr_strdup_null(nrec->odr, srec->diag_message);
-    nrec->diag_details = odr_strdup_null(nrec->odr, srec->diag_details);
-    nrec->diag_set = odr_strdup_null(nrec->odr, srec->diag_set);
-    odr_destroy(odr_enc);
-    return nrec;
-}
-
 ZOOM_API(ZOOM_record)
     ZOOM_resultset_record_immediate(ZOOM_resultset s,size_t pos)
 {
@@ -1571,492 +1139,6 @@ ZOOM_API(ZOOM_record)
     return rec;
 }
 
-ZOOM_API(void)
-    ZOOM_record_destroy(ZOOM_record rec)
-{
-    ZOOM_record_release(rec);
-    yaz_log(log_details0, "ZOOM_record destroy");
-    xfree(rec);
-}
-
-
-static yaz_iconv_t iconv_create_charset(const char *record_charset)
-{
-    char to[40];
-    char from[40];
-    yaz_iconv_t cd = 0;
-
-    *from = '\0';
-    strcpy(to, "UTF-8");
-    if (record_charset && *record_charset)
-    {
-        /* Use "from,to" or just "from" */
-        const char *cp = strchr(record_charset, ',');
-        size_t 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);
-    return cd;
-}
-
-static const char *return_marc_record(WRBUF wrbuf,
-                                      int marc_type,
-                                      int *len,
-                                      const char *buf, int sz,
-                                      const char *record_charset)
-{
-    yaz_iconv_t cd = iconv_create_charset(record_charset);
-    yaz_marc_t mt = yaz_marc_create();
-    const char *ret_string = 0;
-
-    if (cd)
-        yaz_marc_iconv(mt, cd);
-    yaz_marc_xml(mt, marc_type);
-    if (yaz_marc_decode_wrbuf(mt, buf, sz, wrbuf) > 0)
-    {
-        if (len)
-            *len = wrbuf_len(wrbuf);
-        ret_string = wrbuf_cstr(wrbuf);
-    }
-    yaz_marc_destroy(mt);
-    if (cd)
-        yaz_iconv_close(cd);
-    return ret_string;
-}
-
-static const char *return_opac_record(WRBUF wrbuf,
-                                      int marc_type,
-                                      int *len,
-                                      Z_OPACRecord *opac_rec,
-                                      const char *record_charset)
-{
-    yaz_iconv_t cd = iconv_create_charset(record_charset);
-    yaz_marc_t mt = yaz_marc_create();
-
-    if (cd)
-        yaz_marc_iconv(mt, cd);
-    yaz_marc_xml(mt, marc_type);
-
-    yaz_opac_decode_wrbuf(mt, opac_rec, wrbuf);
-    yaz_marc_destroy(mt);
-
-    if (cd)
-        yaz_iconv_close(cd);
-    if (len)
-        *len = wrbuf_len(wrbuf);
-    return wrbuf_cstr(wrbuf);
-}
-
-static const char *return_string_record(WRBUF wrbuf,
-                                        int *len,
-                                        const char *buf, int sz,
-                                        const char *record_charset)
-{
-    yaz_iconv_t cd = iconv_create_charset(record_charset);
-
-    if (cd)
-    {
-        wrbuf_iconv_write(wrbuf, cd, buf, sz);
-        wrbuf_iconv_reset(wrbuf, cd);
-
-        buf = wrbuf_cstr(wrbuf);
-        sz = wrbuf_len(wrbuf);
-        yaz_iconv_close(cd);
-    }
-    if (len)
-        *len = sz;
-    return buf;
-}
-
-static const char *return_record_wrbuf(WRBUF wrbuf, int *len,
-                                       Z_NamePlusRecord *npr,
-                                       int marctype, const char *charset)
-{
-    Z_External *r = (Z_External *) npr->u.databaseRecord;
-    const Odr_oid *oid = r->direct_reference;
-
-    wrbuf_rewind(wrbuf);
-    /* render bibliographic record .. */
-    if (r->which == Z_External_OPAC)
-    {
-        return return_opac_record(wrbuf, marctype, len,
-                                  r->u.opac, charset);
-    }
-    if (r->which == Z_External_sutrs)
-        return return_string_record(wrbuf, len,
-                                    (char*) r->u.sutrs->buf,
-                                    r->u.sutrs->len,
-                                    charset);
-    else if (r->which == Z_External_octet)
-    {
-        if (yaz_oid_is_iso2709(oid))
-        {
-            const char *ret_buf = return_marc_record(
-                wrbuf, marctype, len,
-                (const char *) r->u.octet_aligned->buf,
-                r->u.octet_aligned->len,
-                charset);
-            if (ret_buf)
-                return ret_buf;
-            /* bad ISO2709. Return fail unless raw (ISO2709) is wanted */
-            if (marctype != YAZ_MARC_ISO2709)
-                return 0;
-        }
-        return return_string_record(wrbuf, len,
-                                    (const char *) r->u.octet_aligned->buf,
-                                    r->u.octet_aligned->len,
-                                    charset);
-    }
-    else if (r->which == Z_External_grs1)
-    {
-        yaz_display_grs1(wrbuf, r->u.grs1, 0);
-        return return_string_record(wrbuf, len,
-                                    wrbuf_buf(wrbuf),
-                                    wrbuf_len(wrbuf),
-                                    charset);
-    }
-    return 0;
-}
-    
-ZOOM_API(int)
-    ZOOM_record_error(ZOOM_record rec, const char **cp,
-                      const char **addinfo, const char **diagset)
-{
-    Z_NamePlusRecord *npr;
-    
-    if (!rec)
-        return 0;
-
-    npr = rec->npr;
-    if (rec->diag_uri)
-    {
-        if (cp)
-            *cp = rec->diag_message;
-        if (addinfo)
-            *addinfo = rec->diag_details;
-        if (diagset)
-            *diagset = rec->diag_set;
-        return uri_to_code(rec->diag_uri);
-    }
-    if (npr && npr->which == Z_NamePlusRecord_surrogateDiagnostic)
-    {
-        Z_DiagRec *diag_rec = npr->u.surrogateDiagnostic;
-        int error = YAZ_BIB1_UNSPECIFIED_ERROR;
-        const char *add = 0;
-
-        if (diag_rec->which == Z_DiagRec_defaultFormat)
-        {
-            Z_DefaultDiagFormat *ddf = diag_rec->u.defaultFormat;
-            oid_class oclass;
-    
-            error = *ddf->condition;
-            switch (ddf->which)
-            {
-            case Z_DefaultDiagFormat_v2Addinfo:
-                add = ddf->u.v2Addinfo;
-                break;
-            case Z_DefaultDiagFormat_v3Addinfo:
-                add = ddf->u.v3Addinfo;
-                break;
-            }
-            if (diagset)
-                *diagset =
-                    yaz_oid_to_string(yaz_oid_std(),
-                                      ddf->diagnosticSetId, &oclass);
-        }
-        else
-        {
-            if (diagset)
-                *diagset = "Bib-1";
-        }
-        if (addinfo)
-            *addinfo = add ? add : "";
-        if (cp)
-            *cp = diagbib1_str(error);
-        return error;
-    }
-    return 0;
-}
-
-static const char *get_record_format(WRBUF wrbuf, int *len,
-                                     Z_NamePlusRecord *npr,
-                                     int marctype, const char *charset,
-                                     const char *format)
-{
-    const char *res = return_record_wrbuf(wrbuf, len, npr, marctype, charset);
-#if YAZ_HAVE_XML2
-    if (*format == '1' && len)
-    {
-        /* try to XML format res */
-        xmlDocPtr doc;
-        xmlKeepBlanksDefault(0); /* get get xmlDocFormatMemory to work! */
-        doc = xmlParseMemory(res, *len);
-        if (doc)
-        {
-            xmlChar *xml_mem;
-            int xml_size;
-            xmlDocDumpFormatMemory(doc, &xml_mem, &xml_size, 1);
-            wrbuf_rewind(wrbuf);
-            wrbuf_write(wrbuf, (const char *) xml_mem, xml_size);
-            xmlFree(xml_mem);
-            xmlFreeDoc(doc);
-            res = wrbuf_cstr(wrbuf);
-            *len = wrbuf_len(wrbuf);
-        } 
-    }
-#endif
-    return res;
-}
-
-
-static const char *npr_format(Z_NamePlusRecord *npr, const char *schema,
-                              WRBUF wrbuf,
-                              const char *type_spec, int *len)
-{
-    size_t i;
-    char type[40];
-    char charset[40];
-    char format[3];
-    const char *cp = type_spec;
-
-    for (i = 0; cp[i] && cp[i] != ';' && cp[i] != ' ' && i < sizeof(type)-1;
-         i++)
-        type[i] = cp[i];
-    type[i] = '\0';
-    charset[0] = '\0';
-    format[0] = '\0';
-    while (1)
-    {
-        while (cp[i] == ' ')
-            i++;
-        if (cp[i] != ';')
-            break;
-        i++;
-        while (cp[i] == ' ')
-            i++;
-        if (!strncmp(cp + i, "charset=", 8))
-        {
-            size_t j = 0;
-            i = i + 8; /* skip charset= */
-            for (j = 0; cp[i] && cp[i] != ';' && cp[i] != ' '; i++)
-            {
-                if (j < sizeof(charset)-1)
-                    charset[j++] = cp[i];
-            }
-            charset[j] = '\0';
-        }
-        else if (!strncmp(cp + i, "format=", 7))
-        {
-            size_t j = 0; 
-            i = i + 7;
-            for (j = 0; cp[i] && cp[i] != ';' && cp[i] != ' '; i++)
-            {
-                if (j < sizeof(format)-1)
-                    format[j++] = cp[i];
-            }
-            format[j] = '\0';
-        } 
-    }
-    if (!strcmp(type, "database"))
-    {
-        if (len)
-            *len = (npr->databaseName ? strlen(npr->databaseName) : 0);
-        return npr->databaseName;
-    }
-    else if (!strcmp(type, "schema"))
-    {
-        if (len)
-            *len = schema ? strlen(schema) : 0;
-        return schema;
-    }
-    else if (!strcmp(type, "syntax"))
-    {
-        const char *desc = 0;   
-        if (npr->which == Z_NamePlusRecord_databaseRecord)
-        {
-            Z_External *r = (Z_External *) npr->u.databaseRecord;
-            desc = yaz_oid_to_string(yaz_oid_std(), r->direct_reference, 0);
-        }
-        if (!desc)
-            desc = "none";
-        if (len)
-            *len = strlen(desc);
-        return desc;
-    }
-    if (npr->which != Z_NamePlusRecord_databaseRecord)
-        return 0;
-
-    /* from now on - we have a database record .. */
-    if (!strcmp(type, "render"))
-    {
-        return get_record_format(wrbuf, len, npr, YAZ_MARC_LINE, charset, format);
-    }
-    else if (!strcmp(type, "xml"))
-    {
-        return get_record_format(wrbuf, len, npr, YAZ_MARC_MARCXML, charset,
-                                 format);
-    }
-    else if (!strcmp(type, "txml"))
-    {
-        return get_record_format(wrbuf, len, npr, YAZ_MARC_TURBOMARC, charset,
-                                 format);
-    }
-    else if (!strcmp(type, "raw"))
-    {
-        return get_record_format(wrbuf, len, npr, YAZ_MARC_ISO2709, charset,
-            format);
-    }
-    else if (!strcmp(type, "ext"))
-    {
-        if (len) *len = -1;
-        return (const char *) npr->u.databaseRecord;
-    }
-    else if (!strcmp(type, "opac"))
-    {
-        if (npr->u.databaseRecord->which == Z_External_OPAC)
-            return get_record_format(wrbuf, len, npr, YAZ_MARC_MARCXML, charset,
-                                     format);
-    }
-    return 0;
-}
-
-ZOOM_API(const char *)
-    ZOOM_record_get(ZOOM_record rec, const char *type_spec, int *len)
-{
-    WRBUF wrbuf;
-    
-    if (len)
-        *len = 0; /* default return */
-        
-    if (!rec || !rec->npr)
-        return 0;
-
-#if SHPTR
-    if (!rec->record_wrbuf)
-    {
-        WRBUF w = wrbuf_alloc();
-        YAZ_SHPTR_INIT(rec->record_wrbuf, w);
-    }
-    wrbuf = rec->record_wrbuf->ptr;
-#else
-    if (!rec->wrbuf)
-        rec->wrbuf = wrbuf_alloc();
-    wrbuf = rec->wrbuf;
-#endif
-    return npr_format(rec->npr, rec->schema, wrbuf, type_spec, len);
-}
-
-static int strcmp_null(const char *v1, const char *v2)
-{
-    if (!v1 && !v2)
-        return 0;
-    if (!v1 || !v2)
-        return -1;
-    return strcmp(v1, v2);
-}
-
-static size_t record_hash(int pos)
-{
-    if (pos < 0)
-        pos = 0;
-    return pos % RECORD_HASH_SIZE;
-}
-
-void ZOOM_record_cache_add(ZOOM_resultset r, Z_NamePlusRecord *npr, 
-                           int pos,
-                           const char *syntax, const char *elementSetName,
-                           const char *schema,
-                           Z_SRW_diagnostic *diag)
-{
-    ZOOM_record_cache rc = 0;
-    
-    ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_RECV_RECORD);
-    ZOOM_connection_put_event(r->connection, event);
-
-    for (rc = r->record_hash[record_hash(pos)]; rc; rc = rc->next)
-    {
-        if (pos == rc->pos 
-            && strcmp_null(r->schema, rc->schema) == 0
-            && strcmp_null(elementSetName,rc->elementSetName) == 0
-            && strcmp_null(syntax, rc->syntax) == 0)
-            break;
-    }
-    if (!rc)
-    {
-        rc = (ZOOM_record_cache) odr_malloc(r->odr, sizeof(*rc));
-        rc->rec.odr = 0;
-#if SHPTR
-        YAZ_SHPTR_INC(r->record_wrbuf);
-        rc->rec.record_wrbuf = r->record_wrbuf;
-#else
-        rc->rec.wrbuf = 0;
-#endif
-        rc->elementSetName = odr_strdup_null(r->odr, elementSetName);
-        
-        rc->syntax = odr_strdup_null(r->odr, syntax);
-        
-        rc->schema = odr_strdup_null(r->odr, r->schema);
-
-        rc->pos = pos;
-        rc->next = r->record_hash[record_hash(pos)];
-        r->record_hash[record_hash(pos)] = rc;
-    }
-    rc->rec.npr = npr;
-    rc->rec.schema = odr_strdup_null(r->odr, schema);
-    rc->rec.diag_set = 0;
-    rc->rec.diag_uri = 0;
-    rc->rec.diag_message = 0;
-    rc->rec.diag_details = 0;
-    if (diag)
-    {
-        if (diag->uri)
-        {
-            char *cp;
-            rc->rec.diag_set = odr_strdup(r->odr, diag->uri);
-            if ((cp = strrchr(rc->rec.diag_set, '/')))
-                *cp = '\0';
-            rc->rec.diag_uri = odr_strdup(r->odr, diag->uri);
-        }
-        rc->rec.diag_message = odr_strdup_null(r->odr, diag->message);            
-        rc->rec.diag_details = odr_strdup_null(r->odr, diag->details);
-    }
-}
-
-ZOOM_record ZOOM_record_cache_lookup(ZOOM_resultset r, int pos,
-                                     const char *syntax,
-                                     const char *elementSetName)
-{
-    ZOOM_record_cache rc;
-    
-    for (rc = r->record_hash[record_hash(pos)]; rc; rc = rc->next)
-    {
-        if (pos == rc->pos)
-        {
-            if (strcmp_null(r->schema, rc->schema))
-                continue;
-            if (strcmp_null(elementSetName,rc->elementSetName))
-                continue;
-            if (strcmp_null(syntax, rc->syntax))
-                continue;
-            return &rc->rec;
-        }
-    }
-    return 0;
-}
-                                             
-
 ZOOM_API(ZOOM_scanset)
     ZOOM_connection_scan(ZOOM_connection c, const char *start)
 {
@@ -2075,8 +1157,9 @@ ZOOM_API(ZOOM_scanset)
     ZOOM_connection_scan1(ZOOM_connection c, ZOOM_query q)
 {
     ZOOM_scanset scan = 0;
+    Z_Query *z_query = ZOOM_query_get_Z_Query(q);
 
-    if (!q->z_query)
+    if (!z_query)
         return 0;
     scan = (ZOOM_scanset) xmalloc(sizeof(*scan));
     scan->connection = c;
@@ -2087,7 +1170,7 @@ ZOOM_API(ZOOM_scanset)
     scan->srw_scan_response = 0;
 
     scan->query = q;
-    (q->refcount)++;
+    ZOOM_query_addref(q);
     scan->databaseNames = ZOOM_connection_get_databases(c, c->options,
                                             &scan->num_databaseNames,
                                             scan->odr);
@@ -2142,56 +1225,6 @@ static zoom_ret send_package(ZOOM_connection c)
     return ZOOM_send_buf(c);
 }
 
-#if YAZ_HAVE_XML2
-static zoom_ret ZOOM_connection_srw_send_scan(ZOOM_connection c)
-{
-    ZOOM_scanset scan;
-    Z_SRW_PDU *sr = 0;
-    const char *option_val = 0;
-
-    if (!c->tasks)
-        return zoom_complete;
-    assert (c->tasks->which == ZOOM_TASK_SCAN);
-    scan = c->tasks->u.scan.scan;
-        
-    sr = ZOOM_srw_get_pdu(c, Z_SRW_scan_request);
-
-    /* SRU scan can only carry CQL and PQF */
-    if (scan->query->z_query->which == Z_Query_type_104)
-    {
-        sr->u.scan_request->query_type = Z_SRW_query_type_cql;
-        sr->u.scan_request->scanClause.cql = scan->query->query_string;
-    }
-    else if (scan->query->z_query->which == Z_Query_type_1
-             || scan->query->z_query->which == Z_Query_type_101)
-    {
-        sr->u.scan_request->query_type = Z_SRW_query_type_pqf;
-        sr->u.scan_request->scanClause.pqf = scan->query->query_string;
-    }
-    else
-    {
-        ZOOM_set_error(c, ZOOM_ERROR_UNSUPPORTED_QUERY, 0);
-        return zoom_complete;
-    }
-
-    sr->u.scan_request->maximumTerms = odr_intdup(
-        c->odr_out, ZOOM_options_get_int(scan->options, "number", 10));
-    
-    sr->u.scan_request->responsePosition = odr_intdup(
-        c->odr_out, ZOOM_options_get_int(scan->options, "position", 1));
-    
-    option_val = ZOOM_options_get(scan->options, "extraArgs");
-    yaz_encode_sru_extra(sr, c->odr_out, option_val);
-    return send_srw(c, sr);
-}
-#else
-static zoom_ret ZOOM_connection_srw_send_scan(ZOOM_connection c)
-{
-    return zoom_complete;
-}
-#endif
-
-
 ZOOM_API(size_t)
     ZOOM_scanset_size(ZOOM_scanset scan)
 {
@@ -2419,7 +1452,7 @@ ZOOM_API(int)
             break;
         case ZOOM_TASK_SORT:
             c->tasks->u.sort.resultset->r_sort_spec = 
-                c->tasks->u.sort.q->sort_spec;
+                ZOOM_query_get_sortspec(c->tasks->u.sort.q);
             ret = send_Z3950_sort(c, c->tasks->u.sort.resultset);
             break;
         }
@@ -2443,150 +1476,6 @@ ZOOM_API(int)
 }
 
 #if YAZ_HAVE_XML2
-static zoom_ret handle_srw_response(ZOOM_connection c,
-                                    Z_SRW_searchRetrieveResponse *res)
-{
-    ZOOM_resultset resultset = 0;
-    int i;
-    NMEM nmem;
-    ZOOM_Event event;
-    int *start, *count;
-    const char *syntax, *elementSetName;
-
-    if (!c->tasks)
-        return zoom_complete;
-
-    switch(c->tasks->which)
-    {
-    case ZOOM_TASK_SEARCH:
-        resultset = c->tasks->u.search.resultset;
-        start = &c->tasks->u.search.start;
-        count = &c->tasks->u.search.count;
-        syntax = c->tasks->u.search.syntax;
-        elementSetName = c->tasks->u.search.elementSetName;        
-
-        if (!c->tasks->u.search.recv_search_fired)
-        {
-            event = ZOOM_Event_create(ZOOM_EVENT_RECV_SEARCH);
-            ZOOM_connection_put_event(c, event);
-            c->tasks->u.search.recv_search_fired = 1;
-        }
-        break;
-    case ZOOM_TASK_RETRIEVE:
-        resultset = c->tasks->u.retrieve.resultset;
-        start = &c->tasks->u.retrieve.start;
-        count = &c->tasks->u.retrieve.count;
-        syntax = c->tasks->u.retrieve.syntax;
-        elementSetName = c->tasks->u.retrieve.elementSetName;
-        break;
-    default:
-        return zoom_complete;
-    }
-
-    resultset->size = 0;
-
-    if (res->resultSetId)
-        ZOOM_resultset_option_set(resultset, "resultSetId", res->resultSetId);
-
-    yaz_log(c->log_details, "%p handle_srw_response got SRW response OK", c);
-
-    if (res->num_diagnostics > 0)
-    {
-        set_SRU_error(c, &res->diagnostics[0]);
-    }
-    else
-    {
-        if (res->numberOfRecords)
-            resultset->size = *res->numberOfRecords;
-        for (i = 0; i<res->num_records; i++)
-        {
-            int pos;
-            Z_SRW_record *sru_rec;
-            Z_SRW_diagnostic *diag = 0;
-            int num_diag;
-            
-            Z_NamePlusRecord *npr = (Z_NamePlusRecord *)
-                odr_malloc(c->odr_in, sizeof(Z_NamePlusRecord));
-            
-            if (res->records[i].recordPosition && 
-                *res->records[i].recordPosition > 0)
-                pos = *res->records[i].recordPosition - 1;
-            else
-                pos = *start + i;
-            
-            sru_rec = &res->records[i];
-            
-            npr->databaseName = 0;
-            npr->which = Z_NamePlusRecord_databaseRecord;
-            npr->u.databaseRecord = (Z_External *)
-                odr_malloc(c->odr_in, sizeof(Z_External));
-            npr->u.databaseRecord->descriptor = 0;
-            npr->u.databaseRecord->direct_reference =
-                odr_oiddup(c->odr_in, yaz_oid_recsyn_xml);
-            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 = (unsigned char*)
-                sru_rec->recordData_buf;
-            npr->u.databaseRecord->u.octet_aligned->len = 
-                npr->u.databaseRecord->u.octet_aligned->size = 
-                sru_rec->recordData_len;
-            
-            if (sru_rec->recordSchema 
-                && !strcmp(sru_rec->recordSchema,
-                           "info:srw/schema/1/diagnostics-v1.1"))
-            {
-                sru_decode_surrogate_diagnostics(sru_rec->recordData_buf,
-                                                 sru_rec->recordData_len,
-                                                 &diag, &num_diag,
-                                                 resultset->odr);
-            }
-            ZOOM_record_cache_add(resultset, npr, pos, syntax, elementSetName,
-                                  sru_rec->recordSchema, diag);
-        }
-        *count -= i;
-        *start += i;
-        if (*count + *start > resultset->size)
-            *count = resultset->size - *start;
-        if (*count < 0)
-            *count = 0;
-        
-        nmem = odr_extract_mem(c->odr_in);
-        nmem_transfer(odr_getmem(resultset->odr), nmem);
-        nmem_destroy(nmem);
-
-        if (*count > 0)
-            return ZOOM_connection_srw_send_search(c);
-    }
-    return zoom_complete;
-}
-#endif
-
-#if YAZ_HAVE_XML2
-static void handle_srw_scan_response(ZOOM_connection c,
-                                     Z_SRW_scanResponse *res)
-{
-    NMEM nmem = odr_extract_mem(c->odr_in);
-    ZOOM_scanset scan;
-
-    if (!c->tasks || c->tasks->which != ZOOM_TASK_SCAN)
-        return;
-    scan = c->tasks->u.scan.scan;
-
-    if (res->num_diagnostics > 0)
-        set_SRU_error(c, &res->diagnostics[0]);
-
-    scan->scan_response = 0;
-    scan->srw_scan_response = res;
-    nmem_transfer(odr_getmem(scan->odr), nmem);
-
-    ZOOM_options_set_int(scan->options, "number", res->num_terms);
-    nmem_destroy(nmem);
-}
-#endif
-
-#if YAZ_HAVE_XML2
 static Z_GDU *get_HTTP_Request_url(ODR odr, const char *url)
 {
     Z_GDU *p = z_get_HTTP_Request(odr);
@@ -2613,12 +1502,12 @@ static Z_GDU *get_HTTP_Request_url(ODR odr, const char *url)
     return p;
 }
 
-static zoom_ret send_SRW_redirect(ZOOM_connection c, const char *uri,
+static zoom_ret send_HTTP_redirect(ZOOM_connection c, const char *uri,
                                   Z_HTTP_Response *cookie_hres)
 {
     struct Z_HTTP_Header *h;
     Z_GDU *gdu = get_HTTP_Request_url(c->odr_out, uri);
-    char *combined_cookies;
+    char *combined_cookies = 0;
     int combined_cookies_len = 0;
 
     gdu->u.HTTP_Request->method = odr_strdup(c->odr_out, "GET");
@@ -2665,6 +1554,15 @@ static zoom_ret send_SRW_redirect(ZOOM_connection c, const char *uri,
     return ZOOM_send_buf(c);
 }
 
+#if YAZ_HAVE_XML2
+void ZOOM_set_HTTP_error(ZOOM_connection c, int error,
+                         const char *addinfo, const char *addinfo2)
+{
+    ZOOM_set_dset_error(c, error, "HTTP", addinfo, addinfo2);
+}
+#endif
+
+
 static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres)
 {
     zoom_ret cret = zoom_complete;
@@ -2683,7 +1581,7 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres)
         c->no_redirects++;
         if (c->no_redirects > 10)
         {
-            set_HTTP_error(c, hres->code, 0, 0);
+            ZOOM_set_HTTP_error(c, hres->code, 0, 0);
             c->no_redirects = 0;
             ZOOM_connection_close(c);
         }
@@ -2691,53 +1589,16 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres)
         {
             /* since redirect may change host we just reconnect. A smarter
                implementation might check whether it's the same server */
-            do_connect_host(c, location, 0);
-            send_SRW_redirect(c, location, hres);
+            do_connect_host(c, location);
+            send_HTTP_redirect(c, location, hres);
             /* we're OK for now. Operation is not really complete */
             ret = 0;
             cret = zoom_pending;
         }
     }
     else 
-    {   /* not redirect (normal response) */
-        if (!yaz_srw_check_content_type(hres))
-            addinfo = "content-type";
-        else
-        {
-            Z_SOAP *soap_package = 0;
-            ODR o = c->odr_in;
-            Z_SOAP_Handler soap_handlers[2] = {
-                {YAZ_XMLNS_SRU_v1_1, 0, (Z_SOAP_fun) yaz_srw_codec},
-                {0, 0, 0}
-            };
-            ret = z_soap_codec(o, &soap_package,
-                               &hres->content_buf, &hres->content_len,
-                               soap_handlers);
-            if (!ret && soap_package->which == Z_SOAP_generic &&
-                soap_package->u.generic->no == 0)
-            {
-                Z_SRW_PDU *sr = (Z_SRW_PDU*) soap_package->u.generic->p;
-                
-                ZOOM_options_set(c->options, "sru_version", sr->srw_version);
-                ZOOM_options_setl(c->options, "sru_extra_response_data",
-                                  sr->extraResponseData_buf, sr->extraResponseData_len);
-                if (sr->which == Z_SRW_searchRetrieve_response)
-                    cret = handle_srw_response(c, sr->u.response);
-                else if (sr->which == Z_SRW_scan_response)
-                    handle_srw_scan_response(c, sr->u.scan_response);
-                else
-                    ret = -1;
-            }
-            else if (!ret && (soap_package->which == Z_SOAP_fault
-                              || soap_package->which == Z_SOAP_error))
-            {
-                set_HTTP_error(c, hres->code,
-                               soap_package->u.fault->fault_code,
-                               soap_package->u.fault->fault_string);
-            }
-            else
-                ret = -1;
-        }   
+    {  
+        ret = ZOOM_handle_sru(c, hres, &cret);
         if (ret == 0)
         {
             if (c->no_redirects) /* end of redirect. change hosts again */
@@ -2748,14 +1609,14 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres)
     if (ret)
     {
         if (hres->code != 200)
-            set_HTTP_error(c, hres->code, 0, 0);
+            ZOOM_set_HTTP_error(c, hres->code, 0, 0);
         else
             ZOOM_set_error(c, ZOOM_ERROR_DECODE, addinfo);
         ZOOM_connection_close(c);
     }
     if (cret == zoom_complete)
     {
-        yaz_log(YLOG_LOG, "removing tasks in handle_http");
+        yaz_log(c->log_details, "removing tasks in handle_http");
         ZOOM_connection_remove_task(c);
     }
     {
@@ -3013,6 +1874,12 @@ ZOOM_API(const char *)
         return "CCL configuration error";
     case ZOOM_ERROR_CCL_PARSE:
         return "CCL parsing error";
+    case ZOOM_ERROR_ES_INVALID_ACTION:
+        return "Extended Service. invalid action";
+    case ZOOM_ERROR_ES_INVALID_VERSION:
+        return "Extended Service. invalid version";
+    case ZOOM_ERROR_ES_INVALID_SYNTAX:
+        return "Extended Service. invalid syntax";
     default:
         return diagbib1_str(error);
     }
@@ -3130,69 +1997,6 @@ ZOOM_API(int)
 }
 
 
-static void cql2pqf_wrbuf_puts(const char *buf, void *client_data)
-{
-    WRBUF wrbuf = (WRBUF) client_data;
-    wrbuf_puts(wrbuf, buf);
-}
-
-/*
- * 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;
-    const char *cqlfile;
-    cql_transform_t trans;
-    char *result = 0;
-
-    parser = cql_parser_create();
-    if ((error = cql_parser_string(parser, cql)) != 0) {
-        cql_parser_destroy(parser);
-        ZOOM_set_error(c, ZOOM_ERROR_CQL_PARSE, cql);
-        return 0;
-    }
-
-    cqlfile = ZOOM_connection_option_get(c, "cqlfile");
-    if (cqlfile == 0) 
-    {
-        ZOOM_set_error(c, ZOOM_ERROR_CQL_TRANSFORM, "no CQL transform file");
-    }
-    else if ((trans = cql_transform_open_fname(cqlfile)) == 0) 
-    {
-        char buf[512];        
-        sprintf(buf, "can't open CQL transform file '%.200s': %.200s",
-                cqlfile, strerror(errno));
-        ZOOM_set_error(c, ZOOM_ERROR_CQL_TRANSFORM, buf);
-    }
-    else 
-    {
-        WRBUF wrbuf_result = wrbuf_alloc();
-        error = cql_transform(trans, cql_parser_result(parser),
-                              cql2pqf_wrbuf_puts, wrbuf_result);
-        if (error != 0) {
-            char buf[512];
-            const char *addinfo;
-            error = cql_transform_error(trans, &addinfo);
-            sprintf(buf, "%.200s (addinfo=%.200s)", 
-                    cql_strerror(error), addinfo);
-            ZOOM_set_error(c, ZOOM_ERROR_CQL_TRANSFORM, buf);
-        }
-        else
-        {
-            result = xstrdup(wrbuf_cstr(wrbuf_result));
-        }
-        cql_transform_close(trans);
-        wrbuf_destroy(wrbuf_result);
-    }
-    cql_parser_destroy(parser);
-    return result;
-}
-
 ZOOM_API(int) ZOOM_connection_fire_event_timeout(ZOOM_connection c)
 {
     if (c->mask)