2 * Copyright (C) 1995-2005, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: srwutil.c,v 1.34 2005-12-14 14:05:55 adam Exp $
9 * \brief Implements SRW/SRU utilities.
14 #include <yaz/yaz-iconv.h>
16 static int hex_digit (int ch)
18 if (ch >= '0' && ch <= '9')
20 else if (ch >= 'a' && ch <= 'f')
22 else if (ch >= 'A' && ch <= 'F')
27 int yaz_uri_array(const char *path, ODR o, char ***name, char ***val)
37 while ((cp = strchr(cp, '&')))
42 *name = odr_malloc(o, no * sizeof(char*));
43 *val = odr_malloc(o, no * sizeof(char*));
45 for (no = 0; *path; no++)
47 const char *p1 = strchr(path, '=');
53 (*name)[no] = odr_malloc(o, (p1-path)+1);
54 memcpy((*name)[no], path, p1-path);
55 (*name)[no][p1-path] = '\0';
58 p1 = strchr(path, '&');
60 p1 = strlen(path) + path;
61 (*val)[no] = ret = odr_malloc(o, p1 - path + 1);
62 while (*path && *path != '&')
69 else if (*path == '%' && path[1] && path[2])
71 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
87 char *yaz_uri_val(const char *path, const char *name, ODR o)
89 size_t nlen = strlen(name);
95 const char *p1 = strchr(path, '=');
98 if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
104 p1 = strchr(path, '&');
106 p1 = strlen(path) + path;
107 ret = (char *) odr_malloc(o, p1 - path + 1);
108 while (*path && *path != '&')
115 else if (*path == '%' && path[1] && path[2])
117 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
126 path = strchr(p1, '&');
133 void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
135 const char *v = yaz_uri_val(path, name, o);
137 *intp = odr_intdup(o, atoi(v));
140 void yaz_mk_srw_diagnostic(ODR o, Z_SRW_diagnostic *d,
141 const char *uri, const char *message,
144 d->uri = odr_strdup(o, uri);
146 d->message = odr_strdup(o, message);
150 d->details = odr_strdup(o, details);
155 void yaz_mk_std_diagnostic(ODR o, Z_SRW_diagnostic *d,
156 int code, const char *details)
160 sprintf(uri, "info:srw/diagnostic/1/%d", code);
161 return yaz_mk_srw_diagnostic(o, d, uri, 0, details);
164 void yaz_add_srw_diagnostic_uri(ODR o, Z_SRW_diagnostic **d,
165 int *num, const char *uri,
166 const char *message, const char *details)
168 Z_SRW_diagnostic *d_new;
169 d_new = (Z_SRW_diagnostic *) odr_malloc (o, (*num + 1)* sizeof(**d));
171 memcpy (d_new, *d, *num *sizeof(**d));
174 yaz_mk_srw_diagnostic(o, *d + *num, uri, message, details);
178 void yaz_add_srw_diagnostic(ODR o, Z_SRW_diagnostic **d,
179 int *num, int code, const char *addinfo)
183 sprintf(uri, "info:srw/diagnostic/1/%d", code);
184 return yaz_add_srw_diagnostic_uri(o, d, num, uri, 0, addinfo);
187 int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
188 Z_SOAP **soap_package, ODR decode, char **charset)
190 if (!strcmp(hreq->method, "POST"))
192 const char *content_type = z_HTTP_header_lookup(hreq->headers,
195 (!yaz_strcmp_del("text/xml", content_type, "; ") ||
196 !yaz_strcmp_del("text/plain", content_type, "; ")))
198 char *db = "Default";
199 const char *p0 = hreq->path, *p1;
201 const char *charset_p = 0;
203 static Z_SOAP_Handler soap_handlers[4] = {
205 {"http://www.loc.gov/zing/srw/", 0,
206 (Z_SOAP_fun) yaz_srw_codec},
207 {"http://www.loc.gov/zing/srw/v1.0/", 0,
208 (Z_SOAP_fun) yaz_srw_codec},
209 {"http://www.loc.gov/zing/srw/update/", 0,
210 (Z_SOAP_fun) yaz_ucp_codec},
217 p1 = strchr(p0, '?');
219 p1 = p0 + strlen(p0);
222 db = (char*) odr_malloc(decode, p1 - p0 + 1);
223 memcpy (db, p0, p1 - p0);
227 if (charset && (charset_p = strstr(content_type, "; charset=")))
231 while (i < 20 && charset_p[i] &&
232 !strchr("; \n\r", charset_p[i]))
234 *charset = (char*) odr_malloc(decode, i+1);
235 memcpy(*charset, charset_p, i);
236 (*charset)[i] = '\0';
238 ret = z_soap_codec(decode, soap_package,
239 &hreq->content_buf, &hreq->content_len,
241 if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
243 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
245 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
246 (*srw_pdu)->u.request->database == 0)
247 (*srw_pdu)->u.request->database = db;
249 if ((*srw_pdu)->which == Z_SRW_explain_request &&
250 (*srw_pdu)->u.explain_request->database == 0)
251 (*srw_pdu)->u.explain_request->database = db;
253 if ((*srw_pdu)->which == Z_SRW_scan_request &&
254 (*srw_pdu)->u.scan_request->database == 0)
255 (*srw_pdu)->u.scan_request->database = db;
257 if ((*srw_pdu)->which == Z_SRW_update_request &&
258 (*srw_pdu)->u.update_request->database == 0)
259 (*srw_pdu)->u.update_request->database = db;
270 http://www.loc.gov/z3950/agency/zing/srw/service.html
272 int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
273 Z_SOAP **soap_package, ODR decode, char **charset,
274 Z_SRW_diagnostic **diag, int *num_diag)
277 static Z_SOAP_Handler soap_handlers[2] = {
278 {"http://www.loc.gov/zing/srw/", 0,
279 (Z_SOAP_fun) yaz_srw_codec},
283 const char *content_type = z_HTTP_header_lookup(hreq->headers,
286 SRU GET: allow any content type.
287 SRU POST: we support "application/x-www-form-urlencoded";
288 not "multipart/form-data" .
290 if (!strcmp(hreq->method, "GET")
292 (!strcmp(hreq->method, "POST")
294 !yaz_strcmp_del("application/x-www-form-urlencoded",
299 char *db = "Default";
300 const char *p0 = hreq->path, *p1;
302 const char *operation = 0;
307 char *stylesheet = 0;
308 char *scanClause = 0;
309 char *pScanClause = 0;
310 char *recordXPath = 0;
311 char *recordSchema = 0;
312 char *recordPacking = "xml"; /* xml packing is default for SRU */
313 char *maximumRecords = 0;
314 char *startRecord = 0;
315 char *maximumTerms = 0;
316 char *responsePosition = 0;
317 char *extraRequestData = 0;
326 p1 = strchr(p0, '?');
328 p1 = p0 + strlen(p0);
331 db = (char*) odr_malloc(decode, p1 - p0 + 1);
332 memcpy (db, p0, p1 - p0);
335 if (!strcmp(hreq->method, "POST"))
336 p1 = hreq->content_buf;
337 yaz_uri_array(p1, decode, &uri_name, &uri_val);
342 for (i = 0; uri_name[i]; i++)
344 char *n = uri_name[i];
345 char *v = uri_val[i];
346 if (!strcmp(n, "query"))
348 else if (!strcmp(n, "x-pquery"))
350 else if (!strcmp(n, "operation"))
352 else if (!strcmp(n, "stylesheet"))
354 else if (!strcmp(n, "sortKeys"))
356 else if (!strcmp(n, "recordXPath"))
358 else if (!strcmp(n, "recordSchema"))
360 else if (!strcmp(n, "recordPacking"))
362 else if (!strcmp(n, "version"))
364 else if (!strcmp(n, "scanClause"))
366 else if (!strcmp(n, "x-pScanClause"))
368 else if (!strcmp(n, "maximumRecords"))
370 else if (!strcmp(n, "startRecord"))
372 else if (!strcmp(n, "maximumTerms"))
374 else if (!strcmp(n, "responsePosition"))
375 responsePosition = v;
376 else if (!strcmp(n, "extraRequestData"))
377 extraRequestData = v;
379 yaz_add_srw_diagnostic(decode, diag, num_diag, 8, n);
385 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "version");
388 if (strcmp(version, "1.1"))
389 yaz_add_srw_diagnostic(decode, diag, num_diag, 5, "1.1");
393 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "operation");
394 operation = "explain";
396 if (!strcmp(operation, "searchRetrieve"))
398 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
400 sr->srw_version = version;
404 sr->u.request->query_type = Z_SRW_query_type_cql;
405 sr->u.request->query.cql = query;
409 sr->u.request->query_type = Z_SRW_query_type_pqf;
410 sr->u.request->query.pqf = pQuery;
413 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "query");
417 sr->u.request->sort_type = Z_SRW_sort_type_sort;
418 sr->u.request->sort.sortKeys = sortKeys;
420 sr->u.request->recordXPath = recordXPath;
421 sr->u.request->recordSchema = recordSchema;
422 sr->u.request->recordPacking = recordPacking;
423 sr->u.request->stylesheet = stylesheet;
426 sr->u.request->maximumRecords =
427 odr_intdup(decode, atoi(maximumRecords));
429 sr->u.request->startRecord =
430 odr_intdup(decode, atoi(startRecord));
432 sr->u.request->database = db;
434 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
435 (*soap_package)->which = Z_SOAP_generic;
437 (*soap_package)->u.generic =
438 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
440 (*soap_package)->u.generic->p = sr;
441 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
442 (*soap_package)->u.generic->no = 0;
444 (*soap_package)->ns = "SRU";
448 else if (!strcmp(operation, "explain"))
450 /* Transfer SRU explain parameters to common struct */
451 /* http://www.loc.gov/z3950/agency/zing/srw/explain.html */
452 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
454 sr->srw_version = version;
456 sr->u.explain_request->recordPacking = recordPacking;
457 sr->u.explain_request->database = db;
459 sr->u.explain_request->stylesheet = stylesheet;
461 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
462 (*soap_package)->which = Z_SOAP_generic;
464 (*soap_package)->u.generic =
465 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
467 (*soap_package)->u.generic->p = sr;
468 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
469 (*soap_package)->u.generic->no = 0;
471 (*soap_package)->ns = "SRU";
475 else if (!strcmp(operation, "scan"))
477 /* Transfer SRU scan parameters to common struct */
478 /* http://www.loc.gov/z3950/agency/zing/srw/scan.html */
479 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_scan_request);
481 sr->srw_version = version;
486 sr->u.scan_request->query_type = Z_SRW_query_type_cql;
487 sr->u.scan_request->scanClause.cql = scanClause;
489 else if (pScanClause)
491 sr->u.scan_request->query_type = Z_SRW_query_type_pqf;
492 sr->u.scan_request->scanClause.pqf = pScanClause;
495 yaz_add_srw_diagnostic(decode, diag, num_diag, 7,
497 sr->u.scan_request->database = db;
500 sr->u.scan_request->maximumTerms =
501 odr_intdup(decode, atoi(maximumTerms));
502 if (responsePosition)
503 sr->u.scan_request->responsePosition =
504 odr_intdup(decode, atoi(responsePosition));
506 sr->u.scan_request->stylesheet = stylesheet;
508 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
509 (*soap_package)->which = Z_SOAP_generic;
511 (*soap_package)->u.generic =
512 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
514 (*soap_package)->u.generic->p = sr;
515 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
516 (*soap_package)->u.generic->no = 0;
518 (*soap_package)->ns = "SRU";
524 /* unsupported operation ... */
525 /* Act as if we received a explain request and throw diagnostic. */
527 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
529 sr->srw_version = version;
531 sr->u.explain_request->recordPacking = recordPacking;
532 sr->u.explain_request->database = db;
534 sr->u.explain_request->stylesheet = stylesheet;
536 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
537 (*soap_package)->which = Z_SOAP_generic;
539 (*soap_package)->u.generic =
540 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
542 (*soap_package)->u.generic->p = sr;
543 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
544 (*soap_package)->u.generic->no = 0;
546 (*soap_package)->ns = "SRU";
548 yaz_add_srw_diagnostic(decode, diag, num_diag, 4, operation);
557 Z_SRW_extra_record *yaz_srw_get_extra_record(ODR o)
559 Z_SRW_extra_record *res = (Z_SRW_extra_record *)
560 odr_malloc(o, sizeof(*res));
562 res->recordReviewCode = 0;
563 res->recordReviewNote = 0;
565 res->nonDupRecordId = 0;
566 res->recordLockStatus = 0;
567 res->recordOldVersion = 0;
571 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
573 Z_SRW_PDU *sr = (Z_SRW_PDU *) odr_malloc(o, sizeof(*o));
575 sr->srw_version = odr_strdup(o, "1.1");
579 case Z_SRW_searchRetrieve_request:
580 sr->u.request = (Z_SRW_searchRetrieveRequest *)
581 odr_malloc(o, sizeof(*sr->u.request));
582 sr->u.request->query_type = Z_SRW_query_type_cql;
583 sr->u.request->query.cql = 0;
584 sr->u.request->sort_type = Z_SRW_sort_type_none;
585 sr->u.request->sort.none = 0;
586 sr->u.request->startRecord = 0;
587 sr->u.request->maximumRecords = 0;
588 sr->u.request->recordSchema = 0;
589 sr->u.request->recordPacking = 0;
590 sr->u.request->recordXPath = 0;
591 sr->u.request->database = 0;
592 sr->u.request->resultSetTTL = 0;
593 sr->u.request->stylesheet = 0;
595 case Z_SRW_searchRetrieve_response:
596 sr->u.response = (Z_SRW_searchRetrieveResponse *)
597 odr_malloc(o, sizeof(*sr->u.response));
598 sr->u.response->numberOfRecords = 0;
599 sr->u.response->resultSetId = 0;
600 sr->u.response->resultSetIdleTime = 0;
601 sr->u.response->records = 0;
602 sr->u.response->num_records = 0;
603 sr->u.response->diagnostics = 0;
604 sr->u.response->num_diagnostics = 0;
605 sr->u.response->nextRecordPosition = 0;
606 sr->u.response->extra_records = 0;
608 case Z_SRW_explain_request:
609 sr->u.explain_request = (Z_SRW_explainRequest *)
610 odr_malloc(o, sizeof(*sr->u.explain_request));
611 sr->u.explain_request->recordPacking = 0;
612 sr->u.explain_request->database = 0;
613 sr->u.explain_request->stylesheet = 0;
615 case Z_SRW_explain_response:
616 sr->u.explain_response = (Z_SRW_explainResponse *)
617 odr_malloc(o, sizeof(*sr->u.explain_response));
618 sr->u.explain_response->record.recordData_buf = 0;
619 sr->u.explain_response->record.recordData_len = 0;
620 sr->u.explain_response->record.recordSchema = 0;
621 sr->u.explain_response->record.recordPosition = 0;
622 sr->u.explain_response->record.recordPacking =
623 Z_SRW_recordPacking_string;
624 sr->u.explain_response->diagnostics = 0;
625 sr->u.explain_response->num_diagnostics = 0;
626 sr->u.explain_response->extra_record = 0;
628 case Z_SRW_scan_request:
629 sr->u.scan_request = (Z_SRW_scanRequest *)
630 odr_malloc(o, sizeof(*sr->u.scan_request));
631 sr->u.scan_request->database = 0;
632 sr->u.scan_request->stylesheet = 0;
633 sr->u.scan_request->maximumTerms = 0;
634 sr->u.scan_request->responsePosition = 0;
635 sr->u.scan_request->query_type = Z_SRW_query_type_cql;
636 sr->u.scan_request->scanClause.cql = 0;
638 case Z_SRW_scan_response:
639 sr->u.scan_response = (Z_SRW_scanResponse *)
640 odr_malloc(o, sizeof(*sr->u.scan_response));
641 sr->u.scan_response->terms = 0;
642 sr->u.scan_response->num_terms = 0;
643 sr->u.scan_response->diagnostics = 0;
644 sr->u.scan_response->num_diagnostics = 0;
645 case Z_SRW_update_request:
646 sr->u.update_request = (Z_SRW_updateRequest *)
647 odr_malloc(o, sizeof(*sr->u.update_request));
648 sr->u.update_request->database = 0;
649 sr->u.update_request->stylesheet = 0;
650 sr->u.update_request->record.recordSchema = 0;
651 sr->u.update_request->record.recordPacking = Z_SRW_recordPacking_XML;
652 sr->u.update_request->recordId = 0;
653 sr->u.update_request->recordVersion = 0;
654 sr->u.update_request->recordOldVersion = 0;
655 sr->u.update_request->record.recordData_buf = 0;
656 sr->u.update_request->record.recordData_len = 0;
657 sr->u.update_request->extra_record = 0;
658 sr->u.update_request->extraRequestData = 0;
659 sr->u.request->database = 0;
661 case Z_SRW_update_response:
662 sr->u.update_response = (Z_SRW_updateResponse *)
663 odr_malloc(o, sizeof(*sr->u.update_response));
664 sr->u.update_response->operationStatus = 0;
665 sr->u.update_response->recordId = 0;
666 sr->u.update_response->recordVersion = 0;
667 sr->u.update_response->recordChecksum = 0;
668 sr->u.update_response->record.recordData_buf = 0;
669 sr->u.update_response->record.recordData_len = 0;
670 sr->u.update_response->record.recordSchema = 0;
671 sr->u.update_response->record.recordPacking =
672 Z_SRW_recordPacking_XML;
673 sr->u.update_response->extra_record = 0;
674 sr->u.update_response->extraResponseData = 0;
675 sr->u.update_response->diagnostics = 0;
676 sr->u.update_response->num_diagnostics = 0;
682 static int srw_bib1_map[] = {
692 108, 10, /* Malformed query : Syntax error */
722 100, 1, /* bad map */
770 205, 1, /* bad map */
771 206, 1, /* bad map */
773 208, 1, /* bad map */
784 218, 1, /* bad map */
785 219, 1, /* bad map */
786 220, 1, /* bad map */
787 221, 1, /* bad map */
789 223, 1, /* bad map */
790 224, 1, /* bad map */
791 225, 1, /* bad map */
792 226, 1, /* bad map */
794 228, 1, /* bad map */
799 233, 1, /* bad map */
800 234, 1, /* bad map */
806 240, 1, /* bad map */
807 241, 1, /* bad map */
809 243, 1, /* bad map */
814 1001, 1, /* bad map */
815 1002, 1, /* bad map */
816 1003, 1, /* bad map */
817 1004, 1, /* bad map */
818 1005, 1, /* bad map */
819 1006, 1, /* bad map */
851 int yaz_diag_bib1_to_srw (int code)
853 const int *p = srw_bib1_map;
863 int yaz_diag_srw_to_bib1(int code)
865 const int *p = srw_bib1_map;
878 * indent-tabs-mode: nil
880 * vim: shiftwidth=4 tabstop=8 expandtab