Added continuation line support for MARC line format reader.
[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.55 2007-01-03 08:42:15 adam Exp $
6  */
7 /**
8  * \file srwutil.c
9  * \brief Implements SRW/SRU utilities.
10  */
11
12 #include <stdlib.h>
13 #include <yaz/srw.h>
14 #include <yaz/yaz-iconv.h>
15
16 static int hex_digit (int ch)
17 {
18     if (ch >= '0' && ch <= '9')
19         return ch - '0';
20     else if (ch >= 'a' && ch <= 'f')
21         return ch - 'a'+10;
22     else if (ch >= 'A' && ch <= 'F')
23         return ch - 'A'+10;
24     return 0;
25 }
26
27 void encode_uri_char(char *dst, char ch)
28 {
29     if (ch == ' ')
30         strcpy(dst, "+");
31     else if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
32         (ch >= '0' && ch <= '9'))
33     {
34         dst[0] = ch;
35         dst[1] = '\0';
36     }
37     else
38     {
39         dst[0] = '%';
40         sprintf(dst+1, "%02X", (unsigned char ) ch);
41     }
42 }
43
44 static void yaz_array_to_uri_ex(char **path, ODR o, char **name, char **value,
45                                 const char *extra_args)
46 {
47     size_t i, szp = 0, sz = extra_args ? 1+strlen(extra_args) : 1;
48     for(i = 0; name[i]; i++)
49         sz += strlen(name[i]) + 3 + strlen(value[i]) * 3;
50     *path = odr_malloc(o, sz);
51     
52     for(i = 0; name[i]; i++)
53     {
54         size_t j, ilen;
55         if (i)
56             (*path)[szp++] = '&';
57         ilen = strlen(name[i]);
58         memcpy(*path+szp, name[i], ilen);
59         szp += ilen;
60         (*path)[szp++] = '=';
61         for (j = 0; value[i][j]; j++)
62         {
63             size_t vlen;
64             char vstr[5];
65             encode_uri_char(vstr, value[i][j]);
66             vlen = strlen(vstr);
67             memcpy(*path+szp, vstr, vlen);
68             szp += vlen;
69         }
70     }
71     if (extra_args)
72     {
73         if (i)
74             (*path)[szp++] = '&';
75         memcpy(*path + szp, extra_args, strlen(extra_args));
76         szp += strlen(extra_args);
77     }
78     (*path)[szp] = '\0';
79 }
80
81 void yaz_array_to_uri(char **path, ODR o, char **name, char **value)
82 {
83     yaz_array_to_uri_ex(path, o, name, value, 0);
84 }
85
86 int yaz_uri_array(const char *path, ODR o, char ***name, char ***val)
87 {
88     int no = 2;
89     const char *cp;
90     *name = 0;
91     if (*path == '?')
92         path++;
93     if (!*path)
94         return 0;
95     cp = path;
96     while ((cp = strchr(cp, '&')))
97     {
98         cp++;
99         no++;
100     }
101     *name = odr_malloc(o, no * sizeof(char*));
102     *val = odr_malloc(o, no * sizeof(char*));
103
104     for (no = 0; *path; no++)
105     {
106         const char *p1 = strchr(path, '=');
107         size_t i = 0;
108         char *ret;
109         if (!p1)
110             break;
111
112         (*name)[no] = odr_malloc(o, (p1-path)+1);
113         memcpy((*name)[no], path, p1-path);
114         (*name)[no][p1-path] = '\0';
115
116         path = p1 + 1;
117         p1 = strchr(path, '&');
118         if (!p1)
119             p1 = strlen(path) + path;
120         (*val)[no] = ret = odr_malloc(o, p1 - path + 1);
121         while (*path && *path != '&')
122         {
123             if (*path == '+')
124             {
125                 ret[i++] = ' ';
126                 path++;
127             }
128             else if (*path == '%' && path[1] && path[2])
129             {
130                 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
131                 path = path + 3;
132             }
133             else
134                 ret[i++] = *path++;
135         }
136         ret[i] = '\0';
137
138         if (*path)
139             path++;
140     }
141     (*name)[no] = 0;
142     (*val)[no] = 0;
143     return no;
144 }
145
146 char *yaz_uri_val(const char *path, const char *name, ODR o)
147 {
148     size_t nlen = strlen(name);
149     if (*path != '?')
150         return 0;
151     path++;
152     while (path && *path)
153     {
154         const char *p1 = strchr(path, '=');
155         if (!p1)
156             break;
157         if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
158         {
159             size_t i = 0;
160             char *ret;
161             
162             path = p1 + 1;
163             p1 = strchr(path, '&');
164             if (!p1)
165                 p1 = strlen(path) + path;
166             ret = (char *) odr_malloc(o, p1 - path + 1);
167             while (*path && *path != '&')
168             {
169                 if (*path == '+')
170                 {
171                     ret[i++] = ' ';
172                     path++;
173                 }
174                 else if (*path == '%' && path[1] && path[2])
175                 {
176                     ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
177                     path = path + 3;
178                 }
179                 else
180                     ret[i++] = *path++;
181             }
182             ret[i] = '\0';
183             return ret;
184         }
185         path = strchr(p1, '&');
186         if (path)
187             path++;
188     }
189     return 0;
190 }
191
192 static int yaz_base64decode(const char *in, char *out)
193 {
194     const char *map = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
195         "abcdefghijklmnopqrstuvwxyz0123456789+/";
196     int olen = 0;
197     int len = strlen(in);
198
199     while (len >= 4)
200     {
201         char i0, i1, i2, i3;
202         char *p;
203
204         if (!(p = strchr(map, in[0])))
205             return 0;
206         i0 = p - map;
207         len--;
208         if (!(p = strchr(map, in[1])))
209             return 0;
210         i1 = p - map;
211         len--;
212         *(out++) = i0 << 2 | i1 >> 4;
213         olen++;
214         if (in[2] == '=')
215             break;
216         if (!(p = strchr(map, in[2])))
217             return 0;
218         i2 = p - map;
219         len--;
220         *(out++) = i1 << 4 | i2 >> 2;
221         olen++;
222         if (in[3] == '=')
223             break;
224         if (!(p = strchr(map, in[3])))
225             return 0;
226         i3 = p - map;
227         len--;
228         *(out++) = i2 << 6 | i3;
229         olen++;
230
231         in += 4;
232     }
233
234     *out = '\0';
235     return olen;
236 }
237
238 /**
239  * Look for authentication tokens in HTTP Basic parameters or in x-username/x-password
240  * parameters. Added by SH.
241  */
242 static void yaz_srw_decodeauth(Z_SRW_PDU *sr, Z_HTTP_Request *hreq,
243                                char *username, char *password, ODR decode)
244 {
245     const char *basic = z_HTTP_header_lookup(hreq->headers, "Authorization");
246
247     if (username)
248         sr->username = username;
249     if (password)
250         sr->password = password;
251
252     if (basic) {
253         int len, olen;
254         char out[256];
255         char ubuf[256] = "", pbuf[256] = "", *p;
256         if (strncmp(basic, "Basic ", 6))
257             return;
258         basic += 6;
259         len = strlen(basic);
260         if (!len || len > 256)
261             return;
262         olen = yaz_base64decode(basic, out);
263         /* Format of out should be username:password at this point */
264         strcpy(ubuf, out);
265         if ((p = strchr(ubuf, ':'))) {
266             *(p++) = '\0';
267             if (*p)
268                 strcpy(pbuf, p);
269         }
270         if (*ubuf)
271             sr->username = odr_strdup(decode, ubuf);
272         if (*pbuf)
273             sr->password = odr_strdup(decode, pbuf);
274     }
275 }
276
277 void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
278 {
279     const char *v = yaz_uri_val(path, name, o);
280     if (v)
281         *intp = odr_intdup(o, atoi(v));
282 }
283
284 void yaz_mk_srw_diagnostic(ODR o, Z_SRW_diagnostic *d, 
285                            const char *uri, const char *message,
286                            const char *details)
287 {
288     d->uri = odr_strdup(o, uri);
289     if (message)
290         d->message = odr_strdup(o, message);
291     else
292         d->message = 0;
293     if (details)
294         d->details = odr_strdup(o, details);
295     else
296         d->details = 0;
297 }
298
299 void yaz_mk_std_diagnostic(ODR o, Z_SRW_diagnostic *d, 
300                            int code, const char *details)
301 {
302     char uri[40];
303     
304     sprintf(uri, "info:srw/diagnostic/1/%d", code);
305     yaz_mk_srw_diagnostic(o, d, uri, 0, details);
306 }
307
308 void yaz_add_srw_diagnostic_uri(ODR o, Z_SRW_diagnostic **d,
309                                 int *num, const char *uri,
310                                 const char *message, const char *details)
311 {
312     Z_SRW_diagnostic *d_new;
313     d_new = (Z_SRW_diagnostic *) odr_malloc (o, (*num + 1)* sizeof(**d));
314     if (*num)
315         memcpy (d_new, *d, *num *sizeof(**d));
316     *d = d_new;
317
318     yaz_mk_srw_diagnostic(o, *d + *num, uri, message, details);
319     (*num)++;
320 }
321
322 void yaz_add_srw_diagnostic(ODR o, Z_SRW_diagnostic **d,
323                             int *num, int code, const char *addinfo)
324 {
325     char uri[40];
326     
327     sprintf(uri, "info:srw/diagnostic/1/%d", code);
328     yaz_add_srw_diagnostic_uri(o, d, num, uri, 0, addinfo);
329 }
330
331
332 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) = odr_malloc(decode, sizeof(**soap_package));
636             (*soap_package)->which = Z_SOAP_generic;
637             
638             (*soap_package)->u.generic =
639                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
640             
641             (*soap_package)->u.generic->p = sr;
642             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
643             (*soap_package)->u.generic->no = 0;
644             
645             (*soap_package)->ns = "SRU";
646
647             return 0;
648         }
649         else if (!strcmp(operation, "explain"))
650         {
651             /* Transfer SRU explain parameters to common struct */
652             /* http://www.loc.gov/z3950/agency/zing/srw/explain.html */
653             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
654
655             sr->srw_version = version;
656             yaz_srw_decodeauth(sr, hreq, username, password, decode);
657             *srw_pdu = sr;
658             sr->u.explain_request->recordPacking = recordPacking;
659             sr->u.explain_request->database = db;
660
661             sr->u.explain_request->stylesheet = stylesheet;
662
663             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
664             (*soap_package)->which = Z_SOAP_generic;
665             
666             (*soap_package)->u.generic =
667                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
668             
669             (*soap_package)->u.generic->p = sr;
670             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
671             (*soap_package)->u.generic->no = 0;
672             
673             (*soap_package)->ns = "SRU";
674
675             return 0;
676         }
677         else if (!strcmp(operation, "scan"))
678         {
679             /* Transfer SRU scan parameters to common struct */
680             /* http://www.loc.gov/z3950/agency/zing/srw/scan.html */
681             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_scan_request);
682
683             sr->srw_version = version;
684             *srw_pdu = sr;
685             yaz_srw_decodeauth(sr, hreq, username, password, decode);
686
687             if (scanClause)
688             {
689                 sr->u.scan_request->query_type = Z_SRW_query_type_cql;
690                 sr->u.scan_request->scanClause.cql = scanClause;
691             }
692             else if (pScanClause)
693             {
694                 sr->u.scan_request->query_type = Z_SRW_query_type_pqf;
695                 sr->u.scan_request->scanClause.pqf = pScanClause;
696             }
697             else
698                 yaz_add_srw_diagnostic(
699                     decode, diag, num_diag, 
700                     YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED, "scanClause");
701             sr->u.scan_request->database = db;
702             
703             yaz_sru_decode_integer(decode, "maximumTerms",
704                                    maximumTerms, 
705                                    &sr->u.scan_request->maximumTerms,
706                                    diag, num_diag, 0);
707             
708             yaz_sru_decode_integer(decode, "responsePosition",
709                                    responsePosition, 
710                                    &sr->u.scan_request->responsePosition,
711                                    diag, num_diag, 0);
712
713             sr->u.scan_request->stylesheet = stylesheet;
714
715             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
716             (*soap_package)->which = Z_SOAP_generic;
717             
718             (*soap_package)->u.generic =
719                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
720             
721             (*soap_package)->u.generic->p = sr;
722             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
723             (*soap_package)->u.generic->no = 0;
724             
725             (*soap_package)->ns = "SRU";
726
727             return 0;
728         }
729         else
730         {
731             /* unsupported operation ... */
732             /* Act as if we received a explain request and throw diagnostic. */
733
734             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
735
736             sr->srw_version = version;
737             *srw_pdu = sr;
738             sr->u.explain_request->recordPacking = recordPacking;
739             sr->u.explain_request->database = db;
740
741             sr->u.explain_request->stylesheet = stylesheet;
742
743             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
744             (*soap_package)->which = Z_SOAP_generic;
745             
746             (*soap_package)->u.generic =
747                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
748             
749             (*soap_package)->u.generic->p = sr;
750             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
751             (*soap_package)->u.generic->no = 0;
752             
753             (*soap_package)->ns = "SRU";
754
755             yaz_add_srw_diagnostic(decode, diag, num_diag, 
756                                    YAZ_SRW_UNSUPP_OPERATION, operation);
757             return 0;
758         }
759 #endif
760         return 1;
761     }
762     return 2;
763 }
764
765 Z_SRW_extra_record *yaz_srw_get_extra_record(ODR o)
766 {
767     Z_SRW_extra_record *res = (Z_SRW_extra_record *)
768         odr_malloc(o, sizeof(*res));
769
770     res->extraRecordData_buf = 0;
771     res->extraRecordData_len = 0;
772     res->recordIdentifier = 0;
773     return res;
774 }
775
776
777 Z_SRW_record *yaz_srw_get_records(ODR o, int n)
778 {
779     Z_SRW_record *res = (Z_SRW_record *) odr_malloc(o, n * sizeof(*res));
780     int i;
781
782     for (i = 0; i<n; i++)
783     {
784         res[i].recordSchema = 0;
785         res[i].recordPacking = Z_SRW_recordPacking_string;
786         res[i].recordData_buf = 0;
787         res[i].recordData_len = 0;
788         res[i].recordPosition = 0;
789     }
790     return res;
791 }
792
793 Z_SRW_record *yaz_srw_get_record(ODR o)
794 {
795     return yaz_srw_get_records(o, 1);
796 }
797
798 Z_SRW_PDU *yaz_srw_get_core_v_1_1(ODR o)
799 {
800     Z_SRW_PDU *p = (Z_SRW_PDU *) odr_malloc(o, sizeof(*p));
801     p->srw_version = odr_strdup(o, "1.1");
802     p->username = 0;
803     p->password = 0;
804     p->extra_args = 0;
805     return p;
806 }
807
808 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
809 {
810     Z_SRW_PDU *sr = yaz_srw_get_core_v_1_1(o);
811     sr->which = which;
812     switch(which)
813     {
814     case Z_SRW_searchRetrieve_request:
815         sr->u.request = (Z_SRW_searchRetrieveRequest *)
816             odr_malloc(o, sizeof(*sr->u.request));
817         sr->u.request->query_type = Z_SRW_query_type_cql;
818         sr->u.request->query.cql = 0;
819         sr->u.request->sort_type = Z_SRW_sort_type_none;
820         sr->u.request->sort.none = 0;
821         sr->u.request->startRecord = 0;
822         sr->u.request->maximumRecords = 0;
823         sr->u.request->recordSchema = 0;
824         sr->u.request->recordPacking = 0;
825         sr->u.request->recordXPath = 0;
826         sr->u.request->database = 0;
827         sr->u.request->resultSetTTL = 0;
828         sr->u.request->stylesheet = 0;
829         break;
830     case Z_SRW_searchRetrieve_response:
831         sr->u.response = (Z_SRW_searchRetrieveResponse *)
832             odr_malloc(o, sizeof(*sr->u.response));
833         sr->u.response->numberOfRecords = 0;
834         sr->u.response->resultSetId = 0;
835         sr->u.response->resultSetIdleTime = 0;
836         sr->u.response->records = 0;
837         sr->u.response->num_records = 0;
838         sr->u.response->diagnostics = 0;
839         sr->u.response->num_diagnostics = 0;
840         sr->u.response->nextRecordPosition = 0;
841         sr->u.response->extra_records = 0;
842         break;
843     case Z_SRW_explain_request:
844         sr->u.explain_request = (Z_SRW_explainRequest *)
845             odr_malloc(o, sizeof(*sr->u.explain_request));
846         sr->u.explain_request->recordPacking = 0;
847         sr->u.explain_request->database = 0;
848         sr->u.explain_request->stylesheet = 0;
849         break;
850     case Z_SRW_explain_response:
851         sr->u.explain_response = (Z_SRW_explainResponse *)
852             odr_malloc(o, sizeof(*sr->u.explain_response));
853         sr->u.explain_response->record.recordData_buf = 0;
854         sr->u.explain_response->record.recordData_len = 0;
855         sr->u.explain_response->record.recordSchema = 0;
856         sr->u.explain_response->record.recordPosition = 0;
857         sr->u.explain_response->record.recordPacking =
858             Z_SRW_recordPacking_string;
859         sr->u.explain_response->diagnostics = 0;
860         sr->u.explain_response->num_diagnostics = 0;
861         sr->u.explain_response->extra_record = 0;
862         break;
863     case Z_SRW_scan_request:
864         sr->u.scan_request = (Z_SRW_scanRequest *)
865             odr_malloc(o, sizeof(*sr->u.scan_request));
866         sr->u.scan_request->database = 0;
867         sr->u.scan_request->stylesheet = 0;
868         sr->u.scan_request->maximumTerms = 0;
869         sr->u.scan_request->responsePosition = 0;
870         sr->u.scan_request->query_type = Z_SRW_query_type_cql;
871         sr->u.scan_request->scanClause.cql = 0;
872         break;
873     case Z_SRW_scan_response:
874         sr->u.scan_response = (Z_SRW_scanResponse *)
875             odr_malloc(o, sizeof(*sr->u.scan_response));
876         sr->u.scan_response->terms = 0;
877         sr->u.scan_response->num_terms = 0;
878         sr->u.scan_response->diagnostics = 0;
879         sr->u.scan_response->num_diagnostics = 0;
880         break;
881     case Z_SRW_update_request:
882         sr->u.update_request = (Z_SRW_updateRequest *)
883             odr_malloc(o, sizeof(*sr->u.update_request));
884         sr->u.update_request->database = 0;
885         sr->u.update_request->stylesheet = 0;
886         sr->u.update_request->record = 0;
887         sr->u.update_request->recordId = 0;
888         sr->u.update_request->recordVersions = 0;
889         sr->u.update_request->num_recordVersions = 0;
890         sr->u.update_request->extra_record = 0;
891         sr->u.update_request->extraRequestData_buf = 0;
892         sr->u.update_request->extraRequestData_len = 0;
893         sr->u.request->database = 0;
894         break;
895     case Z_SRW_update_response:
896         sr->u.update_response = (Z_SRW_updateResponse *)
897             odr_malloc(o, sizeof(*sr->u.update_response));
898         sr->u.update_response->operationStatus = 0;
899         sr->u.update_response->recordId = 0;
900         sr->u.update_response->recordVersions = 0;
901         sr->u.update_response->num_recordVersions = 0;
902         sr->u.update_response->record = 0;
903         sr->u.update_response->extra_record = 0;
904         sr->u.update_response->extraResponseData_buf = 0;
905         sr->u.update_response->extraResponseData_len = 0;
906         sr->u.update_response->diagnostics = 0;
907         sr->u.update_response->num_diagnostics = 0;
908     }
909     return sr;
910 }
911
912 /* bib1:srw */
913 static int srw_bib1_map[] = {
914     1, 1,
915     2, 2,
916     3, 11,
917     4, 35,
918     5, 12,
919     6, 38,
920     7, 30,
921     8, 32,
922     9, 29,
923     108, 10,  /* Malformed query : Syntax error */
924     10, 10,
925     11, 12,
926     11, 23,
927     12, 60,
928     13, 61,
929     13, 62,
930     14, 63,
931     14, 64,
932     14, 65,
933     15, 68,
934     15, 69,
935     16, 70,
936     17, 70,
937     18, 50,
938     19, 55,
939     20, 56, 
940     21, 52,
941     22, 50,
942     23, 3,
943     24, 66,
944     25, 66,
945     26, 66,
946     27, 51,
947     28, 52,
948     29, 52,
949     30, 51,
950     31, 57,
951     32, 58,
952     33, 59,
953     100, 1, /* bad map */
954     101, 3,
955     102, 3,
956     103, 3,
957     104, 3,
958     105, 3, 
959     106, 66,
960     107, 11,
961     108, 13,
962     108, 14,
963     108, 25,
964     108, 26,
965     108, 27,
966     108, 45,
967         
968     109, 2,
969     110, 37,
970     111, 1,
971     112, 58,
972     113, 10,
973     114, 16,
974     115, 16,
975     116, 16,
976     117, 19,
977     117, 20,
978     118, 22,
979     119, 32,
980     119, 31,
981     120, 28,
982     121, 15,
983     122, 32,
984     123, 22,
985     123, 17,
986     123, 18,
987     124, 24,
988     125, 36,
989     126, 36, 
990     127, 36,
991     128, 51,
992     129, 39,
993     130, 43,
994     131, 40,
995     132, 42,
996     201, 44,
997     201, 33,
998     201, 34,
999     202, 41,
1000     203, 43,
1001     205, 1,  /* bad map */
1002     206, 1,  /* bad map */
1003     207, 89,
1004     208, 1,  /* bad map */
1005     209, 80,
1006     210, 80,
1007     210, 81,
1008     211, 84,
1009     212, 85,
1010     213, 92,
1011     214, 90,
1012     215, 91,
1013     216, 92,
1014     217, 63,
1015     218, 1,  /* bad map */
1016     219, 1,  /* bad map */
1017     220, 1,  /* bad map */
1018     221, 1,  /* bad map */
1019     222, 3,
1020     223, 1,  /* bad map */
1021     224, 1,  /* bad map */
1022     225, 1,  /* bad map */
1023     226, 1,  /* bad map */
1024     227, 66,
1025     228, 1,  /* bad map */
1026     229, 36,
1027     230, 83,
1028     231, 89,
1029     232, 1,
1030     233, 1, /* bad map */
1031     234, 1, /* bad map */
1032     235, 2,
1033     236, 3, 
1034     237, 82,
1035     238, 67,
1036     239, 66,
1037     240, 1, /* bad map */
1038     241, 1, /* bad map */
1039     242, 70,
1040     243, 1, /* bad map */
1041     244, 66,
1042     245, 10,
1043     246, 10,
1044     247, 10,
1045     1001, 1, /* bad map */
1046     1002, 1, /* bad map */
1047     1003, 1, /* bad map */
1048     1004, 1, /* bad map */
1049     1005, 1, /* bad map */
1050     1006, 1, /* bad map */
1051     1007, 100,
1052     1008, 1, 
1053     1009, 1,
1054     1010, 3,
1055     1011, 3,
1056     1012, 3,
1057     1013, 3,
1058     1014, 3,
1059     1015, 3,
1060     1015, 3,
1061     1016, 3,
1062     1017, 3,
1063     1018, 2,
1064     1019, 2,
1065     1020, 2,
1066     1021, 3,
1067     1022, 3,
1068     1023, 3,
1069     1024, 16,
1070     1025, 3,
1071     1026, 64,
1072     1027, 1,
1073     1028, 65,
1074     1029, 1,
1075     1040, 1,
1076     /* 1041-1065 */
1077     1066, 66,
1078     1066, 67,
1079     0
1080 };
1081
1082 int yaz_diag_bib1_to_srw (int code)
1083 {
1084     const int *p = srw_bib1_map;
1085     while (*p)
1086     {
1087         if (code == p[0])
1088             return p[1];
1089         p += 2;
1090     }
1091     return 1;
1092 }
1093
1094 int yaz_diag_srw_to_bib1(int code)
1095 {
1096     const int *p = srw_bib1_map;
1097     while (*p)
1098     {
1099         if (code == p[1])
1100             return p[0];
1101         p += 2;
1102     }
1103     return 1;
1104 }
1105
1106 static void add_val_int(ODR o, char **name, char **value,  int *i,
1107                         char *a_name, int *val)
1108 {
1109     if (val)
1110     {
1111         name[*i] = a_name;
1112         value[*i] = odr_malloc(o, 30);
1113         sprintf(value[*i], "%d", *val);
1114         (*i)++;
1115     }
1116 }
1117
1118 static void add_val_str(ODR o, char **name, char **value,  int *i,
1119                         char *a_name, char *val)
1120 {
1121     if (val)
1122     {
1123         name[*i] = a_name;
1124         value[*i] = val;
1125         (*i)++;
1126     }
1127 }
1128
1129 static int yaz_get_sru_parms(const Z_SRW_PDU *srw_pdu, ODR encode,
1130                               char **name, char **value)
1131 {
1132     int i = 0;
1133     add_val_str(encode, name, value, &i, "version", srw_pdu->srw_version);
1134     name[i] = "operation";
1135     switch(srw_pdu->which)
1136     {
1137     case Z_SRW_searchRetrieve_request:
1138         value[i++] = "searchRetrieve";
1139         switch(srw_pdu->u.request->query_type)
1140         {
1141         case Z_SRW_query_type_cql:
1142             add_val_str(encode, name, value, &i, "query",
1143                         srw_pdu->u.request->query.cql);
1144             break;
1145         case Z_SRW_query_type_pqf:
1146             add_val_str(encode, name, value, &i, "x-pquery",
1147                         srw_pdu->u.request->query.pqf);
1148             break;
1149         case Z_SRW_query_type_xcql:
1150             add_val_str(encode, name, value, &i, "x-cql",
1151                         srw_pdu->u.request->query.xcql);
1152             break;
1153         }
1154         switch(srw_pdu->u.request->sort_type)
1155         {
1156         case Z_SRW_sort_type_none:
1157             break;
1158         case Z_SRW_sort_type_sort:            
1159             add_val_str(encode, name, value, &i, "sortKeys",
1160                         srw_pdu->u.request->sort.sortKeys);
1161             break;
1162         }
1163         add_val_int(encode, name, value, &i, "startRecord", 
1164                     srw_pdu->u.request->startRecord);
1165         add_val_int(encode, name, value, &i, "maximumRecords", 
1166                     srw_pdu->u.request->maximumRecords);
1167         add_val_str(encode, name, value, &i, "recordSchema",
1168                     srw_pdu->u.request->recordSchema);
1169         add_val_str(encode, name, value, &i, "recordPacking",
1170                     srw_pdu->u.request->recordPacking);
1171         add_val_str(encode, name, value, &i, "recordXPath",
1172                     srw_pdu->u.request->recordXPath);
1173         add_val_str(encode, name, value, &i, "stylesheet",
1174                     srw_pdu->u.request->stylesheet);
1175         add_val_int(encode, name, value, &i, "resultSetTTL", 
1176                     srw_pdu->u.request->resultSetTTL);
1177         break;
1178     case Z_SRW_explain_request:
1179         value[i++] = "explain";
1180         add_val_str(encode, name, value, &i, "stylesheet",
1181                     srw_pdu->u.explain_request->stylesheet);
1182         break;
1183     case Z_SRW_scan_request:
1184         value[i++] = "scan";
1185
1186         switch(srw_pdu->u.scan_request->query_type)
1187         {
1188         case Z_SRW_query_type_cql:
1189             add_val_str(encode, name, value, &i, "scanClause",
1190                         srw_pdu->u.scan_request->scanClause.cql);
1191             break;
1192         case Z_SRW_query_type_pqf:
1193             add_val_str(encode, name, value, &i, "x-pScanClause",
1194                         srw_pdu->u.scan_request->scanClause.pqf);
1195             break;
1196         case Z_SRW_query_type_xcql:
1197             add_val_str(encode, name, value, &i, "x-cqlScanClause",
1198                         srw_pdu->u.scan_request->scanClause.xcql);
1199             break;
1200         }
1201         add_val_int(encode, name, value, &i, "responsePosition", 
1202                     srw_pdu->u.scan_request->responsePosition);
1203         add_val_int(encode, name, value, &i, "maximumTerms", 
1204                     srw_pdu->u.scan_request->maximumTerms);
1205         add_val_str(encode, name, value, &i, "stylesheet",
1206                     srw_pdu->u.scan_request->stylesheet);
1207         break;
1208     case Z_SRW_update_request:
1209         value[i++] = "update";
1210         break;
1211     default:
1212         return -1;
1213     }
1214     name[i++] = 0;
1215     return 0;
1216 }
1217
1218 int yaz_sru_get_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1219                        ODR encode, const char *charset)
1220 {
1221     char *name[30], *value[30]; /* definite upper limit for SRU params */
1222     char *uri_args;
1223     char *path;
1224
1225     if (yaz_get_sru_parms(srw_pdu, encode, name, value))
1226         return -1;
1227     yaz_array_to_uri_ex(&uri_args, encode, name, value, srw_pdu->extra_args);
1228
1229     hreq->method = "GET";
1230     
1231     path = odr_malloc(encode, strlen(hreq->path) + strlen(uri_args) + 4
1232                       +(srw_pdu->extra_args ? strlen(srw_pdu->extra_args) : 0)
1233         );
1234     sprintf(path, "%s?%s", hreq->path, uri_args);
1235     hreq->path = path;
1236
1237     z_HTTP_header_add_content_type(encode, &hreq->headers,
1238                                    "text/xml", charset);
1239     return 0;
1240 }
1241
1242 int yaz_sru_post_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1243                         ODR encode, const char *charset)
1244 {
1245     char *name[30], *value[30]; /* definite upper limit for SRU params */
1246     char *uri_args;
1247
1248     if (yaz_get_sru_parms(srw_pdu, encode, name, value))
1249         return -1;
1250
1251     yaz_array_to_uri_ex(&uri_args, encode, name, value, srw_pdu->extra_args);
1252
1253     hreq->method = "POST";
1254     
1255     hreq->content_buf = uri_args;
1256     hreq->content_len = strlen(uri_args);
1257
1258     z_HTTP_header_add_content_type(encode, &hreq->headers,
1259                                    "application/x-www-form-urlencoded",
1260                                    charset);
1261     return 0;
1262 }
1263
1264 int yaz_sru_soap_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1265                         ODR odr, const char *charset)
1266 {
1267     Z_SOAP_Handler handlers[3] = {
1268 #if YAZ_HAVE_XML2
1269         {YAZ_XMLNS_SRU_v1_1, 0, (Z_SOAP_fun) yaz_srw_codec},
1270         {YAZ_XMLNS_UPDATE_v0_9, 0, (Z_SOAP_fun) yaz_ucp_codec},
1271 #endif
1272         {0, 0, 0}
1273     };
1274     Z_SOAP *p = (Z_SOAP*) odr_malloc(odr, sizeof(*p));
1275
1276     z_HTTP_header_add_content_type(odr,
1277                                    &hreq->headers,
1278                                    "text/xml", charset);
1279     
1280     z_HTTP_header_add(odr, &hreq->headers,
1281                       "SOAPAction", "\"\"");
1282     p->which = Z_SOAP_generic;
1283     p->u.generic = (Z_SOAP_Generic *) odr_malloc(odr, sizeof(*p->u.generic));
1284     p->u.generic->no = 0;
1285     p->u.generic->ns = 0;
1286     p->u.generic->p = srw_pdu;
1287     p->ns = "http://schemas.xmlsoap.org/soap/envelope/";
1288
1289 #if YAZ_HAVE_XML2
1290     if (srw_pdu->which == Z_SRW_update_request ||
1291         srw_pdu->which == Z_SRW_update_response)
1292         p->u.generic->no = 1; /* second handler */
1293 #endif
1294     return z_soap_codec_enc(odr, &p,
1295                             &hreq->content_buf,
1296                             &hreq->content_len, handlers,
1297                             charset);
1298 }
1299
1300 Z_SRW_recordVersion *yaz_srw_get_record_versions(ODR odr, int num )
1301 {
1302     Z_SRW_recordVersion *ver 
1303         = (Z_SRW_recordVersion *) odr_malloc( odr, num * sizeof(*ver) );
1304     int i;
1305     for ( i=0; i < num; ++i ){
1306         ver[i].versionType = 0;
1307         ver[i].versionValue = 0;
1308     }
1309     return ver;
1310 }
1311
1312 const char *yaz_srw_pack_to_str(int pack)
1313 {
1314     switch(pack)
1315     {
1316     case Z_SRW_recordPacking_string:
1317         return "string";
1318     case Z_SRW_recordPacking_XML:
1319         return "xml";
1320     case Z_SRW_recordPacking_URL:
1321         return "url";
1322     }
1323     return 0;
1324 }
1325
1326 int yaz_srw_str_to_pack(const char *str)
1327 {
1328     if (!strcmp(str, "string"))
1329         return Z_SRW_recordPacking_string;
1330     if (!strcmp(str, "xml"))
1331         return Z_SRW_recordPacking_XML;
1332     if (!strcmp(str, "url"))
1333         return Z_SRW_recordPacking_URL;
1334     return -1;
1335 }
1336
1337 /*
1338  * Local variables:
1339  * c-basic-offset: 4
1340  * indent-tabs-mode: nil
1341  * End:
1342  * vim: shiftwidth=4 tabstop=8 expandtab
1343  */
1344