fetching records correctly, honoring recordPacking = xml/string and
[metaproxy-moved-to-github.git] / src / filter_sru_to_z3950.cpp
1 /* $Id: filter_sru_to_z3950.cpp,v 1.11 2006-09-22 11:11:17 marc Exp $
2    Copyright (c) 2005-2006, Index Data.
3
4    See the LICENSE file for details
5  */
6
7 #include "config.hpp"
8 #include "filter.hpp"
9 #include "package.hpp"
10 #include "util.hpp"
11 #include "gduutil.hpp"
12 #include "filter_sru_to_z3950.hpp"
13
14 #include <yaz/zgdu.h>
15 #include <yaz/z-core.h>
16 #include <yaz/srw.h>
17 #include <yaz/pquery.h>
18
19 #include <boost/thread/mutex.hpp>
20
21 #include <iostream>
22 #include <sstream>
23 #include <string>
24
25
26 namespace mp = metaproxy_1;
27 namespace yf = mp::filter;
28
29 namespace metaproxy_1 
30 {
31
32     template<typename T>
33     std::string to_string(const T& t)
34     {
35         std::ostringstream o;
36         if(o << t)
37             return o.str();
38         
39         return std::string();
40     }
41
42     std::string http_header_value(const Z_HTTP_Header* header, 
43                                   const std::string name)
44     {
45         while (header && header->name
46                && std::string(header->name) !=  name)
47             header = header->next;
48         
49         if (header && header->name && std::string(header->name) == name
50             && header->value)
51             return std::string(header->value);
52
53         return std::string();
54     }
55     
56
57 }
58
59
60 namespace metaproxy_1 {
61     namespace filter {
62         class SRUtoZ3950::Rep {
63         private:
64             union SRW_query {char * cql; char * xcql; char * pqf;};
65             typedef const int& SRW_query_type;
66         public:
67             void configure(const xmlNode *xmlnode);
68             void process(metaproxy_1::Package &package) const;
69         private:
70             std::string sru_protocol(const Z_HTTP_Request &http_req) const;
71             std::string debug_http(const Z_HTTP_Request &http_req) const;
72             void http_response(mp::Package &package, 
73                                const std::string &content, 
74                                int http_code = 200) const;
75             bool build_sru_debug_package(mp::Package &package) const;
76             bool build_sru_response(mp::Package &package, 
77                                     mp::odr &odr_en,
78                                     Z_SOAP *soap,
79                                     const Z_SRW_PDU *sru_pdu_res,
80                                     char *charset,
81                                     const char *stylesheet) const;
82             Z_SRW_PDU * decode_sru_request(mp::Package &package,   
83                                            mp::odr &odr_de,
84                                            mp::odr &odr_en,
85                                            Z_SRW_PDU *sru_pdu_res,
86                                            Z_SOAP *&soap,
87                                            char *charset,
88                                            char *stylesheet) const;
89             bool z3950_build_query(mp::odr &odr_en, Z_Query *z_query, 
90                                    const SRW_query &query, 
91                                    SRW_query_type query_type) const;
92             bool z3950_init_request(mp::Package &package, 
93                                          const std::string 
94                                          &database = "Default") const;
95             bool z3950_close_request(mp::Package &package) const;
96             bool z3950_search_request(mp::Package &package,
97                                       mp::odr &odr_en,
98                                       Z_SRW_PDU *sru_pdu_res,
99                                       Z_SRW_searchRetrieveRequest 
100                                           const *sr_req) const;
101             bool z3950_present_request(mp::Package &package,
102                                        mp::odr &odr_en,
103                                        Z_SRW_PDU *sru_pdu_res,
104                                        Z_SRW_searchRetrieveRequest 
105                                        const *sr_req) const;
106             bool z3950_scan_request(mp::Package &package,
107                                     mp::odr &odr_en,
108                                     Z_SRW_PDU *sru_pdu_res,
109                                     Z_SRW_scanRequest 
110                                     const *sr_req) const;
111             Z_ElementSetNames * build_esn_from_schema(mp::odr &odr_en, const char *schema) const;
112         };
113     }
114 }
115
116 yf::SRUtoZ3950::SRUtoZ3950() : m_p(new Rep)
117 {
118 }
119
120 yf::SRUtoZ3950::~SRUtoZ3950()
121 {  // must have a destructor because of boost::scoped_ptr
122 }
123
124 void yf::SRUtoZ3950::configure(const xmlNode *xmlnode)
125 {
126     m_p->configure(xmlnode);
127 }
128
129 void yf::SRUtoZ3950::process(mp::Package &package) const
130 {
131     m_p->process(package);
132 }
133
134 void yf::SRUtoZ3950::Rep::configure(const xmlNode *xmlnode)
135 {
136 }
137
138 void yf::SRUtoZ3950::Rep::process(mp::Package &package) const
139 {
140     Z_GDU *zgdu_req = package.request().get();
141
142     // ignoring all non HTTP_Request packages
143     if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
144         package.move();
145         return;
146     }
147     
148     // only working on  HTTP_Request packages now
149
150
151     // TODO: Z3950 response parsing and translation to SRU package
152     bool ok = true;    
153
154     mp::odr odr_de(ODR_DECODE);
155     Z_SRW_PDU *sru_pdu_req = 0;
156
157     mp::odr odr_en(ODR_ENCODE);
158     //Z_SRW_PDU *sru_pdu_res = 0;
159     Z_SRW_PDU *sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response);
160
161     Z_SOAP *soap = 0;
162     char *charset = 0;
163     char *stylesheet = 0;
164
165     if (! (sru_pdu_req = decode_sru_request(package, odr_de, odr_en, 
166                                             sru_pdu_res, soap,
167                                             charset, stylesheet)))
168     {
169         build_sru_response(package, odr_en, soap, 
170                            sru_pdu_res, charset, stylesheet);
171         return;
172     }
173     
174     
175     // SRU request package translation to Z3950 package
176     if (sru_pdu_req)
177         std::cout << *sru_pdu_req << "\n";
178     else
179         std::cout << "SRU empty\n";
180     
181
182     // explain
183     if (sru_pdu_req && sru_pdu_req->which == Z_SRW_explain_request)
184     {
185         //Z_SRW_searchRetrieveRequest *sr_req = sru_pdu_req->u.request;
186         // sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response);
187         std::cout << "TODO: implement explain response";
188         
189     }
190     
191
192     // searchRetrieve
193     if (sru_pdu_req && sru_pdu_req->which == Z_SRW_searchRetrieve_request)
194     {
195         Z_SRW_searchRetrieveRequest *sr_req = sru_pdu_req->u.request;   
196         
197         sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_searchRetrieve_response);
198
199         if (z3950_init_request(package))
200         {
201             {
202                 ok = z3950_search_request(package, odr_en,
203                                           sru_pdu_res, sr_req);
204
205                 if (ok 
206                     && sru_pdu_res->u.response->numberOfRecords
207                     && *(sru_pdu_res->u.response->numberOfRecords)
208                     && sr_req->maximumRecords
209                     && *(sr_req->maximumRecords))
210                     
211                     ok = z3950_present_request(package, odr_en,
212                                                sru_pdu_res,
213                                                sr_req);
214                 z3950_close_request(package);
215             }
216         }
217     }
218
219     // scan
220     else if (sru_pdu_req && sru_pdu_req->which == Z_SRW_scan_request)
221     {
222         Z_SRW_scanRequest  *sr_req = sru_pdu_req->u.scan_request;   
223
224         sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_scan_response);
225         
226         if (z3950_init_request(package))
227         {
228             z3950_scan_request(package, odr_en, sru_pdu_res, sr_req);    
229             z3950_close_request(package);
230         }        
231     }
232     else
233     {
234         std::cout << "SRU OPERATION NOT SUPPORTED \n";
235         sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response);
236         
237         // TODO: make nice diagnostic return package 
238         package.session().close();
239         return;
240     }
241
242     //build_sru_debug_package(package);
243     build_sru_response(package, odr_en, soap, 
244                        sru_pdu_res, charset, stylesheet);
245     return;
246
247
248
249
250
251
252
253 }
254
255 bool yf::SRUtoZ3950::Rep::build_sru_debug_package(mp::Package &package) const
256 {
257     Z_GDU *zgdu_req = package.request().get();
258     if  (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
259     {    
260         Z_HTTP_Request* http_req =  zgdu_req->u.HTTP_Request;
261         std::string content = debug_http(*http_req);
262         int http_code = 400;    
263         http_response(package, content, http_code);
264         return true;
265     }
266     package.session().close();
267     return false;
268 }
269
270
271 bool yf::SRUtoZ3950::Rep::build_sru_response(mp::Package &package, 
272                                              mp::odr &odr_en,
273                                              Z_SOAP *soap,
274                                              const Z_SRW_PDU *sru_pdu_res,
275                                              char *charset,
276                                              const char *stylesheet) 
277     const
278 {
279
280     // SRU request package translation to Z3950 package
281     if (sru_pdu_res)
282         std::cout << *(const_cast<Z_SRW_PDU *>(sru_pdu_res)) << "\n";
283     else
284         std::cout << "SRU empty\n";
285
286     
287     Z_GDU *zgdu_req = package.request().get();
288     if  (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
289     {    
290         Z_GDU *zgdu_res //= z_get_HTTP_Response(odr_en, 200);
291             = odr_en.create_HTTP_Response(package.session(), 
292                                           zgdu_req->u.HTTP_Request, 
293                                           200);
294
295         // adding HTTP response code and headers
296         Z_HTTP_Response * http_res = zgdu_res->u.HTTP_Response;
297         //http_res->code = http_code;
298         
299         std::string ctype("text/xml");
300         if (charset){
301             ctype += "; charset=";
302             ctype += charset;
303         }
304
305         z_HTTP_header_add(odr_en, 
306                           &http_res->headers, "Content-Type", ctype.c_str());
307
308          // packaging Z_SOAP into HTML response
309          static Z_SOAP_Handler soap_handlers[4] = {
310               {"http://www.loc.gov/zing/srw/", 0,
311                (Z_SOAP_fun) yaz_srw_codec},
312               {"http://www.loc.gov/zing/srw/v1.0/", 0,
313                (Z_SOAP_fun) yaz_srw_codec},
314               {"http://www.loc.gov/zing/srw/update/", 0,
315                (Z_SOAP_fun) yaz_ucp_codec},
316               {0, 0, 0}
317           };
318
319
320          // empty stylesheet means NO stylesheet
321          if (stylesheet && *stylesheet == '\0')
322              stylesheet = 0;
323          
324          // encoding SRU package
325          
326          soap->u.generic->p  = (void*) sru_pdu_res;         
327          //int ret = 
328          z_soap_codec_enc_xsl(odr_en, &soap, 
329                               &http_res->content_buf, &http_res->content_len,
330                               soap_handlers, charset, stylesheet);
331          
332
333          package.response() = zgdu_res;
334          return true;
335     }
336     package.session().close();
337     return false;
338 }
339
340
341
342  Z_SRW_PDU * yf::SRUtoZ3950::Rep::decode_sru_request(mp::Package &package,
343                                                      mp::odr &odr_de,
344                                                      mp::odr &odr_en,
345                                                      Z_SRW_PDU *sru_pdu_res,
346                                                      Z_SOAP *&soap,
347                                                      char *charset,
348                                                      char *stylesheet) 
349      const
350 {
351     Z_GDU *zgdu_req = package.request().get();
352     Z_SRW_PDU *sru_pdu_req = 0;
353
354     assert((zgdu_req->which == Z_GDU_HTTP_Request));
355     
356     //ignoring all non HTTP_Request packages
357     //if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
358     //    return 0;
359     //}
360     
361     Z_HTTP_Request* http_req =  zgdu_req->u.HTTP_Request;
362     if (! http_req)
363         return 0;
364
365     //Z_SRW_PDU *sru_pdu_res_exp = yaz_srw_get(odr_en, Z_SRW_explain_response);
366     
367     if (0 == yaz_sru_decode(http_req, &sru_pdu_req, &soap, 
368                             odr_de, &charset, 
369                             &(sru_pdu_res->u.response->diagnostics), 
370                             &(sru_pdu_res->u.response->num_diagnostics)))
371     {
372         if (sru_pdu_res->u.response->num_diagnostics)
373         {
374             //sru_pdu_res = sru_pdu_res_exp;
375             package.session().close();
376             return 0;
377         }
378         return sru_pdu_req;
379     }
380     else if (0 == yaz_srw_decode(http_req, &sru_pdu_req, &soap, 
381                                  odr_de, &charset))
382         return sru_pdu_req;
383     else 
384     {
385         //sru_pdu_res = sru_pdu_res_exp;
386         package.session().close();
387         return 0;
388     }
389     return 0;
390 }
391
392 bool 
393 yf::SRUtoZ3950::Rep::z3950_init_request(mp::Package &package, 
394                                              const std::string &database) const
395 {
396     // prepare Z3950 package
397     //Session s;
398     //Package z3950_package(s, package.origin());
399     Package z3950_package(package.session(), package.origin());
400     z3950_package.copy_filter(package);
401
402     // set initRequest APDU
403     mp::odr odr_en(ODR_ENCODE);
404     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_initRequest);
405     Z_InitRequest *init_req = apdu->u.initRequest;
406     //TODO: add user name in apdu
407     //TODO: add user passwd in apdu
408     //init_req->idAuthentication = org_init->idAuthentication;
409     //init_req->implementationId = "IDxyz";
410     //init_req->implementationName = "NAMExyz";
411     //init_req->implementationVersion = "VERSIONxyz";
412
413     ODR_MASK_SET(init_req->options, Z_Options_search);
414     ODR_MASK_SET(init_req->options, Z_Options_present);
415     ODR_MASK_SET(init_req->options, Z_Options_namedResultSets);
416     ODR_MASK_SET(init_req->options, Z_Options_scan);
417
418     ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_1);
419     ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_2);
420     ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_3);
421
422     z3950_package.request() = apdu;
423
424     // send Z3950 package
425     // std::cout << "z3950_init_request " << *apdu <<"\n";
426     z3950_package.move();
427
428     // dead Z3950 backend detection
429     if (z3950_package.session().is_closed()){
430         package.session().close();
431         return false;
432     }
433
434     // check successful initResponse
435     Z_GDU *z3950_gdu = z3950_package.response().get();
436
437     if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 
438         && z3950_gdu->u.z3950->which == Z_APDU_initResponse)
439          return true;
440  
441     return false;
442 }
443
444 bool 
445 yf::SRUtoZ3950::Rep::z3950_close_request(mp::Package &package) const
446 {
447     // close SRU package
448     package.session().close();
449
450     // prepare and close Z3950 package 
451     Package z3950_package(package.session(), package.origin());
452     z3950_package.copy_filter(package);
453     z3950_package.session().close();
454
455     // set close APDU
456     //mp::odr odr_en(ODR_ENCODE);
457     //Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_close);
458     //z3950_package.request() = apdu;
459
460     z3950_package.move();
461
462     // check successful close response
463     //Z_GDU *z3950_gdu = z3950_package.response().get();
464     //if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 
465     //    && z3950_gdu->u.z3950->which == Z_APDU_close)
466     //    return true;
467
468     if (z3950_package.session().is_closed()){
469         return true;
470     }
471     return false;
472 }
473
474 bool 
475 yf::SRUtoZ3950::Rep::z3950_search_request(mp::Package &package,  
476                                           mp::odr &odr_en,
477                                           Z_SRW_PDU *sru_pdu_res,
478                                           Z_SRW_searchRetrieveRequest 
479                                           const *sr_req) const
480 {
481     Package z3950_package(package.session(), package.origin());
482     z3950_package.copy_filter(package); 
483     //mp::odr odr_en(ODR_ENCODE);
484     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_searchRequest);
485
486     //add stuff in z3950 apdu
487     Z_SearchRequest *z_searchRequest = apdu->u.searchRequest;
488
489     // z3950'fy database
490     z_searchRequest->num_databaseNames = 1;
491     z_searchRequest->databaseNames = (char**)
492         odr_malloc(odr_en, sizeof(char *));
493     if (sr_req->database)
494         z_searchRequest->databaseNames[0] 
495             = odr_strdup(odr_en, const_cast<char *>(sr_req->database));
496     else
497         z_searchRequest->databaseNames[0] 
498             = odr_strdup(odr_en, "Default");
499
500
501     // z3950'fy query
502     Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
503     z_searchRequest->query = z_query;
504  
505     if (!z3950_build_query(odr_en, z_query, 
506                            (const SRW_query&)sr_req->query, 
507                            sr_req->query_type))
508     {    
509         //send_to_srw_client_error(7, "query");
510         return false;
511     }
512
513     z3950_package.request() = apdu;
514     //std::cout << "z3950_search_request " << *apdu << "\n";
515         
516     z3950_package.move();
517
518
519     Z_GDU *z3950_gdu = z3950_package.response().get();
520     //std::cout << "z3950_search_request " << *z3950_gdu << "\n";
521
522     //TODO: check success condition
523
524     //int yaz_diag_bib1_to_srw (int bib1_code);
525     //int yaz_diag_srw_to_bib1(int srw_code);
526     //Se kode i src/seshigh.c (srw_bend_search, srw_bend_init).
527
528     if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 
529         && z3950_gdu->u.z3950->which == Z_APDU_searchResponse
530         && z3950_gdu->u.z3950->u.searchResponse->searchStatus)
531     {
532
533         Z_SearchResponse *sr = z3950_gdu->u.z3950->u.searchResponse;
534         if (sr)
535         {
536             // srw'fy number of records
537             sru_pdu_res->u.response->numberOfRecords 
538                 = (int *) odr_malloc(odr_en, sizeof(int *));
539             *(sru_pdu_res->u.response->numberOfRecords) = *(sr->resultCount);
540
541             // srw'fy nextRecordPosition
542             //sru_pdu_res->u.response->nextRecordPosition 
543             //    = (int *) odr_malloc(odr_en, sizeof(int *));
544             //*(sru_pdu_res->u.response->nextRecordPosition) = 1;
545
546         }
547
548         return true;
549     }
550     
551     return false;
552 }
553
554 bool 
555 yf::SRUtoZ3950::Rep::z3950_present_request(mp::Package &package, 
556                                            mp::odr &odr_en,
557                                            Z_SRW_PDU *sru_pdu_res,
558                                            Z_SRW_searchRetrieveRequest 
559                                            const *sr_req)
560     const
561 {
562
563     if (!sr_req)
564         return false;
565
566     
567     // no need to work if nobody wants records seen ..
568     if (!(sr_req->maximumRecords) || 0 == *(sr_req->maximumRecords))
569         return true;
570
571     // creating Z3950 package
572     Package z3950_package(package.session(), package.origin());
573     z3950_package.copy_filter(package); 
574     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_presentRequest);
575
576     assert(apdu->u.presentRequest);
577
578     bool send_z3950_present = true;
579
580     // recordXPath unsupported.
581     if (sr_req->recordXPath)
582     {
583         send_z3950_present = false;
584         yaz_add_srw_diagnostic(odr_en,
585                                &(sru_pdu_res->u.response->diagnostics), 
586                                &(sru_pdu_res->u.response->num_diagnostics), 
587                                72, 0);
588     }
589     
590     // resultSetTTL unsupported.
591     // resultSetIdleTime in response
592     if (sr_req->resultSetTTL)
593     {
594         send_z3950_present = false;
595         yaz_add_srw_diagnostic(odr_en,
596                                &(sru_pdu_res->u.response->diagnostics), 
597                                &(sru_pdu_res->u.response->num_diagnostics), 
598                                50, 0);
599     }
600     
601     // sort unsupported
602     if (sr_req->sort_type != Z_SRW_sort_type_none)
603     {
604         send_z3950_present = false;
605         yaz_add_srw_diagnostic(odr_en,
606                                &(sru_pdu_res->u.response->diagnostics), 
607                                &(sru_pdu_res->u.response->num_diagnostics), 
608                                80, 0);
609     }
610     
611     // exit on all these above diagnostics
612     if (!send_z3950_present)
613         return false;
614
615     // now packaging the z3950 present request
616
617     // z3950'fy start record position
618     if (sr_req->startRecord)
619         *(apdu->u.presentRequest->resultSetStartPoint) 
620             = *(sr_req->startRecord);
621     else 
622         *(apdu->u.presentRequest->resultSetStartPoint) = 1;
623     
624     // z3950'fy number of records requested 
625     if (sr_req->maximumRecords)
626         *(apdu->u.presentRequest->numberOfRecordsRequested) 
627             = *(sr_req->maximumRecords);
628      
629     // z3950'fy recordPacking
630     int record_packing = Z_SRW_recordPacking_XML;
631     if (sr_req->recordPacking && 's' == *(sr_req->recordPacking))
632         record_packing = Z_SRW_recordPacking_string;
633
634     // RecordSyntax will always be XML
635     (apdu->u.presentRequest->preferredRecordSyntax)
636         = yaz_oidval_to_z3950oid (odr_en, CLASS_RECSYN, VAL_TEXT_XML);
637
638     // z3950'fy record schema
639      if (sr_req->recordSchema)
640      {
641          apdu->u.presentRequest->recordComposition 
642              = (Z_RecordComposition *) odr_malloc(odr_en, sizeof(Z_RecordComposition));
643          apdu->u.presentRequest->recordComposition->which 
644              = Z_RecordComp_simple;
645          apdu->u.presentRequest->recordComposition->u.simple 
646              = build_esn_from_schema(odr_en, (const char *) sr_req->recordSchema); 
647      }
648
649     // z3950'fy time to live - flagged as diagnostics above
650     //if (sr_req->resultSetTTL)
651
652     // attaching Z3950 package to filter chain
653     z3950_package.request() = apdu;
654
655     //std::cout << "z3950_present_request " << *apdu << "\n";   
656     z3950_package.move();
657
658     //TODO: check success condition
659     Z_GDU *z3950_gdu = z3950_package.response().get();
660     if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 
661         && z3950_gdu->u.z3950->which == Z_APDU_presentResponse)
662
663     {
664         //std::cout << "z3950_present_request OK\n";
665
666         Z_PresentResponse *pr = z3950_gdu->u.z3950->u.presentResponse;
667         if (pr)
668         {
669             Z_SRW_searchRetrieveResponse *sru_res = sru_pdu_res->u.response;
670             
671             // srw'fy nextRecordPosition
672             if (pr->nextResultSetPosition)
673                 sru_res->nextRecordPosition 
674                     = odr_intdup(odr_en, *(pr->nextResultSetPosition));
675             
676             //    = (int *) odr_malloc(odr_en, sizeof(int *));
677             //*(sru_res->nextRecordPosition) 
678                                                      //= *(Pr->nextResultSetPosition);
679
680             // copy all records if existing
681             if (pr->records && pr->records->which == Z_Records_DBOSD)
682             {
683                 // srw'fy number of returned records
684                 sru_res->num_records
685                     = pr->records->u.databaseOrSurDiagnostics->num_records;
686
687                 sru_res->records 
688                     = (Z_SRW_record *) 
689                     odr_malloc(odr_en, 
690                                sru_res->num_records *sizeof(Z_SRW_record));
691
692                 for (int i = 0; i < sru_res->num_records; i++)
693                 {
694                     Z_NamePlusRecord *npr 
695                         = pr->records->u.databaseOrSurDiagnostics->records[i];
696
697                     sru_res->records[i].recordPosition 
698                         = odr_intdup(odr_en, i + *(apdu->u.presentRequest->resultSetStartPoint));
699
700                     sru_res->records[i].recordPacking = record_packing;
701
702                     if (npr->which != Z_NamePlusRecord_databaseRecord)
703                     {
704                         sru_res->records[i].recordSchema = "diagnostic";
705                         sru_res->records[i].recordData_buf = "67";
706                         sru_res->records[i].recordData_len = 2;
707                     }
708                     else
709                     {
710                         Z_External *r = npr->u.databaseRecord;
711                         oident *ent = oid_getentbyoid(r->direct_reference);
712                         if (r->which == Z_External_octet 
713                             && ent->value == VAL_TEXT_XML)
714                         {
715                             sru_res->records[i].recordSchema = "dc";
716                             sru_res->records[i].recordData_buf
717                                 = odr_strdupn(odr_en, 
718                                               (const char *)r->u.octet_aligned->buf, 
719                                               r->u.octet_aligned->len);
720                             sru_res->records[i].recordData_len 
721                                 = r->u.octet_aligned->len;
722                         }
723                         else
724                         {
725                             sru_res->records[i].recordSchema = "diagnostic";
726                             sru_res->records[i].recordData_buf = "67";
727                             sru_res->records[i].recordData_len = 2;
728                         }
729                     }
730                     
731                 }
732                 
733                 
734             }
735         }
736         return true;
737     }
738
739     return false;
740 }
741
742 bool 
743 yf::SRUtoZ3950::Rep::z3950_scan_request(mp::Package &package,
744                                         mp::odr &odr_en,
745                                         Z_SRW_PDU *sru_pdu_res,
746                                         Z_SRW_scanRequest const *sr_req) const 
747 {
748     Package z3950_package(package.session(), package.origin());
749     z3950_package.copy_filter(package); 
750     //mp::odr odr_en(ODR_ENCODE);
751     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_scanRequest);
752
753     //TODO: add stuff in apdu
754     Z_ScanRequest *z_scanRequest = apdu->u.scanRequest;
755
756     // database repackaging
757     z_scanRequest->num_databaseNames = 1;
758     z_scanRequest->databaseNames = (char**)
759         odr_malloc(odr_en, sizeof(char *));
760     if (sr_req->database)
761         z_scanRequest->databaseNames[0] 
762             = odr_strdup(odr_en, const_cast<char *>(sr_req->database));
763     else
764         z_scanRequest->databaseNames[0] 
765             = odr_strdup(odr_en, "Default");
766
767
768     // query repackaging
769     // CQL or XCQL scan is not possible in Z3950, flagging a diagnostic
770     if (sr_req->query_type != Z_SRW_query_type_pqf)
771     {        
772         //send_to_srw_client_error(7, "query");
773         return false;
774     }
775
776     // PQF query repackaging
777     // need to use Z_AttributesPlusTerm structure, not Z_Query
778     // this can be digget out of a 
779     // Z_query->type1(Z_RPNQuery)->RPNStructure(Z_RPNStructure)
780     //   ->u.simple(Z_Operand)->u.attributesPlusTerm(Z_AttributesPlusTerm )
781
782     //Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
783     //z_searchRequest->query = z_query;
784
785     //if (!z3950_build_query(odr_en, z_query, 
786     //                       (const SRW_query&)sr_req->query, 
787     //                       sr_req->query_type))
788     //{    
789         //send_to_srw_client_error(7, "query");
790     //    return false;
791     //}
792
793     // TODO: 
794
795     z3950_package.request() = apdu;
796     std::cout << "z3950_scan_request " << *apdu << "\n";   
797
798     z3950_package.move();
799     //TODO: check success condition
800     return true;
801     return false;
802 }
803
804 bool yf::SRUtoZ3950::Rep::z3950_build_query(mp::odr &odr_en, Z_Query *z_query, 
805                                             const SRW_query &query, 
806                                             SRW_query_type query_type) const
807 {        
808     if (query_type == Z_SRW_query_type_cql)
809     {
810         Z_External *ext = (Z_External *) 
811             odr_malloc(odr_en, sizeof(*ext));
812         ext->direct_reference = 
813             odr_getoidbystr(odr_en, "1.2.840.10003.16.2");
814         ext->indirect_reference = 0;
815         ext->descriptor = 0;
816         ext->which = Z_External_CQL;
817         ext->u.cql = const_cast<char *>(query.cql);
818         
819         z_query->which = Z_Query_type_104;
820         z_query->u.type_104 =  ext;
821         return true;
822     }
823
824     if (query_type == Z_SRW_query_type_pqf)
825     {
826         Z_RPNQuery *RPNquery;
827         YAZ_PQF_Parser pqf_parser;
828         
829         pqf_parser = yaz_pqf_create ();
830         
831         RPNquery = yaz_pqf_parse (pqf_parser, odr_en, query.pqf);
832         if (!RPNquery)
833         {
834             std::cout << "TODO: Handeling of bad PQF\n";
835             std::cout << "TODO: Diagnostic to be send\n";
836         }
837         z_query->which = Z_Query_type_1;
838         z_query->u.type_1 =  RPNquery;
839         
840         yaz_pqf_destroy(pqf_parser);
841         return true;
842     }
843     return false;
844 }
845
846
847 std::string 
848 yf::SRUtoZ3950::Rep::sru_protocol(const Z_HTTP_Request &http_req) const
849 {
850     const std::string mime_urlencoded("application/x-www-form-urlencoded");
851     const std::string mime_text_xml("text/xml");
852     const std::string mime_soap_xml("application/soap+xml");
853
854     const std::string http_method(http_req.method);
855     const std::string http_type 
856         =  http_header_value(http_req.headers, "Content-Type");
857
858     if (http_method == "GET")
859         return "SRU GET";
860
861     if (http_method == "POST"
862               && http_type  == mime_urlencoded)
863         return "SRU POST";
864     
865     if ( http_method == "POST"
866          && (http_type  == mime_text_xml
867              || http_type  == mime_soap_xml))
868         return "SRU SOAP";
869
870     return "HTTP";
871 }
872
873 std::string 
874 yf::SRUtoZ3950::Rep::debug_http(const Z_HTTP_Request &http_req) const
875 {
876     std::string message("<html>\n<body>\n<h1>"
877                         "Metaproxy SRUtoZ3950 filter"
878                         "</h1>\n");
879     
880     message += "<h3>HTTP Info</h3><br/>\n";
881     message += "<p>\n";
882     message += "<b>Method: </b> " + std::string(http_req.method) + "<br/>\n";
883     message += "<b>Version:</b> " + std::string(http_req.version) + "<br/>\n";
884     message += "<b>Path:   </b> " + std::string(http_req.path) + "<br/>\n";
885
886     message += "<b>Content-Type:</b>"
887         + http_header_value(http_req.headers, "Content-Type")
888         + "<br/>\n";
889     message += "<b>Content-Length:</b>"
890         + http_header_value(http_req.headers, "Content-Length")
891         + "<br/>\n";
892     message += "</p>\n";    
893     
894     message += "<h3>Headers</h3><br/>\n";
895     message += "<p>\n";    
896     Z_HTTP_Header* header = http_req.headers;
897     while (header){
898         message += "<b>Header: </b> <i>" 
899             + std::string(header->name) + ":</i> "
900             + std::string(header->value) + "<br/>\n";
901         header = header->next;
902     }
903     message += "</p>\n";    
904     message += "</body>\n</html>\n";
905     return message;
906 }
907
908 void yf::SRUtoZ3950::Rep::http_response(metaproxy_1::Package &package, 
909                                         const std::string &content, 
910                                         int http_code) const
911 {
912
913     Z_GDU *zgdu_req = package.request().get(); 
914     Z_GDU *zgdu_res = 0; 
915     mp::odr odr;
916     zgdu_res 
917        = odr.create_HTTP_Response(package.session(), 
918                                   zgdu_req->u.HTTP_Request, 
919                                   http_code);
920         
921     zgdu_res->u.HTTP_Response->content_len = content.size();
922     zgdu_res->u.HTTP_Response->content_buf 
923         = (char*) odr_malloc(odr, zgdu_res->u.HTTP_Response->content_len);
924     
925     strncpy(zgdu_res->u.HTTP_Response->content_buf, 
926             content.c_str(),  zgdu_res->u.HTTP_Response->content_len);
927     
928     //z_HTTP_header_add(odr, &hres->headers,
929     //                  "Content-Type", content_type.c_str());
930     package.response() = zgdu_res;
931 }
932
933
934 Z_ElementSetNames * yf::SRUtoZ3950::Rep::build_esn_from_schema(mp::odr &odr_en, const char *schema) const
935 {
936   if (!schema)
937         return 0;
938   
939     Z_ElementSetNames *esn 
940         = (Z_ElementSetNames *) odr_malloc(odr_en, sizeof(Z_ElementSetNames));
941     esn->which = Z_ElementSetNames_generic;
942     esn->u.generic = odr_strdup(odr_en, schema);
943     return esn; 
944 }
945
946 static mp::filter::Base* filter_creator()
947 {
948     return new mp::filter::SRUtoZ3950;
949 }
950
951 extern "C" {
952     struct metaproxy_1_filter_struct metaproxy_1_filter_sru_to_z3950 = {
953         0,
954         "SRUtoZ3950",
955         filter_creator
956     };
957 }
958
959
960 /*
961  * Local variables:
962  * c-basic-offset: 4
963  * indent-tabs-mode: nil
964  * c-file-style: "stroustrup"
965  * End:
966  * vim: shiftwidth=4 tabstop=8 expandtab
967  */