Stylesheet support.
[yaz-moved-to-github.git] / src / zoom-c.c
index 188ddf7..af940a8 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 2000-2003, Index Data
  * See the file LICENSE for details.
  *
- * $Id: zoom-c.c,v 1.3 2003-11-17 16:01:12 mike Exp $
+ * $Id: zoom-c.c,v 1.16 2004-01-07 20:36:44 adam Exp $
  *
  * ZOOM layer for C, connections, result sets, queries.
  */
@@ -544,7 +544,12 @@ 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);
-    r->step = ZOOM_options_get_int(r->options, "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");
     if (cp)
@@ -884,7 +889,6 @@ static zoom_ret send_APDU (ZOOM_connection c, Z_APDU *a)
 
 static zoom_ret ZOOM_connection_send_init (ZOOM_connection c)
 {
-    const char *impid, *impname, *impver;
     Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_initRequest);
     Z_InitRequest *ireq = apdu->u.initRequest;
     Z_IdAuthentication *auth = (Z_IdAuthentication *)
@@ -892,7 +896,8 @@ static zoom_ret ZOOM_connection_send_init (ZOOM_connection c)
     const char *auth_groupId = ZOOM_options_get (c->options, "group");
     const char *auth_userId = ZOOM_options_get (c->options, "user");
     const char *auth_password = ZOOM_options_get (c->options, "pass");
-    
+    char *version;
+
     ODR_MASK_SET(ireq->options, Z_Options_search);
     ODR_MASK_SET(ireq->options, Z_Options_present);
     ODR_MASK_SET(ireq->options, Z_Options_scan);
@@ -903,40 +908,22 @@ static zoom_ret ZOOM_connection_send_init (ZOOM_connection c)
     ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_1);
     ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_2);
     ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_3);
