New ZOOM connection options: targetImplementation{Id,Name,Version}
[yaz-moved-to-github.git] / zutil / zoom-c.c
index 58a51bf..1363725 100644 (file)
@@ -1,5 +1,8 @@
 /*
- * $Id: zoom-c.c,v 1.1 2002-09-16 18:45:14 adam Exp $
+ * Copyright (c) 2000-2002, Index Data
+ * See the file LICENSE for details.
+ *
+ * $Id: zoom-c.c,v 1.10 2002-12-09 23:32:29 adam Exp $
  *
  * ZOOM layer for C, connections, result sets, queries.
  */
@@ -8,6 +11,7 @@
 #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 <sys/poll.h>
 #endif
 
-static int ZOOM_connection_send_init (ZOOM_connection c);
-static int do_write_ex (ZOOM_connection c, char *buf_out, int len_out);
+typedef enum {
+    zoom_pending,
+    zoom_complete
+} zoom_ret;
+
+
+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 ZOOM_Event ZOOM_Event_create (int kind)
 {
@@ -70,6 +80,14 @@ static ZOOM_Event ZOOM_connection_get_event(ZOOM_connection c)
     return event;
 }
 
+static void set_bib1_error (ZOOM_connection c, int error)
+{
+    xfree (c->addinfo);
+    c->addinfo = 0;
+    c->error = error;
+    c->diagset = "Bib-1";
+}
+
 static void clear_error (ZOOM_connection c)
 {
 
@@ -83,9 +101,7 @@ static void clear_error (ZOOM_connection c)
     case ZOOM_ERROR_INTERNAL:
         break;
     default:
-        c->error = ZOOM_ERROR_NONE;
-        xfree (c->addinfo);
-        c->addinfo = 0;
+        set_bib1_error(c, ZOOM_ERROR_NONE);
     }
 }
 
@@ -162,8 +178,8 @@ ZOOM_connection_create (ZOOM_options options)
     c->mask = 0;
     c->reconnect_ok = 0;
     c->state = STATE_IDLE;
-    c->error = ZOOM_ERROR_NONE;
     c->addinfo = 0;
+    set_bib1_error(c, ZOOM_ERROR_NONE);
     c->buf_in = 0;
     c->len_in = 0;
     c->buf_out = 0;
@@ -317,7 +333,7 @@ ZOOM_connection_connect(ZOOM_connection c,
 
     c->async = ZOOM_options_get_bool (c->options, "async", 0);
  
-    c->error = ZOOM_ERROR_NONE;
+    set_bib1_error(c, ZOOM_ERROR_NONE);
 
     task = ZOOM_connection_add_task (c, ZOOM_TASK_CONNECT);
 
@@ -376,7 +392,7 @@ ZOOM_query_sortby(ZOOM_query s, const char *criteria)
     return 0;
 }
 
-static int do_write(ZOOM_connection c);
+static zoom_ret do_write(ZOOM_connection c);
 
 ZOOM_API(void)
 ZOOM_connection_destroy(ZOOM_connection c)
@@ -408,12 +424,17 @@ ZOOM_connection_destroy(ZOOM_connection c)
 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);
