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