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