GFS: scan may return extra response data (SRU)
[yaz-moved-to-github.git] / src / seshigh.c
index bc16416..08c4def 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2012 Index Data
+ * Copyright (C) 1995-2013 Index Data
  * See the file LICENSE for details.
  */
 /**
@@ -639,23 +639,57 @@ static int retrieve_fetch(association *assoc, bend_fetch_rr *rr)
             rr->request_format = backend_syntax;
     }
     (*assoc->init->bend_fetch)(assoc->backend, rr);
-    if (rc && rr->record && rr->errcode == 0 && rr->len > 0)
+    if (rc && rr->record && rr->errcode == 0)
     {   /* post conversion must take place .. */
         WRBUF output_record = wrbuf_alloc();
-        int r = yaz_record_conv_record(rc, rr->record, rr->len, output_record);
-        if (r)
-        {
-            const char *details = yaz_record_conv_get_error(rc);
-            rr->errcode = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
-            if (details)
-                rr->errstring = odr_strdup(rr->stream, details);
+        int r = 1;
+        const char *details = 0;
+        if (rr->len > 0)
+        {
+            r = yaz_record_conv_record(rc, rr->record, rr->len, output_record);
+            if (r)
+                details = yaz_record_conv_get_error(rc);
+        }
+        else if (rr->len == -1 && rr->output_format &&
+                 !oid_oidcmp(rr->output_format, yaz_oid_recsyn_opac))
+        {
+            r = yaz_record_conv_opac_record(
+                rc, (Z_OPACRecord *) rr->record, output_record);
+            if (r)
+                details = yaz_record_conv_get_error(rc);
+        }
+        if (r == 0 && match_syntax &&
+            !oid_oidcmp(match_syntax, yaz_oid_recsyn_opac))
+        {
+            yaz_marc_t mt = yaz_marc_create();
+            Z_OPACRecord *opac = 0;
+            if (yaz_xml_to_opac(mt, wrbuf_buf(output_record),
+                                wrbuf_len(output_record),
+                                &opac, 0 /* iconv */, rr->stream->mem, 0)
+                && opac)
+            {
+                rr->len = -1;
+                rr->record = (char *) opac;
+            }
+            else
+            {
+                details = "XML to OPAC conversion failed";
+                r = 1;
+            }
+            yaz_marc_destroy(mt);
         }
-        else
+        else if (r == 0)
         {
             rr->len = wrbuf_len(output_record);
             rr->record = (char *) odr_malloc(rr->stream, rr->len);
             memcpy(rr->record, wrbuf_buf(output_record), rr->len);
         }
+        if (r)
+        {
+            rr->errcode = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
+            if (details)
+                rr->errstring = odr_strdup(rr->stream, details);
+        }
         wrbuf_destroy(output_record);
     }
     if (match_syntax)