-    
-    impid = ZOOM_options_get (c->options, "implementationId");
-    ireq->implementationId =
-       (char *) odr_malloc (c->odr_out, 15 + (impid ? strlen(impid) : 0));
-    strcpy (ireq->implementationId, "");
-    if (impid)
-    {
-       strcat (ireq->implementationId, impid);
-       strcat (ireq->implementationId, "/");
-    }                                         
-    strcat (ireq->implementationId, "81"); /* Index's implementor ID */
-    
-    impname = ZOOM_options_get (c->options, "implementationName");
-    ireq->implementationName =
-       (char *) odr_malloc (c->odr_out, 15 + (impname ? strlen(impname) : 0));
-    strcpy (ireq->implementationName, "");
-    if (impname)
-    {
-       strcat (ireq->implementationName, impname);
-       strcat (ireq->implementationName, "/");
-    }                                         
-    strcat (ireq->implementationName, "ZOOM-C/YAZ");
-    
-    impver = ZOOM_options_get (c->options, "implementationVersion");
-    ireq->implementationVersion =
-       (char *) odr_malloc (c->odr_out, strlen("$Revision: 1.3 $") + 2 +
-                            (impver ? strlen(impver) : 0));
-    strcpy (ireq->implementationVersion, "");
-    if (impver)
-    {
-       strcat (ireq->implementationVersion, impver);
-       strcat (ireq->implementationVersion, "/");
-    }                                         
-    strcat (ireq->implementationVersion, "$Revision: 1.3 $");
+
+    /* 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));
+
+    ireq->implementationName = odr_prepend(c->odr_out,
+       ZOOM_options_get(c->options, "implementationName"),
+       odr_prepend(c->odr_out, "ZOOM-C", ireq->implementationName));
+
+    version = odr_strdup(c->odr_out, "$Revision: 1.16 $");
+    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));
 
     *ireq->maximumRecordSize =
        ZOOM_options_get_int (c->options, "maximumRecordSize", 1024*1024);
@@ -1017,7 +1004,7 @@ static zoom_ret send_srw (ZOOM_connection c, Z_SRW_PDU *sr)
 {
     char ctype[50];
     Z_SOAP_Handler h[2] = {
-        {"http://www.loc.gov/zing/srw/v1.0/", 0, (Z_SOAP_fun) yaz_srw_codec},
+        {"http://www.loc.gov/zing/srw/", 0, (Z_SOAP_fun) yaz_srw_codec},
         {0, 0, 0}
     };
     ODR o = odr_createmem(ODR_ENCODE);
@@ -1072,7 +1059,7 @@ static zoom_ret send_srw (ZOOM_connection c, Z_SRW_PDU *sr)
     ret = z_soap_codec_enc(o, &p,
                            &gdu->u.HTTP_Request->content_buf,
                            &gdu->u.HTTP_Request->content_len, h,
-                           c->charset);
+                           c->charset, 0);
 
     if (!z_GDU(c->odr_out, &gdu, 0, 0))
         return zoom_complete;
@@ -1372,6 +1359,62 @@ ZOOM_record_destroy (ZOOM_record rec)
     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)
+{
+    char to[40];
+    char from[40];
+    yaz_iconv_t cd = 0;
+    yaz_marc_t mt = yaz_marc_create();
+
+    *from = '\0';
+    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';
+    }
+
+    if (*from && *to)
+    {
+       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();
+    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);
+    return 0;
+}
+
 static const char *record_iconv_return(ZOOM_record rec, int *len,
                                       const char *buf, int sz,
                                       const char *record_charset)
@@ -1504,8 +1547,11 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
             *len = strlen(desc);
        return desc;
     }
-    else if (!strcmp (type, "render") && 
-             npr->which == Z_NamePlusRecord_databaseRecord)
+    if (npr->which != Z_NamePlusRecord_databaseRecord)
+       return 0;
+
+    /* from now on - we have a database record .. */
+    if (!strcmp (type, "render"))
     {
         Z_External *r = (Z_External *) npr->u.databaseRecord;
         oident *ent = oid_getentbyoid(r->direct_reference);
@@ -1524,7 +1570,7 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
                                       charset);
         else if (r->which == Z_External_octet)
         {
-            yaz_marc_t mt;
+           const char *ret_buf;
             switch (ent->value)
             {
             case VAL_SOIF:
@@ -1535,23 +1581,13 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
             case VAL_APPLICATION_XML:
                 break;
             default:
-                if (!rec->wrbuf_marc)
-                    rec->wrbuf_marc = wrbuf_alloc();
-
-                mt = yaz_marc_create();
-                wrbuf_rewind (rec->wrbuf_marc);
-                if (yaz_marc_decode_wrbuf (
-                        mt, (const char *) r->u.octet_aligned->buf,
-                        r->u.octet_aligned->len,
-                        rec->wrbuf_marc) > 0)
-                {
-                    yaz_marc_destroy(mt);
-                   return record_iconv_return(rec, len,
-                                              wrbuf_buf(rec->wrbuf_marc),
-                                              wrbuf_len(rec->wrbuf_marc),
-                                              charset);
-                }
-                yaz_marc_destroy(mt);
+               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,
@@ -1571,8 +1607,7 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
         }
        return 0;
     }
-    else if (npr->which == Z_NamePlusRecord_databaseRecord &&
-             (!strcmp (type, "xml") || !strcmp(type, "oai")))
+    else if (!strcmp (type, "xml") || !strcmp(type, "oai"))
     {
         Z_External *r = (Z_External *) npr->u.databaseRecord;
         oident *ent = oid_getentbyoid(r->direct_reference);
@@ -1593,7 +1628,7 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
                                       charset);
         else if (r->which == Z_External_octet)
         {
-            yaz_marc_t mt;
+           const char *ret_buf;
             int marc_decode_type = YAZ_MARC_MARCXML;
 
             if (!strcmp(type, "oai"))
@@ -1608,24 +1643,13 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
             case VAL_APPLICATION_XML:
                 break;
             default:
-                if (!rec->wrbuf_marc)
-                    rec->wrbuf_marc = wrbuf_alloc();
-                wrbuf_rewind (rec->wrbuf_marc);
-                mt = yaz_marc_create();
-
-                yaz_marc_xml(mt, YAZ_MARC_MARCXML);
-                if (yaz_marc_decode_wrbuf (
-                        mt, (const char *) r->u.octet_aligned->buf,
-                        r->u.octet_aligned->len,
-                        rec->wrbuf_marc) > 0)
-                {
-                    yaz_marc_destroy(mt);
-                   return record_iconv_return(rec, len,
-                                              wrbuf_buf(rec->wrbuf_marc),
-                                              wrbuf_len(rec->wrbuf_marc),
-                                              charset);
-                }
-                yaz_marc_destroy(mt);
+               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,
@@ -1641,36 +1665,31 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len)
     }
     else if (!strcmp (type, "raw"))
     {
-       if (npr->which == Z_NamePlusRecord_databaseRecord)
+       Z_External *r = (Z_External *) npr->u.databaseRecord;
+       
+       if (r->which == Z_External_sutrs)
        {
-           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;
-           }
+           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 (npr->which == Z_NamePlusRecord_databaseRecord)
-            return (const char *) npr->u.databaseRecord;
-       return 0;
+       if (len) *len = -1;
+       return (const char *) npr->u.databaseRecord;
     }
