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