2.0.9 candidate
[yaz-moved-to-github.git] / src / srwutil.c
1 /*
2  * Copyright (c) 2002-2003, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: srwutil.c,v 1.3 2004-01-05 09:34:42 adam Exp $
6  */
7
8 #include <yaz/srw.h>
9 #include <yaz/yaz-iconv.h>
10
11 static int hex_digit (int ch)
12 {
13     if (ch >= '0' && ch <= '9')
14         return ch - '0';
15     else if (ch >= 'a' && ch <= 'f')
16         return ch - 'a'+10;
17     else if (ch >= 'A' && ch <= 'F')
18         return ch - 'A'+10;
19     return 0;
20 }
21
22 char *yaz_uri_val(const char *path, const char *name, ODR o)
23 {
24     size_t nlen = strlen(name);
25     if (*path != '?')
26         return 0;
27     path++;
28     while (path && *path)
29     {
30         const char *p1 = strchr(path, '=');
31         if (!p1)
32             break;
33         if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
34         {
35             size_t i = 0;
36             char *ret;
37             
38             path = p1 + 1;
39             p1 = strchr(path, '&');
40             if (!p1)
41                 p1 = strlen(path) + path;
42             ret = odr_malloc(o, p1 - path + 1);
43             while (*path && *path != '&')
44             {
45                 if (*path == '+')
46                 {
47                     ret[i++] = ' ';
48                     path++;
49                 }
50                 else if (*path == '%' && path[1] && path[2])
51                 {
52                     ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
53                     path = path + 3;
54                 }
55                 else
56                     ret[i++] = *path++;
57             }
58             ret[i] = '\0';
59             return ret;
60         }
61         path = strchr(p1, '&');
62         if (path)
63             path++;
64     }
65     return 0;
66 }
67
68 void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
69 {
70     const char *v = yaz_uri_val(path, name, o);
71     if (v)
72         *intp = odr_intdup(o, atoi(v));
73 }
74
75 int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
76                    Z_SOAP **soap_package, ODR decode, char **charset)
77 {
78     if (!strcmp(hreq->method, "POST"))
79     {
80         const char *content_type = z_HTTP_header_lookup(hreq->headers,
81                                                         "Content-Type");
82         if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
83         {
84             char *db = "Default";
85             const char *p0 = hreq->path, *p1;
86             int ret = -1;
87             const char *charset_p = 0;
88             
89             static Z_SOAP_Handler soap_handlers[3] = {
90 #if HAVE_XML2
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},
95 #endif
96                 {0, 0, 0}
97             };
98             
99             if (*p0 == '/')
100                 p0++;
101             p1 = strchr(p0, '?');
102             if (!p1)
103                 p1 = p0 + strlen(p0);
104             if (p1 != p0)
105             {
106                 db = (char*) odr_malloc(decode, p1 - p0 + 1);
107                 memcpy (db, p0, p1 - p0);
108                 db[p1 - p0] = '\0';
109             }
110
111             if (charset && (charset_p = strstr(content_type, "; charset=")))
112             {
113                 int i = 0;
114                 charset_p += 10;
115                 while (i < 20 && charset_p[i] &&
116                        !strchr("; \n\r", charset_p[i]))
117                     i++;
118                 *charset = (char*) odr_malloc(decode, i+1);
119                 memcpy(*charset, charset_p, i);
120                 (*charset)[i] = '\0';
121             }
122             ret = z_soap_codec(decode, soap_package, 
123                                &hreq->content_buf, &hreq->content_len,
124                                soap_handlers);
125             if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
126             {
127                 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
128                 
129                 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
130                     (*srw_pdu)->u.request->database == 0)
131                     (*srw_pdu)->u.request->database = db;
132
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;
136
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;
140
141                 return 0;
142             }
143             return 1;
144         }
145     }
146     return 2;
147 }
148
149 int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
150                    Z_SOAP **soap_package, ODR decode, char **charset)
151 {
152 #if HAVE_XML2
153     static Z_SOAP_Handler soap_handlers[2] = {
154         {"http://www.loc.gov/zing/srw/", 0,
155          (Z_SOAP_fun) yaz_srw_codec},
156         {0, 0, 0}
157     };
158 #endif
159     if (!strcmp(hreq->method, "GET"))
160     {
161         char *db = "Default";
162         const char *p0 = hreq->path, *p1;
163         const char *operation = 0;
164         char *query = 0;
165         char *pQuery = 0;
166         
167         if (charset)
168             *charset = 0;
169         if (*p0 == '/')
170             p0++;
171         p1 = strchr(p0, '?');
172         if (!p1)
173             p1 = p0 + strlen(p0);
174         if (p1 != p0)
175         {
176             db = (char*) odr_malloc(decode, p1 - p0 + 1);
177             memcpy (db, p0, p1 - p0);
178             db[p1 - p0] = '\0';
179         }
180 #if HAVE_XML2
181         query = yaz_uri_val(p1, "query", decode);
182         pQuery = yaz_uri_val(p1, "pQuery", decode);
183         operation = yaz_uri_val(p1, "operation", decode);
184         if (!operation)
185             operation = "explain";
186         if ((operation && !strcmp(operation, "searchRetrieve"))
187             || pQuery || query)
188         {
189             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
190             char *sortKeys = yaz_uri_val(p1, "sortKeys", decode);
191             
192             *srw_pdu = sr;
193             if (query)
194             {
195                 sr->u.request->query_type = Z_SRW_query_type_cql;
196                 sr->u.request->query.cql = query;
197             }
198             if (pQuery)
199             {
200                 sr->u.request->query_type = Z_SRW_query_type_pqf;
201                 sr->u.request->query.pqf = pQuery;
202             }
203             if (sortKeys)
204             {
205                 sr->u.request->sort_type = Z_SRW_sort_type_sort;
206                 sr->u.request->sort.sortKeys = sortKeys;
207             }
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);
216
217             sr->u.request->database = db;
218
219             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
220             (*soap_package)->which = Z_SOAP_generic;
221             
222             (*soap_package)->u.generic =
223                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
224             
225             (*soap_package)->u.generic->p = sr;
226             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
227             (*soap_package)->u.generic->no = 0;
228             
229             (*soap_package)->ns = "SRU";
230
231             return 0;
232         }
233         else if (p1 && !strcmp(operation, "explain"))
234         {
235             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
236
237             *srw_pdu = sr;
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;
243
244             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
245             (*soap_package)->which = Z_SOAP_generic;
246             
247             (*soap_package)->u.generic =
248                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
249             
250             (*soap_package)->u.generic->p = sr;
251             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
252             (*soap_package)->u.generic->no = 0;
253             
254             (*soap_package)->ns = "SRU";
255
256             return 0;
257         }
258 #endif
259         return 1;
260     }
261     return 2;
262 }
263
264 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
265 {
266     Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
267
268     sr->srw_version = odr_strdup(o, "1.1");
269     sr->which = which;
270     switch(which)
271     {
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;
287         break;
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;
299         break;
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;
305         break;
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;
317     }
318     return sr;
319 }
320
321
322 static struct {
323     int code;
324     const char *msg;
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, "Illegal query"}, 
331 {11, "Unsupported query type (XCQL vs CQL)"}, 
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"},
407 {0, 0}
408 };
409
410 const char *yaz_diag_srw_str (int code)
411 {
412     int i;
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;
416     return 0;
417 }
418
419
420 /* bib1:srw */
421 static int srw_bib1_map[] = {
422     1, 1,
423     2, 2,
424     3, 11,
425     4, 35,
426     5, 12,
427     6, 38,
428     7, 30,
429     8, 32,
430     9, 29,
431     10, 10,
432     11, 12,
433     11, 23,
434     12, 60,
435     13, 61,
436     13, 62,
437     14, 63,
438     14, 64,
439     14, 65,
440     15, 68,
441     15, 69,
442     16, 70,
443     17, 70,
444     18, 50,
445     19, 55,
446     20, 56, 
447     21, 52,
448     22, 50,
449     23, 1,  /* bad map */
450     24, 63, /* bad map */
451     25, 63, /* bad map */
452     26, 63, /* bad map */
453     27, 51,
454     28, 52,
455     29, 52,
456     30, 51,
457     31, 57,
458     32, 58,
459     33, 59,
460     100, 1, /* bad map */
461     101, 3,
462     102, 3,
463     103, 3,
464     104, 3,
465     105, 3, 
466     106, 66,
467     107, 11,
468     108, 10,
469     108, 13,
470     108, 14,
471     108, 25,
472     108, 26,
473     108, 27,
474     108, 45,
475         
476     109, 1,
477     110, 37,
478     111, 1,
479     112, 58,
480     113, 10,
481     114, 16,
482     115, 16,
483     116, 16,
484     117, 19,
485     118, 22,
486     119, 32,
487     119, 31,
488     120, 28,
489     121, 15,
490     122, 32,
491     123, 22,
492     123, 17,
493     123, 18,
494     124, 24,
495     125, 36,
496     126, 36, 
497     127, 36,
498     128, 51,
499     129, 39,
500     130, 43,
501     131, 40,
502     132, 42,
503     201, 44,
504     201, 33,
505     201, 34,
506     202, 41,
507     203, 43,
508     205, 1,  /* bad map */
509     206, 1,  /* bad map */
510     207, 89,
511     208, 1,  /* bad map */
512     209, 80,
513     210, 80,
514     210, 81,
515     211, 84,
516     212, 85,
517     213, 92,
518     214, 90,
519     215, 91,
520     216, 92,
521     217, 63,
522     218, 1,  /* bad map */
523     219, 1,  /* bad map */
524     220, 1,  /* bad map */
525     221, 1,  /* bad map */
526     222, 1,  /* bad map */
527     223, 1,  /* bad map */
528     224, 1,  /* bad map */
529     225, 1,  /* bad map */
530     226, 1,  /* bad map */
531     227, 66,
532     228, 1,  /* bad map */
533     229, 36,
534     230, 83,
535     231, 89,
536     232, 1,
537     233, 1, /* bad map */
538     234, 1, /* bad map */
539     235, 2,
540     236, 3, 
541     237, 82,
542     238, 67,
543     239, 66,
544     240, 1, /* bad map */
545     241, 1, /* bad map */
546     242, 70,
547     243, 1, /* bad map */
548     244, 66,
549     245, 10,
550     246, 10,
551     247, 10,
552     1001, 1, /* bad map */
553     1002, 1, /* bad map */
554     1003, 1, /* bad map */
555     1004, 1, /* bad map */
556     1005, 1, /* bad map */
557     1006, 1, /* bad map */
558     1007, 100,
559     1008, 1, 
560     1009, 1,
561     1010, 3,
562     1011, 3,
563     1012, 3,
564     1013, 3,
565     1014, 3,
566     1015, 3,
567     1015, 3,
568     1016, 3,
569     1017, 3,
570     1018, 2,
571     1019, 2,
572     1020, 2,
573     1021, 3,
574     1022, 3,
575     1023, 3,
576     1024, 16,
577     1025, 3,
578     1026, 64,
579     1027, 1,
580     1028, 65,
581     1029, 1,
582     1040, 1,
583     /* 1041-1065 */
584     1066, 66,
585     1066, 67,
586     0
587 };
588
589 int yaz_diag_bib1_to_srw (int code)
590 {
591     const int *p = srw_bib1_map;
592     while (*p)
593     {
594         if (code == p[0])
595             return p[1];
596         p += 2;
597     }
598     return 1;
599 }
600
601 int yaz_diag_srw_to_bib1(int code)
602 {
603     const int *p = srw_bib1_map;
604     while (*p)
605     {
606         if (code == p[1])
607             return p[0];
608         p += 2;
609     }
610     return 1;
611 }
612