+    }
 }
 ZOOM_resultset ZOOM_resultset_create ()
 {
     ZOOM_resultset r = (ZOOM_resultset) xmalloc (sizeof(*r));
 
+    yaz_log (LOG_DEBUG, "ZOOM_resultset_create r = %p", r);
     r->refcount = 1;
     r->size = 0;
     r->odr = odr_createmem (ODR_ENCODE);
@@ -488,7 +509,8 @@ ZOOM_resultset_destroy(ZOOM_resultset r)
     if (!r)
         return;
     (r->refcount)--;
-    yaz_log (LOG_DEBUG, "destroy r = %p count=%d", r, r->refcount);
+    yaz_log (LOG_DEBUG, "ZOOM_resultset_destroy r = %p count=%d",
+             r, r->refcount);
     if (r->refcount == 0)
     {
         ZOOM_record_cache rc;
@@ -576,7 +598,7 @@ ZOOM_resultset_records (ZOOM_resultset r, ZOOM_record *recs,
     }
 }
 
-static int do_connect (ZOOM_connection c)
+static zoom_ret do_connect (ZOOM_connection c)
 {
     void *add;
     const char *effective_host;
@@ -600,7 +622,7 @@ static int do_connect (ZOOM_connection c)
             ZOOM_connection_put_event(c, event);
             ZOOM_connection_send_init(c);
             c->state = STATE_ESTABLISHED;
-            return 1;
+            return zoom_pending;
         }
         else if (ret > 0)
        {
@@ -610,12 +632,12 @@ static int do_connect (ZOOM_connection c)
                 c->mask += ZOOM_SELECT_WRITE;
             if (c->cs->io_pending & CS_WANT_READ)
                 c->mask += ZOOM_SELECT_READ;
-           return 1;
+           return zoom_pending;
        }
     }
     c->state = STATE_IDLE;
-    c->error = ZOOM_ERROR_CONNECT;
-    return 0;
+    set_bib1_error(c, ZOOM_ERROR_CONNECT);
+    return zoom_complete;
 }
 
 int z3950_connection_socket(ZOOM_connection c)
@@ -692,29 +714,33 @@ static int encode_APDU(ZOOM_connection c, Z_APDU *a, ODR out)
            z_APDU(odr_pr, &a, 0, 0);
            odr_destroy(odr_pr);
        }
-       c->error = ZOOM_ERROR_ENCODE;
-       do_close (c);
+        yaz_log (LOG_DEBUG, "encoding failed");
+        set_bib1_error(c, ZOOM_ERROR_ENCODE);
+       odr_reset(out);
        return -1;
     }
     
     return 0;
 }
 
-static int send_APDU (ZOOM_connection c, Z_APDU *a)
+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 -1;
+       return zoom_complete;
     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);
-    do_write (c);
-    return 0;
+    return do_write (c);
 }
 
-static int ZOOM_connection_send_init (ZOOM_connection c)
+/* returns 1 if PDU was sent OK (still pending )
+           0 if PDU was not sent OK (nothing to wait for) 
+*/
+
+static zoom_ret ZOOM_connection_send_init (ZOOM_connection c)
 {
     const char *impname;
     Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_initRequest);
@@ -818,12 +844,10 @@ static int ZOOM_connection_send_init (ZOOM_connection c)
        }
     }
     assert (apdu);
-    send_APDU (c, apdu);
-    
-    return 0;
+    return send_APDU (c, apdu);
 }
 
-static int ZOOM_connection_send_search (ZOOM_connection c)
+static zoom_ret ZOOM_connection_send_search (ZOOM_connection c)
 {
     ZOOM_resultset r;
     int lslb, ssub, mspn;
@@ -934,7 +958,7 @@ static int ZOOM_connection_send_search (ZOOM_connection c)
                     break;
             }
             r->setname = xstrdup (setname);
-            yaz_log (LOG_DEBUG, "allocating %s", r->setname);
+            yaz_log (LOG_DEBUG, "allocating set %s", r->setname);
         }
         else
             r->setname = xstrdup ("default");
@@ -942,12 +966,12 @@ static int ZOOM_connection_send_search (ZOOM_connection c)
     }
     search_req->resultSetName = odr_strdup(c->odr_out, r->setname);
     /* send search request */
