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