Update SRW/SRU diagnostic message definitions and store them in separate
[yaz-moved-to-github.git] / src / srwutil.c
1 /*
2  * Copyright (c) 2002-2004, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: srwutil.c,v 1.19 2004-11-21 21:56:28 adam Exp $
6  */
7 /**
8  * \file srwutil.c
9  * \brief Implements SRW/SRU utilities.
10  */
11
12 #include <yaz/srw.h>
13 #include <yaz/yaz-iconv.h>
14
15 static int hex_digit (int ch)
16 {
17     if (ch >= '0' && ch <= '9')
18         return ch - '0';
19     else if (ch >= 'a' && ch <= 'f')
20         return ch - 'a'+10;
21     else if (ch >= 'A' && ch <= 'F')
22         return ch - 'A'+10;
23     return 0;
24 }
25
26 int yaz_uri_array(const char *path, ODR o, char ***name, char ***val)
27 {
28     int no = 2;
29     const char *cp;
30     *name = 0;
31     if (*path != '?')
32         return no;
33     path++;
34     cp = path;
35     while ((cp = strchr(cp, '&')))
36     {
37         cp++;
38         no++;
39     }
40     *name = odr_malloc(o, no * sizeof(char**));
41     *val = odr_malloc(o, no * sizeof(char**));
42
43     for (no = 0; *path; no++)
44     {
45         const char *p1 = strchr(path, '=');
46         size_t i = 0;
47         char *ret;
48         if (!p1)
49             break;
50
51         (*name)[no] = odr_malloc(o, (p1-path)+1);
52         memcpy((*name)[no], path, p1-path);
53         (*name)[no][p1-path] = '\0';
54
55         path = p1 + 1;
56         p1 = strchr(path, '&');
57         if (!p1)
58             p1 = strlen(path) + path;
59         (*val)[no] = ret = odr_malloc(o, p1 - path + 1);
60         while (*path && *path != '&')
61         {
62             if (*path == '+')
63             {
64                 ret[i++] = ' ';
65                 path++;
66             }
67             else if (*path == '%' && path[1] && path[2])
68             {
69                 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
70                 path = path + 3;
71             }
72             else
73                 ret[i++] = *path++;
74         }
75         ret[i] = '\0';
76
77         if (*path)
78             path++;
79     }
80     (*name)[no] = 0;
81     (*val)[no] = 0;
82     return no;
83 }
84
85 char *yaz_uri_val(const char *path, const char *name, ODR o)
86 {
87     size_t nlen = strlen(name);
88     if (*path != '?')
89         return 0;
90     path++;
91     while (path && *path)
92     {
93         const char *p1 = strchr(path, '=');
94         if (!p1)
95             break;
96         if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
97         {
98             size_t i = 0;
99             char *ret;
100             
101             path = p1 + 1;
102             p1 = strchr(path, '&');
103             if (!p1)
104                 p1 = strlen(path) + path;
105             ret = (char *) odr_malloc(o, p1 - path + 1);
106             while (*path && *path != '&')
107             {
108                 if (*path == '+')
109                 {
110                     ret[i++] = ' ';
111                     path++;
112                 }
113                 else if (*path == '%' && path[1] && path[2])
114                 {
115                     ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
116                     path = path + 3;
117                 }
118                 else
119                     ret[i++] = *path++;
120             }
121             ret[i] = '\0';
122             return ret;
123         }
124         path = strchr(p1, '&');
125         if (path)
126             path++;
127     }
128     return 0;
129 }
130
131 void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
132 {
133     const char *v = yaz_uri_val(path, name, o);
134     if (v)
135         *intp = odr_intdup(o, atoi(v));
136 }
137
138 void yaz_mk_std_diagnostic(ODR o, Z_SRW_diagnostic *d, 
139                            int code, const char *details)
140 {
141     d->uri = (char *) odr_malloc(o, 50);
142     sprintf(d->uri, "info:srw/diagnostic/1/%d", code);
143     d->message = 0;
144     if (details)
145         d->details = odr_strdup(o, details);
146     else
147         d->details = 0;
148 }
149
150 void yaz_add_srw_diagnostic(ODR o, Z_SRW_diagnostic **d,
151                             int *num, int code, const char *addinfo)
152 {
153     Z_SRW_diagnostic *d_new;
154     d_new = (Z_SRW_diagnostic *) odr_malloc (o, (*num + 1)* sizeof(**d));
155     if (*num)
156         memcpy (d_new, *d, *num *sizeof(**d));
157     *d = d_new;
158
159     yaz_mk_std_diagnostic(o, *d + *num, code, addinfo);
160     (*num)++;
161 }
162
163 int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
164                    Z_SOAP **soap_package, ODR decode, char **charset)
165 {
166     if (!strcmp(hreq->method, "POST"))
167     {
168         const char *content_type = z_HTTP_header_lookup(hreq->headers,
169                                                         "Content-Type");
170         if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
171         {
172             char *db = "Default";
173             const char *p0 = hreq->path, *p1;
174             int ret = -1;
175             const char *charset_p = 0;
176             
177             static Z_SOAP_Handler soap_handlers[3] = {
178 #if HAVE_XML2
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},
183 #endif
184                 {0, 0, 0}
185             };
186             
187             if (*p0 == '/')
188                 p0++;
189             p1 = strchr(p0, '?');
190             if (!p1)
191                 p1 = p0 + strlen(p0);
192             if (p1 != p0)
193             {
194                 db = (char*) odr_malloc(decode, p1 - p0 + 1);
195                 memcpy (db, p0, p1 - p0);
196                 db[p1 - p0] = '\0';
197             }
198
199             if (charset && (charset_p = strstr(content_type, "; charset=")))
200             {
201                 int i = 0;
202                 charset_p += 10;
203                 while (i < 20 && charset_p[i] &&
204                        !strchr("; \n\r", charset_p[i]))
205                     i++;
206                 *charset = (char*) odr_malloc(decode, i+1);
207                 memcpy(*charset, charset_p, i);
208                 (*charset)[i] = '\0';
209             }
210             ret = z_soap_codec(decode, soap_package, 
211                                &hreq->content_buf, &hreq->content_len,
212                                soap_handlers);
213             if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
214             {
215                 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
216                 
217                 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
218                     (*srw_pdu)->u.request->database == 0)
219                     (*srw_pdu)->u.request->database = db;
220
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;
224
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;
228
229                 return 0;
230             }
231             return 1;
232         }
233     }
234     return 2;
235 }
236
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)
240 {
241 #if HAVE_XML2
242     static Z_SOAP_Handler soap_handlers[2] = {
243         {"http://www.loc.gov/zing/srw/", 0,
244          (Z_SOAP_fun) yaz_srw_codec},
245         {0, 0, 0}
246     };
247 #endif
248     if (!strcmp(hreq->method, "GET"))
249     {
250         char *db = "Default";
251         const char *p0 = hreq->path, *p1;
252         const char *operation = 0;
253         char *version = 0;
254         char *query = 0;
255         char *pQuery = 0;
256         char *sortKeys = 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;
264         char **uri_name;
265         char **uri_val;
266
267         if (charset)
268             *charset = 0;
269         if (*p0 == '/')
270             p0++;
271         p1 = strchr(p0, '?');
272         if (!p1)
273             p1 = p0 + strlen(p0);
274         if (p1 != p0)
275         {
276             db = (char*) odr_malloc(decode, p1 - p0 + 1);
277             memcpy (db, p0, p1 - p0);
278             db[p1 - p0] = '\0';
279         }
280         yaz_uri_array(p1, decode, &uri_name, &uri_val);
281 #if HAVE_XML2
282         if (uri_name)
283         {
284             int i;
285             for (i = 0; uri_name[i]; i++)
286             {
287                 char *n = uri_name[i];
288                 char *v = uri_val[i];
289                 if (!strcmp(n, "query"))
290                     query = v;
291                 else if (!strcmp(n, "x-pquery"))
292                     pQuery = v;
293                 else if (!strcmp(n, "operation"))
294                     operation = v;
295                 else if (!strcmp(n, "stylesheet"))
296                     stylesheet = v;
297                 else if (!strcmp(n, "sortKeys"))
298                     sortKeys = v;
299                 else if (!strcmp(n, "recordXPath"))
300                     recordXPath = v;
301                 else if (!strcmp(n, "recordSchema"))
302                     recordSchema = v;
303                 else if (!strcmp(n, "recordPacking"))
304                     recordPacking = v;
305                 else if (!strcmp(n, "version"))
306                     version = v;
307                 else if (!strcmp(n, "scanClause"))
308                     scanClause = v;
309                 else if (!strcmp(n, "maximumRecords"))
310                     maximumRecords = v;
311                 else if (!strcmp(n, "startRecord"))
312                     startRecord = v;
313                 else
314                     yaz_add_srw_diagnostic(decode, diag, num_diag, 8, n);
315             }
316         }
317         if (!version)
318         {
319             if (uri_name)
320                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "version");
321             version = "1.1";
322         }
323         if (strcmp(version, "1.1"))
324             yaz_add_srw_diagnostic(decode, diag, num_diag, 5, "1.1");
325         if (!operation)
326         {
327             if (uri_name)
328                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "operation");
329             operation = "explain";
330         }
331         if (!strcmp(operation, "searchRetrieve"))
332         {
333             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
334
335             sr->srw_version = version;
336             *srw_pdu = sr;
337             if (query)
338             {
339                 sr->u.request->query_type = Z_SRW_query_type_cql;
340                 sr->u.request->query.cql = query;
341             }
342             else if (pQuery)
343             {
344                 sr->u.request->query_type = Z_SRW_query_type_pqf;
345                 sr->u.request->query.pqf = pQuery;
346             }
347             else
348                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "query");
349
350             if (sortKeys)
351             {
352                 sr->u.request->sort_type = Z_SRW_sort_type_sort;
353                 sr->u.request->sort.sortKeys = sortKeys;
354             }
355             sr->u.request->recordXPath = recordXPath;
356             sr->u.request->recordSchema = recordSchema;
357             sr->u.request->recordPacking = recordPacking;
358             sr->u.request->stylesheet = stylesheet;
359
360             if (maximumRecords)
361                 sr->u.request->maximumRecords =
362                     odr_intdup(decode, atoi(maximumRecords));
363             if (startRecord)
364                 sr->u.request->startRecord =
365                     odr_intdup(decode, atoi(startRecord));
366
367             sr->u.request->database = db;
368
369             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
370             (*soap_package)->which = Z_SOAP_generic;
371             
372             (*soap_package)->u.generic =
373                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
374             
375             (*soap_package)->u.generic->p = sr;
376             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
377             (*soap_package)->u.generic->no = 0;
378             
379             (*soap_package)->ns = "SRU";
380
381             return 0;
382         }
383         else if (!strcmp(operation, "explain"))
384         {
385             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
386
387             sr->srw_version = version;
388             *srw_pdu = sr;
389             sr->u.explain_request->recordPacking = recordPacking;
390             sr->u.explain_request->database = db;
391
392             sr->u.explain_request->stylesheet = stylesheet;
393
394             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
395             (*soap_package)->which = Z_SOAP_generic;
396             
397             (*soap_package)->u.generic =
398                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
399             
400             (*soap_package)->u.generic->p = sr;
401             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
402             (*soap_package)->u.generic->no = 0;
403             
404             (*soap_package)->ns = "SRU";
405
406             return 0;
407         }
408         else if (!strcmp(operation, "scan"))
409         {
410             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_scan_request);
411
412             if (!scanClause)
413                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7,
414                                        "scanClause");
415             sr->srw_version = version;
416             *srw_pdu = sr;
417             sr->u.scan_request->scanClause = scanClause;
418             sr->u.scan_request->database = db;
419             sr->u.scan_request->stylesheet = stylesheet;
420
421             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
422             (*soap_package)->which = Z_SOAP_generic;
423             
424             (*soap_package)->u.generic =
425                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
426             
427             (*soap_package)->u.generic->p = sr;
428             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
429             (*soap_package)->u.generic->no = 0;
430             
431             (*soap_package)->ns = "SRU";
432
433             return 0;
434         }
435         else
436         {
437             /* unsupported operation ... */
438             /* Act as if we received a explain request and throw diagnostic. */
439
440             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
441
442             sr->srw_version = version;
443             *srw_pdu = sr;
444             sr->u.explain_request->recordPacking = recordPacking;
445             sr->u.explain_request->database = db;
446
447             sr->u.explain_request->stylesheet = stylesheet;
448
449             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
450             (*soap_package)->which = Z_SOAP_generic;
451             
452             (*soap_package)->u.generic =
453                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
454             
455             (*soap_package)->u.generic->p = sr;
456             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
457             (*soap_package)->u.generic->no = 0;
458             
459             (*soap_package)->ns = "SRU";
460
461             yaz_add_srw_diagnostic(decode, diag, num_diag, 4, operation);
462             return 0;
463         }
464 #endif
465         return 1;
466     }
467     return 2;
468 }
469
470 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
471 {
472     Z_SRW_PDU *sr = (Z_SRW_PDU *) odr_malloc(o, sizeof(*o));
473
474     sr->srw_version = odr_strdup(o, "1.1");
475     sr->which = which;
476     switch(which)
477     {
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;
493         break;
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;
505         break;
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;
512         break;
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;
524         break;
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;
533         break;
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;
541     }
542     return sr;
543 }
544
545
546
547 /* bib1:srw */
548 static int srw_bib1_map[] = {
549     1, 1,
550     2, 2,
551     3, 11,
552     4, 35,
553     5, 12,
554     6, 38,
555     7, 30,
556     8, 32,
557     9, 29,
558     108, 10,  /* Malformed query : Syntax error */
559     10, 10,
560     11, 12,
561     11, 23,
562     12, 60,
563     13, 61,
564     13, 62,
565     14, 63,
566     14, 64,
567     14, 65,
568     15, 68,
569     15, 69,
570     16, 70,
571     17, 70,
572     18, 50,
573     19, 55,
574     20, 56, 
575     21, 52,
576     22, 50,
577     23, 3,
578     24, 66,
579     25, 66,
580     26, 66,
581     27, 51,
582     28, 52,
583     29, 52,
584     30, 51,
585     31, 57,
586     32, 58,
587     33, 59,
588     100, 1, /* bad map */
589     101, 3,
590     102, 3,
591     103, 3,
592     104, 3,
593     105, 3, 
594     106, 66,
595     107, 11,
596     108, 13,
597     108, 14,
598     108, 25,
599     108, 26,
600     108, 27,
601     108, 45,
602         
603     109, 2,
604     110, 37,
605     111, 1,
606     112, 58,
607     113, 10,
608     114, 16,
609     115, 16,
610     116, 16,
611     117, 19,
612     117, 20,
613     118, 22,
614     119, 32,
615     119, 31,
616     120, 28,
617     121, 15,
618     122, 32,
619     123, 22,
620     123, 17,
621     123, 18,
622     124, 24,
623     125, 36,
624     126, 36, 
625     127, 36,
626     128, 51,
627     129, 39,
628     130, 43,
629     131, 40,
630     132, 42,
631     201, 44,
632     201, 33,
633     201, 34,
634     202, 41,
635     203, 43,
636     205, 1,  /* bad map */
637     206, 1,  /* bad map */
638     207, 89,
639     208, 1,  /* bad map */
640     209, 80,
641     210, 80,
642     210, 81,
643     211, 84,
644     212, 85,
645     213, 92,
646     214, 90,
647     215, 91,
648     216, 92,
649     217, 63,
650     218, 1,  /* bad map */
651     219, 1,  /* bad map */
652     220, 1,  /* bad map */
653     221, 1,  /* bad map */
654     222, 1,  /* bad map */
655     223, 1,  /* bad map */
656     224, 1,  /* bad map */
657     225, 1,  /* bad map */
658     226, 1,  /* bad map */
659     227, 66,
660     228, 1,  /* bad map */
661     229, 36,
662     230, 83,
663     231, 89,
664     232, 1,
665     233, 1, /* bad map */
666     234, 1, /* bad map */
667     235, 2,
668     236, 3, 
669     237, 82,
670     238, 67,
671     239, 66,
672     240, 1, /* bad map */
673     241, 1, /* bad map */
674     242, 70,
675     243, 1, /* bad map */
676     244, 66,
677     245, 10,
678     246, 10,
679     247, 10,
680     1001, 1, /* bad map */
681     1002, 1, /* bad map */
682     1003, 1, /* bad map */
683     1004, 1, /* bad map */
684     1005, 1, /* bad map */
685     1006, 1, /* bad map */
686     1007, 100,
687     1008, 1, 
688     1009, 1,
689     1010, 3,
690     1011, 3,
691     1012, 3,
692     1013, 3,
693     1014, 3,
694     1015, 3,
695     1015, 3,
696     1016, 3,
697     1017, 3,
698     1018, 2,
699     1019, 2,
700     1020, 2,
701     1021, 3,
702     1022, 3,
703     1023, 3,
704     1024, 16,
705     1025, 3,
706     1026, 64,
707     1027, 1,
708     1028, 65,
709     1029, 1,
710     1040, 1,
711     /* 1041-1065 */
712     1066, 66,
713     1066, 67,
714     0
715 };
716
717 int yaz_diag_bib1_to_srw (int code)
718 {
719     const int *p = srw_bib1_map;
720     while (*p)
721     {
722         if (code == p[0])
723             return p[1];
724         p += 2;
725     }
726     return 1;
727 }
728
729 int yaz_diag_srw_to_bib1(int code)
730 {
731     const int *p = srw_bib1_map;
732     while (*p)
733     {
734         if (code == p[1])
735             return p[0];
736         p += 2;
737     }
738     return 1;
739 }
740