Update source headers for 2008. Omit CVS ID keyword subst.
[yaz-moved-to-github.git] / src / srw.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2008 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file srw.c
7  * \brief Implements SRW/SRU package encoding and decoding
8  */
9
10 #include <yaz/srw.h>
11 #if YAZ_HAVE_XML2
12 #include <libxml/parser.h>
13 #include <libxml/tree.h>
14 #include <assert.h>
15
16 static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len,
17                       xmlNsPtr ns_ptr)
18 {
19     if (val)
20     {
21         xmlDocPtr doc = xmlParseMemory(val,len);
22         if (doc)
23         {
24             xmlNodePtr c = xmlNewChild(ptr, ns_ptr, BAD_CAST elem, 0);
25             xmlNodePtr t = xmlDocGetRootElement(doc);
26             xmlAddChild(c, xmlCopyNode(t,1));
27             xmlFreeDoc(doc);
28         }
29     }
30 }
31
32 xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, const char *val,
33                             int len)
34 {
35     if (val)
36     {
37         xmlNodePtr c = xmlNewChild(ptr, 0, BAD_CAST elem, 0);
38         xmlNodePtr t = xmlNewTextLen(BAD_CAST val, len);
39         xmlAddChild(c, t);
40         return t;
41     }
42     return 0;
43 }
44
45 xmlNodePtr add_xsd_string_ns(xmlNodePtr ptr, const char *elem, const char *val,
46                              xmlNsPtr ns_ptr)
47 {
48     if (val)
49     {
50         xmlNodePtr c = xmlNewChild(ptr, ns_ptr, BAD_CAST elem, 0);
51         xmlNodePtr t = xmlNewText(BAD_CAST val);
52         xmlAddChild(c, t);
53         return t;
54     }
55     return 0;
56 }
57
58 xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, const char *val)
59 {
60     return add_xsd_string_ns(ptr, elem, val, 0);
61 }
62
63 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, const int *val)
64 {
65     if (val)
66     {
67         char str[30];
68         sprintf(str, "%d", *val);
69         xmlNewTextChild(ptr, 0, BAD_CAST elem, BAD_CAST str);
70     }
71 }
72
73 static int match_element(xmlNodePtr ptr, const char *elem)
74 {
75     if (ptr->type == XML_ELEMENT_NODE && !xmlStrcmp(ptr->name, BAD_CAST elem))
76     {
77         return 1;
78     }
79     return 0;
80 }
81
82 #define CHECK_TYPE 0
83
84 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
85                               char **val, int *len)
86 {
87 #if CHECK_TYPE
88     struct _xmlAttr *attr;
89 #endif
90     if (!match_element(ptr, elem))
91         return 0;
92 #if CHECK_TYPE
93     for (attr = ptr->properties; attr; attr = attr->next)
94         if (!strcmp(attr->name, "type") &&
95             attr->children && attr->children->type == XML_TEXT_NODE)
96         {
97             const char *t = strchr(attr->children->content, ':');
98             if (t)
99                 t = t + 1;
100             else
101                 t = attr->children->content;
102             if (!strcmp(t, "string"))
103                 break;
104         }
105     if (!attr)
106         return 0;
107 #endif
108     ptr = ptr->children;
109     if (!ptr || ptr->type != XML_TEXT_NODE)
110     {
111         *val = "";
112         return 1;
113     }
114     *val = odr_strdup(o, (const char *) ptr->content);
115     if (len)
116         *len = xmlStrlen(ptr->content);
117     return 1;
118 }
119
120
121 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
122                             char **val)
123 {
124     return match_xsd_string_n(ptr, elem, o, val, 0);
125 }
126
127 static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
128                            char **val, int *len)
129 {
130     xmlBufferPtr buf;
131
132     if (!match_element(ptr, elem))
133         return 0;
134
135     buf = xmlBufferCreate();
136
137     /* Copy each element nodes at top.
138        In most cases there is only one root node.. At least one server
139        http://www.theeuropeanlibrary.org/sru/sru.pl
140        has multiple root nodes in recordData.
141     */
142     for (ptr = ptr->children; ptr; ptr = ptr->next)
143     {
144         if (ptr->type == XML_ELEMENT_NODE)
145         {
146             /* copy node to get NS right (bug #740). */
147             xmlNode *tmp = xmlCopyNode(ptr, 1);
148             
149             xmlNodeDump(buf, tmp->doc, tmp, 0, 0);
150             
151             xmlFreeNode(tmp);
152         }
153     }
154     
155     *val = (char *) odr_malloc(o, buf->use+1);
156     memcpy (*val, buf->content, buf->use);
157     (*val)[buf->use] = '\0';
158
159     if (len)
160         *len = buf->use;
161
162     xmlBufferFree(buf);
163
164     return 1;
165 }
166                      
167 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
168 {
169 #if CHECK_TYPE
170     struct _xmlAttr *attr;
171 #endif
172     if (!match_element(ptr, elem))
173         return 0;
174 #if CHECK_TYPE
175     for (attr = ptr->properties; attr; attr = attr->next)
176         if (!strcmp(attr->name, "type") &&
177             attr->children && attr->children->type == XML_TEXT_NODE)
178         {
179             const char *t = strchr(attr->children->content, ':');
180             if (t)
181                 t = t + 1;
182             else
183                 t = attr->children->content;
184             if (!strcmp(t, "integer"))
185                 break;
186         }
187     if (!attr)
188         return 0;
189 #endif
190     ptr = ptr->children;
191     if (!ptr || ptr->type != XML_TEXT_NODE)
192         return 0;
193     *val = odr_intdup(o, atoi((const char *) ptr->content));
194     return 1;
195 }
196
197 char *yaz_negotiate_sru_version(char *input_ver)
198 {
199     if (!input_ver)
200         input_ver = "1.1";
201
202     if (!strcmp(input_ver, "1.1"))
203         return "1.1";
204     return  "1.2"; /* our latest supported version */
205 }
206
207 static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
208                           Z_SRW_extra_record **extra,
209                           void *client_data, const char *ns)
210 {
211     if (o->direction == ODR_DECODE)
212     {
213         Z_SRW_extra_record ex;
214
215         char *spack = 0;
216         int pack = Z_SRW_recordPacking_string;
217         xmlNodePtr ptr;
218         xmlNodePtr data_ptr = 0;
219         rec->recordSchema = 0;
220         rec->recordData_buf = 0;
221         rec->recordData_len = 0;
222         rec->recordPosition = 0;
223         *extra = 0;
224
225         ex.extraRecordData_buf = 0;
226         ex.extraRecordData_len = 0;
227         ex.recordIdentifier = 0;
228
229         for (ptr = pptr->children; ptr; ptr = ptr->next)
230         {
231             
232             if (match_xsd_string(ptr, "recordSchema", o, 
233                                  &rec->recordSchema))
234                 ;
235             else if (match_xsd_string(ptr, "recordPacking", o, &spack))
236             {
237                 if (spack)
238                     pack = yaz_srw_str_to_pack(spack);
239             }
240             else if (match_xsd_integer(ptr, "recordPosition", o, 
241                                        &rec->recordPosition))
242                 ;
243             else if (match_element(ptr, "recordData"))
244             {
245                 /* save position of Data until after the loop
246                    then we will know the packing (hopefully), and
247                    unpacking is done once
248                 */
249                 data_ptr = ptr;
250             }
251             else if (match_xsd_XML_n(ptr, "extraRecordData", o, 
252                                      &ex.extraRecordData_buf,
253                                      &ex.extraRecordData_len) )
254                 ;
255             else if (match_xsd_string(ptr, "recordIdentifier", o, 
256                                       &ex.recordIdentifier))
257                 ;
258
259         }
260         if (data_ptr)
261         {
262             switch(pack)
263             {
264             case Z_SRW_recordPacking_XML:
265                 match_xsd_XML_n(data_ptr, "recordData", o, 
266                                 &rec->recordData_buf, &rec->recordData_len);
267                 break;
268             case Z_SRW_recordPacking_URL:
269                 /* just store it as a string.
270                    leave it to the backend to collect the document */
271                 match_xsd_string_n(data_ptr, "recordData", o, 
272                                    &rec->recordData_buf, &rec->recordData_len);
273                 break;
274             case Z_SRW_recordPacking_string:
275                 match_xsd_string_n(data_ptr, "recordData", o, 
276                                    &rec->recordData_buf, &rec->recordData_len);
277                 break;
278             }
279         }
280         rec->recordPacking = pack;
281         if (ex.extraRecordData_buf || ex.recordIdentifier)
282         {
283             *extra = (Z_SRW_extra_record *)
284                 odr_malloc(o, sizeof(Z_SRW_extra_record));
285             memcpy(*extra, &ex, sizeof(Z_SRW_extra_record));
286         }
287     }
288     else if (o->direction == ODR_ENCODE)
289     {
290         xmlNodePtr ptr = pptr;
291         int pack = rec->recordPacking;
292         const char *spack = yaz_srw_pack_to_str(pack);
293
294         add_xsd_string(ptr, "recordSchema", rec->recordSchema);
295         if (spack)
296             add_xsd_string(ptr, "recordPacking", spack);
297         switch(pack)
298         {
299         case Z_SRW_recordPacking_string:
300             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
301                              rec->recordData_len);
302             break;
303         case Z_SRW_recordPacking_XML:
304             add_XML_n(ptr, "recordData", rec->recordData_buf,
305                       rec->recordData_len, 0);
306             break;
307         case Z_SRW_recordPacking_URL:
308             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
309                              rec->recordData_len);
310             break;
311         }
312         if (rec->recordPosition)
313             add_xsd_integer(ptr, "recordPosition", rec->recordPosition );
314         if (extra && *extra)
315         {
316             if ((*extra)->recordIdentifier)
317                 add_xsd_string(ptr, "recordIdentifier",
318                                (*extra)->recordIdentifier);
319             if ((*extra)->extraRecordData_buf)
320                 add_XML_n(ptr, "extraRecordData",
321                           (*extra)->extraRecordData_buf,
322                           (*extra)->extraRecordData_len, 0);
323         }
324     }
325     return 0;
326 }
327
328 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
329                            Z_SRW_extra_record ***extra,
330                            int *num, void *client_data, const char *ns)
331 {
332     if (o->direction == ODR_DECODE)
333     {
334         int i;
335         xmlNodePtr ptr;
336         *num = 0;
337         for (ptr = pptr->children; ptr; ptr = ptr->next)
338         {
339             if (ptr->type == XML_ELEMENT_NODE &&
340                 !xmlStrcmp(ptr->name, BAD_CAST "record"))
341                 (*num)++;
342         }
343         if (!*num)
344             return 1;
345         *recs = (Z_SRW_record *) odr_malloc(o, *num * sizeof(**recs));
346         *extra = (Z_SRW_extra_record **) odr_malloc(o, *num * sizeof(**extra));
347         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
348         {
349             if (ptr->type == XML_ELEMENT_NODE &&
350                 !xmlStrcmp(ptr->name, BAD_CAST "record"))
351             {
352                 yaz_srw_record(o, ptr, *recs + i, *extra + i, client_data, ns);
353                 i++;
354             }
355         }
356     }
357     else if (o->direction == ODR_ENCODE)
358     {
359         int i;
360         for (i = 0; i < *num; i++)
361         {
362             xmlNodePtr rptr = xmlNewChild(pptr, 0, BAD_CAST "record",
363                                           0);
364             yaz_srw_record(o, rptr, (*recs)+i, (*extra ? *extra + i : 0),
365                            client_data, ns);
366         }
367     }
368     return 0;
369 }
370
371 static int yaz_srw_version(ODR o, xmlNodePtr pptr, Z_SRW_recordVersion *rec,
372                            void *client_data, const char *ns)
373 {
374     if (o->direction == ODR_DECODE)
375     {
376         xmlNodePtr ptr;
377         rec->versionType = 0;
378         rec->versionValue = 0;
379         for (ptr = pptr->children; ptr; ptr = ptr->next)
380         {
381             
382             if (match_xsd_string(ptr, "versionType", o, 
383                                  &rec->versionType))
384                 ;
385             else if (match_xsd_string(ptr, "versionValue", o, 
386                                       &rec->versionValue))
387                 ;
388         }
389     }
390     else if (o->direction == ODR_ENCODE)
391         {
392         xmlNodePtr ptr = pptr;
393         add_xsd_string(ptr, "versionType", rec->versionType);
394         add_xsd_string(ptr, "versionValue", rec->versionValue);
395     }
396     return 0;
397 }
398
399 static int yaz_srw_versions(ODR o, xmlNodePtr pptr, 
400                             Z_SRW_recordVersion **vers,
401                             int *num, void *client_data, const char *ns)
402 {
403     if (o->direction == ODR_DECODE)
404     {
405         int i;
406         xmlNodePtr ptr;
407         *num = 0;
408         for (ptr = pptr->children; ptr; ptr = ptr->next)
409         {
410             if (ptr->type == XML_ELEMENT_NODE &&
411                 !xmlStrcmp(ptr->name, BAD_CAST "recordVersion"))
412                 (*num)++;
413         }
414         if (!*num)
415             return 1;
416         *vers = (Z_SRW_recordVersion *) odr_malloc(o, *num * sizeof(**vers));
417         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
418         {
419             if (ptr->type == XML_ELEMENT_NODE &&
420                 !xmlStrcmp(ptr->name, BAD_CAST "recordVersion"))
421             {
422                 yaz_srw_version(o, ptr, *vers + i, client_data, ns);
423                 i++;
424             }
425         }
426     }
427     else if (o->direction == ODR_ENCODE)
428     {
429         int i;
430         for (i = 0; i < *num; i++)
431             {
432             xmlNodePtr rptr = xmlNewChild(pptr, 0, BAD_CAST "version",
433                                           0);
434             yaz_srw_version(o, rptr, (*vers)+i, client_data, ns);
435         }
436     }
437     return 0;
438 }
439
440
441 static int yaz_srw_decode_diagnostics(ODR o, xmlNodePtr pptr,
442                                       Z_SRW_diagnostic **recs, int *num,
443                                       void *client_data, const char *ns)
444     
445 {
446     int i;
447     xmlNodePtr ptr;
448     *num = 0;
449     for (ptr = pptr; ptr; ptr = ptr->next)
450     {
451             if (ptr->type == XML_ELEMENT_NODE &&
452                 !xmlStrcmp(ptr->name, BAD_CAST "diagnostic"))
453                 (*num)++;
454     }
455     if (!*num)
456         return 1;
457     *recs = (Z_SRW_diagnostic *) odr_malloc(o, *num * sizeof(**recs));
458     for (i = 0; i < *num; i++)
459         {
460             (*recs)[i].uri = 0;
461             (*recs)[i].details = 0;
462             (*recs)[i].message = 0;
463         } 
464     for (i = 0, ptr = pptr; ptr; ptr = ptr->next)
465     {
466         if (ptr->type == XML_ELEMENT_NODE &&
467             !xmlStrcmp(ptr->name, BAD_CAST "diagnostic"))
468         {
469             xmlNodePtr rptr;
470             (*recs)[i].uri = 0;
471             (*recs)[i].details = 0;
472             (*recs)[i].message = 0;
473             for (rptr = ptr->children; rptr; rptr = rptr->next)
474             {
475                 if (match_xsd_string(rptr, "uri", o, 
476                                      &(*recs)[i].uri))
477                     ;
478                 else if (match_xsd_string(rptr, "details", o, 
479                                           &(*recs)[i].details))
480                     ;
481                 else if (match_xsd_string(rptr, "message", o, 
482                                           &(*recs)[i].message))
483                     ;
484             }
485             i++;
486         }
487     }
488     return 0;
489 }
490
491 int sru_decode_surrogate_diagnostics(const char *buf, size_t len,
492                                      Z_SRW_diagnostic **diag,
493                                      int *num, ODR odr)
494 {
495     int ret = 0;
496     xmlDocPtr doc = xmlParseMemory(buf, len);
497     if (doc)
498     {
499         xmlNodePtr ptr = xmlDocGetRootElement(doc);
500         while (ptr && ptr->type != XML_ELEMENT_NODE)
501             ptr = ptr->next;
502         if (ptr && ptr->ns 
503             && !xmlStrcmp(ptr->ns->href,
504                           BAD_CAST "http://www.loc.gov/zing/srw/diagnostic/"))
505         {
506             ret = yaz_srw_decode_diagnostics(odr, ptr, diag, num, 0, 0);
507         }
508         xmlFreeDoc(doc);
509     }
510     return ret;
511 }
512
513 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
514                                int *num, void *client_data, const char *ns)
515 {
516     if (o->direction == ODR_DECODE)
517     {
518         return yaz_srw_decode_diagnostics(o, pptr->children, recs, num, client_data, ns);
519     }
520     else if (o->direction == ODR_ENCODE)
521     {
522         int i;
523         xmlNsPtr ns_diag =
524             xmlNewNs(pptr, BAD_CAST YAZ_XMLNS_DIAG_v1_1, BAD_CAST "diag" );
525         for (i = 0; i < *num; i++)
526         {
527             const char *std_diag = "info:srw/diagnostic/1/";
528             const char *ucp_diag = "info:srw/diagnostic/12/";
529             xmlNodePtr rptr = xmlNewChild(pptr, ns_diag,
530                                           BAD_CAST "diagnostic", 0);
531             add_xsd_string(rptr, "uri", (*recs)[i].uri);
532             if ((*recs)[i].message)
533                 add_xsd_string(rptr, "message", (*recs)[i].message);
534             else if ((*recs)[i].uri )
535             {
536                 if (!strncmp((*recs)[i].uri, std_diag, strlen(std_diag)))
537                 {
538                     int no = atoi((*recs)[i].uri + strlen(std_diag));
539                     const char *message = yaz_diag_srw_str(no);
540                     if (message)
541                         add_xsd_string(rptr, "message", message);
542                 }
543                 else if (!strncmp((*recs)[i].uri, ucp_diag, strlen(ucp_diag)))
544                 {
545                     int no = atoi((*recs)[i].uri + strlen(ucp_diag));
546                     const char *message = yaz_diag_sru_update_str(no);
547                     if (message)
548                         add_xsd_string(rptr, "message", message);
549                 }
550             }
551             add_xsd_string(rptr, "details", (*recs)[i].details);
552         }
553     }
554     return 0;
555 }
556
557 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
558                         void *client_data, const char *ns)
559 {
560     if (o->direction == ODR_DECODE)
561     {
562         xmlNodePtr ptr;
563         term->value = 0;
564         term->numberOfRecords = 0;
565         term->displayTerm = 0;
566         term->whereInList = 0;
567         for (ptr = pptr->children; ptr; ptr = ptr->next)
568         {
569             if (match_xsd_string(ptr, "value", o,  &term->value))
570                 ;
571             else if (match_xsd_integer(ptr, "numberOfRecords", o, 
572                                    &term->numberOfRecords))
573                 ;
574             else if (match_xsd_string(ptr, "displayTerm", o, 
575                                       &term->displayTerm))
576                 ;
577             else if (match_xsd_string(ptr, "whereInList", o, 
578                                       &term->whereInList))
579                 ;
580         }
581     }
582     else if (o->direction == ODR_ENCODE)
583     {
584         xmlNodePtr ptr = pptr;
585         add_xsd_string(ptr, "value", term->value);
586         add_xsd_integer(ptr, "numberOfRecords", term->numberOfRecords);
587         add_xsd_string(ptr, "displayTerm", term->displayTerm);
588         add_xsd_string(ptr, "whereInList", term->whereInList);
589     }
590     return 0;
591 }
592
593 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
594                          int *num, void *client_data, const char *ns)
595 {
596     if (o->direction == ODR_DECODE)
597     {
598         int i;
599         xmlNodePtr ptr;
600         *num = 0;
601         for (ptr = pptr->children; ptr; ptr = ptr->next)
602         {
603             if (ptr->type == XML_ELEMENT_NODE &&
604                 !xmlStrcmp(ptr->name, BAD_CAST "term"))
605                 (*num)++;
606         }
607         if (!*num)
608             return 1;
609         *terms = (Z_SRW_scanTerm *) odr_malloc(o, *num * sizeof(**terms));
610         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
611         {
612             if (ptr->type == XML_ELEMENT_NODE &&
613                 !xmlStrcmp(ptr->name, BAD_CAST "term"))
614                 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
615         }
616     }
617     else if (o->direction == ODR_ENCODE)
618     {
619         int i;
620         for (i = 0; i < *num; i++)
621         {
622             xmlNodePtr rptr = xmlNewChild(pptr, 0, BAD_CAST "term", 0);
623             yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
624         }
625     }
626     return 0;
627 }
628
629 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
630                   void *client_data, const char *ns)
631 {
632     xmlNodePtr pptr = (xmlNodePtr) vptr;
633     if (o->direction == ODR_DECODE)
634     {
635         Z_SRW_PDU **p = handler_data;
636         xmlNodePtr method = pptr->children;
637         char *neg_version;
638
639         while (method && method->type == XML_TEXT_NODE)
640             method = method->next;
641         
642         if (!method)
643             return -1;
644         if (method->type != XML_ELEMENT_NODE)
645             return -1;
646
647         *p = yaz_srw_get_core_v_1_1(o);
648         
649         if (!xmlStrcmp(method->name, BAD_CAST "searchRetrieveRequest"))
650         {
651             xmlNodePtr ptr = method->children;
652             Z_SRW_searchRetrieveRequest *req;
653
654             (*p)->which = Z_SRW_searchRetrieve_request;
655             req = (*p)->u.request = (Z_SRW_searchRetrieveRequest *)
656                 odr_malloc(o, sizeof(*req));
657             req->query_type = Z_SRW_query_type_cql;
658             req->query.cql = 0;
659             req->sort_type = Z_SRW_sort_type_none;
660             req->sort.none = 0;
661             req->startRecord = 0;
662             req->maximumRecords = 0;
663             req->recordSchema = 0;
664             req->recordPacking = 0;
665             req->recordXPath = 0;
666             req->resultSetTTL = 0;
667             req->stylesheet = 0;
668             req->database = 0;
669
670             for (; ptr; ptr = ptr->next)
671             {
672                 if (match_xsd_string(ptr, "version", o,
673                                      &(*p)->srw_version))
674                     ;
675                 else if (match_xsd_string(ptr, "query", o, 
676                                      &req->query.cql))
677                     req->query_type = Z_SRW_query_type_cql;
678                 else if (match_xsd_string(ptr, "pQuery", o, 
679                                      &req->query.pqf))
680                     req->query_type = Z_SRW_query_type_pqf;
681                 else if (match_xsd_string(ptr, "xQuery", o, 
682                                      &req->query.xcql))
683                     req->query_type = Z_SRW_query_type_xcql;
684                 else if (match_xsd_integer(ptr, "startRecord", o,
685                                            &req->startRecord))
686                     ;
687                 else if (match_xsd_integer(ptr, "maximumRecords", o,
688                                            &req->maximumRecords))
689                     ;
690                 else if (match_xsd_string(ptr, "recordPacking", o,
691                                           &req->recordPacking))
692                     ;
693                 else if (match_xsd_string(ptr, "recordSchema", o, 
694                                           &req->recordSchema))
695                     ;
696                 else if (match_xsd_string(ptr, "recordXPath", o,
697                                           &req->recordXPath))
698                     ;
699                 else if (match_xsd_integer(ptr, "resultSetTTL", o,
700                                            &req->resultSetTTL))
701                     ;
702                 else if (match_xsd_string(ptr, "sortKeys", o, 
703                                           &req->sort.sortKeys))
704                     req->sort_type = Z_SRW_sort_type_sort;
705                 else if (match_xsd_string(ptr, "stylesheet", o,
706                                            &req->stylesheet))
707                     ;
708                 else if (match_xsd_string(ptr, "database", o,
709                                            &req->database))
710                     ;
711             }
712             if (!req->query.cql && !req->query.pqf && !req->query.xcql)
713             {
714                 /* should put proper diagnostic here */
715                 return -1;
716             }
717         }
718         else if (!xmlStrcmp(method->name, BAD_CAST "searchRetrieveResponse"))
719         {
720             xmlNodePtr ptr = method->children;
721             Z_SRW_searchRetrieveResponse *res;
722
723             (*p)->which = Z_SRW_searchRetrieve_response;
724             res = (*p)->u.response = (Z_SRW_searchRetrieveResponse *)
725                 odr_malloc(o, sizeof(*res));
726
727             res->numberOfRecords = 0;
728             res->resultSetId = 0;
729             res->resultSetIdleTime = 0;
730             res->records = 0;
731             res->num_records = 0;
732             res->diagnostics = 0;
733             res->num_diagnostics = 0;
734             res->nextRecordPosition = 0;
735
736             for (; ptr; ptr = ptr->next)
737             {
738                 if (match_xsd_string(ptr, "version", o,
739                                      &(*p)->srw_version))
740                     ;
741                 else if (match_xsd_integer(ptr, "numberOfRecords", o, 
742                                       &res->numberOfRecords))
743                     ;
744                 else if (match_xsd_string(ptr, "resultSetId", o, 
745                                           &res->resultSetId))
746                     ;
747                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
748                                            &res->resultSetIdleTime))
749                     ;
750                 else if (match_element(ptr, "records"))
751                     yaz_srw_records(o, ptr, &res->records,
752                                     &res->extra_records,
753                                     &res->num_records, client_data, ns);
754                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
755                                            &res->nextRecordPosition))
756                     ;
757                 else if (match_element(ptr, "diagnostics"))
758                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
759                                         &res->num_diagnostics,
760                                         client_data, ns);
761             }
762         }
763         else if (!xmlStrcmp(method->name, BAD_CAST "explainRequest"))
764         {
765             Z_SRW_explainRequest *req;
766             xmlNodePtr ptr = method->children;
767             
768             (*p)->which = Z_SRW_explain_request;
769             req = (*p)->u.explain_request = (Z_SRW_explainRequest *)
770                 odr_malloc(o, sizeof(*req));
771             req->recordPacking = 0;
772             req->database = 0;
773             req->stylesheet = 0;
774             for (; ptr; ptr = ptr->next)
775             {
776                 if (match_xsd_string(ptr, "version", o,
777                                            &(*p)->srw_version))
778                     ;
779                 else if (match_xsd_string(ptr, "stylesheet", o,
780                                           &req->stylesheet))
781                     ;
782                 else if (match_xsd_string(ptr, "recordPacking", o,
783                                      &req->recordPacking))
784                     ;
785                 else if (match_xsd_string(ptr, "database", o,
786                                      &req->database))
787                     ;
788             }
789         }
790         else if (!xmlStrcmp(method->name, BAD_CAST "explainResponse"))
791         {
792             Z_SRW_explainResponse *res;
793             xmlNodePtr ptr = method->children;
794
795             (*p)->which = Z_SRW_explain_response;
796             res = (*p)->u.explain_response = (Z_SRW_explainResponse*)
797                 odr_malloc(o, sizeof(*res));
798             res->diagnostics = 0;
799             res->num_diagnostics = 0;
800             res->record.recordSchema = 0;
801             res->record.recordData_buf = 0;
802             res->record.recordData_len = 0;
803             res->record.recordPosition = 0;
804
805             for (; ptr; ptr = ptr->next)
806             {
807                 if (match_xsd_string(ptr, "version", o,
808                                            &(*p)->srw_version))
809                     ;
810                 else if (match_element(ptr, "record"))
811                     yaz_srw_record(o, ptr, &res->record, &res->extra_record,
812                                    client_data, ns);
813                 else if (match_element(ptr, "diagnostics"))
814                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
815                                         &res->num_diagnostics,
816                                         client_data, ns);
817                 ;
818             }
819         }
820         else if (!xmlStrcmp(method->name, BAD_CAST "scanRequest"))
821         {
822             Z_SRW_scanRequest *req;
823             xmlNodePtr ptr = method->children;
824
825             (*p)->which = Z_SRW_scan_request;
826             req = (*p)->u.scan_request = (Z_SRW_scanRequest *)
827                 odr_malloc(o, sizeof(*req));
828             req->query_type = Z_SRW_query_type_cql;
829             req->scanClause.cql = 0;
830             req->responsePosition = 0;
831             req->maximumTerms = 0;
832             req->stylesheet = 0;
833             req->database = 0;
834             
835             for (; ptr; ptr = ptr->next)
836             {
837                 if (match_xsd_string(ptr, "version", o,
838                                      &(*p)->srw_version))
839                     ;
840                 else if (match_xsd_string(ptr, "scanClause", o,
841                                      &req->scanClause.cql))
842                     ;
843                 else if (match_xsd_string(ptr, "pScanClause", o,
844                                           &req->scanClause.pqf))
845                 {
846                     req->query_type = Z_SRW_query_type_pqf;
847                 }
848                 else if (match_xsd_integer(ptr, "responsePosition", o,
849                                            &req->responsePosition))
850                     ;
851                 else if (match_xsd_integer(ptr, "maximumTerms", o,
852                                            &req->maximumTerms))
853                     ;
854                 else if (match_xsd_string(ptr, "stylesheet", o,
855                                           &req->stylesheet))
856                     ;
857                 else if (match_xsd_string(ptr, "database", o,
858                                           &req->database))
859                     ;
860             }
861         }
862         else if (!xmlStrcmp(method->name, BAD_CAST "scanResponse"))
863         {
864             Z_SRW_scanResponse *res;
865             xmlNodePtr ptr = method->children;
866
867             (*p)->which = Z_SRW_scan_response;
868             res = (*p)->u.scan_response = (Z_SRW_scanResponse *)
869                 odr_malloc(o, sizeof(*res));
870             res->terms = 0;
871             res->num_terms = 0;
872             res->diagnostics = 0;
873             res->num_diagnostics = 0;
874             
875             for (; ptr; ptr = ptr->next)
876             {
877                 if (match_xsd_string(ptr, "version", o,
878                                      &(*p)->srw_version))
879                     ;
880                 else if (match_element(ptr, "terms"))
881                     yaz_srw_terms(o, ptr, &res->terms,
882                                   &res->num_terms, client_data,
883                                   ns);
884                 else if (match_element(ptr, "diagnostics"))
885                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
886                                         &res->num_diagnostics,
887                                         client_data, ns);
888             }
889         }
890         else
891         {
892             *p = 0;
893             return -1;
894         }
895         neg_version = yaz_negotiate_sru_version((*p)->srw_version);
896         if (neg_version)
897             (*p)->srw_version = neg_version;
898     }
899     else if (o->direction == ODR_ENCODE)
900     {
901         Z_SRW_PDU **p = handler_data;
902         xmlNsPtr ns_srw;
903         
904         if ((*p)->which == Z_SRW_searchRetrieve_request)
905         {
906             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
907             xmlNodePtr ptr = xmlNewChild(pptr, 0,
908                                          BAD_CAST "searchRetrieveRequest", 0);
909             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
910             xmlSetNs(ptr, ns_srw);
911
912             if ((*p)->srw_version)
913                 add_xsd_string(ptr, "version", (*p)->srw_version);
914             switch(req->query_type)
915             {
916             case Z_SRW_query_type_cql:
917                 add_xsd_string(ptr, "query", req->query.cql);
918                 break;
919             case Z_SRW_query_type_xcql:
920                 add_xsd_string(ptr, "xQuery", req->query.xcql);
921                 break;
922             case Z_SRW_query_type_pqf:
923                 add_xsd_string(ptr, "pQuery", req->query.pqf);
924                 break;
925             }
926             add_xsd_integer(ptr, "startRecord", req->startRecord);
927             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
928             add_xsd_string(ptr, "recordPacking", req->recordPacking);
929             add_xsd_string(ptr, "recordSchema", req->recordSchema);
930             add_xsd_string(ptr, "recordXPath", req->recordXPath);
931             add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
932             switch(req->sort_type)
933             {
934             case Z_SRW_sort_type_none:
935                 break;
936             case Z_SRW_sort_type_sort:
937                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
938                 break;
939             case Z_SRW_sort_type_xSort:
940                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
941                 break;
942             }
943             add_xsd_string(ptr, "stylesheet", req->stylesheet);
944             add_xsd_string(ptr, "database", req->database);
945         }
946         else if ((*p)->which == Z_SRW_searchRetrieve_response)
947         {
948             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
949             xmlNodePtr ptr = xmlNewChild(pptr, 0,
950                                          BAD_CAST "searchRetrieveResponse", 0);
951             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
952             xmlSetNs(ptr, ns_srw);
953
954             if ((*p)->srw_version)
955                 add_xsd_string(ptr, "version", (*p)->srw_version);
956             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
957             add_xsd_string(ptr, "resultSetId", res->resultSetId);
958             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
959             if (res->num_records)
960             {
961                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "records", 0);
962                 yaz_srw_records(o, rptr, &res->records, &res->extra_records,
963                                 &res->num_records,
964                                 client_data, ns);
965             }
966             add_xsd_integer(ptr, "nextRecordPosition",
967                             res->nextRecordPosition);
968             if (res->num_diagnostics)
969             {
970                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
971                                               0);
972                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
973                                     &res->num_diagnostics, client_data, ns);
974             }
975         }
976         else if ((*p)->which == Z_SRW_explain_request)
977         {
978             Z_SRW_explainRequest *req = (*p)->u.explain_request;
979             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "explainRequest",
980                                          0);
981             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
982             xmlSetNs(ptr, ns_srw);
983
984             add_xsd_string(ptr, "version", (*p)->srw_version);
985             add_xsd_string(ptr, "recordPacking", req->recordPacking);
986             add_xsd_string(ptr, "stylesheet", req->stylesheet);
987             add_xsd_string(ptr, "database", req->database);
988         }
989         else if ((*p)->which == Z_SRW_explain_response)
990         {
991             Z_SRW_explainResponse *res = (*p)->u.explain_response;
992             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "explainResponse",
993                                          0);
994             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
995             xmlSetNs(ptr, ns_srw);
996
997             add_xsd_string(ptr, "version", (*p)->srw_version);
998             if (1)
999             {
1000                 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
1001                 yaz_srw_record(o, ptr1, &res->record, &res->extra_record,
1002                                client_data, ns);
1003             }
1004             if (res->num_diagnostics)
1005             {
1006                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
1007                                               0);
1008                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1009                                     &res->num_diagnostics, client_data, ns);
1010             }
1011         }
1012         else if ((*p)->which == Z_SRW_scan_request)
1013         {
1014             Z_SRW_scanRequest *req = (*p)->u.scan_request;
1015             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "scanRequest", 0);
1016             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1017             xmlSetNs(ptr, ns_srw);
1018
1019             add_xsd_string(ptr, "version", (*p)->srw_version);
1020             switch(req->query_type)
1021             {
1022             case Z_SRW_query_type_cql:
1023                 add_xsd_string(ptr, "scanClause", req->scanClause.cql);
1024                 break;
1025             case Z_SRW_query_type_pqf:
1026                 add_xsd_string(ptr, "pScanClause", req->scanClause.pqf);
1027                 break;
1028             }
1029             add_xsd_integer(ptr, "responsePosition", req->responsePosition);
1030             add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
1031             add_xsd_string(ptr, "stylesheet", req->stylesheet);
1032             add_xsd_string(ptr, "database", req->database);
1033         }
1034         else if ((*p)->which == Z_SRW_scan_response)
1035         {
1036             Z_SRW_scanResponse *res = (*p)->u.scan_response;
1037             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "scanResponse", 0);
1038             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1039             xmlSetNs(ptr, ns_srw);
1040
1041             add_xsd_string(ptr, "version", (*p)->srw_version);
1042
1043             if (res->num_terms)
1044             {
1045                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "terms", 0);
1046                 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
1047                               client_data, ns);
1048             }
1049             if (res->num_diagnostics)
1050             {
1051                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
1052                                               0);
1053                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1054                                     &res->num_diagnostics, client_data, ns);
1055             }
1056         }
1057         else
1058             return -1;
1059
1060     }
1061     return 0;
1062 }
1063
1064 int yaz_ucp_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
1065                   void *client_data, const char *ns_ucp_str)
1066 {
1067     xmlNodePtr pptr = (xmlNodePtr) vptr;
1068     const char *ns_srw_str = YAZ_XMLNS_SRU_v1_1;
1069     if (o->direction == ODR_DECODE)
1070     {
1071         Z_SRW_PDU **p = handler_data;
1072         xmlNodePtr method = pptr->children;
1073
1074         while (method && method->type == XML_TEXT_NODE)
1075             method = method->next;
1076         
1077         if (!method)
1078             return -1;
1079         if (method->type != XML_ELEMENT_NODE)
1080             return -1;
1081
1082         *p = yaz_srw_get_core_v_1_1(o);
1083         
1084         if (!xmlStrcmp(method->name, BAD_CAST "updateRequest"))
1085         {
1086             xmlNodePtr ptr = method->children;
1087             Z_SRW_updateRequest *req;
1088             char *oper = 0;
1089
1090             (*p)->which = Z_SRW_update_request;
1091             req = (*p)->u.update_request = (Z_SRW_updateRequest *)
1092                 odr_malloc(o, sizeof(*req));
1093             req->database = 0;
1094             req->operation = 0;
1095             req->recordId = 0;
1096             req->recordVersions = 0;
1097             req->num_recordVersions = 0;
1098             req->record = 0;
1099             req->extra_record = 0;
1100             req->extraRequestData_buf = 0;
1101             req->extraRequestData_len = 0;
1102             req->stylesheet = 0;
1103
1104             for (; ptr; ptr = ptr->next)
1105             {
1106                 if (match_xsd_string(ptr, "version", o,
1107                                      &(*p)->srw_version))
1108                     ;
1109                 else if (match_xsd_string(ptr, "action", o, 
1110                                           &oper)){
1111                     if ( oper ){
1112                         if ( !strcmp(oper, "info:srw/action/1/delete"))
1113                             req->operation = "delete";
1114                         else if (!strcmp(oper,"info:srw/action/1/replace" ))
1115                             req->operation = "replace";
1116                         else if ( !strcmp( oper, "info:srw/action/1/create"))
1117                             req->operation = "insert";
1118                     }
1119                 }
1120                 else if (match_xsd_string(ptr, "recordIdentifier", o,
1121                                           &req->recordId))
1122                     ;
1123                 else if (match_element(ptr, "recordVersions" ) )
1124                     yaz_srw_versions( o, ptr, &req->recordVersions,
1125                                       &req->num_recordVersions, client_data,
1126                                       ns_ucp_str);
1127                 else if (match_element(ptr, "record"))
1128                 {
1129                     req->record = yaz_srw_get_record(o);
1130                     yaz_srw_record(o, ptr, req->record, &req->extra_record,
1131                                    client_data, ns_ucp_str);
1132                 }
1133                 else if (match_xsd_string(ptr, "stylesheet", o,
1134                                            &req->stylesheet))
1135                     ;
1136                 else if (match_xsd_string(ptr, "database", o,
1137                                            &req->database))
1138                     ;
1139             }
1140         }
1141         else if (!xmlStrcmp(method->name, BAD_CAST "updateResponse"))
1142         {
1143             xmlNodePtr ptr = method->children;
1144             Z_SRW_updateResponse *res;
1145
1146             (*p)->which = Z_SRW_update_response;
1147             res = (*p)->u.update_response = (Z_SRW_updateResponse *)
1148                 odr_malloc(o, sizeof(*res));
1149
1150             res->operationStatus = 0;
1151             res->recordId = 0;
1152             res->recordVersions = 0;
1153             res->num_recordVersions = 0;
1154             res->diagnostics = 0;
1155             res->num_diagnostics = 0;
1156             res->record = 0;
1157             res->extra_record = 0;
1158             res->extraResponseData_buf = 0;
1159             res->extraResponseData_len = 0;
1160
1161             for (; ptr; ptr = ptr->next)
1162             {
1163                 if (match_xsd_string(ptr, "version", o,
1164                                      &(*p)->srw_version))
1165                     ;
1166                 else if (match_xsd_string(ptr, "operationStatus", o, 
1167                                       &res->operationStatus ))
1168                     ;
1169                 else if (match_xsd_string(ptr, "recordIdentifier", o, 
1170                                           &res->recordId))
1171                     ;
1172                 else if (match_element(ptr, "recordVersions" )) 
1173                     yaz_srw_versions(o, ptr, &res->recordVersions,
1174                                      &res->num_recordVersions,
1175                                      client_data, ns_ucp_str);
1176                 else if (match_element(ptr, "record"))
1177                 {
1178                     res->record = yaz_srw_get_record(o);
1179                     yaz_srw_record(o, ptr, res->record, &res->extra_record,
1180                                    client_data, ns_ucp_str);
1181                 }
1182                 else if (match_element(ptr, "diagnostics"))
1183                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
1184                                         &res->num_diagnostics,
1185                                         client_data, ns_ucp_str);
1186             }
1187         }
1188         else if (!xmlStrcmp(method->name, BAD_CAST "explainUpdateRequest"))
1189         {
1190         }
1191         else if (!xmlStrcmp(method->name, BAD_CAST "explainUpdateResponse"))
1192         {
1193         }
1194         else
1195         {
1196             *p = 0;
1197             return -1;
1198         }
1199     }
1200     else if (o->direction == ODR_ENCODE)
1201     {
1202         Z_SRW_PDU **p = handler_data;
1203         xmlNsPtr ns_ucp, ns_srw;
1204
1205
1206         if ((*p)->which == Z_SRW_update_request)
1207         {
1208             Z_SRW_updateRequest *req = (*p)->u.update_request;
1209             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "updateRequest", 0);
1210             ns_ucp = xmlNewNs(ptr, BAD_CAST ns_ucp_str, BAD_CAST "zu");
1211             xmlSetNs(ptr, ns_ucp);
1212             ns_srw = xmlNewNs(ptr, BAD_CAST ns_srw_str, BAD_CAST "zs");
1213
1214             add_xsd_string_ns(ptr, "version", (*p)->srw_version, ns_srw);
1215             add_xsd_string(ptr, "action", req->operation);
1216             add_xsd_string(ptr, "recordIdentifier", req->recordId );
1217             if (req->recordVersions)
1218                 yaz_srw_versions( o, ptr, &req->recordVersions,
1219                                   &req->num_recordVersions,
1220                                   client_data, ns_ucp_str);
1221             if (req->record && req->record->recordData_len)
1222             {
1223                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
1224                 xmlSetNs(rptr, ns_srw);
1225                 yaz_srw_record(o, rptr, req->record, &req->extra_record,
1226                                client_data, ns_ucp_str);
1227             }
1228             if (req->extraRequestData_len)
1229             {
1230                 add_XML_n(ptr, "extraRequestData", 
1231                           req->extraRequestData_buf, 
1232                           req->extraRequestData_len, ns_srw);
1233             }
1234             add_xsd_string(ptr, "stylesheet", req->stylesheet);
1235             add_xsd_string(ptr, "database", req->database);
1236         }
1237         else if ((*p)->which == Z_SRW_update_response)
1238         {
1239             Z_SRW_updateResponse *res = (*p)->u.update_response;
1240             xmlNodePtr ptr = xmlNewChild(pptr, 0, (xmlChar *) 
1241                                          "updateResponse", 0);
1242             ns_ucp = xmlNewNs(ptr, BAD_CAST ns_ucp_str, BAD_CAST "zu");
1243             xmlSetNs(ptr, ns_ucp);
1244             ns_srw = xmlNewNs(ptr, BAD_CAST ns_srw_str, BAD_CAST "zs");
1245             
1246             add_xsd_string_ns(ptr, "version", (*p)->srw_version, ns_srw);
1247             add_xsd_string(ptr, "operationStatus", res->operationStatus );
1248             add_xsd_string(ptr, "recordIdentifier", res->recordId );
1249             if (res->recordVersions)
1250                 yaz_srw_versions(o, ptr, &res->recordVersions,
1251                                  &res->num_recordVersions,
1252                                  client_data, ns_ucp_str);
1253             if (res->record && res->record->recordData_len)
1254             {
1255                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
1256                 xmlSetNs(rptr, ns_srw);
1257                 yaz_srw_record(o, rptr, res->record, &res->extra_record,
1258                                client_data, ns_ucp_str);
1259             }
1260             if (res->num_diagnostics)
1261             {
1262                 xmlNsPtr ns_diag =
1263                     xmlNewNs(pptr, BAD_CAST YAZ_XMLNS_DIAG_v1_1,
1264                              BAD_CAST "diag" );
1265                 
1266                 xmlNodePtr rptr = xmlNewChild(ptr, ns_diag, BAD_CAST "diagnostics", 0);
1267                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1268                                     &res->num_diagnostics, client_data,
1269                                     ns_ucp_str);
1270             }
1271             if (res->extraResponseData_len)
1272                 add_XML_n(ptr, "extraResponseData", 
1273                           res->extraResponseData_buf, 
1274                           res->extraResponseData_len, ns_srw);
1275         }
1276         else
1277             return -1;
1278
1279     }
1280     return 0;
1281 }
1282
1283 #endif
1284
1285
1286 /*
1287  * Local variables:
1288  * c-basic-offset: 4
1289  * indent-tabs-mode: nil
1290  * End:
1291  * vim: shiftwidth=4 tabstop=8 expandtab
1292  */
1293