Implemented bug #635: YAZ/ZOOM layer should include non SRU options in the
[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.46 2006-08-16 22:47:10 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     return 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(ODR o, int which)
757 {
758     Z_SRW_PDU *sr = yaz_srw_get_core_v_1_1(o);
759     sr->which = which;
760     switch(which)
761     {
762     case Z_SRW_searchRetrieve_request:
763         sr->u.request = (Z_SRW_searchRetrieveRequest *)
764             odr_malloc(o, sizeof(*sr->u.request));
765         sr->u.request->query_type = Z_SRW_query_type_cql;
766         sr->u.request->query.cql = 0;
767         sr->u.request->sort_type = Z_SRW_sort_type_none;
768         sr->u.request->sort.none = 0;
769         sr->u.request->startRecord = 0;
770         sr->u.request->maximumRecords = 0;
771         sr->u.request->recordSchema = 0;
772         sr->u.request->recordPacking = 0;
773         sr->u.request->recordXPath = 0;
774         sr->u.request->database = 0;
775         sr->u.request->resultSetTTL = 0;
776         sr->u.request->stylesheet = 0;
777         break;
778     case Z_SRW_searchRetrieve_response:
779         sr->u.response = (Z_SRW_searchRetrieveResponse *)
780             odr_malloc(o, sizeof(*sr->u.response));
781         sr->u.response->numberOfRecords = 0;
782         sr->u.response->resultSetId = 0;
783         sr->u.response->resultSetIdleTime = 0;
784         sr->u.response->records = 0;
785         sr->u.response->num_records = 0;
786         sr->u.response->diagnostics = 0;
787         sr->u.response->num_diagnostics = 0;
788         sr->u.response->nextRecordPosition = 0;
789         sr->u.response->extra_records = 0;
790         break;
791     case Z_SRW_explain_request:
792         sr->u.explain_request = (Z_SRW_explainRequest *)
793             odr_malloc(o, sizeof(*sr->u.explain_request));
794         sr->u.explain_request->recordPacking = 0;
795         sr->u.explain_request->database = 0;
796         sr->u.explain_request->stylesheet = 0;
797         break;
798     case Z_SRW_explain_response:
799         sr->u.explain_response = (Z_SRW_explainResponse *)
800             odr_malloc(o, sizeof(*sr->u.explain_response));
801         sr->u.explain_response->record.recordData_buf = 0;
802         sr->u.explain_response->record.recordData_len = 0;
803         sr->u.explain_response->record.recordSchema = 0;
804         sr->u.explain_response->record.recordPosition = 0;
805         sr->u.explain_response->record.recordPacking =
806             Z_SRW_recordPacking_string;
807         sr->u.explain_response->diagnostics = 0;
808         sr->u.explain_response->num_diagnostics = 0;
809         sr->u.explain_response->extra_record = 0;
810         break;
811     case Z_SRW_scan_request:
812         sr->u.scan_request = (Z_SRW_scanRequest *)
813             odr_malloc(o, sizeof(*sr->u.scan_request));
814         sr->u.scan_request->database = 0;
815         sr->u.scan_request->stylesheet = 0;
816         sr->u.scan_request->maximumTerms = 0;
817         sr->u.scan_request->responsePosition = 0;
818         sr->u.scan_request->query_type = Z_SRW_query_type_cql;
819         sr->u.scan_request->scanClause.cql = 0;
820         break;
821     case Z_SRW_scan_response:
822         sr->u.scan_response = (Z_SRW_scanResponse *)
823             odr_malloc(o, sizeof(*sr->u.scan_response));
824         sr->u.scan_response->terms = 0;
825         sr->u.scan_response->num_terms = 0;
826         sr->u.scan_response->diagnostics = 0;
827         sr->u.scan_response->num_diagnostics = 0;
828         break;
829     case Z_SRW_update_request:
830         sr->u.update_request = (Z_SRW_updateRequest *)
831             odr_malloc(o, sizeof(*sr->u.update_request));
832         sr->u.update_request->database = 0;
833         sr->u.update_request->stylesheet = 0;
834         sr->u.update_request->record.recordSchema = 0;
835         sr->u.update_request->record.recordPacking = Z_SRW_recordPacking_XML;
836         sr->u.update_request->recordId = 0;
837         sr->u.update_request->recordVersion = 0;
838         sr->u.update_request->recordOldVersion = 0;
839         sr->u.update_request->record.recordData_buf = 0;
840         sr->u.update_request->record.recordData_len = 0;
841         sr->u.update_request->extra_record = 0;
842         sr->u.update_request->extraRequestData = 0;
843         sr->u.request->database = 0;
844         break;
845     case Z_SRW_update_response:
846         sr->u.update_response = (Z_SRW_updateResponse *)
847             odr_malloc(o, sizeof(*sr->u.update_response));
848         sr->u.update_response->operationStatus = 0;
849         sr->u.update_response->recordId = 0;
850         sr->u.update_response->recordVersion = 0;
851         sr->u.update_response->recordChecksum = 0;
852         sr->u.update_response->record.recordData_buf = 0;
853         sr->u.update_response->record.recordData_len = 0;
854         sr->u.update_response->record.recordSchema = 0;
855         sr->u.update_response->record.recordPacking =
856             Z_SRW_recordPacking_XML;
857         sr->u.update_response->extra_record = 0;
858         sr->u.update_response->extraResponseData = 0;
859         sr->u.update_response->diagnostics = 0;
860         sr->u.update_response->num_diagnostics = 0;
861     }
862     return sr;
863 }
864
865 /* bib1:srw */
866 static int srw_bib1_map[] = {
867     1, 1,
868     2, 2,
869     3, 11,
870     4, 35,
871     5, 12,
872     6, 38,
873     7, 30,
874     8, 32,
875     9, 29,
876     108, 10,  /* Malformed query : Syntax error */
877     10, 10,
878     11, 12,
879     11, 23,
880     12, 60,
881     13, 61,
882     13, 62,
883     14, 63,
884     14, 64,
885     14, 65,
886     15, 68,
887     15, 69,
888     16, 70,
889     17, 70,
890     18, 50,
891     19, 55,
892     20, 56, 
893     21, 52,
894     22, 50,
895     23, 3,
896     24, 66,
897     25, 66,
898     26, 66,
899     27, 51,
900     28, 52,
901     29, 52,
902     30, 51,
903     31, 57,
904     32, 58,
905     33, 59,
906     100, 1, /* bad map */
907     101, 3,
908     102, 3,
909     103, 3,
910     104, 3,
911     105, 3, 
912     106, 66,
913     107, 11,
914     108, 13,
915     108, 14,
916     108, 25,
917     108, 26,
918     108, 27,
919     108, 45,
920         
921     109, 2,
922     110, 37,
923     111, 1,
924     112, 58,
925     113, 10,
926     114, 16,
927     115, 16,
928     116, 16,
929     117, 19,
930     117, 20,
931     118, 22,
932     119, 32,
933     119, 31,
934     120, 28,
935     121, 15,
936     122, 32,
937     123, 22,
938     123, 17,
939     123, 18,
940     124, 24,
941     125, 36,
942     126, 36, 
943     127, 36,
944     128, 51,
945     129, 39,
946     130, 43,
947     131, 40,
948     132, 42,
949     201, 44,
950     201, 33,
951     201, 34,
952     202, 41,
953     203, 43,
954     205, 1,  /* bad map */
955     206, 1,  /* bad map */
956     207, 89,
957     208, 1,  /* bad map */
958     209, 80,
959     210, 80,
960     210, 81,
961     211, 84,
962     212, 85,
963     213, 92,
964     214, 90,
965     215, 91,
966     216, 92,
967     217, 63,
968     218, 1,  /* bad map */
969     219, 1,  /* bad map */
970     220, 1,  /* bad map */
971     221, 1,  /* bad map */
972     222, 3,
973     223, 1,  /* bad map */
974     224, 1,  /* bad map */
975     225, 1,  /* bad map */
976     226, 1,  /* bad map */
977     227, 66,
978     228, 1,  /* bad map */
979     229, 36,
980     230, 83,
981     231, 89,
982     232, 1,
983     233, 1, /* bad map */
984     234, 1, /* bad map */
985     235, 2,
986     236, 3, 
987     237, 82,
988     238, 67,
989     239, 66,
990     240, 1, /* bad map */
991     241, 1, /* bad map */
992     242, 70,
993     243, 1, /* bad map */
994     244, 66,
995     245, 10,
996     246, 10,
997     247, 10,
998     1001, 1, /* bad map */
999     1002, 1, /* bad map */
1000     1003, 1, /* bad map */
1001     1004, 1, /* bad map */
1002     1005, 1, /* bad map */
1003     1006, 1, /* bad map */
1004     1007, 100,
1005     1008, 1, 
1006     1009, 1,
1007     1010, 3,
1008     1011, 3,
1009     1012, 3,
1010     1013, 3,
1011     1014, 3,
1012     1015, 3,
1013     1015, 3,
1014     1016, 3,
1015     1017, 3,
1016     1018, 2,
1017     1019, 2,
1018     1020, 2,
1019     1021, 3,
1020     1022, 3,
1021     1023, 3,
1022     1024, 16,
1023     1025, 3,
1024     1026, 64,
1025     1027, 1,
1026     1028, 65,
1027     1029, 1,
1028     1040, 1,
1029     /* 1041-1065 */
1030     1066, 66,
1031     1066, 67,
1032     0
1033 };
1034
1035 int yaz_diag_bib1_to_srw (int code)
1036 {
1037     const int *p = srw_bib1_map;
1038     while (*p)
1039     {
1040         if (code == p[0])
1041             return p[1];
1042         p += 2;
1043     }
1044     return 1;
1045 }
1046
1047 int yaz_diag_srw_to_bib1(int code)
1048 {
1049     const int *p = srw_bib1_map;
1050     while (*p)
1051     {
1052         if (code == p[1])
1053             return p[0];
1054         p += 2;
1055     }
1056     return 1;
1057 }
1058
1059 static void add_val_int(ODR o, char **name, char **value,  int *i,
1060                         char *a_name, int *val)
1061 {
1062     if (val)
1063     {
1064         name[*i] = a_name;
1065         value[*i] = odr_malloc(o, 30);
1066         sprintf(value[*i], "%d", *val);
1067         (*i)++;
1068     }
1069 }
1070
1071 static void add_val_str(ODR o, char **name, char **value,  int *i,
1072                         char *a_name, char *val)
1073 {
1074     if (val)
1075     {
1076         name[*i] = a_name;
1077         value[*i] = val;
1078         (*i)++;
1079     }
1080 }
1081
1082 static int yaz_get_sru_parms(const Z_SRW_PDU *srw_pdu, ODR encode,
1083                               char **name, char **value)
1084 {
1085     int i = 0;
1086     add_val_str(encode, name, value, &i, "version", srw_pdu->srw_version);
1087     name[i] = "operation";
1088     switch(srw_pdu->which)
1089     {
1090     case Z_SRW_searchRetrieve_request:
1091         value[i++] = "searchRetrieve";
1092         switch(srw_pdu->u.request->query_type)
1093         {
1094         case Z_SRW_query_type_cql:
1095             add_val_str(encode, name, value, &i, "query",
1096                         srw_pdu->u.request->query.cql);
1097             break;
1098         case Z_SRW_query_type_pqf:
1099             add_val_str(encode, name, value, &i, "x-pquery",
1100                         srw_pdu->u.request->query.pqf);
1101             break;
1102         case Z_SRW_query_type_xcql:
1103             add_val_str(encode, name, value, &i, "x-cql",
1104                         srw_pdu->u.request->query.xcql);
1105             break;
1106         }
1107         switch(srw_pdu->u.request->sort_type)
1108         {
1109         case Z_SRW_sort_type_none:
1110             break;
1111         case Z_SRW_sort_type_sort:            
1112             add_val_str(encode, name, value, &i, "sortKeys",
1113                         srw_pdu->u.request->sort.sortKeys);
1114             break;
1115         }
1116         add_val_int(encode, name, value, &i, "startRecord", 
1117                     srw_pdu->u.request->startRecord);
1118         add_val_int(encode, name, value, &i, "maximumRecords", 
1119                     srw_pdu->u.request->maximumRecords);
1120         add_val_str(encode, name, value, &i, "recordSchema",
1121                     srw_pdu->u.request->recordSchema);
1122         add_val_str(encode, name, value, &i, "recordPacking",
1123                     srw_pdu->u.request->recordPacking);
1124         add_val_str(encode, name, value, &i, "recordXPath",
1125                     srw_pdu->u.request->recordXPath);
1126         add_val_str(encode, name, value, &i, "stylesheet",
1127                     srw_pdu->u.request->stylesheet);
1128         add_val_int(encode, name, value, &i, "resultSetTTL", 
1129                     srw_pdu->u.request->resultSetTTL);
1130         break;
1131     case Z_SRW_explain_request:
1132         value[i++] = "explain";
1133         add_val_str(encode, name, value, &i, "stylesheet",
1134                     srw_pdu->u.explain_request->stylesheet);
1135         break;
1136     case Z_SRW_scan_request:
1137         value[i++] = "scan";
1138
1139         switch(srw_pdu->u.scan_request->query_type)
1140         {
1141         case Z_SRW_query_type_cql:
1142             add_val_str(encode, name, value, &i, "scanClause",
1143                         srw_pdu->u.scan_request->scanClause.cql);
1144             break;
1145         case Z_SRW_query_type_pqf:
1146             add_val_str(encode, name, value, &i, "x-pScanClause",
1147                         srw_pdu->u.scan_request->scanClause.pqf);
1148             break;
1149         case Z_SRW_query_type_xcql:
1150             add_val_str(encode, name, value, &i, "x-cqlScanClause",
1151                         srw_pdu->u.scan_request->scanClause.xcql);
1152             break;
1153         }
1154         add_val_int(encode, name, value, &i, "responsePosition", 
1155                     srw_pdu->u.scan_request->responsePosition);
1156         add_val_int(encode, name, value, &i, "maximumTerms", 
1157                     srw_pdu->u.scan_request->maximumTerms);
1158         add_val_str(encode, name, value, &i, "stylesheet",
1159                     srw_pdu->u.scan_request->stylesheet);
1160         break;
1161     case Z_SRW_update_request:
1162         value[i++] = "update";
1163         break;
1164     default:
1165         return -1;
1166     }
1167     name[i++] = 0;
1168     return 0;
1169 }
1170
1171 int yaz_sru_get_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1172                        ODR encode, const char *charset)
1173 {
1174     char *name[30], *value[30]; /* definite upper limit for SRU params */
1175     char *uri_args;
1176     char *path;
1177
1178     if (yaz_get_sru_parms(srw_pdu, encode, name, value))
1179         return -1;
1180     yaz_array_to_uri_ex(&uri_args, encode, name, value, srw_pdu->extra_args);
1181
1182     hreq->method = "GET";
1183     
1184     path = odr_malloc(encode, strlen(hreq->path) + strlen(uri_args) + 4
1185                       +(srw_pdu->extra_args ? strlen(srw_pdu->extra_args) : 0)
1186         );
1187     sprintf(path, "%s?%s", hreq->path, uri_args);
1188     hreq->path = path;
1189
1190     z_HTTP_header_add_content_type(encode, &hreq->headers,
1191                                    "text/xml", charset);
1192     return 0;
1193 }
1194
1195 int yaz_sru_post_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1196                         ODR encode, const char *charset)
1197 {
1198     char *name[30], *value[30]; /* definite upper limit for SRU params */
1199     char *uri_args;
1200
1201     if (yaz_get_sru_parms(srw_pdu, encode, name, value))
1202         return -1;
1203
1204     yaz_array_to_uri_ex(&uri_args, encode, name, value, srw_pdu->extra_args);
1205
1206     hreq->method = "POST";
1207     
1208     hreq->content_buf = uri_args;
1209     hreq->content_len = strlen(uri_args);
1210
1211     z_HTTP_header_add_content_type(encode, &hreq->headers,
1212                                    "application/x-www-form-urlencoded",
1213                                    charset);
1214     return 0;
1215 }
1216
1217 int yaz_sru_soap_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1218                         ODR odr, const char *charset)
1219 {
1220     Z_SOAP_Handler handlers[2] = {
1221 #if YAZ_HAVE_XML2
1222         {"http://www.loc.gov/zing/srw/", 0, (Z_SOAP_fun) yaz_srw_codec},
1223 #endif
1224         {0, 0, 0}
1225     };
1226     Z_SOAP *p = (Z_SOAP*) odr_malloc(odr, sizeof(*p));
1227     z_HTTP_header_add_content_type(odr,
1228                                    &hreq->headers,
1229                                    "text/xml", charset);
1230     
1231     z_HTTP_header_add(odr, &hreq->headers,
1232                       "SOAPAction", "\"\"");
1233     p->which = Z_SOAP_generic;
1234     p->u.generic = (Z_SOAP_Generic *) odr_malloc(odr, sizeof(*p->u.generic));
1235     p->u.generic->no = 0;
1236     p->u.generic->ns = 0;
1237     p->u.generic->p = srw_pdu;
1238     p->ns = "http://schemas.xmlsoap.org/soap/envelope/";
1239     
1240     return z_soap_codec_enc(odr, &p,
1241                             &hreq->content_buf,
1242                             &hreq->content_len, handlers,
1243                             charset);
1244 }
1245
1246 /*
1247  * Local variables:
1248  * c-basic-offset: 4
1249  * indent-tabs-mode: nil
1250  * End:
1251  * vim: shiftwidth=4 tabstop=8 expandtab
1252  */
1253