2 * Copyright (c) 2002-2004, Index Data.
3 * See the file LICENSE for details.
5 * $Id: srwutil.c,v 1.6 2004-01-07 20:36:44 adam Exp $
9 #include <yaz/yaz-iconv.h>
11 static int hex_digit (int ch)
13 if (ch >= '0' && ch <= '9')
15 else if (ch >= 'a' && ch <= 'f')
17 else if (ch >= 'A' && ch <= 'F')
22 char *yaz_uri_val(const char *path, const char *name, ODR o)
24 size_t nlen = strlen(name);
30 const char *p1 = strchr(path, '=');
33 if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
39 p1 = strchr(path, '&');
41 p1 = strlen(path) + path;
42 ret = odr_malloc(o, p1 - path + 1);
43 while (*path && *path != '&')
50 else if (*path == '%' && path[1] && path[2])
52 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
61 path = strchr(p1, '&');
68 void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
70 const char *v = yaz_uri_val(path, name, o);
72 *intp = odr_intdup(o, atoi(v));
75 int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
76 Z_SOAP **soap_package, ODR decode, char **charset)
78 if (!strcmp(hreq->method, "POST"))
80 const char *content_type = z_HTTP_header_lookup(hreq->headers,
82 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
85 const char *p0 = hreq->path, *p1;
87 const char *charset_p = 0;
89 static Z_SOAP_Handler soap_handlers[3] = {
91 {"http://www.loc.gov/zing/srw/", 0,
92 (Z_SOAP_fun) yaz_srw_codec},
93 {"http://www.loc.gov/zing/srw/v1.0/", 0,
94 (Z_SOAP_fun) yaz_srw_codec},
101 p1 = strchr(p0, '?');
103 p1 = p0 + strlen(p0);
106 db = (char*) odr_malloc(decode, p1 - p0 + 1);
107 memcpy (db, p0, p1 - p0);
111 if (charset && (charset_p = strstr(content_type, "; charset=")))
115 while (i < 20 && charset_p[i] &&
116 !strchr("; \n\r", charset_p[i]))
118 *charset = (char*) odr_malloc(decode, i+1);
119 memcpy(*charset, charset_p, i);
120 (*charset)[i] = '\0';
122 ret = z_soap_codec(decode, soap_package,
123 &hreq->content_buf, &hreq->content_len,
125 if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
127 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
129 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
130 (*srw_pdu)->u.request->database == 0)
131 (*srw_pdu)->u.request->database = db;
133 if ((*srw_pdu)->which == Z_SRW_explain_request &&
134 (*srw_pdu)->u.explain_request->database == 0)
135 (*srw_pdu)->u.explain_request->database = db;
137 if ((*srw_pdu)->which == Z_SRW_scan_request &&
138 (*srw_pdu)->u.scan_request->database == 0)
139 (*srw_pdu)->u.scan_request->database = db;
149 int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
150 Z_SOAP **soap_package, ODR decode, char **charset)
153 static Z_SOAP_Handler soap_handlers[2] = {
154 {"http://www.loc.gov/zing/srw/", 0,
155 (Z_SOAP_fun) yaz_srw_codec},
159 if (!strcmp(hreq->method, "GET"))
161 char *db = "Default";
162 const char *p0 = hreq->path, *p1;
163 const char *operation = 0;
166 char *stylesheet = 0;
172 p1 = strchr(p0, '?');
174 p1 = p0 + strlen(p0);
177 db = (char*) odr_malloc(decode, p1 - p0 + 1);
178 memcpy (db, p0, p1 - p0);
182 query = yaz_uri_val(p1, "query", decode);
183 pQuery = yaz_uri_val(p1, "pQuery", decode);
184 operation = yaz_uri_val(p1, "operation", decode);
185 stylesheet = yaz_uri_val(p1, "stylesheet", decode);
187 operation = "explain";
188 if ((operation && !strcmp(operation, "searchRetrieve"))
191 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
192 char *sortKeys = yaz_uri_val(p1, "sortKeys", decode);
197 sr->u.request->query_type = Z_SRW_query_type_cql;
198 sr->u.request->query.cql = query;
202 sr->u.request->query_type = Z_SRW_query_type_pqf;
203 sr->u.request->query.pqf = pQuery;
207 sr->u.request->sort_type = Z_SRW_sort_type_sort;
208 sr->u.request->sort.sortKeys = sortKeys;
210 sr->u.request->recordSchema = yaz_uri_val(p1, "recordSchema", decode);
211 sr->u.request->recordPacking = yaz_uri_val(p1, "recordPacking", decode);
212 sr->u.request->stylesheet = stylesheet;
214 if (!sr->u.request->recordPacking)
215 sr->u.request->recordPacking = "xml";
216 yaz_uri_val_int(p1, "maximumRecords", decode,
217 &sr->u.request->maximumRecords);
218 yaz_uri_val_int(p1, "startRecord", decode,
219 &sr->u.request->startRecord);
221 sr->u.request->database = db;
223 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
224 (*soap_package)->which = Z_SOAP_generic;
226 (*soap_package)->u.generic =
227 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
229 (*soap_package)->u.generic->p = sr;
230 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
231 (*soap_package)->u.generic->no = 0;
233 (*soap_package)->ns = "SRU";
237 else if (p1 && !strcmp(operation, "explain"))
239 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
242 sr->u.explain_request->recordPacking =
243 yaz_uri_val(p1, "recordPacking", decode);
244 if (!sr->u.explain_request->recordPacking)
245 sr->u.explain_request->recordPacking = "xml";
246 sr->u.explain_request->database = db;
248 sr->u.explain_request->stylesheet = stylesheet;
250 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
251 (*soap_package)->which = Z_SOAP_generic;
253 (*soap_package)->u.generic =
254 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
256 (*soap_package)->u.generic->p = sr;
257 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
258 (*soap_package)->u.generic->no = 0;
260 (*soap_package)->ns = "SRU";
270 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
272 Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
274 sr->srw_version = odr_strdup(o, "1.1");
278 case Z_SRW_searchRetrieve_request:
279 sr->u.request = (Z_SRW_searchRetrieveRequest *)
280 odr_malloc(o, sizeof(*sr->u.request));
281 sr->u.request->query_type = Z_SRW_query_type_cql;
282 sr->u.request->query.cql = 0;
283 sr->u.request->sort_type = Z_SRW_sort_type_none;
284 sr->u.request->sort.none = 0;
285 sr->u.request->startRecord = 0;
286 sr->u.request->maximumRecords = 0;
287 sr->u.request->recordSchema = 0;
288 sr->u.request->recordPacking = 0;
289 sr->u.request->recordXPath = 0;
290 sr->u.request->database = 0;
291 sr->u.request->resultSetTTL = 0;
292 sr->u.request->stylesheet = 0;
294 case Z_SRW_searchRetrieve_response:
295 sr->u.response = (Z_SRW_searchRetrieveResponse *)
296 odr_malloc(o, sizeof(*sr->u.response));
297 sr->u.response->numberOfRecords = 0;
298 sr->u.response->resultSetId = 0;
299 sr->u.response->resultSetIdleTime = 0;
300 sr->u.response->records = 0;
301 sr->u.response->num_records = 0;
302 sr->u.response->diagnostics = 0;
303 sr->u.response->num_diagnostics = 0;
304 sr->u.response->nextRecordPosition = 0;
306 case Z_SRW_explain_request:
307 sr->u.explain_request = (Z_SRW_explainRequest *)
308 odr_malloc(o, sizeof(*sr->u.explain_request));
309 sr->u.explain_request->recordPacking = 0;
310 sr->u.explain_request->database = 0;
311 sr->u.explain_request->stylesheet = 0;
313 case Z_SRW_explain_response:
314 sr->u.explain_response = (Z_SRW_explainResponse *)
315 odr_malloc(o, sizeof(*sr->u.explain_response));
316 sr->u.explain_response->record.recordData_buf = 0;
317 sr->u.explain_response->record.recordData_len = 0;
318 sr->u.explain_response->record.recordSchema = 0;
319 sr->u.explain_response->record.recordPosition = 0;
320 sr->u.explain_response->record.recordPacking =
321 Z_SRW_recordPacking_string;
322 sr->u.explain_response->diagnostics = 0;
323 sr->u.explain_response->num_diagnostics = 0;
332 } yaz_srw_codes [] = {
333 {1, "Permanent system error"},
334 {2, "System temporarily unavailable"},
335 {3, "Authentication error"},
336 /* Diagnostics Relating to CQL */
337 {10, "Query syntax error"},
338 {11, "Unsupported query type"},
339 {12, "Too many characters in query"},
340 {13, "Unbalanced or illegal use of parentheses"},
341 {14, "Unbalanced or illegal use of quotes"},
342 {15, "Illegal or unsupported context set"},
343 {16, "Illegal or unsupported index"},
344 {17, "Illegal or unsupported combination of index and context set"},
345 {18, "Illegal or unsupported combination of indexes"},
346 {19, "Illegal or unsupported relation"},
347 {20, "Illegal or unsupported relation modifier"},
348 {21, "Illegal or unsupported combination of relation modifers"},
349 {22, "Illegal or unsupported combination of relation and index"},
350 {23, "Too many characters in term"},
351 {24, "Illegal combination of relation and term"},
352 {25, "Special characters not quoted in term"},
353 {26, "Non special character escaped in term"},
354 {27, "Empty term unsupported"},
355 {28, "Masking character not supported"},
356 {29, "Masked words too short"},
357 {30, "Too many masking characters in term"},
358 {31, "Anchoring character not supported"},
359 {32, "Anchoring character in illegal or unsupported position"},
360 {33, "Combination of proximity/adjacency and masking characters not supported"},
361 {34, "Combination of proximity/adjacency and anchoring characters not supported"},
362 {35, "Terms only exclusion (stop) words"},
363 {36, "Term in invalid format for index or relation"},
364 {37, "Illegal or unsupported boolean operator"},
365 {38, "Too many boolean operators in query"},
366 {39, "Proximity not supported"},
367 {40, "Illegal or unsupported proximity relation"},
368 {41, "Illegal or unsupported proximity distance"},
369 {42, "Illegal or unsupported proximity unit"},
370 {43, "Illegal or unsupported proximity ordering"},
371 {44, "Illegal or unsupported combination of proximity modifiers"},
372 {45, "context set name (prefix) assigned to multiple identifiers"},
373 /* Diagnostics Relating to Result Sets */
374 {50, "Result sets not supported"},
375 {51, "Result set does not exist"},
376 {52, "Result set temporarily unavailable"},
377 {53, "Result sets only supported for retrieval"},
378 {54, "Retrieval may only occur from an existing result set"},
379 {55, "Combination of result sets with search terms not supported"},
380 {56, "Only combination of single result set with search terms supported"},
381 {57, "Result set created but no records available"},
382 {58, "Result set created with unpredictable partial results available"},
383 {59, "Result set created with valid partial results available"},
384 /* Diagnostics Relating to Records */
385 {60, "Too many records retrieved"},
386 {61, "First record position out of range"},
387 {62, "Negative number of records requested"},
388 {63, "System error in retrieving records"},
389 {64, "Record temporarily unavailable"},
390 {65, "Record does not exist"},
391 {66, "Unknown schema for retrieval"},
392 {67, "Record not available in this schema"},
393 {68, "Not authorised to send record"},
394 {69, "Not authorised to send record in this schema"},
395 {70, "Record too large to send"},
396 /* Diagnostics Relating to Sorting */
397 {80, "Sort not supported"},
398 {81, "Unsupported sort type (sortKeys vs xSortKeys)"},
399 {82, "Illegal or unsupported sort sequence"},
400 {83, "Too many records"},
401 {84, "Too many sort keys"},
402 {85, "Duplicate sort keys"},
403 {86, "Incompatible record formats"},
404 {87, "Unsupported schema for sort"},
405 {88, "Unsupported tag path for sort"},
406 {89, "Tag path illegal or unsupported for schema"},
407 {90, "Illegal or unsupported direction value"},
408 {91, "Illegal or unsupported case value"},
409 {92, "Illegal or unsupported missing value action"},
410 /* Diagnostics Relating to Explain */
411 {100, "Explain not supported"},
412 {101, "Explain request type not supported (SOAP vs GET)"},
413 {102, "Explain record temporarily unavailable"},
417 const char *yaz_diag_srw_str (int code)
420 for (i = 0; yaz_srw_codes[i].code; i++)
421 if (yaz_srw_codes[i].code == code)
422 return yaz_srw_codes[i].msg;
428 static int srw_bib1_map[] = {
438 108, 10, /* Malformed query : Syntax error */
468 100, 1, /* bad map */
516 205, 1, /* bad map */
517 206, 1, /* bad map */
519 208, 1, /* bad map */
530 218, 1, /* bad map */
531 219, 1, /* bad map */
532 220, 1, /* bad map */
533 221, 1, /* bad map */
534 222, 1, /* bad map */
535 223, 1, /* bad map */
536 224, 1, /* bad map */
537 225, 1, /* bad map */
538 226, 1, /* bad map */
540 228, 1, /* bad map */
545 233, 1, /* bad map */
546 234, 1, /* bad map */
552 240, 1, /* bad map */
553 241, 1, /* bad map */
555 243, 1, /* bad map */
560 1001, 1, /* bad map */
561 1002, 1, /* bad map */
562 1003, 1, /* bad map */
563 1004, 1, /* bad map */
564 1005, 1, /* bad map */
565 1006, 1, /* bad map */
597 int yaz_diag_bib1_to_srw (int code)
599 const int *p = srw_bib1_map;
609 int yaz_diag_srw_to_bib1(int code)
611 const int *p = srw_bib1_map;