-    send_APDU (c, apdu);
-    return 1;
+    return send_APDU (c, apdu);
 }
 
 static void response_diag (ZOOM_connection c, Z_DiagRec *p)
 {
+    int oclass;
     Z_DefaultDiagFormat *r;
     char *addinfo = 0;
     
@@ -955,10 +979,12 @@ static void response_diag (ZOOM_connection c, Z_DiagRec *p)
     c->addinfo = 0;
     if (p->which != Z_DiagRec_defaultFormat)
     {
-       c->error = ZOOM_ERROR_DECODE;
+        set_bib1_error(c, ZOOM_ERROR_DECODE);
        return;
     }
     r = p->u.defaultFormat;
+    c->diagset = yaz_z3950oid_to_str(r->diagnosticSetId, &oclass);
+
     switch (r->which)
     {
     case Z_DefaultDiagFormat_v2Addinfo:
@@ -1041,18 +1067,19 @@ ZOOM_record_get (ZOOM_record rec, const char *type, int *len)
     }
     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)
-           {
-               if (len)
-                    *len = strlen(ent->desc);
-               return ent->desc;
-           }
+               desc = ent->desc;
        }
-       return "none";
+       if (!desc)
+            desc = "none";
+       if (len)
+            *len = strlen(desc);
+       return desc;
     }
     else if (!strcmp (type, "render") && 
              npr->which == Z_NamePlusRecord_databaseRecord)
@@ -1095,13 +1122,18 @@ ZOOM_record_get (ZOOM_record rec, const char *type, int *len)
         }
         else if (r->which == Z_External_grs1)
         {
-            if (len) *len = 5;
-            return "GRS-1";
+            if (!rec->wrbuf_marc)
+                rec->wrbuf_marc = wrbuf_alloc();
+            wrbuf_rewind (rec->wrbuf_marc);
+            yaz_display_grs1(rec->wrbuf_marc, r->u.grs1, 0);
+            if (len) 
+                *len = wrbuf_len(rec->wrbuf_marc);
+            return wrbuf_buf(rec->wrbuf_marc);
         }
        return 0;
     }
-    else if (!strcmp (type, "xml") && 
-             npr->which == Z_NamePlusRecord_databaseRecord)
+    else if (npr->which == Z_NamePlusRecord_databaseRecord &&
+             (!strcmp (type, "xml") || !strcmp(type, "MarcXML")))
     {
         Z_External *r = (Z_External *) npr->u.databaseRecord;
         oident *ent = oid_getentbyoid(r->direct_reference);
@@ -1113,6 +1145,10 @@ ZOOM_record_get (ZOOM_record rec, const char *type, int *len)
         }
         else if (r->which == Z_External_octet)
         {
+            int marc_decode_type = YAZ_MARC_OAIMARC;
+
+            if (!strcmp(type, "MarcXML"))
+                marc_decode_type = YAZ_MARC_MARCXML;
             switch (ent->value)
             {
             case VAL_SOIF:
@@ -1130,7 +1166,7 @@ ZOOM_record_get (ZOOM_record rec, const char *type, int *len)
                                      r->u.octet_aligned->buf,
                                      rec->wrbuf_marc, 0,
                                      r->u.octet_aligned->len,
-                                     1) > 0)
+                                     marc_decode_type) > 0)
                 {
                     if (len) *len = wrbuf_len(rec->wrbuf_marc);
                     return wrbuf_buf(rec->wrbuf_marc);
@@ -1284,7 +1320,7 @@ static void handle_records (ZOOM_connection c, Z_Records *sr,
        if (sr->u.multipleNonSurDiagnostics->num_diagRecs >= 1)
            response_diag(c, sr->u.multipleNonSurDiagnostics->diagRecs[0]);
        else
-           c->error = ZOOM_ERROR_DECODE;
+            set_bib1_error(c, ZOOM_ERROR_DECODE);
     }
     else 
     {
@@ -1315,7 +1351,7 @@ static void handle_records (ZOOM_connection c, Z_Records *sr,
        else if (present_phase)
        {
            /* present response and we didn't get any records! */
-           c->error = ZOOM_ERROR_DECODE;
+            set_bib1_error(c, ZOOM_ERROR_DECODE);
        }
     }
 }
@@ -1372,19 +1408,19 @@ static int scan_response (ZOOM_connection c, Z_ScanResponse *res)
     return 1;
 }
 
