5e5eab6d8774fe749c356d5f6f99e325763339e1
[yaz-moved-to-github.git] / src / srwutil.c
1 /*
2  * Copyright (C) 1995-2006, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: srwutil.c,v 1.52 2006-10-24 09:18:34 adam Exp $
6  */
7 /**
8  * \file srwutil.c
9  * \brief Implements SRW/SRU utilities.
10  */
11
12 #include <stdlib.h>
13 #include <yaz/srw.h>
14 #include <yaz/yaz-iconv.h>
15
16 static int hex_digit (int ch)
17 {
18     if (ch >= '0' && ch <= '9')
19         return ch - '0';
20     else if (ch >= 'a' && ch <= 'f')
21         return ch - 'a'+10;
22     else if (ch >= 'A' && ch <= 'F')
23         return ch - 'A'+10;
24     return 0;
25 }
26
27 void encode_uri_char(char *dst, char ch)
28 {
29     if (ch == ' ')
30         strcpy(dst, "+");
31     else if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
32         (ch >= '0' && ch <= '9'))
33     {
34         dst[0] = ch;
35         dst[1] = '\0';
36     }
37     else
38     {
39         dst[0] = '%';
40         sprintf(dst+1, "%02X", (unsigned char ) ch);
41     }
42 }
43
44 static void yaz_array_to_uri_ex(char **path, ODR o, char **name, char **value,
45                                 const char *extra_args)
46 {
47     size_t i, szp = 0, sz = extra_args ? 1+strlen(extra_args) : 1;
48     for(i = 0; name[i]; i++)
49         sz += strlen(name[i]) + 3 + strlen(value[i]) * 3;
50     *path = odr_malloc(o, sz);
51     
52     for(i = 0; name[i]; i++)
53     {
54         size_t j, ilen;
55         if (i)
56             (*path)[szp++] = '&';
57         ilen = strlen(name[i]);
58         memcpy(*path+szp, name[i], ilen);
59         szp += ilen;
60         (*path)[szp++] = '=';
61         for (j = 0; value[i][j]; j++)
62         {
63             size_t vlen;
64             char vstr[5];
65             encode_uri_char(vstr, value[i][j]);
66             vlen = strlen(vstr);
67             memcpy(*path+szp, vstr, vlen);
68             szp += vlen;
69         }
70     }
71     if (extra_args)
72     {
73         if (i)
74             (*path)[szp++] = '&';
75         memcpy(*path + szp, extra_args, strlen(extra_args));
76         szp += strlen(extra_args);
77     }
78     (*path)[szp] = '\0';
79 }
80
81 void yaz_array_to_uri(char **path, ODR o, char **name, char **value)
82 {
83     yaz_array_to_uri_ex(path, o, name, value, 0);
84 }
85
86 int yaz_uri_array(const char *path, ODR o, char ***name, char ***val)
87 {
88     int no = 2;
89     const char *cp;
90     *name = 0;
91     if (*path == '?')
92         path++;
93     if (!*path)
94         return 0;
95     cp = path;
96     while ((cp = strchr(cp, '&')))
97     {
98         cp++;
99         no++;
100     }
101     *name = odr_malloc(o, no * sizeof(char*));
102     *val = odr_malloc(o, no * sizeof(char*));
103
104     for (no = 0; *path; no++)
105     {
106         const char *p1 = strchr(path, '=');
107         size_t i = 0;
108         char *ret;
109         if (!p1)
110             break;
111
112         (*name)[no] = odr_malloc(o, (p1-path)+1);
113         memcpy((*name)[no], path, p1-path);
114         (*name)[no][p1-path] = '\0';
115
116         path = p1 + 1;
117         p1 = strchr(path, '&');
118         if (!p1)
119             p1 = strlen(path) + path;
120         (*val)[no] = ret = odr_malloc(o, p1 - path + 1);
121         while (*path && *path != '&')
122         {
123             if (*path == '+')
124             {
125                 ret[i++] = ' ';
126                 path++;
127             }
128             else if (*path == '%' && path[1] && path[2])
129             {
130                 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
131                 path = path + 3;
132             }
133             else
134                 ret[i++] = *path++;
135         }
136         ret[i] = '\0';
137
138         if (*path)
139             path++;
140     }
141     (*name)[no] = 0;
142     (*val)[no] = 0;
143     return no;
144 }
145
146 char *yaz_uri_val(const char *path, const char *name, ODR o)
147 {
148     size_t nlen = strlen(name);
149     if (*path != '?')
150         return 0;
151     path++;
152     while (path && *path)
153     {
154         const char *p1 = strchr(path, '=');
155         if (!p1)
156             break;
157         if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
158         {
159             size_t i = 0;
160             char *ret;
161             
162             path = p1 + 1;
163             p1 = strchr(path, '&');
164             if (!p1)
165                 p1 = strlen(path) + path;
166             ret = (char *) odr_malloc(o, p1 - path + 1);
167             while (*path && *path != '&')
168             {
169                 if (*path == '+')
170                 {
171                     ret[i++] = ' ';
172                     path++;
173                 }
174                 else if (*path == '%' && path[1] && path[2])
175                 {
176                     ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
177                     path = path + 3;
178                 }
179                 else
180                     ret[i++] = *path++;
181             }
182             ret[i] = '\0';
183             return ret;
184         }
185         path = strchr(p1, '&');
186         if (path)
187             path++;
188     }
189     return 0;
190 }
191
192 static int yaz_base64decode(const char *in, char *out)
193 {
194     const char *map = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
195         "abcdefghijklmnopqrstuvwxyz0123456789+/";
196     int olen = 0;
197     int len = strlen(in);
198
199     while (len >= 4)
200     {
201         char i0, i1, i2, i3;
202         char *p;
203
204         if (!(p = strchr(map, in[0])))
205             return 0;
206         i0 = p - map;
207         len--;
208         if (!(p = strchr(map, in[1])))
209             return 0;
210         i1 = p - map;
211         len--;
212         *(out++) = i0 << 2 | i1 >> 4;
213         olen++;
214         if (in[2] == '=')
215             break;
216         if (!(p = strchr(map, in[2])))
217             return 0;
218         i2 = p - map;
219         len--;
220         *(out++) = i1 << 4 | i2 >> 2;
221         olen++;
222         if (in[3] == '=')
223             break;
224         if (!(p = strchr(map, in[3])))
225             return 0;
226         i3 = p - map;
227         len--;
228         *(out++) = i2 << 6 | i3;
229         olen++;
230
231         in += 4;
232     }
233
234     *out = '\0';
235     return olen;
236 }
237
238 /**
239  * Look for authentication tokens in HTTP Basic parameters or in x-username/x-password
240  * parameters. Added by SH.
241  */
242 static void yaz_srw_decodeauth(Z_SRW_PDU *sr, Z_HTTP_Request *hreq,
243                                char *username, char *password, ODR decode)
244 {
245     const char *basic = z_HTTP_header_lookup(hreq->headers, "Authorization");
246
247     if (username)
248         sr->username = username;
249     if (password)
250         sr->password = password;
251
252     if (basic) {
253         int len, olen;
254         char out[256];
255         char ubuf[256] = "", pbuf[256] = "", *p;
256         if (strncmp(basic, "Basic ", 6))
257             return;
258         basic += 6;
259         len = strlen(basic);
260         if (!len || len > 256)
261             return;
262         olen = yaz_base64decode(basic, out);
263         /* Format of out should be username:password at this point */
264         strcpy(ubuf, out);
265         if ((p = strchr(ubuf, ':'))) {
266             *(p++) = '\0';
267             if (*p)
268                 strcpy(pbuf, p);
269         }
270         if (*ubuf)
271             sr->username = odr_strdup(decode, ubuf);
272         if (*pbuf)
273             sr->password = odr_strdup(decode, pbuf);
274     }
275 }
276
277 void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
278 {
279     const char *v = yaz_uri_val(path, name, o);
280     if (v)
281         *intp = odr_intdup(o, atoi(v));
282 }
283
284 void yaz_mk_srw_diagnostic(ODR o, Z_SRW_diagnostic *d, 
285                            const char *uri, const char *message,
286                            const char *details)
287 {
288     d->uri = odr_strdup(o, uri);
289     if (message)
290         d->message = odr_strdup(o, message);
291     else
292         d->message = 0;
293     if (details)
294         d->details = odr_strdup(o, details);
295     else
296         d->details = 0;
297 }
298
299 void yaz_mk_std_diagnostic(ODR o, Z_SRW_diagnostic *d, 
300                            int code, const char *details)
301 {
302     char uri[40];
303     
304     sprintf(uri, "info:srw/diagnostic/1/%d", code);
305     yaz_mk_srw_diagnostic(o, d, uri, 0, details);
306 }
307
308 void yaz_add_srw_diagnostic_uri(ODR o, Z_SRW_diagnostic **d,
309                                 int *num, const char *uri,
310                                 const char *message, const char *details)
311 {
312     Z_SRW_diagnostic *d_new;
313     d_new = (Z_SRW_diagnostic *) odr_malloc (o, (*num + 1)* sizeof(**d));
314     if (*num)
315         memcpy (d_new, *d, *num *sizeof(**d));
316     *d = d_new;
317
318     yaz_mk_srw_diagnostic(o, *d + *num, uri, message, details);
319     (*num)++;
320 }
321
322 void yaz_add_srw_diagnostic(ODR o, Z_SRW_diagnostic **d,
323                             int *num, int code, const char *addinfo)
324 {
325     char uri[40];
326     
327     sprintf(uri, "info:srw/diagnostic/1/%d", code);
328     yaz_add_srw_diagnostic_uri(o, d, num, uri, 0, addinfo);
329 }
330
331
332 static void grab_charset(ODR o, const char *content_type, char **charset)
333 {
334     if (charset)
335     { 
336         const char *charset_p = 0;
337         if (content_type && (charset_p = strstr(content_type, "; charset=")))
338         {
339             int i = 0;
340             charset_p += 10;
341             while (i < 20 && charset_p[i] &&
342                    !strchr("; \n\r", charset_p[i]))
343                 i++;
344             *charset = (char*) odr_malloc(o, i+1);
345             memcpy(*charset, charset_p, i);
346             (*charset)[i] = '\0';
347         }
348     }
349 }
350
351 int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
352                    Z_SOAP **soap_package, ODR decode, char **charset)
353 {
354     if (!strcmp(hreq->method, "POST"))
355     {
356         const char *content_type = z_HTTP_header_lookup(hreq->headers,
357                                                         "Content-Type");
358         if (content_type && 
359             (!yaz_strcmp_del("text/xml", content_type, "; ") ||
360              !yaz_strcmp_del("application/soap+xml", content_type, "; ") ||
361              !yaz_strcmp_del("text/plain", content_type, "; ")))
362         {
363             char *db = "Default";
364             const char *p0 = hreq->path, *p1;
365             int ret = -1;
366             
367             static Z_SOAP_Handler soap_handlers[4] = {
368 #if YAZ_HAVE_XML2
369                 {"http://www.loc.gov/zing/srw/", 0,
370                  (Z_SOAP_fun) yaz_srw_codec},
371                 {"http://www.loc.gov/zing/srw/v1.0/", 0,
372                  (Z_SOAP_fun) yaz_srw_codec},
373                 {"http://www.loc.gov/zing/srw/update/", 0,
374                  (Z_SOAP_fun) yaz_ucp_codec},
375 #endif
376                 {0, 0, 0}
377             };
378             
379             if (*p0 == '/')
380                 p0++;
381             p1 = strchr(p0, '?');
382             if (!p1)
383                 p1 = p0 + strlen(p0);
384             if (p1 != p0)
385             {
386                 db = (char*) odr_malloc(decode, p1 - p0 + 1);
387                 memcpy (db, p0, p1 - p0);
388                 db[p1 - p0] = '\0';
389             }
390
391             grab_charset(decode, content_type, charset);
392
393             ret = z_soap_codec(decode, soap_package, 
394                                &hreq->content_buf, &hreq->content_len,
395                                soap_handlers);
396             if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
397             {
398                 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
399                 
400                 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
401                     (*srw_pdu)->u.request->database == 0)
402                     (*srw_pdu)->u.request->database = db;
403
404                 if ((*srw_pdu)->which == Z_SRW_explain_request &&
405                     (*srw_pdu)->u.explain_request->database == 0)
406                     (*srw_pdu)->u.explain_request->database = db;
407
408                 if ((*srw_pdu)->which == Z_SRW_scan_request &&
409                     (*srw_pdu)->u.scan_request->database == 0)
410                     (*srw_pdu)->u.scan_request->database = db;
411
412                 if ((*srw_pdu)->which == Z_SRW_update_request &&
413                     (*srw_pdu)->u.update_request->database == 0)
414                     (*srw_pdu)->u.update_request->database = db;
415
416                 return 0;
417             }
418             return 1;
419         }
420     }
421     return 2;
422 }
423
424 static int yaz_sru_decode_integer(ODR odr, const char *pname, 
425                                   const char *valstr, int **valp,
426                                   Z_SRW_diagnostic **diag, int *num_diag,
427                                   int min_value)
428 {
429     int ival;
430     if (!valstr)
431         return 0;
432     if (sscanf(valstr, "%d", &ival) != 1)
433     {
434         yaz_add_srw_diagnostic(odr, diag, num_diag,
435                                YAZ_SRW_UNSUPP_PARAMETER_VALUE, pname);
436         return 0;
437     }
438     if (min_value >= 0 && ival < min_value)
439     {
440         yaz_add_srw_diagnostic(odr, diag, num_diag,
441                                YAZ_SRW_UNSUPP_PARAMETER_VALUE, pname);
442         return 0;
443     }
444     *valp = odr_intdup(odr, ival);
445     return 1;
446 }
447
448 /**
449   http://www.loc.gov/z3950/agency/zing/srw/service.html
450 */ 
451 int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
452                    Z_SOAP **soap_package, ODR decode, char **charset,
453                    Z_SRW_diagnostic **diag, int *num_diag)
454 {
455 #if YAZ_HAVE_XML2
456     static Z_SOAP_Handler soap_handlers[2] = {
457         {"http://www.loc.gov/zing/srw/", 0,
458          (Z_SOAP_fun) yaz_srw_codec},
459         {0, 0, 0}
460     };
461 #endif
462     const char *content_type = z_HTTP_header_lookup(hreq->headers,
463                                             "Content-Type");
464
465     /*
466       SRU GET: ignore content type.
467       SRU POST: we support "application/x-www-form-urlencoded";
468       not  "multipart/form-data" .
469     */
470     if (!strcmp(hreq->method, "GET")
471         || 
472              (!strcmp(hreq->method, "POST") && content_type &&
473               !yaz_strcmp_del("application/x-www-form-urlencoded",
474                               content_type, "; ")))
475     {
476         char *db = "Default";
477         const char *p0 = hreq->path, *p1;
478 #if YAZ_HAVE_XML2
479         const char *operation = 0;
480         char *version = 0;
481         char *query = 0;
482         char *pQuery = 0;
483         char *username = 0;
484         char *password = 0;
485         char *sortKeys = 0;
486         char *stylesheet = 0;
487         char *scanClause = 0;
488         char *pScanClause = 0;
489         char *recordXPath = 0;
490         char *recordSchema = 0;
491         char *recordPacking = "xml";  /* xml packing is default for SRU */
492         char *maximumRecords = 0;
493         char *startRecord = 0;
494         char *maximumTerms = 0;
495         char *responsePosition = 0;
496         char *extraRequestData = 0;
497 #endif
498         char **uri_name;
499         char **uri_val;
500
501         grab_charset(decode, content_type, charset);
502         if (charset && *charset == 0 && !strcmp(hreq->method, "GET"))
503             *charset = "UTF-8";
504
505         if (*p0 == '/')
506             p0++;
507         p1 = strchr(p0, '?');
508         if (!p1)
509             p1 = p0 + strlen(p0);
510         if (p1 != p0)
511         {
512             db = (char*) odr_malloc(decode, p1 - p0 + 1);
513             memcpy (db, p0, p1 - p0);
514             db[p1 - p0] = '\0';
515         }
516         if (!strcmp(hreq->method, "POST"))
517             p1 = hreq->content_buf;
518         yaz_uri_array(p1, decode, &uri_name, &uri_val);
519 #if YAZ_HAVE_XML2
520         if (uri_name)
521         {
522             int i;
523             for (i = 0; uri_name[i]; i++)
524             {
525                 char *n = uri_name[i];
526                 char *v = uri_val[i];
527                 if (!strcmp(n, "query"))
528                     query = v;
529                 else if (!strcmp(n, "x-pquery"))
530                     pQuery = v;
531                 else if (!strcmp(n, "x-username"))
532                     username = v;
533                 else if (!strcmp(n, "x-password"))
534                     password = v;
535                 else if (!strcmp(n, "operation"))
536                     operation = v;
537                 else if (!strcmp(n, "stylesheet"))
538                     stylesheet = v;
539                 else if (!strcmp(n, "sortKeys"))
540                     sortKeys = v;
541                 else if (!strcmp(n, "recordXPath"))
542                     recordXPath = v;
543                 else if (!strcmp(n, "recordSchema"))
544                     recordSchema = v;
545                 else if (!strcmp(n, "recordPacking"))
546                     recordPacking = v;
547                 else if (!strcmp(n, "version"))
548                     version = v;
549                 else if (!strcmp(n, "scanClause"))
550                     scanClause = v;
551                 else if (!strcmp(n, "x-pScanClause"))
552                     pScanClause = v;
553                 else if (!strcmp(n, "maximumRecords"))
554                     maximumRecords = v;
555                 else if (!strcmp(n, "startRecord"))
556                     startRecord = v;
557                 else if (!strcmp(n, "maximumTerms"))
558                     maximumTerms = v;
559                 else if (!strcmp(n, "responsePosition"))
560                     responsePosition = v;
561                 else if (!strcmp(n, "extraRequestData"))
562                     extraRequestData = v;
563                 else
564                     yaz_add_srw_diagnostic(decode, diag, num_diag,
565                                            YAZ_SRW_UNSUPP_PARAMETER, n);
566             }
567         }
568         if (!version)
569         {
570             if (uri_name)
571                 yaz_add_srw_diagnostic(
572                     decode, diag, num_diag,
573                     YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED, "version");
574             version = "1.1";
575         }
576         if (strcmp(version, "1.1"))
577             yaz_add_srw_diagnostic(decode, diag, num_diag,
578                                    YAZ_SRW_UNSUPP_VERSION, "1.1");
579         if (!operation)
580         {
581             if (uri_name)
582                 yaz_add_srw_diagnostic(
583                     decode, diag, num_diag, 
584                     YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED, "operation");
585             operation = "explain";
586         }
587         if (!strcmp(operation, "searchRetrieve"))
588         {
589             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
590
591             sr->srw_version = version;
592             *srw_pdu = sr;
593             yaz_srw_decodeauth(sr, hreq, username, password, decode);
594             if (query)
595             {
596                 sr->u.request->query_type = Z_SRW_query_type_cql;
597                 sr->u.request->query.cql = query;
598             }
599             else if (pQuery)
600             {
601                 sr->u.request->query_type = Z_SRW_query_type_pqf;
602                 sr->u.request->query.pqf = pQuery;
603             }
604             else
605                 yaz_add_srw_diagnostic(
606                     decode, diag, num_diag, 
607                     YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED, "query");
608
609             if (sortKeys)
610             {
611                 sr->u.request->sort_type = Z_SRW_sort_type_sort;
612                 sr->u.request->sort.sortKeys = sortKeys;
613             }
614             sr->u.request->recordXPath = recordXPath;
615             sr->u.request->recordSchema = recordSchema;
616             sr->u.request->recordPacking = recordPacking;
617             sr->u.request->stylesheet = stylesheet;
618
619             yaz_sru_decode_integer(decode, "maximumRecords", maximumRecords, 
620                                    &sr->u.request->maximumRecords, 
621                                    diag, num_diag, 0);
622             
623             yaz_sru_decode_integer(decode, "startRecord", startRecord, 
624                                    &sr->u.request->startRecord,
625                                    diag, num_diag, 1);
626
627             sr->u.request->database = db;
628
629             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
630             (*soap_package)->which = Z_SOAP_generic;
631             
632             (*soap_package)->u.generic =
633                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
634             
635             (*soap_package)->u.generic->p = sr;
636             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
637             (*soap_package)->u.generic->no = 0;
638             
639             (*soap_package)->ns = "SRU";
640
641             return 0;
642         }
643         else if (!strcmp(operation, "explain"))
644         {
645             /* Transfer SRU explain parameters to common struct */
646             /* http://www.loc.gov/z3950/agency/zing/srw/explain.html */
647             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
648
649             sr->srw_version = version;
650             yaz_srw_decodeauth(sr, hreq, username, password, decode);
651             *srw_pdu = sr;
652             sr->u.explain_request->recordPacking = recordPacking;
653             sr->u.explain_request->database = db;
654
655             sr->u.explain_request->stylesheet = stylesheet;
656
657             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
658             (*soap_package)->which = Z_SOAP_generic;
659             
660             (*soap_package)->u.generic =
661                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
662             
663             (*soap_package)->u.generic->p = sr;
664             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
665             (*soap_package)->u.generic->no = 0;
666             
667             (*soap_package)->ns = "SRU";
668
669             return 0;
670         }
671         else if (!strcmp(operation, "scan"))
672         {
673             /* Transfer SRU scan parameters to common struct */
674             /* http://www.loc.gov/z3950/agency/zing/srw/scan.html */
675             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_scan_request);
676
677             sr->srw_version = version;
678             *srw_pdu = sr;
679             yaz_srw_decodeauth(sr, hreq, username, password, decode);
680
681             if (scanClause)
682             {
683                 sr->u.scan_request->query_type = Z_SRW_query_type_cql;
684                 sr->u.scan_request->scanClause.cql = scanClause;
685             }
686             else if (pScanClause)
687             {
688                 sr->u.scan_request->query_type = Z_SRW_query_type_pqf;
689                 sr->u.scan_request->scanClause.pqf = pScanClause;
690             }
691             else
692                 yaz_add_srw_diagnostic(
693                     decode, diag, num_diag, 
694                     YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED, "scanClause");
695             sr->u.scan_request->database = db;
696             
697             yaz_sru_decode_integer(decode, "maximumTerms",
698                                    maximumTerms, 
699                                    &sr->u.scan_request->maximumTerms,
700                                    diag, num_diag, 0);
701             
702             yaz_sru_decode_integer(decode, "responsePosition",
703                                    responsePosition, 
704                                    &sr->u.scan_request->responsePosition,
705                                    diag, num_diag, 0);
706
707             sr->u.scan_request->stylesheet = stylesheet;
708
709             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
710             (*soap_package)->which = Z_SOAP_generic;
711             
712             (*soap_package)->u.generic =
713                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
714             
715             (*soap_package)->u.generic->p = sr;
716             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
717             (*soap_package)->u.generic->no = 0;
718             
719             (*soap_package)->ns = "SRU";
720
721             return 0;
722         }
723         else
724         {
725             /* unsupported operation ... */
726             /* Act as if we received a explain request and throw diagnostic. */
727
728             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
729
730             sr->srw_version = version;
731             *srw_pdu = sr;
732             sr->u.explain_request->recordPacking = recordPacking;
733             sr->u.explain_request->database = db;
734
735             sr->u.explain_request->stylesheet = stylesheet;
736
737             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
738             (*soap_package)->which = Z_SOAP_generic;
739             
740             (*soap_package)->u.generic =
741                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
742             
743             (*soap_package)->u.generic->p = sr;
744             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
745             (*soap_package)->u.generic->no = 0;
746             
747             (*soap_package)->ns = "SRU";
748
749             yaz_add_srw_diagnostic(decode, diag, num_diag, 
750                                    YAZ_SRW_UNSUPP_OPERATION, operation);
751             return 0;
752         }
753 #endif
754         return 1;
755     }
756     return 2;
757 }
758
759 Z_SRW_extra_record *yaz_srw_get_extra_record(ODR o)
760 {
761     Z_SRW_extra_record *res = (Z_SRW_extra_record *)
762         odr_malloc(o, sizeof(*res));
763     res->type = 1;
764     res->recordReviewCode = 0;
765     res->recordReviewNote = 0;
766     res->recordId = 0;
767     res->nonDupRecordId = 0;
768     res->recordLockStatus = 0;
769     res->recordOldVersion = 0;
770     return res;
771 }
772
773 Z_SRW_PDU *yaz_srw_get_core_v_1_1(ODR o)
774 {
775     Z_SRW_PDU *p = (Z_SRW_PDU *) odr_malloc(o, sizeof(*p));
776     p->srw_version = odr_strdup(o, "1.1");
777     p->username = 0;
778     p->password = 0;
779     p->extra_args = 0;
780     return p;
781 }
782
783 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
784 {
785     Z_SRW_PDU *sr = yaz_srw_get_core_v_1_1(o);
786     sr->which = which;
787     switch(which)
788     {
789     case Z_SRW_searchRetrieve_request:
790         sr->u.request = (Z_SRW_searchRetrieveRequest *)
791             odr_malloc(o, sizeof(*sr->u.request));
792         sr->u.request->query_type = Z_SRW_query_type_cql;
793         sr->u.request->query.cql = 0;
794         sr->u.request->sort_type = Z_SRW_sort_type_none;
795         sr->u.request->sort.none = 0;
796         sr->u.request->startRecord = 0;
797         sr->u.request->maximumRecords = 0;
798         sr->u.request->recordSchema = 0;
799         sr->u.request->recordPacking = 0;
800         sr->u.request->recordXPath = 0;
801         sr->u.request->database = 0;
802         sr->u.request->resultSetTTL = 0;
803         sr->u.request->stylesheet = 0;
804         break;
805     case Z_SRW_searchRetrieve_response:
806         sr->u.response = (Z_SRW_searchRetrieveResponse *)
807             odr_malloc(o, sizeof(*sr->u.response));
808         sr->u.response->numberOfRecords = 0;
809         sr->u.response->resultSetId = 0;
810         sr->u.response->resultSetIdleTime = 0;
811         sr->u.response->records = 0;
812         sr->u.response->num_records = 0;
813         sr->u.response->diagnostics = 0;
814         sr->u.response->num_diagnostics = 0;
815         sr->u.response->nextRecordPosition = 0;
816         sr->u.response->extra_records = 0;
817         break;
818     case Z_SRW_explain_request:
819         sr->u.explain_request = (Z_SRW_explainRequest *)
820             odr_malloc(o, sizeof(*sr->u.explain_request));
821         sr->u.explain_request->recordPacking = 0;
822         sr->u.explain_request->database = 0;
823         sr->u.explain_request->stylesheet = 0;
824         break;
825     case Z_SRW_explain_response:
826         sr->u.explain_response = (Z_SRW_explainResponse *)
827             odr_malloc(o, sizeof(*sr->u.explain_response));
828         sr->u.explain_response->record.recordData_buf = 0;
829         sr->u.explain_response->record.recordData_len = 0;
830         sr->u.explain_response->record.recordSchema = 0;
831         sr->u.explain_response->record.recordPosition = 0;
832         sr->u.explain_response->record.recordPacking =
833             Z_SRW_recordPacking_string;
834         sr->u.explain_response->diagnostics = 0;
835         sr->u.explain_response->num_diagnostics = 0;
836         sr->u.explain_response->extra_record = 0;
837         break;
838     case Z_SRW_scan_request:
839         sr->u.scan_request = (Z_SRW_scanRequest *)
840             odr_malloc(o, sizeof(*sr->u.scan_request));
841         sr->u.scan_request->database = 0;
842         sr->u.scan_request->stylesheet = 0;
843         sr->u.scan_request->maximumTerms = 0;
844         sr->u.scan_request->responsePosition = 0;
845         sr->u.scan_request->query_type = Z_SRW_query_type_cql;
846         sr->u.scan_request->scanClause.cql = 0;
847         break;
848     case Z_SRW_scan_response:
849         sr->u.scan_response = (Z_SRW_scanResponse *)
850             odr_malloc(o, sizeof(*sr->u.scan_response));
851         sr->u.scan_response->terms = 0;
852         sr->u.scan_response->num_terms = 0;
853         sr->u.scan_response->diagnostics = 0;
854         sr->u.scan_response->num_diagnostics = 0;
855         break;
856     case Z_SRW_update_request:
857         sr->u.update_request = (Z_SRW_updateRequest *)
858             odr_malloc(o, sizeof(*sr->u.update_request));
859         sr->u.update_request->database = 0;
860         sr->u.update_request->stylesheet = 0;
861         sr->u.update_request->record.recordSchema = 0;
862         sr->u.update_request->record.recordPacking = Z_SRW_recordPacking_XML;
863         sr->u.update_request->recordId = 0;
864         sr->u.update_request->recordVersion = 0;
865         sr->u.update_request->recordOldVersion = 0;
866         sr->u.update_request->record.recordData_buf = 0;
867         sr->u.update_request->record.recordData_len = 0;
868         sr->u.update_request->extra_record = 0;
869         sr->u.update_request->extraRequestData = 0;
870         sr->u.request->database = 0;
871         break;
872     case Z_SRW_update_response:
873         sr->u.update_response = (Z_SRW_updateResponse *)
874             odr_malloc(o, sizeof(*sr->u.update_response));
875         sr->u.update_response->operationStatus = 0;
876         sr->u.update_response->recordId = 0;
877         sr->u.update_response->recordVersion = 0;
878         sr->u.update_response->recordChecksum = 0;
879         sr->u.update_response->record.recordData_buf = 0;
880         sr->u.update_response->record.recordData_len = 0;
881         sr->u.update_response->record.recordSchema = 0;
882         sr->u.update_response->record.recordPacking =
883             Z_SRW_recordPacking_XML;
884         sr->u.update_response->extra_record = 0;
885         sr->u.update_response->extraResponseData = 0;
886         sr->u.update_response->diagnostics = 0;
887         sr->u.update_response->num_diagnostics = 0;
888     }
889     return sr;
890 }
891
892 /* bib1:srw */
893 static int srw_bib1_map[] = {
894     1, 1,
895     2, 2,
896     3, 11,
897     4, 35,
898     5, 12,
899     6, 38,
900     7, 30,
901     8, 32,
902     9, 29,
903     108, 10,  /* Malformed query : Syntax error */
904     10, 10,
905     11, 12,
906     11, 23,
907     12, 60,
908     13, 61,
909     13, 62,
910     14, 63,
911     14, 64,
912     14, 65,
913     15, 68,
914     15, 69,
915     16, 70,
916     17, 70,
917     18, 50,
918     19, 55,
919     20, 56, 
920     21, 52,
921     22, 50,
922     23, 3,
923     24, 66,
924     25, 66,
925     26, 66,
926     27, 51,
927     28, 52,
928     29, 52,
929     30, 51,
930     31, 57,
931     32, 58,
932     33, 59,
933     100, 1, /* bad map */
934     101, 3,
935     102, 3,
936     103, 3,
937     104, 3,
938     105, 3, 
939     106, 66,
940     107, 11,
941     108, 13,
942     108, 14,
943     108, 25,
944     108, 26,
945     108, 27,
946     108, 45,
947         
948     109, 2,
949     110, 37,
950     111, 1,
951     112, 58,
952     113, 10,
953     114, 16,
954     115, 16,
955     116, 16,
956     117, 19,
957     117, 20,
958     118, 22,
959     119, 32,
960     119, 31,
961     120, 28,
962     121, 15,
963     122, 32,
964     123, 22,
965     123, 17,
966     123, 18,
967     124, 24,
968     125, 36,
969     126, 36, 
970     127, 36,
971     128, 51,
972     129, 39,
973     130, 43,
974     131, 40,
975     132, 42,
976     201, 44,
977     201, 33,
978     201, 34,
979     202, 41,
980     203, 43,
981     205, 1,  /* bad map */
982     206, 1,  /* bad map */
983     207, 89,
984     208, 1,  /* bad map */
985     209, 80,
986     210, 80,
987     210, 81,
988     211, 84,
989     212, 85,
990     213, 92,
991     214, 90,
992     215, 91,
993     216, 92,
994     217, 63,
995     218, 1,  /* bad map */
996     219, 1,  /* bad map */
997     220, 1,  /* bad map */
998     221, 1,  /* bad map */
999     222, 3,
1000     223, 1,  /* bad map */
1001     224, 1,  /* bad map */
1002     225, 1,  /* bad map */
1003     226, 1,  /* bad map */
1004     227, 66,
1005     228, 1,  /* bad map */
1006     229, 36,
1007     230, 83,
1008     231, 89,
1009     232, 1,
1010     233, 1, /* bad map */
1011     234, 1, /* bad map */
1012     235, 2,
1013     236, 3, 
1014     237, 82,
1015     238, 67,
1016     239, 66,
1017     240, 1, /* bad map */
1018     241, 1, /* bad map */
1019     242, 70,
1020     243, 1, /* bad map */
1021     244, 66,
1022     245, 10,
1023     246, 10,
1024     247, 10,
1025     1001, 1, /* bad map */
1026     1002, 1, /* bad map */
1027     1003, 1, /* bad map */
1028     1004, 1, /* bad map */
1029     1005, 1, /* bad map */
1030     1006, 1, /* bad map */
1031     1007, 100,
1032     1008, 1, 
1033     1009, 1,
1034     1010, 3,
1035     1011, 3,
1036     1012, 3,
1037     1013, 3,
1038     1014, 3,
1039     1015, 3,
1040     1015, 3,
1041     1016, 3,
1042     1017, 3,
1043     1018, 2,
1044     1019, 2,
1045     1020, 2,
1046     1021, 3,
1047     1022, 3,
1048     1023, 3,
1049     1024, 16,
1050     1025, 3,
1051     1026, 64,
1052     1027, 1,
1053     1028, 65,
1054     1029, 1,
1055     1040, 1,
1056     /* 1041-1065 */
1057     1066, 66,
1058     1066, 67,
1059     0
1060 };
1061
1062 int yaz_diag_bib1_to_srw (int code)
1063 {
1064     const int *p = srw_bib1_map;
1065     while (*p)
1066     {
1067         if (code == p[0])
1068             return p[1];
1069         p += 2;
1070     }
1071     return 1;
1072 }
1073
1074 int yaz_diag_srw_to_bib1(int code)
1075 {
1076     const int *p = srw_bib1_map;
1077     while (*p)
1078     {
1079         if (code == p[1])
1080             return p[0];
1081         p += 2;
1082     }
1083     return 1;
1084 }
1085
1086 static void add_val_int(ODR o, char **name, char **value,  int *i,
1087                         char *a_name, int *val)
1088 {
1089     if (val)
1090     {
1091         name[*i] = a_name;
1092         value[*i] = odr_malloc(o, 30);
1093         sprintf(value[*i], "%d", *val);
1094         (*i)++;
1095     }
1096 }
1097
1098 static void add_val_str(ODR o, char **name, char **value,  int *i,
1099                         char *a_name, char *val)
1100 {
1101     if (val)
1102     {
1103         name[*i] = a_name;
1104         value[*i] = val;
1105         (*i)++;
1106     }
1107 }
1108
1109 static int yaz_get_sru_parms(const Z_SRW_PDU *srw_pdu, ODR encode,
1110                               char **name, char **value)
1111 {
1112     int i = 0;
1113     add_val_str(encode, name, value, &i, "version", srw_pdu->srw_version);
1114     name[i] = "operation";
1115     switch(srw_pdu->which)
1116     {
1117     case Z_SRW_searchRetrieve_request:
1118         value[i++] = "searchRetrieve";
1119         switch(srw_pdu->u.request->query_type)
1120         {
1121         case Z_SRW_query_type_cql:
1122             add_val_str(encode, name, value, &i, "query",
1123                         srw_pdu->u.request->query.cql);
1124             break;
1125         case Z_SRW_query_type_pqf:
1126             add_val_str(encode, name, value, &i, "x-pquery",
1127                         srw_pdu->u.request->query.pqf);
1128             break;
1129         case Z_SRW_query_type_xcql:
1130             add_val_str(encode, name, value, &i, "x-cql",
1131                         srw_pdu->u.request->query.xcql);
1132             break;
1133         }
1134         switch(srw_pdu->u.request->sort_type)
1135         {
1136         case Z_SRW_sort_type_none:
1137             break;
1138         case Z_SRW_sort_type_sort:            
1139             add_val_str(encode, name, value, &i, "sortKeys",
1140                         srw_pdu->u.request->sort.sortKeys);
1141             break;
1142         }
1143         add_val_int(encode, name, value, &i, "startRecord", 
1144                     srw_pdu->u.request->startRecord);
1145         add_val_int(encode, name, value, &i, "maximumRecords", 
1146                     srw_pdu->u.request->maximumRecords);
1147         add_val_str(encode, name, value, &i, "recordSchema",
1148                     srw_pdu->u.request->recordSchema);
1149         add_val_str(encode, name, value, &i, "recordPacking",
1150                     srw_pdu->u.request->recordPacking);
1151         add_val_str(encode, name, value, &i, "recordXPath",
1152                     srw_pdu->u.request->recordXPath);
1153         add_val_str(encode, name, value, &i, "stylesheet",
1154                     srw_pdu->u.request->stylesheet);
1155         add_val_int(encode, name, value, &i, "resultSetTTL", 
1156                     srw_pdu->u.request->resultSetTTL);
1157         break;
1158     case Z_SRW_explain_request:
1159         value[i++] = "explain";
1160         add_val_str(encode, name, value, &i, "stylesheet",
1161                     srw_pdu->u.explain_request->stylesheet);
1162         break;
1163     case Z_SRW_scan_request:
1164         value[i++] = "scan";
1165
1166         switch(srw_pdu->u.scan_request->query_type)
1167         {
1168         case Z_SRW_query_type_cql:
1169             add_val_str(encode, name, value, &i, "scanClause",
1170                         srw_pdu->u.scan_request->scanClause.cql);
1171             break;
1172         case Z_SRW_query_type_pqf:
1173             add_val_str(encode, name, value, &i, "x-pScanClause",
1174                         srw_pdu->u.scan_request->scanClause.pqf);
1175             break;
1176         case Z_SRW_query_type_xcql:
1177             add_val_str(encode, name, value, &i, "x-cqlScanClause",
1178                         srw_pdu->u.scan_request->scanClause.xcql);
1179             break;
1180         }
1181         add_val_int(encode, name, value, &i, "responsePosition", 
1182                     srw_pdu->u.scan_request->responsePosition);
1183         add_val_int(encode, name, value, &i, "maximumTerms", 
1184                     srw_pdu->u.scan_request->maximumTerms);
1185         add_val_str(encode, name, value, &i, "stylesheet",
1186                     srw_pdu->u.scan_request->stylesheet);
1187         break;
1188     case Z_SRW_update_request:
1189         value[i++] = "update";
1190         break;
1191     default:
1192         return -1;
1193     }
1194     name[i++] = 0;
1195     return 0;
1196 }
1197
1198 int yaz_sru_get_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1199                        ODR encode, const char *charset)
1200 {
1201     char *name[30], *value[30]; /* definite upper limit for SRU params */
1202     char *uri_args;
1203     char *path;
1204
1205     if (yaz_get_sru_parms(srw_pdu, encode, name, value))
1206         return -1;
1207     yaz_array_to_uri_ex(&uri_args, encode, name, value, srw_pdu->extra_args);
1208
1209     hreq->method = "GET";
1210     
1211     path = odr_malloc(encode, strlen(hreq->path) + strlen(uri_args) + 4
1212                       +(srw_pdu->extra_args ? strlen(srw_pdu->extra_args) : 0)
1213         );
1214     sprintf(path, "%s?%s", hreq->path, uri_args);
1215     hreq->path = path;
1216
1217     z_HTTP_header_add_content_type(encode, &hreq->headers,
1218                                    "text/xml", charset);
1219     return 0;
1220 }
1221
1222 int yaz_sru_post_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1223                         ODR encode, const char *charset)
1224 {
1225     char *name[30], *value[30]; /* definite upper limit for SRU params */
1226     char *uri_args;
1227
1228     if (yaz_get_sru_parms(srw_pdu, encode, name, value))
1229         return -1;
1230
1231     yaz_array_to_uri_ex(&uri_args, encode, name, value, srw_pdu->extra_args);
1232
1233     hreq->method = "POST";
1234     
1235     hreq->content_buf = uri_args;
1236     hreq->content_len = strlen(uri_args);
1237
1238     z_HTTP_header_add_content_type(encode, &hreq->headers,
1239                                    "application/x-www-form-urlencoded",
1240                                    charset);
1241     return 0;
1242 }
1243
1244 int yaz_sru_soap_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1245                         ODR odr, const char *charset)
1246 {
1247     Z_SOAP_Handler handlers[2] = {
1248 #if YAZ_HAVE_XML2
1249         {"http://www.loc.gov/zing/srw/", 0, (Z_SOAP_fun) yaz_srw_codec},
1250 #endif
1251         {0, 0, 0}
1252     };
1253     Z_SOAP *p = (Z_SOAP*) odr_malloc(odr, sizeof(*p));
1254     z_HTTP_header_add_content_type(odr,
1255                                    &hreq->headers,
1256                                    "text/xml", charset);
1257     
1258     z_HTTP_header_add(odr, &hreq->headers,
1259                       "SOAPAction", "\"\"");
1260     p->which = Z_SOAP_generic;
1261     p->u.generic = (Z_SOAP_Generic *) odr_malloc(odr, sizeof(*p->u.generic));
1262     p->u.generic->no = 0;
1263     p->u.generic->ns = 0;
1264     p->u.generic->p = srw_pdu;
1265     p->ns = "http://schemas.xmlsoap.org/soap/envelope/";
1266     
1267     return z_soap_codec_enc(odr, &p,
1268                             &hreq->content_buf,
1269                             &hreq->content_len, handlers,
1270                             charset);
1271 }
1272
1273 /*
1274  * Local variables:
1275  * c-basic-offset: 4
1276  * indent-tabs-mode: nil
1277  * End:
1278  * vim: shiftwidth=4 tabstop=8 expandtab
1279  */
1280