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