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