-static int send_sort (ZOOM_connection c)
+static zoom_ret send_sort (ZOOM_connection c)
 {
     ZOOM_resultset  resultset;
 
     if (!c->tasks || c->tasks->which != ZOOM_TASK_SEARCH)
-       return 0;
+       return zoom_complete;
 
     resultset = c->tasks->u.search.resultset;
 
     if (c->error)
     {
        resultset->r_sort_spec = 0;
-       return 0;
+       return zoom_complete;
     }
     if (resultset->r_sort_spec)
     {
@@ -1399,13 +1435,12 @@ static int send_sort (ZOOM_connection c)
        req->sortedResultSetName = odr_strdup (c->odr_out, resultset->setname);
        req->sortSequence = resultset->r_sort_spec;
        resultset->r_sort_spec = 0;
-       send_APDU (c, apdu);
-       return 1;
+       return send_APDU (c, apdu);
     }
-    return 0;
+    return zoom_complete;
 }
 
-static int send_present (ZOOM_connection c)
+static zoom_ret send_present (ZOOM_connection c)
 {
     Z_APDU *apdu = 0;
     Z_PresentRequest *req = 0;
@@ -1416,7 +1451,7 @@ static int send_present (ZOOM_connection c)
     ZOOM_resultset  resultset;
 
     if (!c->tasks)
-       return 0;
+       return zoom_complete;
 
     switch (c->tasks->which)
     {
@@ -1429,12 +1464,12 @@ static int send_present (ZOOM_connection c)
         resultset->count = c->tasks->u.retrieve.count;
 
         if (resultset->start >= resultset->size)
-            return 0;
+            return zoom_complete;
         if (resultset->start + resultset->count > resultset->size)
             resultset->count = resultset->size - resultset->start;
        break;
     default:
-        return 0;
+        return zoom_complete;
     }
 
     syntax = ZOOM_resultset_option_get (resultset, "preferredRecordSyntax");
@@ -1442,9 +1477,9 @@ static int send_present (ZOOM_connection c)
     schema = ZOOM_resultset_option_get (resultset, "schema");
 
     if (c->error)                  /* don't continue on error */
-       return 0;
+       return zoom_complete;
     if (resultset->start < 0)
-       return 0;
+       return zoom_complete;
     for (i = 0; i<resultset->count; i++)
     {
        ZOOM_record rec =
@@ -1453,7 +1488,7 @@ static int send_present (ZOOM_connection c)
            break;
     }
     if (i == resultset->count)
-       return 0;
+       return zoom_complete;
 
     apdu = zget_APDU(c->odr_out, Z_APDU_presentRequest);
     req = apdu->u.presentRequest;
@@ -1524,8 +1559,7 @@ static int send_present (ZOOM_connection c)
        req->recordComposition = compo;
     }
     req->resultSetId = odr_strdup(c->odr_out, resultset->setname);
-    send_APDU (c, apdu);
-    return 1;
+    return send_APDU (c, apdu);
 }
 
 ZOOM_API(ZOOM_scanset)
@@ -1571,28 +1605,27 @@ ZOOM_scanset_destroy (ZOOM_scanset scan)
     }
 }
 
-static int send_package (ZOOM_connection c)
+static zoom_ret send_package (ZOOM_connection c)
 {
     ZOOM_Event event;
     if (!c->tasks)
-        return 0;
+        return zoom_complete;
     assert (c->tasks->which == ZOOM_TASK_PACKAGE);
-
+    
     event = ZOOM_Event_create (ZOOM_EVENT_SEND_APDU);
     ZOOM_connection_put_event (c, event);
-
-    do_write_ex (c, c->tasks->u.package->buf_out,
-                 c->tasks->u.package->len_out);
-    return 1;
+    
+    return do_write_ex (c, c->tasks->u.package->buf_out,
+                        c->tasks->u.package->len_out);
 }
 
-static int send_scan (ZOOM_connection c)
+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;
     if (!c->tasks)