-    else if (npr->which == Z_NamePlusRecord_databaseRecord &&
-             !strcmp (type, "opac"))
+    else if (!strcmp (type, "opac"))
             
     {
        Z_External *r = (Z_External *) npr->u.databaseRecord;
@@ -2150,7 +2169,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);
@@ -2175,6 +2194,37 @@ 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)
+{
+    const char *term = 0;
+    size_t noent = ZOOM_scanset_size (scan);
+    Z_ScanResponse *res = scan->scan_response;
+    
+    *len = 0;
+    *occ = 0;
+    if (pos >= noent)
+        return 0;
+    if (res->entries->entries[pos]->which == Z_Entry_termInfo)
+    {
+        Z_TermInfo *t = res->entries->entries[pos]->u.termInfo;
+
+        if (t->displayTerm)
+       {
+           term = (const char *) t->term->u.general->buf;
+           *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;
+        }
+        *occ = t->globalOccurrences ? *t->globalOccurrences : 0;
+    }
+    return term;
+}
+
+ZOOM_API(const char *)
 ZOOM_scanset_option_get (ZOOM_scanset scan, const char *key)
 {
     return ZOOM_options_get (scan->options, key);
@@ -2332,6 +2382,167 @@ static Z_ItemOrder *encode_item_order(ZOOM_package p)
     return req;
 }
 
