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