-        return 0;
+        return zoom_complete;
     assert (c->tasks->which == ZOOM_TASK_SCAN);
     scan = c->tasks->u.scan.scan;
 
@@ -1613,9 +1646,7 @@ static int send_scan (ZOOM_connection c)
     req->databaseNames = set_DatabaseNames (c, scan->options, 
                                             &req->num_databaseNames);
 
-    send_APDU (c, apdu);
-
-    return 1;
+    return send_APDU (c, apdu);
 }
 
 ZOOM_API(size_t)
@@ -1665,8 +1696,6 @@ ZOOM_scanset_option_set (ZOOM_scanset scan, const char *key,
     ZOOM_options_set (scan->options, key, val);
 }
 
-
-
 static Z_APDU *create_es_package (ZOOM_package p, int type)
 {
     const char *str;
@@ -1744,7 +1773,8 @@ static Z_External *encode_ill_request (ZOOM_package p)
                
         r->u.single_ASN1_type = (Odr_oct *)
             odr_malloc (out, sizeof(*r->u.single_ASN1_type));
-        r->u.single_ASN1_type->buf = odr_malloc (out, illRequest_size);
+        r->u.single_ASN1_type->buf = (unsigned char*)
+            odr_malloc (out, illRequest_size);
         r->u.single_ASN1_type->len = illRequest_size;
         r->u.single_ASN1_type->size = illRequest_size;
         memcpy (r->u.single_ASN1_type->buf, illRequest_buf, illRequest_size);
@@ -1754,7 +1784,7 @@ static Z_External *encode_ill_request (ZOOM_package p)
 
 static Z_ItemOrder *encode_item_order(ZOOM_package p)
 {
-    Z_ItemOrder *req = odr_malloc (p->odr_out, sizeof(*req));
+    Z_ItemOrder *req = (Z_ItemOrder *) odr_malloc (p->odr_out, sizeof(*req));
     const char *str;
     
     req->which=Z_IOItemOrder_esRequest;
@@ -1765,7 +1795,7 @@ static Z_ItemOrder *encode_item_order(ZOOM_package p)
     req->u.esRequest->toKeep = (Z_IOOriginPartToKeep *)
        odr_malloc(p->odr_out,sizeof(Z_IOOriginPartToKeep));
     req->u.esRequest->toKeep->supplDescription = 0;
-    req->u.esRequest->toKeep->contact =
+    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");
@@ -1823,7 +1853,7 @@ ZOOM_API(void)
         apdu = create_es_package (p, VAL_ITEMORDER);
         if (apdu)
         {
-            r = odr_malloc (p->odr_out, sizeof(*r));
+            r = (Z_External *) odr_malloc (p->odr_out, sizeof(*r));
             
             r->direct_reference =
                 yaz_oidval_to_z3950oid(p->odr_out, CLASS_EXTSERV,
@@ -1845,7 +1875,7 @@ ZOOM_API(void)
             ZOOM_task task = ZOOM_connection_add_task (c, ZOOM_TASK_PACKAGE);
             task->u.package = p;
             buf = odr_getbuf(p->odr_out, &p->len_out, 0);
-            p->buf_out = xmalloc (p->len_out);
+            p->buf_out = (char *) xmalloc (p->len_out);
             memcpy (p->buf_out, buf, p->len_out);
             
             (p->refcount)++;
@@ -1904,52 +1934,60 @@ ZOOM_package_option_set (ZOOM_package p, const char *key,
 static int ZOOM_connection_exec_task (ZOOM_connection c)
 {
     ZOOM_task task = c->tasks;
+    zoom_ret ret = zoom_complete;
 
-    yaz_log (LOG_DEBUG, "ZOOM_connection_exec_task");
     if (!task)
-       return 0;
-    if (c->error != ZOOM_ERROR_NONE ||
-        (!c->cs && task->which != ZOOM_TASK_CONNECT))
     {
-       ZOOM_connection_remove_tasks (c);
+        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);
+    if (c->error != ZOOM_ERROR_NONE ||
+        (!c->cs && task->which != ZOOM_TASK_CONNECT))
+    {
+        yaz_log (LOG_DEBUG, "remove tasks because of error = %d", c->error);
+        ZOOM_connection_remove_tasks (c);
+        return 0;
+    }
     if (task->running)
+    {
+        yaz_log (LOG_DEBUG, "task already running");
        return 0;
+    }
     task->running = 1;
     switch (task->which)
     {
     case ZOOM_TASK_SEARCH:
-       /* see if search hasn't been sent yet. */
-       if (ZOOM_connection_send_search (c))
-           return 1;
+       ret = ZOOM_connection_send_search (c);
        break;
     case ZOOM_TASK_RETRIEVE:
-       if (send_present (c))
-           return 1;
+       ret = send_present (c);
        break;
     case ZOOM_TASK_CONNECT:
-        if (do_connect(c))
-            return 1;
+        ret = do_connect(c);
         break;
     case ZOOM_TASK_SCAN:
-        if (send_scan(c))
-            return 1;
+        ret = send_scan(c);
         break;
     case ZOOM_TASK_PACKAGE:
-        if (send_package(c))
-            return 1;
+        ret = send_package(c);
+        break;
     }
-    ZOOM_connection_remove_task (c);
-    return 0;
+    if (ret == zoom_complete)
+    {
+        yaz_log (LOG_DEBUG, "task removed (complete)");
+        ZOOM_connection_remove_task (c);
+        return 0;
+    }
+    yaz_log (LOG_DEBUG, "task pending");
+    return 1;
 }
 
-static int send_sort_present (ZOOM_connection c)
+static zoom_ret send_sort_present (ZOOM_connection c)
 {
-    int r = send_sort (c);
-    if (!r)
+    zoom_ret r = send_sort (c);
+    if (r == zoom_complete)
        r = send_present (c);
     return r;
 }
@@ -1969,7 +2007,7 @@ static int es_response (ZOOM_connection c,
         
         if (id)
             ZOOM_options_setl (c->tasks->u.package->options,
-                               "targetReference", id->buf, id->len);
+                               "targetReference", (char*) id->buf, id->len);
     }
     return 1;
 }
@@ -1980,14 +2018,23 @@ static void handle_apdu (ZOOM_connection c, Z_APDU *apdu)
     Z_InitResponse *initrs;
     
     c->mask = 0;
-    yaz_log (LOG_DEBUG, "hande_apdu type=%d", apdu->which);
+    yaz_log (LOG_DEBUG, "handle_apdu type=%d", apdu->which);
     switch(apdu->which)
     {
     case Z_APDU_initResponse:
        initrs = apdu->u.initResponse;
+        ZOOM_connection_option_set(c, "targetImplementationId",
+                                   initrs->implementationId ?
+                                   initrs->implementationId : "");
+        ZOOM_connection_option_set(c, "targetImplementationName",
+                                   initrs->implementationName ?
+                                   initrs->implementationName : "");
+        ZOOM_connection_option_set(c, "targetImplementationVersion",
+                                   initrs->implementationVersion ?
+                                   initrs->implementationVersion : "");
        if (!*initrs->result)
        {
-           c->error = ZOOM_ERROR_INIT;
+            set_bib1_error(c, ZOOM_ERROR_INIT);
        }
        else
        {
@@ -2017,30 +2064,35 @@ static void handle_apdu (ZOOM_connection c, Z_APDU *apdu)
             if (p)
             {
                 char *charset=NULL, *lang=NULL;
-                int selected;
-                
-                yaz_get_response_charneg(tmpmem, p, &charset, &lang, &selected);
-                yaz_log(LOG_DEBUG, "Target accepted: charset - %s,"
-                        "language - %s, select - %d",
-                        charset, lang, selected);
+                int sel;
                 
+                yaz_get_response_charneg(tmpmem, p, &charset, &lang, &sel);
+                yaz_log(LOG_DEBUG, "Target accepted: charset %s, "
+                        "language %s, select %d",
+                        charset ? charset : "none", lang ? lang : "none", sel);
+                if (charset)
+                    ZOOM_connection_option_set (c, "negotiation-charset",
+                                                charset);
+                if (lang)
+                    ZOOM_connection_option_set (c, "negotiation-lang",
+                                                lang);
                 nmem_destroy(tmpmem);
             }
        }       
        break;
     case Z_APDU_searchResponse:
        handle_search_response (c, apdu->u.searchResponse);
-       if (!send_sort_present (c))
+       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))
+       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))
+       if (send_present (c) == zoom_complete)
            ZOOM_connection_remove_task (c);
         break;
     case Z_APDU_scanResponse:
@@ -2060,12 +2112,12 @@ static void handle_apdu (ZOOM_connection c, Z_APDU *apdu)
         }
         else
         {
-            c->error = ZOOM_ERROR_CONNECTION_LOST;
+            set_bib1_error(c, ZOOM_ERROR_CONNECTION_LOST);
             do_close(c);
         }
         break;
     default:
-        c->error = ZOOM_ERROR_DECODE;
+        set_bib1_error(c, ZOOM_ERROR_DECODE);
         do_close(c);
     }
 }
@@ -2109,7 +2161,7 @@ static int do_read (ZOOM_connection c)
         ZOOM_connection_put_event (c, event);
        if (!z_APDU (c->odr_in, &apdu, 0, 0))
        {
-           c->error = ZOOM_ERROR_DECODE;
+            set_bib1_error(c, ZOOM_ERROR_DECODE);
            do_close (c);
        }
        else
@@ -2119,7 +2171,7 @@ static int do_read (ZOOM_connection c)
     return 1;
 }
 
-static int do_write_ex (ZOOM_connection c, char *buf_out, int len_out)
+static zoom_ret do_write_ex (ZOOM_connection c, char *buf_out, int len_out)
 {
     int r;
     ZOOM_Event event;
@@ -2137,14 +2189,14 @@ static int do_write_ex (ZOOM_connection c, char *buf_out, int len_out)
             yaz_log (LOG_DEBUG, "reconnect write");
             c->tasks->running = 0;
             ZOOM_connection_insert_task (c, ZOOM_TASK_CONNECT);
-            return 0;
+            return zoom_complete;
         }
        if (c->state == STATE_CONNECTING)
