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