2 * Copyright (c) 2002-2003, Index Data.
3 * See the file LICENSE for details.
5 * $Id: srwutil.c,v 1.5 2004-01-06 11:20:15 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;
171 p1 = strchr(p0, '?');
173 p1 = p0 + strlen(p0);
176 db = (char*) odr_malloc(decode, p1 - p0 + 1);
177 memcpy (db, p0, p1 - p0);
181 query = yaz_uri_val(p1, "query", decode);
182 pQuery = yaz_uri_val(p1, "pQuery", decode);
183 operation = yaz_uri_val(p1, "operation", decode);
185 operation = "explain";
186 if ((operation && !strcmp(operation, "searchRetrieve"))
189 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
190 char *sortKeys = yaz_uri_val(p1, "sortKeys", decode);
195 sr->u.request->query_type = Z_SRW_query_type_cql;
196 sr->u.request->query.cql = query;
200 sr->u.request->query_type = Z_SRW_query_type_pqf;
201 sr->u.request->query.pqf = pQuery;
205 sr->u.request->sort_type = Z_SRW_sort_type_sort;
206 sr->u.request->sort.sortKeys = sortKeys;
208 sr->u.request->recordSchema = yaz_uri_val(p1, "recordSchema", decode);
209 sr->u.request->recordPacking = yaz_uri_val(p1, "recordPacking", decode);
210 if (!sr->u.request->recordPacking)
211 sr->u.request->recordPacking = "xml";
212 yaz_uri_val_int(p1, "maximumRecords", decode,
213 &sr->u.request->maximumRecords);
214 yaz_uri_val_int(p1, "startRecord", decode,
215 &sr->u.request->startRecord);
217 sr->u.request->database = db;
219 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
220 (*soap_package)->which = Z_SOAP_generic;
222 (*soap_package)->u.generic =
223 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
225 (*soap_package)->u.generic->p = sr;
226 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
227 (*soap_package)->u.generic->no = 0;
229 (*soap_package)->ns = "SRU";
233 else if (p1 && !strcmp(operation, "explain"))
235 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
238 sr->u.explain_request->recordPacking =
239 yaz_uri_val(p1, "recordPacking", decode);
240 if (!sr->u.explain_request->recordPacking)
241 sr->u.explain_request->recordPacking = "xml";
242 sr->u.explain_request->database = db;
244 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
245 (*soap_package)->which = Z_SOAP_generic;
247 (*soap_package)->u.generic =
248 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
250 (*soap_package)->u.generic->p = sr;
251 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
252 (*soap_package)->u.generic->no = 0;
254 (*soap_package)->ns = "SRU";
264 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
266 Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
268 sr->srw_version = odr_strdup(o, "1.1");
272 case Z_SRW_searchRetrieve_request:
273 sr->u.request = (Z_SRW_searchRetrieveRequest *)
274 odr_malloc(o, sizeof(*sr->u.request));
275 sr->u.request->query_type = Z_SRW_query_type_cql;
276 sr->u.request->query.cql = 0;
277 sr->u.request->sort_type = Z_SRW_sort_type_none;
278 sr->u.request->sort.none = 0;
279 sr->u.request->startRecord = 0;
280 sr->u.request->maximumRecords = 0;
281 sr->u.request->recordSchema = 0;
282 sr->u.request->recordPacking = 0;
283 sr->u.request->recordXPath = 0;
284 sr->u.request->database = 0;
285 sr->u.request->resultSetTTL = 0;
286 sr->u.request->stylesheet = 0;
288 case Z_SRW_searchRetrieve_response:
289 sr->u.response = (Z_SRW_searchRetrieveResponse *)
290 odr_malloc(o, sizeof(*sr->u.response));
291 sr->u.response->numberOfRecords = 0;
292 sr->u.response->resultSetId = 0;
293 sr->u.response->resultSetIdleTime = 0;
294 sr->u.response->records = 0;
295 sr->u.response->num_records = 0;
296 sr->u.response->diagnostics = 0;
297 sr->u.response->num_diagnostics = 0;
298 sr->u.response->nextRecordPosition = 0;
300 case Z_SRW_explain_request:
301 sr->u.explain_request = (Z_SRW_explainRequest *)
302 odr_malloc(o, sizeof(*sr->u.explain_request));
303 sr->u.explain_request->recordPacking = 0;
304 sr->u.explain_request->database = 0;
306 case Z_SRW_explain_response:
307 sr->u.explain_response = (Z_SRW_explainResponse *)
308 odr_malloc(o, sizeof(*sr->u.explain_response));
309 sr->u.explain_response->record.recordData_buf = 0;
310 sr->u.explain_response->record.recordData_len = 0;
311 sr->u.explain_response->record.recordSchema = 0;
312 sr->u.explain_response->record.recordPosition = 0;
313 sr->u.explain_response->record.recordPacking =
314 Z_SRW_recordPacking_string;
315 sr->u.explain_response->diagnostics = 0;
316 sr->u.explain_response->num_diagnostics = 0;
325 } yaz_srw_codes [] = {
326 {1, "Permanent system error"},
327 {2, "System temporarily unavailable"},
328 {3, "Authentication error"},
329 /* Diagnostics Relating to CQL */
330 {10, "Query syntax error"},
331 {11, "Unsupported query type"},
332 {12, "Too many characters in query"},
333 {13, "Unbalanced or illegal use of parentheses"},
334 {14, "Unbalanced or illegal use of quotes"},
335 {15, "Illegal or unsupported context set"},
336 {16, "Illegal or unsupported index"},
337 {17, "Illegal or unsupported combination of index and context set"},
338 {18, "Illegal or unsupported combination of indexes"},
339 {19, "Illegal or unsupported relation"},
340 {20, "Illegal or unsupported relation modifier"},
341 {21, "Illegal or unsupported combination of relation modifers"},
342 {22, "Illegal or unsupported combination of relation and index"},
343 {23, "Too many characters in term"},
344 {24, "Illegal combination of relation and term"},
345 {25, "Special characters not quoted in term"},
346 {26, "Non special character escaped in term"},
347 {27, "Empty term unsupported"},
348 {28, "Masking character not supported"},
349 {29, "Masked words too short"},
350 {30, "Too many masking characters in term"},
351 {31, "Anchoring character not supported"},
352 {32, "Anchoring character in illegal or unsupported position"},
353 {33, "Combination of proximity/adjacency and masking characters not supported"},
354 {34, "Combination of proximity/adjacency and anchoring characters not supported"},
355 {35, "Terms only exclusion (stop) words"},
356 {36, "Term in invalid format for index or relation"},
357 {37, "Illegal or unsupported boolean operator"},
358 {38, "Too many boolean operators in query"},
359 {39, "Proximity not supported"},
360 {40, "Illegal or unsupported proximity relation"},
361 {41, "Illegal or unsupported proximity distance"},
362 {42, "Illegal or unsupported proximity unit"},
363 {43, "Illegal or unsupported proximity ordering"},
364 {44, "Illegal or unsupported combination of proximity modifiers"},
365 {45, "context set name (prefix) assigned to multiple identifiers"},
366 /* Diagnostics Relating to Result Sets */
367 {50, "Result sets not supported"},
368 {51, "Result set does not exist"},
369 {52, "Result set temporarily unavailable"},
370 {53, "Result sets only supported for retrieval"},
371 {54, "Retrieval may only occur from an existing result set"},
372 {55, "Combination of result sets with search terms not supported"},
373 {56, "Only combination of single result set with search terms supported"},
374 {57, "Result set created but no records available"},
375 {58, "Result set created with unpredictable partial results available"},
376 {59, "Result set created with valid partial results available"},
377 /* Diagnostics Relating to Records */
378 {60, "Too many records retrieved"},
379 {61, "First record position out of range"},
380 {62, "Negative number of records requested"},
381 {63, "System error in retrieving records"},
382 {64, "Record temporarily unavailable"},
383 {65, "Record does not exist"},
384 {66, "Unknown schema for retrieval"},
385 {67, "Record not available in this schema"},
386 {68, "Not authorised to send record"},
387 {69, "Not authorised to send record in this schema"},
388 {70, "Record too large to send"},
389 /* Diagnostics Relating to Sorting */
390 {80, "Sort not supported"},
391 {81, "Unsupported sort type (sortKeys vs xSortKeys)"},
392 {82, "Illegal or unsupported sort sequence"},
393 {83, "Too many records"},
394 {84, "Too many sort keys"},
395 {85, "Duplicate sort keys"},
396 {86, "Incompatible record formats"},
397 {87, "Unsupported schema for sort"},
398 {88, "Unsupported tag path for sort"},
399 {89, "Tag path illegal or unsupported for schema"},
400 {90, "Illegal or unsupported direction value"},
401 {91, "Illegal or unsupported case value"},
402 {92, "Illegal or unsupported missing value action"},
403 /* Diagnostics Relating to Explain */
404 {100, "Explain not supported"},
405 {101, "Explain request type not supported (SOAP vs GET)"},
406 {102, "Explain record temporarily unavailable"},
410 const char *yaz_diag_srw_str (int code)
413 for (i = 0; yaz_srw_codes[i].code; i++)
414 if (yaz_srw_codes[i].code == code)
415 return yaz_srw_codes[i].msg;
421 static int srw_bib1_map[] = {
431 108, 10, /* Malformed query : Syntax error */
461 100, 1, /* bad map */
509 205, 1, /* bad map */
510 206, 1, /* bad map */
512 208, 1, /* bad map */
523 218, 1, /* bad map */
524 219, 1, /* bad map */
525 220, 1, /* bad map */
526 221, 1, /* bad map */
527 222, 1, /* bad map */
528 223, 1, /* bad map */
529 224, 1, /* bad map */
530 225, 1, /* bad map */
531 226, 1, /* bad map */
533 228, 1, /* bad map */
538 233, 1, /* bad map */
539 234, 1, /* bad map */
545 240, 1, /* bad map */
546 241, 1, /* bad map */
548 243, 1, /* bad map */
553 1001, 1, /* bad map */
554 1002, 1, /* bad map */
555 1003, 1, /* bad map */
556 1004, 1, /* bad map */
557 1005, 1, /* bad map */
558 1006, 1, /* bad map */
590 int yaz_diag_bib1_to_srw (int code)
592 const int *p = srw_bib1_map;
602 int yaz_diag_srw_to_bib1(int code)
604 const int *p = srw_bib1_map;