-           c->error = ZOOM_ERROR_CONNECT;
+           set_bib1_error(c, ZOOM_ERROR_CONNECT);
        else
-           c->error = ZOOM_ERROR_CONNECTION_LOST;
+            set_bib1_error(c, ZOOM_ERROR_CONNECTION_LOST);
        do_close (c);
-       return 1;
+       return zoom_complete;
     }
     else if (r == 1)
     {    
@@ -2157,14 +2209,13 @@ static int do_write_ex (ZOOM_connection c, char *buf_out, int len_out)
     }
     else
     {
-        // c->reconnect_ok = 0;
         c->mask = ZOOM_SELECT_READ|ZOOM_SELECT_EXCEPT;
         yaz_log (LOG_DEBUG, "do_write_ex 2 mask=%d", c->mask);
     }
-    return 0;
+    return zoom_pending;
 }
 
-static int do_write(ZOOM_connection c)
+static zoom_ret do_write(ZOOM_connection c)
 {
     return do_write_ex (c, c->buf_out, c->len_out);
 }
@@ -2219,47 +2270,57 @@ ZOOM_connection_addinfo (ZOOM_connection c)
     return addinfo;
 }
 
+ZOOM_API(const char *)
+ZOOM_diag_str (int error)
+{
+    switch (error)
+    {
+    case ZOOM_ERROR_NONE:
+       return "No error";
+    case ZOOM_ERROR_CONNECT:
+       return "Connect failed";
+    case ZOOM_ERROR_MEMORY:
+       return "Out of memory";
+    case ZOOM_ERROR_ENCODE:
+       return "Encoding failed";
+    case ZOOM_ERROR_DECODE:
+       return "Decoding failed";
+    case ZOOM_ERROR_CONNECTION_LOST:
+       return "Connection lost";
+    case ZOOM_ERROR_INIT:
+       return "Init rejected";
+    case ZOOM_ERROR_INTERNAL:
+       return "Internal failure";
+    case ZOOM_ERROR_TIMEOUT:
+       return "Timeout";
+    default:
+       return diagbib1_str (error);
+    }
+}
+
 ZOOM_API(int)
