Use odr_prepend() to generate implementation{Id,Name,Version}
[yaz-moved-to-github.git] / src / zoom-c.c
index da9ca8b..19947c3 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 2000-2003, Index Data
  * See the file LICENSE for details.
  *
- * $Id: zoom-c.c,v 1.1 2003-10-27 12:21:36 adam Exp $
+ * $Id: zoom-c.c,v 1.8 2003-11-26 16:22:35 mike 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,7 @@ static zoom_ret send_APDU (ZOOM_connection c, Z_APDU *a)
 
 static zoom_ret ZOOM_connection_send_init (ZOOM_connection c)
 {
-    const char *impname;
+    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 +897,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,18 +909,23 @@ 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);
-    
-    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");
-    
+
+    /* 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.8 $");
+    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[10], ireq->implementationVersion));
+
     *ireq->maximumRecordSize =
        ZOOM_options_get_int (c->options, "maximumRecordSize", 1024*1024);
     *ireq->preferredMessageSize =
@@ -1025,7 +1036,7 @@ static zoom_ret send_srw (ZOOM_connection c, Z_SRW_PDU *sr)
             memcpy (h, cp0, cp1 - cp0);
             h[cp1-cp0] = '\0';
             z_HTTP_header_add(c->odr_out, &gdu->u.HTTP_Request->headers,
-                              "host", h);
+                              "Host", h);
         }
     }
 
@@ -1481,8 +1492,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);
@@ -1548,8 +1562,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);
@@ -1618,36 +1631,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;
@@ -2127,7 +2135,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);
@@ -2152,6 +2160,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);
@@ -2309,6 +2348,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)
 {
@@ -2322,11 +2522,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,
@@ -2339,6 +2538,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)
@@ -2511,6 +2724,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 : "");
@@ -2755,7 +2978,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);
@@ -2789,7 +3011,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)