Fixed bug in yaz_srw_get: case Z_SRW_scan_response missed a break.
[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.38 2006-04-20 00:01:01 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         break;
693     case Z_SRW_update_request:
694         sr->u.update_request = (Z_SRW_updateRequest *)
695             odr_malloc(o, sizeof(*sr->u.update_request));
696         sr->u.update_request->database = 0;
697         sr->u.update_request->stylesheet = 0;
698         sr->u.update_request->record.recordSchema = 0;
699         sr->u.update_request->record.recordPacking = Z_SRW_recordPacking_XML;
700         sr->u.update_request->recordId = 0;
701         sr->u.update_request->recordVersion = 0;
702         sr->u.update_request->recordOldVersion = 0;
703         sr->u.update_request->record.recordData_buf = 0;
704         sr->u.update_request->record.recordData_len = 0;
705         sr->u.update_request->extra_record = 0;
706         sr->u.update_request->extraRequestData = 0;
707         sr->u.request->database = 0;
708         break;
709     case Z_SRW_update_response:
710         sr->u.update_response = (Z_SRW_updateResponse *)
711             odr_malloc(o, sizeof(*sr->u.update_response));
712         sr->u.update_response->operationStatus = 0;
713         sr->u.update_response->recordId = 0;
714         sr->u.update_response->recordVersion = 0;
715         sr->u.update_response->recordChecksum = 0;
716         sr->u.update_response->record.recordData_buf = 0;
717         sr->u.update_response->record.recordData_len = 0;
718         sr->u.update_response->record.recordSchema = 0;
719         sr->u.update_response->record.recordPacking =
720             Z_SRW_recordPacking_XML;
721         sr->u.update_response->extra_record = 0;
722         sr->u.update_response->extraResponseData = 0;
723         sr->u.update_response->diagnostics = 0;
724         sr->u.update_response->num_diagnostics = 0;
725     }
726     return sr;
727 }
728
729 /* bib1:srw */
730 static int srw_bib1_map[] = {
731     1, 1,
732     2, 2,
733     3, 11,
734     4, 35,
735     5, 12,
736     6, 38,
737     7, 30,
738     8, 32,
739     9, 29,
740     108, 10,  /* Malformed query : Syntax error */
741     10, 10,
742     11, 12,
743     11, 23,
744     12, 60,
745     13, 61,
746     13, 62,
747     14, 63,
748     14, 64,
749     14, 65,
750     15, 68,
751     15, 69,
752     16, 70,
753     17, 70,
754     18, 50,
755     19, 55,
756     20, 56, 
757     21, 52,
758     22, 50,
759     23, 3,
760     24, 66,
761     25, 66,
762     26, 66,
763     27, 51,
764     28, 52,
765     29, 52,
766     30, 51,
767     31, 57,
768     32, 58,
769     33, 59,
770     100, 1, /* bad map */
771     101, 3,
772     102, 3,
773     103, 3,
774     104, 3,
775     105, 3, 
776     106, 66,
777     107, 11,
778     108, 13,
779     108, 14,
780     108, 25,
781     108, 26,
782     108, 27,
783     108, 45,
784         
785     109, 2,
786     110, 37,
787     111, 1,
788     112, 58,
789     113, 10,
790     114, 16,
791     115, 16,
792     116, 16,
793     117, 19,
794     117, 20,
795     118, 22,
796     119, 32,
797     119, 31,
798     120, 28,
799     121, 15,
800     122, 32,
801     123, 22,
802     123, 17,
803     123, 18,
804     124, 24,
805     125, 36,
806     126, 36, 
807     127, 36,
808     128, 51,
809     129, 39,
810     130, 43,
811     131, 40,
812     132, 42,
813     201, 44,
814     201, 33,
815     201, 34,
816     202, 41,
817     203, 43,
818     205, 1,  /* bad map */
819     206, 1,  /* bad map */
820     207, 89,
821     208, 1,  /* bad map */
822     209, 80,
823     210, 80,
824     210, 81,
825     211, 84,
826     212, 85,
827     213, 92,
828     214, 90,
829     215, 91,
830     216, 92,
831     217, 63,
832     218, 1,  /* bad map */
833     219, 1,  /* bad map */
834     220, 1,  /* bad map */
835     221, 1,  /* bad map */
836     222, 3,
837     223, 1,  /* bad map */
838     224, 1,  /* bad map */
839     225, 1,  /* bad map */
840     226, 1,  /* bad map */
841     227, 66,
842     228, 1,  /* bad map */
843     229, 36,
844     230, 83,
845     231, 89,
846     232, 1,
847     233, 1, /* bad map */
848     234, 1, /* bad map */
849     235, 2,
850     236, 3, 
851     237, 82,
852     238, 67,
853     239, 66,
854     240, 1, /* bad map */
855     241, 1, /* bad map */
856     242, 70,
857     243, 1, /* bad map */
858     244, 66,
859     245, 10,
860     246, 10,
861     247, 10,
862     1001, 1, /* bad map */
863     1002, 1, /* bad map */
864     1003, 1, /* bad map */
865     1004, 1, /* bad map */
866     1005, 1, /* bad map */
867     1006, 1, /* bad map */
868     1007, 100,
869     1008, 1, 
870     1009, 1,
871     1010, 3,
872     1011, 3,
873     1012, 3,
874     1013, 3,
875     1014, 3,
876     1015, 3,
877     1015, 3,
878     1016, 3,
879     1017, 3,
880     1018, 2,
881     1019, 2,
882     1020, 2,
883     1021, 3,
884     1022, 3,
885     1023, 3,
886     1024, 16,
887     1025, 3,
888     1026, 64,
889     1027, 1,
890     1028, 65,
891     1029, 1,
892     1040, 1,
893     /* 1041-1065 */
894     1066, 66,
895     1066, 67,
896     0
897 };
898
899 int yaz_diag_bib1_to_srw (int code)
900 {
901     const int *p = srw_bib1_map;
902     while (*p)
903     {
904         if (code == p[0])
905             return p[1];
906         p += 2;
907     }
908     return 1;
909 }
910
911 int yaz_diag_srw_to_bib1(int code)
912 {
913     const int *p = srw_bib1_map;
914     while (*p)
915     {
916         if (code == p[1])
917             return p[0];
918         p += 2;
919     }
920     return 1;
921 }
922
923 static void add_val_int(ODR o, char **name, char **value,  int *i,
924                         char *a_name, int *val)
925 {
926     if (val)
927     {
928         name[*i] = a_name;
929         value[*i] = odr_malloc(o, 30);
930         sprintf(value[*i], "%d", *val);
931         (*i)++;
932     }
933 }
934
935 static void add_val_str(ODR o, char **name, char **value,  int *i,
936                         char *a_name, char *val)
937 {
938     if (val)
939     {
940         name[*i] = a_name;
941         value[*i] = val;
942         (*i)++;
943     }
944 }
945
946 static int yaz_get_sru_parms(const Z_SRW_PDU *srw_pdu, ODR encode,
947                               char **name, char **value)
948 {
949     int i = 0;
950     add_val_str(encode, name, value, &i, "version", srw_pdu->srw_version);
951     name[i] = "operation";
952     switch(srw_pdu->which)
953     {
954     case Z_SRW_searchRetrieve_request:
955         value[i++] = "searchRetrieve";
956         switch(srw_pdu->u.request->query_type)
957         {
958         case Z_SRW_query_type_cql:
959             add_val_str(encode, name, value, &i, "query",
960                         srw_pdu->u.request->query.cql);
961             break;
962         case Z_SRW_query_type_pqf:
963             add_val_str(encode, name, value, &i, "x-pquery",
964                         srw_pdu->u.request->query.pqf);
965             break;
966         case Z_SRW_query_type_xcql:
967             add_val_str(encode, name, value, &i, "x-cql",
968                         srw_pdu->u.request->query.xcql);
969             break;
970         }
971         switch(srw_pdu->u.request->sort_type)
972         {
973         case Z_SRW_sort_type_none:
974             break;
975         case Z_SRW_sort_type_sort:            
976             add_val_str(encode, name, value, &i, "sortKeys",
977                         srw_pdu->u.request->sort.sortKeys);
978             break;
979         }
980         add_val_int(encode, name, value, &i, "startRecord", 
981                     srw_pdu->u.request->startRecord);
982         add_val_int(encode, name, value, &i, "maximumRecords", 
983                     srw_pdu->u.request->maximumRecords);
984         add_val_str(encode, name, value, &i, "recordSchema",
985                     srw_pdu->u.request->recordSchema);
986         add_val_str(encode, name, value, &i, "recordPacking",
987                     srw_pdu->u.request->recordPacking);
988         add_val_str(encode, name, value, &i, "recordXPath",
989                     srw_pdu->u.request->recordXPath);
990         add_val_str(encode, name, value, &i, "stylesheet",
991                     srw_pdu->u.request->stylesheet);
992         add_val_int(encode, name, value, &i, "resultSetTTL", 
993                     srw_pdu->u.request->resultSetTTL);
994         break;
995     case Z_SRW_explain_request:
996         value[i++] = "explain";
997         add_val_str(encode, name, value, &i, "stylesheet",
998                     srw_pdu->u.explain_request->stylesheet);
999         break;
1000     case Z_SRW_scan_request:
1001         value[i++] = "scan";
1002
1003         switch(srw_pdu->u.scan_request->query_type)
1004         {
1005         case Z_SRW_query_type_cql:
1006             add_val_str(encode, name, value, &i, "scanClause",
1007                         srw_pdu->u.scan_request->scanClause.cql);
1008             break;
1009         case Z_SRW_query_type_pqf:
1010             add_val_str(encode, name, value, &i, "x-pScanClause",
1011                         srw_pdu->u.scan_request->scanClause.pqf);
1012             break;
1013         case Z_SRW_query_type_xcql:
1014             add_val_str(encode, name, value, &i, "x-cqlScanClause",
1015                         srw_pdu->u.scan_request->scanClause.xcql);
1016             break;
1017         }
1018         add_val_int(encode, name, value, &i, "responsePosition", 
1019                     srw_pdu->u.scan_request->responsePosition);
1020         add_val_int(encode, name, value, &i, "maximumTerms", 
1021                     srw_pdu->u.scan_request->maximumTerms);
1022         add_val_str(encode, name, value, &i, "stylesheet",
1023                     srw_pdu->u.scan_request->stylesheet);
1024         break;
1025     case Z_SRW_update_request:
1026         value[i++] = "update";
1027         break;
1028     default:
1029         return -1;
1030     }
1031     name[i++] = 0;
1032     return 0;
1033 }
1034
1035 int yaz_sru_get_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1036                        ODR encode, char *charset)
1037 {
1038     char *name[30], *value[30]; /* definite upper limit for SRU params */
1039     char *uri_args;
1040     char *path;
1041
1042     if (yaz_get_sru_parms(srw_pdu, encode, name, value))
1043         return -1;
1044     yaz_array_to_uri(&uri_args, encode, name, value);
1045
1046     hreq->method = "GET";
1047     
1048     path = odr_malloc(encode, strlen(hreq->path) + strlen(uri_args) + 3);
1049     sprintf(path, "%s?%s", hreq->path, uri_args);
1050     hreq->path = path;
1051
1052     z_HTTP_header_add_content_type(encode, &hreq->headers,
1053                                    "text/xml", charset);
1054     return 0;
1055 }
1056
1057 int yaz_sru_post_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
1058                         ODR encode, char *charset)
1059 {
1060     char *name[30], *value[30]; /* definite upper limit for SRU params */
1061     char *uri_args;
1062
1063     if (yaz_get_sru_parms(srw_pdu, encode, name, value))
1064         return -1;
1065
1066     yaz_array_to_uri(&uri_args, encode, name, value);
1067
1068     hreq->method = "POST";
1069     
1070     hreq->content_buf = uri_args;
1071     hreq->content_len = strlen(uri_args);
1072
1073     z_HTTP_header_add_content_type(encode, &hreq->headers,
1074                                    "application/x-www-form-urlencoded",
1075                                    charset);
1076     return 0;
1077 }
1078
1079 /*
1080  * Local variables:
1081  * c-basic-offset: 4
1082  * indent-tabs-mode: nil
1083  * End:
1084  * vim: shiftwidth=4 tabstop=8 expandtab
1085  */
1086