-ZOOM_connection_error (ZOOM_connection c, const char **cp,
-                           const char **addinfo)
+ZOOM_connection_error_x (ZOOM_connection c, const char **cp,
+                         const char **addinfo, const char **diagset)
 {
     int error = c->error;
     if (cp)
     {
-       switch (error)
-       {
-       case ZOOM_ERROR_NONE:
-           *cp = "No error"; break;
-       case ZOOM_ERROR_CONNECT:
-           *cp = "Connect failed"; break;
-       case ZOOM_ERROR_MEMORY:
-           *cp = "Out of memory"; break;
-       case ZOOM_ERROR_ENCODE:
-           *cp = "Encoding failed"; break;
-       case ZOOM_ERROR_DECODE:
-           *cp = "Decoding failed"; break;
-       case ZOOM_ERROR_CONNECTION_LOST:
-           *cp = "Connection lost"; break;
-       case ZOOM_ERROR_INIT:
-           *cp = "Init rejected"; break;
-       case ZOOM_ERROR_INTERNAL:
-           *cp = "Internal failure"; break;
-       case ZOOM_ERROR_TIMEOUT:
-           *cp = "Timeout"; break;
-       default:
-           *cp = diagbib1_str (error);
-       }
+       *cp = ZOOM_diag_str(error);
     }
     if (addinfo)
-    {
-       if (c->addinfo)
-           *addinfo = c->addinfo;
-       else
-           *addinfo = "";
-    }
+        *addinfo = c->addinfo ? c->addinfo : "";
+    if (diagset)
+        *diagset = c->diagset ? c->diagset : "";
     return c->error;
 }
 
+ZOOM_API(int)
+ZOOM_connection_error (ZOOM_connection c, const char **cp,
+                       const char **addinfo)
+{
+    return ZOOM_connection_error_x(c, cp, addinfo, 0);
+}
+
 static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
 {
     ZOOM_Event event = 0;
@@ -2270,7 +2331,7 @@ static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
     if (r == CS_NONE)
     {
         event = ZOOM_Event_create (ZOOM_EVENT_CONNECT);
-       c->error = ZOOM_ERROR_CONNECT;
+       set_bib1_error(c, ZOOM_ERROR_CONNECT);
        do_close (c);
         ZOOM_connection_put_event (c, event);
     }
@@ -2298,7 +2359,7 @@ static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
         }
         else
         {
-            c->error = ZOOM_ERROR_CONNECT;
+            set_bib1_error(c, ZOOM_ERROR_CONNECT);
             do_close (c);
             ZOOM_connection_put_event (c, event);
         }
@@ -2447,7 +2508,7 @@ ZOOM_event (int no, ZOOM_connection *cs)
         {
             ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT);
            /* timeout and this connection was waiting */
-           c->error = ZOOM_ERROR_TIMEOUT;
+           set_bib1_error(c, ZOOM_ERROR_TIMEOUT);
             do_close (c);
             ZOOM_connection_put_event(c, event);
         }
@@ -2483,7 +2544,7 @@ ZOOM_event (int no, ZOOM_connection *cs)
        {
             ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT);
            /* timeout and this connection was waiting */
-           c->error = ZOOM_ERROR_TIMEOUT;
+           set_bib1_error(c, ZOOM_ERROR_TIMEOUT);
             do_close (c);
             yaz_log (LOG_DEBUG, "timeout");
             ZOOM_connection_put_event(c, event);