@@ -671,7 +705,7 @@ static int retrieve_fetch(association *assoc, bend_fetch_rr *rr)
 static int srw_bend_fetch(association *assoc, int pos,
                           Z_SRW_searchRetrieveRequest *srw_req,
                           Z_SRW_record *record,
-                          const char **addinfo)
+                          const char **addinfo, int *last_in_set)
 {
     bend_fetch_rr rr;
     ODR o = assoc->encode;
@@ -730,6 +764,8 @@ static int srw_bend_fetch(association *assoc, int pos,
 
     retrieve_fetch(assoc, &rr);
 
+    *last_in_set = rr.last_in_set;
+
     if (rr.errcode && rr.surrogate_flag)
     {
         int code = yaz_diag_bib1_to_srw(rr.errcode);
@@ -894,6 +930,8 @@ static void srw_bend_search(association *assoc,
         rr.query->u.type_1 = 0;
         rr.extra_args = sr->extra_args;
         rr.extra_response_data = 0;
+        rr.present_number = srw_req->maximumRecords ?
+            *srw_req->maximumRecords : 0;
 
         if (srw_req->query_type == Z_SRW_query_type_cql)
         {
@@ -1088,6 +1126,7 @@ static void srw_bend_search(association *assoc,
                         for (i = 0; i<number; i++)
                         {
                             int errcode;
+                            int last_in_set = 0;
                             const char *addinfo = 0;
 
                             srw_res->records[j].recordPacking = packing;
@@ -1096,7 +1135,7 @@ static void srw_bend_search(association *assoc,
                             yaz_log(YLOG_DEBUG, "srw_bend_fetch %d", i+start);
                             errcode = srw_bend_fetch(assoc, i+start, srw_req,
                                                      srw_res->records + j,
-                                                     &addinfo);
+                                                     &addinfo, &last_in_set);
                             if (errcode)
                             {
                                 yaz_add_srw_diagnostic(assoc->encode,
@@ -1109,6 +1148,8 @@ static void srw_bend_search(association *assoc,
                             }
                             if (srw_res->records[j].recordData_buf)
                                 j++;
+                            if (last_in_set)
+                                break;
                         }
                         srw_res->num_records = j;
                         if (!j)
@@ -1256,10 +1297,11 @@ static void srw_bend_explain(association *assoc,
 
 static void srw_bend_scan(association *assoc,
                           Z_SRW_PDU *sr,
-                          Z_SRW_scanResponse *srw_res,
+                          Z_SRW_PDU *res,
                           int *http_code)
 {
     Z_SRW_scanRequest *srw_req = sr->u.scan_request;
+    Z_SRW_scanResponse *srw_res = res->u.scan_response;
     yaz_log(log_requestdetail, "Got SRW ScanRequest");
 
     *http_code = 200;
@@ -1287,6 +1329,7 @@ static void srw_bend_scan(association *assoc,
         bsrr->step_size = &step_size;
         bsrr->entries = 0;
         bsrr->setname = 0;
+        bsrr->extra_response_data = 0;
 
         if (bsrr->num_entries > 0)
         {
@@ -1356,6 +1399,11 @@ static void srw_bend_scan(association *assoc,
                                    &srw_res->num_diagnostics,
                                    YAZ_SRW_UNSUPP_OPERATION, "scan");
         }
+        if (bsrr->extra_response_data)
+        {
+            res->extraResponseData_buf = bsrr->extra_response_data;
+            res->extraResponseData_len = strlen(bsrr->extra_response_data);
+        }
         if (bsrr->errcode)
         {
             int srw_error;
@@ -1840,7 +1888,7 @@ static void process_http_request(association *assoc, request *req)
                 res->u.scan_response->diagnostics = diagnostic;
                 res->u.scan_response->num_diagnostics = num_diagnostic;
             }
-            srw_bend_scan(assoc, sr, res->u.scan_response, &http_code);
+            srw_bend_scan(assoc, sr, res, &http_code);
             if (http_code == 200)
                 soap_package->u.generic->p = res;
         }
@@ -2322,6 +2370,10 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
                 assoc->init->implementation_id,
                 resp->implementationId);
 
+    resp->implementationVersion = odr_prepend(assoc->encode,
+                assoc->init->implementation_version,
+                resp->implementationVersion);
+
     resp->implementationName = odr_prepend(assoc->encode,
                 assoc->init->implementation_name,
                 odr_prepend(assoc->encode, "GFS", resp->implementationName));
@@ -2591,6 +2643,8 @@ static Z_Records *pack_records(association *a, char *setname, Odr_int start,
             return 0;
         reclist->records[reclist->num_records] = thisrec;
         reclist->num_records++;
+        if (freq.last_in_set)
+            break;
     }
     *num = reclist->num_records;
     return records;
@@ -2639,6 +2693,7 @@ static Z_APDU *process_searchRequest(association *assoc, request *reqb)
         bsrr->errstring = NULL;
         bsrr->search_info = NULL;
         bsrr->search_input = req->otherInfo;
+        bsrr->present_number = *req->mediumSetPresentNumber;
 
         if (assoc->server && assoc->server->cql_transform
             && req->query->which == Z_Query_type_104
@@ -2996,6 +3051,7 @@ static Z_APDU *process_scanRequest(association *assoc, request *reqb)
     bsrr->setname = yaz_oi_get_string_oid(&req->otherInfo,
                                           yaz_oid_userinfo_scan_set, 1, 0);
     bsrr->entries = 0;
+    bsrr->extra_response_data = 0;
     /* For YAZ 2.0 and earlier it was the backend handler that
        initialized entries (member display_term did not exist)
        YAZ 2.0 and later sets 'entries'  and initialize all members