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