+Z_APDU *create_admin_package(ZOOM_package p, int type, 
+                            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;
+    }
+    return apdu;
+}
+
+static Z_APDU *create_update_package(ZOOM_package p)
+{
+    Z_APDU *apdu = 0;
+    const char *first_db = "Default";
+    int num_db;
+    char **db = set_DatabaseNames(p->connection, p->options, &num_db);
+    const char *action = ZOOM_options_get(p->options, "action");
+    const char *recordId = ZOOM_options_get(p->options, "recordId");
+    const char *record_buf = ZOOM_options_get(p->options, "record");
+    const char *syntax_str = ZOOM_options_get(p->options, "syntax");
+    int syntax_oid = VAL_NONE;
+    int action_no = -1;
+    
+    if (syntax_str)
+       syntax_oid = oid_getvalbyname(syntax_str);
+    if (!record_buf)
+    {
+       record_buf = "void";
+       syntax_oid = VAL_SUTRS;
+    }
+    if (syntax_oid != VAL_NONE)
+       syntax_oid = VAL_TEXT_XML;
+    
+    if (num_db > 0)
+       first_db = db[0];
+    
+    if (!action)
+       action = "specialUpdate";
+    
+    if (!strcmp(action, "recordInsert"))
+       action_no = Z_IUOriginPartToKeep_recordInsert;
+    else if (!strcmp(action, "recordReplace"))
+       action_no = Z_IUOriginPartToKeep_recordReplace;
+    else if (!strcmp(action, "recordDelete"))
+       action_no = Z_IUOriginPartToKeep_recordDelete;
+    else if (!strcmp(action, "elementUpdate"))
+       action_no = Z_IUOriginPartToKeep_elementUpdate;
+    else if (!strcmp(action, "specialUpdate"))
+       action_no = Z_IUOriginPartToKeep_specialUpdate;
+    else
+       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 (recordId)
+       {
+           notToKeep->elements[0]->u.opaque = (Odr_oct *)
+               odr_malloc (p->odr_out, sizeof(Odr_oct));
+           notToKeep->elements[0]->u.opaque->size = strlen(recordId);
+           notToKeep->elements[0]->u.opaque->len = strlen(recordId);
+           notToKeep->elements[0]->u.opaque->buf =
+               odr_strdup(p->odr_out, recordId);
+       }
+       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)
+    {
+       ODR print = odr_createmem(ODR_PRINT);
+
+       z_APDU(print, &apdu, 0, 0);
+       odr_destroy(print);
+    }
+    return apdu;
+}
+
 ZOOM_API(void)
     ZOOM_package_send (ZOOM_package p, const char *type)
 {
@@ -2345,11 +2556,10 @@ ZOOM_API(void)
     p->buf_out = 0;
     if (!strcmp(type, "itemorder"))
     {
-        Z_External *r;
         apdu = create_es_package (p, VAL_ITEMORDER);
         if (apdu)
         {
-            r = (Z_External *) odr_malloc (p->odr_out, sizeof(*r));
+            Z_External *r = (Z_External *) odr_malloc (p->odr_out, sizeof(*r));
             
             r->direct_reference =
                 yaz_oidval_to_z3950oid(p->odr_out, CLASS_EXTSERV,
@@ -2362,6 +2572,20 @@ ZOOM_API(void)
             apdu->u.extendedServicesRequest->taskSpecificParameters = r;
         }
     }
+    if (!strcmp(type, "create"))  /* create database */
+    {
+       apdu = create_admin_package(p, Z_ESAdminOriginPartToKeep_create,
+                                   0, 0);
+    }  
+    if (!strcmp(type, "drop"))  /* drop database */
+    {
+       apdu = create_admin_package(p, Z_ESAdminOriginPartToKeep_drop,
+                                   0, 0);
+    }
+    if (!strcmp(type, "update")) /* update record(s) */
+    {
+       apdu = create_update_package(p);
+    }
     if (apdu)
     {
         if (encode_APDU(p->connection, apdu, p->odr_out) == 0)
@@ -2534,6 +2758,16 @@ static void handle_apdu (ZOOM_connection c, Z_APDU *apdu)
     {
     case Z_APDU_initResponse:
        initrs = apdu->u.initResponse;
+        ZOOM_connection_option_set(c, "serverImplementationId",
+                                   initrs->implementationId ?
+                                   initrs->implementationId : "");
+        ZOOM_connection_option_set(c, "serverImplementationName",
+                                   initrs->implementationName ?
+                                   initrs->implementationName : "");
+        ZOOM_connection_option_set(c, "serverImplementationVersion",
+                                   initrs->implementationVersion ?
+                                   initrs->implementationVersion : "");
+       /* Set the three old options too, for old applications */
         ZOOM_connection_option_set(c, "targetImplementationId",
                                    initrs->implementationId ?
                                    initrs->implementationId : "");
@@ -2717,9 +2951,9 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres)
     if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
     {
         Z_SOAP *soap_package = 0;
-        ODR o = odr_createmem(ODR_DECODE);
+        ODR o = c->odr_in;
         Z_SOAP_Handler soap_handlers[2] = {
-            {"http://www.loc.gov/zing/srw/v1.0/", 0,
+            {"http://www.loc.gov/zing/srw/", 0,
              (Z_SOAP_fun) yaz_srw_codec},
             {0, 0, 0}
         };
@@ -2744,7 +2978,6 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres)
         }
         else
             ret = -1;
-        odr_destroy(o);
     }
     if (ret)
     {
@@ -2778,7 +3011,6 @@ static int do_read (ZOOM_connection c)
     event = ZOOM_Event_create (ZOOM_EVENT_RECV_DATA);
     ZOOM_connection_put_event (c, event);
     
-
     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);
@@ -2812,7 +3044,13 @@ static int do_read (ZOOM_connection c)
 
        if (!z_GDU (c->odr_in, &gdu, 0, 0))
        {
-            set_ZOOM_error(c, ZOOM_ERROR_DECODE, 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)