Accept application/soap+xml as content-type for SOAP msg
[yaz-moved-to-github.git] / src / srwutil.c
1 /*
2  * Copyright (C) 1995-2005, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: srwutil.c,v 1.37 2006-03-22 13:03:59 adam Exp $
6  */
7 /**
8  * \file srwutil.c
9  * \brief Implements SRW/SRU utilities.
10  */
11
12 #include <stdlib.h>
13 #include <yaz/srw.h>
14 #include <yaz/yaz-iconv.h>
15
16 static int hex_digit (int ch)
17 {
18     if (ch >= '0' && ch <= '9')
19         return ch - '0';
20     else if (ch >= 'a' && ch <= 'f')
21         return ch - 'a'+10;
22     else if (ch >= 'A' && ch <= 'F')
23         return ch - 'A'+10;
24     return 0;
25 }
26
27 void encode_uri_char(char *dst, char ch)
28 {
29     if (ch == ' ')
30         strcpy(dst, "+");
31     else if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
32         (ch >= '0' && ch <= '9'))
33     {
34         dst[0] = ch;
35         dst[1] = '\0';
36     }
37     else
38     {
39         dst[0] = '%';
40         sprintf(dst+1, "%02X", (unsigned char ) ch);
41     }
42 }
43
44 void yaz_array_to_uri(char **path, ODR o, char **name, char **value)
45 {
46     size_t i, szp = 0, sz = 0;
47     for(i = 0; name[i]; i++)
48         sz += strlen(name[i]) + 3 + strlen(value[i]) * 3;
49     *path = odr_malloc(o, sz);
50     
51     for(i = 0; name[i]; i++)
52     {
53         size_t j, ilen;
54         if (i)
55             (*path)[szp++] = '&';
56         ilen = strlen(name[i]);
57         memcpy(*path+szp, name[i], ilen);
58         szp += ilen;
59         (*path)[szp++] = '=';
60         for (j = 0; value[i][j]; j++)
61         {
62             size_t vlen;
63             char vstr[5];
64             encode_uri_char(vstr, value[i][j]);
65             vlen = strlen(vstr);
66             memcpy(*path+szp, vstr, vlen);
67             szp += vlen;
68         }
69     }
70     (*path)[szp] = '\0';
71 }
72
73 int yaz_uri_array(const char *path, ODR o, char ***name, char ***val)
74 {
75     int no = 2;
76     const char *cp;
77     *name = 0;
78     if (*path == '?')
79         path++;
80     if (!*path)
81         return 0;
82     cp = path;
83     while ((cp = strchr(cp, '&')))
84     {
85         cp++;
86         no++;
87     }
88     *name = odr_malloc(o, no * sizeof(char*));
89     *val = odr_malloc(o, no * sizeof(char*));
90
91     for (no = 0; *path; no++)
92     {
93         const char *p1 = strchr(path, '=');
94         size_t i = 0;
95         char *ret;
96         if (!p1)
97             break;
98
99         (*name)[no] = odr_malloc(o, (p1-path)+1);
100         memcpy((*name)[no], path, p1-path);
101         (*name)[no][p1-path] = '\0';
102
103         path = p1 + 1;
104         p1 = strchr(path, '&');
105         if (!p1)
106             p1 = strlen(path) + path;
107         (*val)[no] = ret = odr_malloc(o, p1 - path + 1);
108         while (*path && *path != '&')
109         {
110             if (*path == '+')
111             {
112                 ret[i++] = ' ';
113                 path++;
114             }
115             else if (*path == '%' && path[1] && path[2])
116             {
117                 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
118                 path = path + 3;
119             }
120             else
121                 ret[i++] = *path++;
122         }
123         ret[i] = '\0';
124
125         if (*path)
126             path++;
127     }
128     (*name)[no] = 0;
129     (*val)[no] = 0;
130     return no;
131 }
132
133 char *yaz_uri_val(const char *path, const char *name, ODR o)
134 {
135     size_t nlen = strlen(name);
136     if (*path != '?')
137         return 0;
138     path++;
139     while (path && *path)
140     {
141         const char *p1 = strchr(path, '=');
142         if (!p1)
143             break;
144         if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
145         {
146             size_t i = 0;
147             char *ret;
148             
149             path = p1 + 1;
150             p1 = strchr(path, '&');
151             if (!p1)
152                 p1 = strlen(path) + path;
153             ret = (char *) odr_malloc(o, p1 - path + 1);
154             while (*path && *path != '&')
155             {
156                 if (*path == '+')
157                 {
158                     ret[i++] = ' ';
159                     path++;
160                 }
161                 else if (*path == '%' && path[1] && path[2])
162                 {
163                     ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
164                     path = path + 3;
165                 }
166                 else
167                     ret[i++] = *path++;
168             }
169             ret[i] = '\0';
170             return ret;
171         }
172         path = strchr(p1, '&');
173         if (path)
174             path++;
175     }
176     return 0;
177 }
178
179 void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
180 {
181     const char *v = yaz_uri_val(path, name, o);
182     if (v)
183         *intp = odr_intdup(o, atoi(v));
184 }
185
186 void yaz_mk_srw_diagnostic(ODR o, Z_SRW_diagnostic *d, 
187                            const char *uri, const char *message,
188                            const char *details)
189 {
190     d->uri = odr_strdup(o, uri);
191     if (message)
192         d->message = odr_strdup(o, message);
193     else
194         d->message = 0;
195     if (details)
196         d->details = odr_strdup(o, details);
197     else
198         d->details = 0;
199 }
200
201 void yaz_mk_std_diagnostic(ODR o, Z_SRW_diagnostic *d, 
202                            int code, const char *details)
203 {
204     char uri[40];
205     
206     sprintf(uri, "info:srw/diagnostic/1/%d", code);
207     yaz_mk_srw_diagnostic(o, d, uri, 0, details);
208 }
209
210 void yaz_add_srw_diagnostic_uri(ODR o, Z_SRW_diagnostic **d,
211                                 int *num, const char *uri,
212                                 const char *message, const char *details)
213 {
214     Z_SRW_diagnostic *d_new;
215     d_new = (Z_SRW_diagnostic *) odr_malloc (o, (*num + 1)* sizeof(**d));
216     if (*num)
217         memcpy (d_new, *d, *num *sizeof(**d));
218     *d = d_new;
219
220     yaz_mk_srw_diagnostic(o, *d + *num, uri, message, details);
221     (*num)++;
222 }
223
224 void yaz_add_srw_diagnostic(ODR o, Z_SRW_diagnostic **d,
225                             int *num, int code, const char *addinfo)
226 {
227     char uri[40];
228     
229     sprintf(uri, "info:srw/diagnostic/1/%d", code);
230     yaz_add_srw_diagnostic_uri(o, d, num, uri, 0, addinfo);
231 }
232
233 int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
234                    Z_SOAP **soap_package, ODR decode, char **charset)
235 {
236     if (!strcmp(hreq->method, "POST"))
237     {
238         const char *content_type = z_HTTP_header_lookup(hreq->headers,
239                                                         "Content-Type");
240         if (content_type && 
241             (!yaz_strcmp_del("text/xml", content_type, "; ") ||
242              !yaz_strcmp_del("application/soap+xml", content_type, "; ") ||
243              !yaz_strcmp_del("text/plain", content_type, "; ")))
244         {
245             char *db = "Default";
246             const char *p0 = hreq->path, *p1;
247             int ret = -1;
248             const char *charset_p = 0;
249             
250             static Z_SOAP_Handler soap_handlers[4] = {
251 #if HAVE_XML2
252                 {"http://www.loc.gov/zing/srw/", 0,
253                  (Z_SOAP_fun) yaz_srw_codec},
254                 {"http://www.loc.gov/zing/srw/v1.0/", 0,
255                  (Z_SOAP_fun) yaz_srw_codec},
256                 {"http://www.loc.gov/zing/srw/update/", 0,
257                  (Z_SOAP_fun) yaz_ucp_codec},
258 #endif
259                 {0, 0, 0}
260             };
261             
262             if (*p0 == '/')
263                 p0++;
264             p1 = strchr(p0, '?');
265             if (!p1)
266                 p1 = p0 + strlen(p0);
267             if (p1 != p0)
268             {
269                 db = (char*) odr_malloc(decode, p1 - p0 + 1);
270                 memcpy (db, p0, p1 - p0);
271                 db[p1 - p0] = '\0';
272             }
273
274             if (charset && (charset_p = strstr(content_type, "; charset=")))
275             {
276                 int i = 0;
277                 charset_p += 10;
278                 while (i < 20 && charset_p[i] &&
279                        !strchr("; \n\r", charset_p[i]))
280                     i++;
281                 *charset = (char*) odr_malloc(decode, i+1);
282                 memcpy(*charset, charset_p, i);
283                 (*charset)[i] = '\0';
284             }
285             ret = z_soap_codec(decode, soap_package, 
286                                &hreq->content_buf, &hreq->content_len,
287                                soap_handlers);
288             if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
289             {
290                 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
291                 
292                 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
293                     (*srw_pdu)->u.request->database == 0)
294                     (*srw_pdu)->u.request->database = db;
295
296                 if ((*srw_pdu)->which == Z_SRW_explain_request &&
297                     (*srw_pdu)->u.explain_request->database == 0)
298                     (*srw_pdu)->u.explain_request->database = db;
299
300                 if ((*srw_pdu)->which == Z_SRW_scan_request &&
301                     (*srw_pdu)->u.scan_request->database == 0)
302                     (*srw_pdu)->u.scan_request->database = db;
303
304                 if ((*srw_pdu)->which == Z_SRW_update_request &&
305                     (*srw_pdu)->u.update_request->database == 0)
306                     (*srw_pdu)->u.update_request->database = db;
307
308                 return 0;
309             }
310             return 1;
311         }
312     }
313     return 2;
314 }
315
316 /**
317   http://www.loc.gov/z3950/agency/zing/srw/service.html
318 */ 
319 int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
320                    Z_SOAP **soap_package, ODR decode, char **charset,
321                    Z_SRW_diagnostic **diag, int *num_diag)
322 {
323 #if HAVE_XML2
324     static Z_SOAP_Handler soap_handlers[2] = {
325         {"http://www.loc.gov/zing/srw/", 0,
326          (Z_SOAP_fun) yaz_srw_codec},
327         {0, 0, 0}
328     };
329 #endif
330     const char *content_type = z_HTTP_header_lookup(hreq->headers,
331                                                     "Content-Type");
332     /*
333       SRU GET: allow any content type.
334       SRU POST: we support "application/x-www-form-urlencoded";
335       not  "multipart/form-data" .
336     */
337     if (!strcmp(hreq->method, "GET") 
338         ||
339         (!strcmp(hreq->method, "POST") 
340          && content_type &&
341          !yaz_strcmp_del("application/x-www-form-urlencoded",
342                          content_type, "; ")
343             )
344         )
345     {
346         char *db = "Default";
347         const char *p0 = hreq->path, *p1;
348 #if HAVE_XML2
349         const char *operation = 0;
350         char *version = 0;
351         char *query = 0;
352         char *pQuery = 0;
353         char *sortKeys = 0;
354         char *stylesheet = 0;
355         char *scanClause = 0;
356         char *pScanClause = 0;
357         char *recordXPath = 0;
358         char *recordSchema = 0;
359         char *recordPacking = "xml";  /* xml packing is default for SRU */
360         char *maximumRecords = 0;
361         char *startRecord = 0;
362         char *maximumTerms = 0;
363         char *responsePosition = 0;
364         char *extraRequestData = 0;
365 #endif
366         char **uri_name;
367         char **uri_val;
368
369         if (charset)
370             *charset = 0;
371         if (*p0 == '/')
372             p0++;
373         p1 = strchr(p0, '?');
374         if (!p1)
375             p1 = p0 + strlen(p0);
376         if (p1 != p0)
377         {
378             db = (char*) odr_malloc(decode, p1 - p0 + 1);
379             memcpy (db, p0, p1 - p0);
380             db[p1 - p0] = '\0';
381         }
382         if (!strcmp(hreq->method, "POST"))
383             p1 = hreq->content_buf;
384         yaz_uri_array(p1, decode, &uri_name, &uri_val);
385 #if HAVE_XML2
386         if (uri_name)
387         {
388             int i;
389             for (i = 0; uri_name[i]; i++)
390             {
391                 char *n = uri_name[i];
392                 char *v = uri_val[i];
393                 if (!strcmp(n, "query"))
394                     query = v;
395                 else if (!strcmp(n, "x-pquery"))
396                     pQuery = v;
397                 else if (!strcmp(n, "operation"))
398                     operation = v;
399                 else if (!strcmp(n, "stylesheet"))
400                     stylesheet = v;
401                 else if (!strcmp(n, "sortKeys"))
402                     sortKeys = v;
403                 else if (!strcmp(n, "recordXPath"))
404                     recordXPath = v;
405                 else if (!strcmp(n, "recordSchema"))
406                     recordSchema = v;
407                 else if (!strcmp(n, "recordPacking"))
408                     recordPacking = v;
409                 else if (!strcmp(n, "version"))
410                     version = v;
411                 else if (!strcmp(n, "scanClause"))
412                     scanClause = v;
413                 else if (!strcmp(n, "x-pScanClause"))
414                     pScanClause = v;
415                 else if (!strcmp(n, "maximumRecords"))
416                     maximumRecords = v;
417                 else if (!strcmp(n, "startRecord"))
418                     startRecord = v;
419                 else if (!strcmp(n, "maximumTerms"))
420                     maximumTerms = v;
421                 else if (!strcmp(n, "responsePosition"))
422                     responsePosition = v;
423                 else if (!strcmp(n, "extraRequestData"))
424                     extraRequestData = v;
425                 else
426                     yaz_add_srw_diagnostic(decode, diag, num_diag, 8, n);
427             }
428         }
429         if (!version)
430         {
431             if (uri_name)
432                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "version");
433             version = "1.1";
434         }
435         if (strcmp(version, "1.1"))
436             yaz_add_srw_diagnostic(decode, diag, num_diag, 5, "1.1");
437         if (!operation)
438         {
439             if (uri_name)
440                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "operation");
441             operation = "explain";
442         }
443         if (!strcmp(operation, "searchRetrieve"))
444         {
445             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
446
447             sr->srw_version = version;
448             *srw_pdu = sr;
449             if (query)
450             {
451                 sr->u.request->query_type = Z_SRW_query_type_cql;
452                 sr->u.request->query.cql = query;
453             }
454             else if (pQuery)
455             {
456                 sr->u.request->query_type = Z_SRW_query_type_pqf;
457                 sr->u.request->query.pqf = pQuery;
458             }
459             else
460                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "query");
461
462             if (sortKeys)
463             {
464                 sr->u.request->sort_type = Z_SRW_sort_type_sort;
465                 sr->u.request->sort.sortKeys = sortKeys;
466             }
467             sr->u.request->recordXPath = recordXPath;
468             sr->u.request->recordSchema = recordSchema;
469             sr->u.request->recordPacking = recordPacking;
470             sr->u.request->stylesheet = stylesheet;
471
472             if (maximumRecords)
473                 sr->u.request->maximumRecords =
474                     odr_intdup(decode, atoi(maximumRecords));
475             if (startRecord)
476                 sr->u.request->startRecord =
477                     odr_intdup(decode, atoi(startRecord));
478
479             sr->u.request->database = db;
480
481             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
482             (*soap_package)->which = Z_SOAP_generic;
483             
484             (*soap_package)->u.generic =
485                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
486             
487             (*soap_package)->u.generic->p = sr;
488             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
489             (*soap_package)->u.generic->no = 0;
490             
491             (*soap_package)->ns = "SRU";
492
493             return 0;
494         }
495         else if (!strcmp(operation, "explain"))
496         {
497             /* Transfer SRU explain parameters to common struct */
498             /* http://www.loc.gov/z3950/agency/zing/srw/explain.html */
499             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
500
501             sr->srw_version = version;
502             *srw_pdu = sr;
503             sr->u.explain_request->recordPacking = recordPacking;
504             sr->u.explain_request->database = db;
505
506             sr->u.explain_request->stylesheet = stylesheet;
507
508             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
509             (*soap_package)->which = Z_SOAP_generic;
510             
511             (*soap_package)->u.generic =
512                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
513             
514             (*soap_package)->u.generic->p = sr;
515             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
516             (*soap_package)->u.generic->no = 0;
517             
518             (*soap_package)->ns = "SRU";
519
520             return 0;
521         }
522         else if (!strcmp(operation, "scan"))
523         {
524             /* Transfer SRU scan parameters to common struct */
525             /* http://www.loc.gov/z3950/agency/zing/srw/scan.html */
526             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_scan_request);
527
528             sr->srw_version = version;
529             *srw_pdu = sr;
530
531             if (scanClause)
532             {
533                 sr->u.scan_request->query_type = Z_SRW_query_type_cql;
534                 sr->u.scan_request->scanClause.cql = scanClause;
535             }
536             else if (pScanClause)
537             {
538                 sr->u.scan_request->query_type = Z_SRW_query_type_pqf;
539                 sr->u.scan_request->scanClause.pqf = pScanClause;
540             }
541             else
542                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7,
543                                        "scanClause");
544             sr->u.scan_request->database = db;
545
546             if (maximumTerms)
547                 sr->u.scan_request->maximumTerms =
548                     odr_intdup(decode, atoi(maximumTerms));
549             if (responsePosition)
550                 sr->u.scan_request->responsePosition =
551                     odr_intdup(decode, atoi(responsePosition));
552
553             sr->u.scan_request->stylesheet = stylesheet;
554
555             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
556             (*soap_package)->which = Z_SOAP_generic;
557             
558             (*soap_package)->u.generic =
559                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
560             
561             (*soap_package)->u.generic->p = sr;
562             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
563             (*soap_package)->u.generic->no = 0;
564             
565             (*soap_package)->ns = "SRU";
566
567             return 0;
568         }
569         else
570         {
571             /* unsupported operation ... */
572             /* Act as if we received a explain request and throw diagnostic. */
573
574             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
575
576             sr->srw_version = version;
577             *srw_pdu = sr;
578             sr->u.explain_request->recordPacking = recordPacking;
579             sr->u.explain_request->database = db;
580
581             sr->u.explain_request->stylesheet = stylesheet;
582
583             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
584             (*soap_package)->which = Z_SOAP_generic;
585             
586             (*soap_package)->u.generic =
587                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
588             
589             (*soap_package)->u.generic->p = sr;
590             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
591             (*soap_package)->u.generic->no = 0;
592             
593             (*soap_package)->ns = "SRU";
594
595             yaz_add_srw_diagnostic(decode, diag, num_diag, 4, operation);
596             return 0;
597         }
598 #endif
599         return 1;
600     }
601     return 2;
602 }
603
604 Z_SRW_extra_record *yaz_srw_get_extra_record(ODR o)
605 {
606     Z_SRW_extra_record *res = (Z_SRW_extra_record *)
607         odr_malloc(o, sizeof(*res));
608     res->type = 1;
609     res->recordReviewCode = 0;
610     res->recordReviewNote = 0;
611     res->recordId = 0;
612     res->nonDupRecordId = 0;
613     res->recordLockStatus = 0;
614     res->recordOldVersion = 0;
615     return res;
616 }
617
618 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
619 {
620     Z_SRW_PDU *sr = (Z_SRW_PDU *) odr_malloc(o, sizeof(*o));
621
622     sr->srw_version = odr_strdup(o, "1.1");
623     sr->which = which;
624     switch(which)
625     {
626     case Z_SRW_searchRetrieve_request:
627         sr->u.request = (Z_SRW_searchRetrieveRequest *)
628             odr_malloc(o, sizeof(*sr->u.request));
629         sr->u.request->query_type = Z_SRW_query_type_cql;
630         sr->u.request->query.cql = 0;
631         sr->u.request->sort_type = Z_SRW_sort_type_none;
632         sr->u.request->sort.none = 0;
633         sr->u.request->startRecord = 0;
634         sr->u.request->maximumRecords = 0;
635         sr->u.request->recordSchema = 0;
636         sr->u.request->recordPacking = 0;
637         sr->u.request->recordXPath = 0;
638         sr->u.request->database = 0;
639         sr->u.request->resultSetTTL = 0;
640         sr->u.request->stylesheet = 0;
641         break;
642     case Z_SRW_searchRetrieve_response:
643         sr->u.response = (Z_SRW_searchRetrieveResponse *)
644             odr_malloc(o, sizeof(*sr->u.response));
645         sr->u.response->numberOfRecords = 0;
646         sr->u.response->resultSetId = 0;
647         sr->u.response->resultSetIdleTime = 0;
648         sr->u.response->records = 0;
649         sr->u.response->num_records = 0;
650         sr->u.response->diagnostics = 0;
651         sr->u.response->num_diagnostics = 0;
652         sr->u.response->nextRecordPosition = 0;
653         sr->u.response->extra_records = 0;
654         break;
655     case Z_SRW_explain_request:
656         sr->u.explain_request = (Z_SRW_explainRequest *)
657             odr_malloc(o, sizeof(*sr->u.explain_request));
658         sr->u.explain_request->recordPacking = 0;
659         sr->u.explain_request->database = 0;
660         sr->u.explain_request->stylesheet = 0;
661         break;
662     case Z_SRW_explain_response:
663         sr->u.explain_response = (Z_SRW_explainResponse *)
664             odr_malloc(o, sizeof(*sr->u.explain_response));
665         sr->u.explain_response->record.recordData_buf = 0;
666         sr->u.explain_response->record.recordData_len = 0;
667         sr->u.explain_response->record.recordSchema = 0;
668         sr->u.explain_response->record.recordPosition = 0;
669         sr->u.explain_response->record.recordPacking =
670             Z_SRW_recordPacking_string;
671         sr->u.explain_response->diagnostics = 0;
672         sr->u.explain_response->num_diagnostics = 0;
673         sr->u.explain_response->extra_record = 0;
674         break;
675     case Z_SRW_scan_request:
676         sr->u.scan_request = (Z_SRW_scanRequest *)
677             odr_malloc(o, sizeof(*sr->u.scan_request));
678         sr->u.scan_request->database = 0;
679         sr->u.scan_request->stylesheet = 0;
680         sr->u.scan_request->maximumTerms = 0;
681         sr->u.scan_request->responsePosition = 0;
682         sr->u.scan_request->query_type = Z_SRW_query_type_cql;
683         sr->u.scan_request->scanClause.cql = 0;
684         break;
685     case Z_SRW_scan_response:
686         sr->u.scan_response = (Z_SRW_scanResponse *)
687             odr_malloc(o, sizeof(*sr->u.scan_response));
688         sr->u.scan_response->terms = 0;
689         sr->u.scan_response->num_terms = 0;
690         sr->u.scan_response->diagnostics = 0;
691         sr->u.scan_response->num_diagnostics = 0;
692     case Z_SRW_update_request:
693         sr->u.update_request = (Z_SRW_updateRequest *)
694             odr_malloc(o, sizeof(*sr->u.update_request));
695         sr->u.update_request->database = 0;
696         sr->u.update_request->stylesheet = 0;
697         sr->u.update_request->record.recordSchema = 0;
698         sr->u.update_request->record.recordPacking = Z_SRW_recordPacking_XML;
699         sr->u.update_request->recordId = 0;
700         sr->u.update_request->recordVersion = 0;
701         sr->u.update_request->recordOldVersion = 0;
702         sr->u.update_request->record.recordData_buf = 0;
703         sr->u.update_request->record.recordData_len = 0;
704         sr->u.update_request->extra_record = 0;
705         sr->u.update_request->extraRequestData = 0;
706         sr->u.request->database = 0;
707         break;
708     case Z_SRW_update_response:
709         sr->u.update_response = (Z_SRW_updateResponse *)
710             odr_malloc(o, sizeof(*sr->u.update_response));
711         sr->u.update_response->operationStatus = 0;
712         sr->u.update_response->recordId = 0;
713         sr->u.update_response->recordVersion = 0;
714         sr->u.update_response->recordChecksum = 0;
715         sr->u.update_response->record.recordData_buf = 0;
716         sr->u.update_response->record.recordData_len = 0;
717         sr->u.update_response->record.recordSchema = 0;
718         sr->u.update_response->record.recordPacking =
719             Z_SRW_recordPacking_XML;
720         sr->u.update_response->extra_record = 0;
721         sr->u.update_response->extraResponseData = 0;
722         sr->u.update_response->diagnostics = 0;
723         sr->u.update_response->num_diagnostics = 0;
724     }
725     return sr;
726 }
727
728 /* bib1:srw */
729 static int srw_bib1_map[] = {
730     1, 1,
731     2, 2,
732     3, 11,
733     4, 35,
734     5, 12,
735     6, 38,
736     7, 30,
737     8, 32,
738     9, 29,
739     108, 10,  /* Malformed query : Syntax error */
740     10, 10,
741     11, 12,
742     11, 23,
743     12, 60,
744     13, 61,
745     13, 62,
746     14, 63,
747     14, 64,
748     14, 65,
749     15, 68,
750     15, 69,
751     16, 70,
752     17, 70,
753     18, 50,
754     19, 55,
755     20, 56, 
756     21, 52,
757     22, 50,
758     23, 3,
759     24, 66,
760     25, 66,
761     26, 66,
762     27, 51,
763     28, 52,
764     29, 52,
765     30, 51,
766     31, 57,
767     32, 58,
768     33, 59,
769     100, 1, /* bad map */
770     101, 3,
771     102, 3,
772     103, 3,
773     104, 3,
774     105, 3, 
775     106, 66,
776     107, 11,
777     108, 13,
778     108, 14,
779     108, 25,
780     108, 26,
781     108, 27,
782     108, 45,
783         
784     109, 2,
785     110, 37,
786     111, 1,
787     112, 58,
788     113, 10,
789     114, 16,
790     115, 16,
791     116, 16,
792     117, 19,
793     117, 20,
794     118, 22,
795     119, 32,
796     119, 31,
797     120, 28,
798     121, 15,
799     122, 32,
800     123, 22,
801     123, 17,
802     123, 18,
803     124, 24,
804     125, 36,
805     126, 36, 
806     127, 36,
807     128, 51,
808     129, 39,
809     130, 43,
810     131, 40,
811     132, 42,
812     201, 44,
813     201, 33,
814     201, 34,
815     202, 41,
816     203, 43,
817     205, 1,  /* bad map */
818     206, 1,  /* bad map */
819     207, 89,
820     208, 1,  /* bad map */
821     209, 80,
822     210, 80,
823     210, 81,
824     211, 84,
825     212, 85,
826     213, 92,
827     214, 90,
828     215, 91,
829     216, 92,
830     217, 63,
831     218, 1,  /* bad map */
832     219, 1,  /* bad map */
833     220, 1,  /* bad map */
834     221, 1,  /* bad map */
835     222, 3,
836     223, 1,  /* bad map */
837     224, 1,  /* bad map */
838     225, 1,  /* bad map */
839     226, 1,  /* bad map */
840     227, 66,
841     228, 1,  /* bad map */
842     229, 36,
843     230, 83,
844     231, 89,
845     232, 1,
846     233, 1, /* bad map */
847     234, 1, /* bad map */
848     235, 2,
849     236, 3, 
850     237, 82,
851     238, 67,
852     239, 66,
853     240, 1, /* bad map */
854     241, 1, /* bad map */
855     242, 70,
856     243, 1, /* bad map */
857     244, 66,
858     245, 10,
859     246, 10,
860     247, 10,
861     1001, 1, /* bad map */
862     1002, 1, /* bad map */
863     1003, 1, /* bad map */
864     1004, 1, /* bad map */
865     1005, 1, /* bad map */
866     1006, 1, /* bad map */
867     1007, 100,
868     1008, 1, 
869     1009, 1,
870     1010, 3,
871     1011, 3,
872     1012, 3,
873     1013, 3,
874     1014, 3,
875     1015, 3,
876     1015, 3,
877     1016, 3,
878     1017, 3,
879     1018, 2,
880     1019, 2,
881     1020, 2,
882     1021, 3,
883     1022, 3,
884     1023, 3,
885     1024, 16,
886     1025, 3,
887     1026, 64,
888     1027, 1,
889     1028, 65,
890     1029, 1,
891     1040, 1,
892     /* 1041-1065 */
893     1066, 66,
894     1066, 67,
895     0
896 };
897
898 int yaz_diag_bib1_to_srw (int code)
899 {
900     const int *p = srw_bib1_map;
901     while (*p)
902     {
903         if (code == p[0])
904             return p[1];
905         p += 2;
906     }
907     return 1;
908 }
909
910 int yaz_diag_srw_to_bib1(int code)
911 {
912     const int *p = srw_bib1_map;
913     while (*p)
914     {
915         if (code == p[1])
916             return p[0];
917         p += 2;
918     }
919     return 1;
920 }
921
922 static void add_val_int(ODR o, char **name, char **value,  int *i,
923                         char *a_name, int *val)
924 {
925     if (val)
926     {
927         name[*i] = a_name;
928         value[*i] = odr_malloc(o, 30);
929         sprintf(value[*i], "%d", *val);
930         (*i)++;
931     }
932 }
933
934 static void add_val_str(ODR o, char **name, char **value,  int *i,
935                         char *a_name, char *val)
936 {
937     if (val)
938     {
939         name[*i] = a_name;
940         value[*i] = val;
941         (*i)++;
942     }
943 }
944
945 static int yaz_get_sru_parms(const Z_SRW_PDU *srw_pdu, ODR encode,
946                               char **name, char **value)
947 {
948     int i = 0;
949     add_val_str(encode, name, value, &i, "version", srw_pdu->srw_version);
950     name[i] = "operation";
951     switch(srw_pdu->which)
952     {
953     case Z_SRW_searchRetrieve_request:
954         value[i++] = "searchRetrieve";
955         switch(srw_pdu->u.request->query_type)
956         {
957         case Z_SRW_query_type_cql:
958             add_val_str(encode, name, value, &i, "query",
959                         srw_pdu->u.request->query.cql);
960             break;
961         case Z_SRW_query_type_pqf:
962             add_val_str(encode, name, value, &i, "x-pquery",
963                         srw_pdu->u.request->query.pqf);
964             break;
965         case Z_SRW_query_type_xcql:
966             add_val_str(encode, name, value, &i, "x-cql",
967                         srw_pdu->u.request->query.xcql);
968             break;
969         }
970         switch(srw_pdu->u.request->sort_type)
971         {
972         case Z_SRW_sort_type_none:
973             break;
974         case Z_SRW_sort_type_sort:            
975             add_val_str(encode, name, value, &i, "sortKeys",
976                         srw_pdu->u.request->sort.sortKeys);
977             break;
978         }
979         add_val_int(encode, name, value, &i, "startRecord", 
980                     srw_pdu->u.request->startRecord);
981         add_val_int(encode, name, value, &i, "maximumRecords", 
982                     srw_pdu->u.request->maximumRecords);
983         add_val_str(encode, name, value, &i, "recordSchema",
984                     srw_pdu->u.request->recordSchema);
985         add_val_str(encode, name, value, &i, "recordPacking",
986                     srw_pdu->u.request->recordPacking);
987         add_val_str(encode, name, value, &i, "recordXPath",
988                     srw_pdu->u.request->recordXPath);
989         add_val_str(encode, name, value, &i, "stylesheet",
990                     srw_pdu->u.request->stylesheet);
991         add_val_int(encode, name, value, &i, "resultSetTTL", 
992                     srw_pdu->u.request->resultSetTTL);
993         break;
994     case Z_SRW_explain_request:
995         value[i++] = "explain";
996         add_val_str(encode, name, value, &i, "stylesheet",
997                     srw_pdu->u.explain_request->stylesheet);
998         break;
999     case Z_SRW_scan_request:
1000         value[i++] = "scan";
1001
1002         switch(srw_pdu->u.scan_request->query_type)
1003         {
1004         case Z_SRW_query_type_cql:
1005             add_val_str(encode, name, value, &i, "scanClause",
1006                         srw_pdu->u.scan_request->scanClause.cql);
1007             break;
1008         case Z_SRW_query_type_pqf:
1009             add_val_str(encode, name, value, &i, "x-pScanClause",
1010                         srw_pdu->u.scan_request->scanClause.pqf);
1011             break;
1012         case Z_SRW_query_type_xcql:
1013             add_val_str(encode, name, value, &i, "x-cqlScanClause",
1014                         srw_pdu->u.scan_request->scanClause.xcql);
1015             break;
1016         }
1017         add_val_int(encode, name, value, &i, "responsePosition", 
1018                     srw_pdu->u.scan_request->responsePosition);
1019         add_val_int(encode, name, value, &i, "maximumTerms", 
1020                     srw_pdu->u.scan_request->maximumTerms);
1021         add_val_str(encode, name, value, &i, "stylesheet",
1022                     srw_pdu->u.scan_request->stylesheet);
1023         break;
1024     case Z_SRW_update_request:
1025         value[i++] = "update";
1026         break;
1027     default:
1028         return -1;
1029     }
1030     name[i++] = 0;
1031     return 0;
1032 }
1033
1034 int yaz_sru_get_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1035                        ODR encode, char *charset)
1036 {
1037     char *name[30], *value[30]; /* definite upper limit for SRU params */
1038     char *uri_args;
1039     char *path;
1040
1041     if (yaz_get_sru_parms(srw_pdu, encode, name, value))
1042         return -1;
1043     yaz_array_to_uri(&uri_args, encode, name, value);
1044
1045     hreq->method = "GET";
1046     
1047     path = odr_malloc(encode, strlen(hreq->path) + strlen(uri_args) + 3);
1048     sprintf(path, "%s?%s", hreq->path, uri_args);
1049     hreq->path = path;
1050
1051     z_HTTP_header_add_content_type(encode, &hreq->headers,
1052                                    "text/xml", charset);
1053     return 0;
1054 }
1055
1056 int yaz_sru_post_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1057                         ODR encode, char *charset)
1058 {
1059     char *name[30], *value[30]; /* definite upper limit for SRU params */
1060     char *uri_args;
1061
1062     if (yaz_get_sru_parms(srw_pdu, encode, name, value))
1063         return -1;
1064
1065     yaz_array_to_uri(&uri_args, encode, name, value);
1066
1067     hreq->method = "POST";
1068     
1069     hreq->content_buf = uri_args;
1070     hreq->content_len = strlen(uri_args);
1071
1072     z_HTTP_header_add_content_type(encode, &hreq->headers,
1073                                    "application/x-www-form-urlencoded",
1074                                    charset);
1075     return 0;
1076 }
1077
1078 /*
1079  * Local variables:
1080  * c-basic-offset: 4
1081  * indent-tabs-mode: nil
1082  * End:
1083  * vim: shiftwidth=4 tabstop=8 expandtab
1084  */
1085