2 * Copyright (c) 2002-2004, Index Data.
3 * See the file LICENSE for details.
5 * $Id: srwutil.c,v 1.18 2004-10-15 00:19:01 adam Exp $
9 * \brief Implements SRW/SRU utilities.
13 #include <yaz/yaz-iconv.h>
15 static int hex_digit (int ch)
17 if (ch >= '0' && ch <= '9')
19 else if (ch >= 'a' && ch <= 'f')
21 else if (ch >= 'A' && ch <= 'F')
26 int yaz_uri_array(const char *path, ODR o, char ***name, char ***val)
35 while ((cp = strchr(cp, '&')))
40 *name = odr_malloc(o, no * sizeof(char**));
41 *val = odr_malloc(o, no * sizeof(char**));
43 for (no = 0; *path; no++)
45 const char *p1 = strchr(path, '=');
51 (*name)[no] = odr_malloc(o, (p1-path)+1);
52 memcpy((*name)[no], path, p1-path);
53 (*name)[no][p1-path] = '\0';
56 p1 = strchr(path, '&');
58 p1 = strlen(path) + path;
59 (*val)[no] = ret = odr_malloc(o, p1 - path + 1);
60 while (*path && *path != '&')
67 else if (*path == '%' && path[1] && path[2])
69 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
85 char *yaz_uri_val(const char *path, const char *name, ODR o)
87 size_t nlen = strlen(name);
93 const char *p1 = strchr(path, '=');
96 if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
102 p1 = strchr(path, '&');
104 p1 = strlen(path) + path;
105 ret = (char *) odr_malloc(o, p1 - path + 1);
106 while (*path && *path != '&')
113 else if (*path == '%' && path[1] && path[2])
115 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
124 path = strchr(p1, '&');
131 void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
133 const char *v = yaz_uri_val(path, name, o);
135 *intp = odr_intdup(o, atoi(v));
138 void yaz_mk_std_diagnostic(ODR o, Z_SRW_diagnostic *d,
139 int code, const char *details)
141 d->uri = (char *) odr_malloc(o, 50);
142 sprintf(d->uri, "info:srw/diagnostic/1/%d", code);
145 d->details = odr_strdup(o, details);
150 void yaz_add_srw_diagnostic(ODR o, Z_SRW_diagnostic **d,
151 int *num, int code, const char *addinfo)
153 Z_SRW_diagnostic *d_new;
154 d_new = (Z_SRW_diagnostic *) odr_malloc (o, (*num + 1)* sizeof(**d));
156 memcpy (d_new, *d, *num *sizeof(**d));
159 yaz_mk_std_diagnostic(o, *d + *num, code, addinfo);
163 int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
164 Z_SOAP **soap_package, ODR decode, char **charset)
166 if (!strcmp(hreq->method, "POST"))
168 const char *content_type = z_HTTP_header_lookup(hreq->headers,
170 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
172 char *db = "Default";
173 const char *p0 = hreq->path, *p1;
175 const char *charset_p = 0;
177 static Z_SOAP_Handler soap_handlers[3] = {
179 {"http://www.loc.gov/zing/srw/", 0,
180 (Z_SOAP_fun) yaz_srw_codec},
181 {"http://www.loc.gov/zing/srw/v1.0/", 0,
182 (Z_SOAP_fun) yaz_srw_codec},
189 p1 = strchr(p0, '?');
191 p1 = p0 + strlen(p0);
194 db = (char*) odr_malloc(decode, p1 - p0 + 1);
195 memcpy (db, p0, p1 - p0);
199 if (charset && (charset_p = strstr(content_type, "; charset=")))
203 while (i < 20 && charset_p[i] &&
204 !strchr("; \n\r", charset_p[i]))
206 *charset = (char*) odr_malloc(decode, i+1);
207 memcpy(*charset, charset_p, i);
208 (*charset)[i] = '\0';
210 ret = z_soap_codec(decode, soap_package,
211 &hreq->content_buf, &hreq->content_len,
213 if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
215 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
217 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
218 (*srw_pdu)->u.request->database == 0)
219 (*srw_pdu)->u.request->database = db;
221 if ((*srw_pdu)->which == Z_SRW_explain_request &&
222 (*srw_pdu)->u.explain_request->database == 0)
223 (*srw_pdu)->u.explain_request->database = db;
225 if ((*srw_pdu)->which == Z_SRW_scan_request &&
226 (*srw_pdu)->u.scan_request->database == 0)
227 (*srw_pdu)->u.scan_request->database = db;
237 int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
238 Z_SOAP **soap_package, ODR decode, char **charset,
239 Z_SRW_diagnostic **diag, int *num_diag)
242 static Z_SOAP_Handler soap_handlers[2] = {
243 {"http://www.loc.gov/zing/srw/", 0,
244 (Z_SOAP_fun) yaz_srw_codec},
248 if (!strcmp(hreq->method, "GET"))
250 char *db = "Default";
251 const char *p0 = hreq->path, *p1;
252 const char *operation = 0;
257 char *stylesheet = 0;
258 char *scanClause = 0;
259 char *recordXPath = 0;
260 char *recordSchema = 0;
261 char *recordPacking = "xml"; /* xml packing is default for SRU */
262 char *maximumRecords = 0;
263 char *startRecord = 0;
271 p1 = strchr(p0, '?');
273 p1 = p0 + strlen(p0);
276 db = (char*) odr_malloc(decode, p1 - p0 + 1);
277 memcpy (db, p0, p1 - p0);
280 yaz_uri_array(p1, decode, &uri_name, &uri_val);
285 for (i = 0; uri_name[i]; i++)
287 char *n = uri_name[i];
288 char *v = uri_val[i];
289 if (!strcmp(n, "query"))
291 else if (!strcmp(n, "x-pquery"))
293 else if (!strcmp(n, "operation"))
295 else if (!strcmp(n, "stylesheet"))
297 else if (!strcmp(n, "sortKeys"))
299 else if (!strcmp(n, "recordXPath"))
301 else if (!strcmp(n, "recordSchema"))
303 else if (!strcmp(n, "recordPacking"))
305 else if (!strcmp(n, "version"))
307 else if (!strcmp(n, "scanClause"))
309 else if (!strcmp(n, "maximumRecords"))
311 else if (!strcmp(n, "startRecord"))
314 yaz_add_srw_diagnostic(decode, diag, num_diag, 8, n);
320 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "version");
323 if (strcmp(version, "1.1"))
324 yaz_add_srw_diagnostic(decode, diag, num_diag, 5, "1.1");
328 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "operation");
329 operation = "explain";
331 if (!strcmp(operation, "searchRetrieve"))
333 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
335 sr->srw_version = version;
339 sr->u.request->query_type = Z_SRW_query_type_cql;
340 sr->u.request->query.cql = query;
344 sr->u.request->query_type = Z_SRW_query_type_pqf;
345 sr->u.request->query.pqf = pQuery;
348 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "query");
352 sr->u.request->sort_type = Z_SRW_sort_type_sort;
353 sr->u.request->sort.sortKeys = sortKeys;
355 sr->u.request->recordXPath = recordXPath;
356 sr->u.request->recordSchema = recordSchema;
357 sr->u.request->recordPacking = recordPacking;
358 sr->u.request->stylesheet = stylesheet;
361 sr->u.request->maximumRecords =
362 odr_intdup(decode, atoi(maximumRecords));
364 sr->u.request->startRecord =
365 odr_intdup(decode, atoi(startRecord));
367 sr->u.request->database = db;
369 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
370 (*soap_package)->which = Z_SOAP_generic;
372 (*soap_package)->u.generic =
373 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
375 (*soap_package)->u.generic->p = sr;
376 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
377 (*soap_package)->u.generic->no = 0;
379 (*soap_package)->ns = "SRU";
383 else if (!strcmp(operation, "explain"))
385 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
387 sr->srw_version = version;
389 sr->u.explain_request->recordPacking = recordPacking;
390 sr->u.explain_request->database = db;
392 sr->u.explain_request->stylesheet = stylesheet;
394 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
395 (*soap_package)->which = Z_SOAP_generic;
397 (*soap_package)->u.generic =
398 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
400 (*soap_package)->u.generic->p = sr;
401 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
402 (*soap_package)->u.generic->no = 0;
404 (*soap_package)->ns = "SRU";
408 else if (!strcmp(operation, "scan"))
410 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_scan_request);
413 yaz_add_srw_diagnostic(decode, diag, num_diag, 7,
415 sr->srw_version = version;
417 sr->u.scan_request->scanClause = scanClause;
418 sr->u.scan_request->database = db;
419 sr->u.scan_request->stylesheet = stylesheet;
421 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
422 (*soap_package)->which = Z_SOAP_generic;
424 (*soap_package)->u.generic =
425 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
427 (*soap_package)->u.generic->p = sr;
428 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
429 (*soap_package)->u.generic->no = 0;
431 (*soap_package)->ns = "SRU";
437 /* unsupported operation ... */
438 /* Act as if we received a explain request and throw diagnostic. */
440 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
442 sr->srw_version = version;
444 sr->u.explain_request->recordPacking = recordPacking;
445 sr->u.explain_request->database = db;
447 sr->u.explain_request->stylesheet = stylesheet;
449 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
450 (*soap_package)->which = Z_SOAP_generic;
452 (*soap_package)->u.generic =
453 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
455 (*soap_package)->u.generic->p = sr;
456 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
457 (*soap_package)->u.generic->no = 0;
459 (*soap_package)->ns = "SRU";
461 yaz_add_srw_diagnostic(decode, diag, num_diag, 4, operation);
470 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
472 Z_SRW_PDU *sr = (Z_SRW_PDU *) odr_malloc(o, sizeof(*o));
474 sr->srw_version = odr_strdup(o, "1.1");
478 case Z_SRW_searchRetrieve_request:
479 sr->u.request = (Z_SRW_searchRetrieveRequest *)
480 odr_malloc(o, sizeof(*sr->u.request));
481 sr->u.request->query_type = Z_SRW_query_type_cql;
482 sr->u.request->query.cql = 0;
483 sr->u.request->sort_type = Z_SRW_sort_type_none;
484 sr->u.request->sort.none = 0;
485 sr->u.request->startRecord = 0;
486 sr->u.request->maximumRecords = 0;
487 sr->u.request->recordSchema = 0;
488 sr->u.request->recordPacking = 0;
489 sr->u.request->recordXPath = 0;
490 sr->u.request->database = 0;
491 sr->u.request->resultSetTTL = 0;
492 sr->u.request->stylesheet = 0;
494 case Z_SRW_searchRetrieve_response:
495 sr->u.response = (Z_SRW_searchRetrieveResponse *)
496 odr_malloc(o, sizeof(*sr->u.response));
497 sr->u.response->numberOfRecords = 0;
498 sr->u.response->resultSetId = 0;
499 sr->u.response->resultSetIdleTime = 0;
500 sr->u.response->records = 0;
501 sr->u.response->num_records = 0;
502 sr->u.response->diagnostics = 0;
503 sr->u.response->num_diagnostics = 0;
504 sr->u.response->nextRecordPosition = 0;
506 case Z_SRW_explain_request:
507 sr->u.explain_request = (Z_SRW_explainRequest *)
508 odr_malloc(o, sizeof(*sr->u.explain_request));
509 sr->u.explain_request->recordPacking = 0;
510 sr->u.explain_request->database = 0;
511 sr->u.explain_request->stylesheet = 0;
513 case Z_SRW_explain_response:
514 sr->u.explain_response = (Z_SRW_explainResponse *)
515 odr_malloc(o, sizeof(*sr->u.explain_response));
516 sr->u.explain_response->record.recordData_buf = 0;
517 sr->u.explain_response->record.recordData_len = 0;
518 sr->u.explain_response->record.recordSchema = 0;
519 sr->u.explain_response->record.recordPosition = 0;
520 sr->u.explain_response->record.recordPacking =
521 Z_SRW_recordPacking_string;
522 sr->u.explain_response->diagnostics = 0;
523 sr->u.explain_response->num_diagnostics = 0;
525 case Z_SRW_scan_request:
526 sr->u.scan_request = (Z_SRW_scanRequest *)
527 odr_malloc(o, sizeof(*sr->u.scan_request));
528 sr->u.scan_request->database = 0;
529 sr->u.scan_request->stylesheet = 0;
530 sr->u.scan_request->maximumTerms = 0;
531 sr->u.scan_request->responsePosition = 0;
532 sr->u.scan_request->scanClause = 0;
534 case Z_SRW_scan_response:
535 sr->u.scan_response = (Z_SRW_scanResponse *)
536 odr_malloc(o, sizeof(*sr->u.scan_response));
537 sr->u.scan_response->terms = 0;
538 sr->u.scan_response->num_terms = 0;
539 sr->u.scan_response->diagnostics = 0;
540 sr->u.scan_response->num_diagnostics = 0;
549 } yaz_srw_codes [] = {
550 {1, "Permanent system error"},
551 {2, "System temporarily unavailable"},
552 {3, "Authentication error"},
553 {4, "Unsupported operation"},
554 {5, "Unsupported version"},
555 {6, "Unsupported parameter value"},
556 {7, "Mandatory parameter not supplied"},
557 {8, "Unsupported parameter"},
558 /* Diagnostics Relating to CQL */
559 {10, "Query syntax error"},
560 {11, "Unsupported query type"},
561 {12, "Too many characters in query"},
562 {13, "Invalid or unsupported use of parentheses"},
563 {14, "Invalid or unsupported use of quotes"},
564 {15, "Unsupported context set"},
565 {16, "Unsupported index"},
566 {17, "Unsupported combination of index and context set"},
567 {18, "Unsupported combination of indexes"},
568 {19, "Unsupported relation"},
569 {20, "Unsupported relation modifier"},
570 {21, "Unsupported combination of relation modifers"},
571 {22, "Unsupported combination of relation and index"},
572 {23, "Too many characters in term"},
573 {24, "Unsupported combination of relation and term"},
574 {25, "Special characters not quoted in term"},
575 {26, "Non special character escaped in term"},
576 {27, "Empty term unsupported"},
577 {28, "Masking character not supported"},
578 {29, "Masked words too short"},
579 {30, "Too many masking characters in term"},
580 {31, "Anchoring character not supported"},
581 {32, "Anchoring character in unsupported position"},
582 {33, "Combination of proximity/adjacency and masking characters not supported"},
583 {34, "Combination of proximity/adjacency and anchoring characters not supported"},
584 {35, "Terms only exclusion stopwords"},
585 {36, "Term in invalid format for index or relation"},
586 {37, "Unsupported boolean operator"},
587 {38, "Too many boolean operators in query"},
588 {39, "Proximity not supported"},
589 {40, "Unsupported proximity relation"},
590 {41, "Unsupported proximity distance"},
591 {42, "Unsupported proximity unit"},
592 {43, "Unsupported proximity ordering"},
593 {44, "Unsupported combination of proximity modifiers"},
594 {45, "context set name (prefix) assigned to multiple identifiers"},
595 /* Diagnostics Relating to Result Sets */
596 {50, "Result sets not supported"},
597 {51, "Result set does not exist"},
598 {52, "Result set temporarily unavailable"},
599 {53, "Result sets only supported for retrieval"},
600 {54, "Retrieval may only occur from an existing result set"},
601 {55, "Combination of result sets with search terms not supported"},
602 {56, "Only combination of single result set with search terms supported"},
603 {57, "Result set created but no records available"},
604 {58, "Result set created with unpredictable partial results available"},
605 {59, "Result set created with valid partial results available"},
606 /* Diagnostics Relating to Records */
607 {60, "Result set no created: too many records retrieved"},
608 {61, "First record position out of range"},
609 {62, "Negative number of records requested"},
610 {63, "System error in retrieving records"},
611 {64, "Record temporarily unavailable"},
612 {65, "Record does not exist"},
613 {66, "Unknown schema for retrieval"},
614 {67, "Record not available in this schema"},
615 {68, "Not authorised to send record"},
616 {69, "Not authorised to send record in this schema"},
617 {70, "Record too large to send"},
618 {71, "Unsupported record packing"},
619 {72, "XPath retrieval unsupported"},
620 {73, "XPath expression contains unsupported feature"},
621 {74, "Unable to evaluate XPath expression"},
622 /* Diagnostics Relating to Sorting */
623 {80, "Sort not supported"},
624 {81, "Unsupported sort type"},
625 {82, "Unsupported sort sequence"},
626 {83, "Too many records to sort"},
627 {84, "Too many sort keys to sort"},
628 {85, "Duplicate sort keys"},
629 {86, "Cannot sort: incompatible record formats"},
630 {87, "Unsupported schema for sort"},
631 {88, "Unsupported path for sort"},
632 {89, "Path unsupported for schema"},
633 {90, "Unsupported direction value"},
634 {91, "Unsupported case value"},
635 {92, "Unsupported missing value action"},
636 /* Diagnostics Relating to Explain */
637 {100, "Explain not supported"},
638 {101, "Explain request type not supported (SOAP vs GET)"},
639 {102, "Explain record temporarily unavailable"},
640 /* Diagnostics Relating to Stylesheets */
641 {110, "Stylesheets not supported"},
642 {111, "Unsupported stylesheet"},
643 /* Diagnostics relating to Scan */
644 {120, "Response position out of range"},
648 const char *yaz_diag_srw_str (int code)
651 for (i = 0; yaz_srw_codes[i].code; i++)
652 if (yaz_srw_codes[i].code == code)
653 return yaz_srw_codes[i].msg;
659 static int srw_bib1_map[] = {
669 108, 10, /* Malformed query : Syntax error */
699 100, 1, /* bad map */
747 205, 1, /* bad map */
748 206, 1, /* bad map */
750 208, 1, /* bad map */
761 218, 1, /* bad map */
762 219, 1, /* bad map */
763 220, 1, /* bad map */
764 221, 1, /* bad map */
765 222, 1, /* bad map */
766 223, 1, /* bad map */
767 224, 1, /* bad map */
768 225, 1, /* bad map */
769 226, 1, /* bad map */
771 228, 1, /* bad map */
776 233, 1, /* bad map */
777 234, 1, /* bad map */
783 240, 1, /* bad map */
784 241, 1, /* bad map */
786 243, 1, /* bad map */
791 1001, 1, /* bad map */
792 1002, 1, /* bad map */
793 1003, 1, /* bad map */
794 1004, 1, /* bad map */
795 1005, 1, /* bad map */
796 1006, 1, /* bad map */
828 int yaz_diag_bib1_to_srw (int code)
830 const int *p = srw_bib1_map;
840 int yaz_diag_srw_to_bib1(int code)
842 const int *p = srw_bib1_map;