sending SRU searchRetrieve and scan response object. Still needs to
[metaproxy-moved-to-github.git] / src / filter_sru_to_z3950.cpp
1 /* $Id: filter_sru_to_z3950.cpp,v 1.9 2006-09-20 15:08:27 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             //friend class SRUtoZ3950;
64         private:
65             union SRW_query {char * cql; char * xcql; char * pqf;};
66             typedef const int& SRW_query_type;
67         public:
68             void configure(const xmlNode *xmlnode);
69             void process(metaproxy_1::Package &package) const;
70         private:
71             std::string sru_protocol(const Z_HTTP_Request &http_req) const;
72             std::string debug_http(const Z_HTTP_Request &http_req) const;
73             void http_response(mp::Package &package, 
74                                const std::string &content, 
75                                int http_code = 200) const;
76             bool build_sru_debug_package(mp::Package &package) const;
77             bool build_sru_response(mp::Package &package, 
78                                     mp::odr &odr_en,
79                                     Z_SOAP *soap,
80                                     const Z_SRW_PDU *sru_pdu_res,
81                                     char *charset,
82                                     const char *stylesheet) const;
83             Z_SRW_PDU * decode_sru_request(mp::Package &package,   
84                                            mp::odr &odr_de,
85                                            Z_SOAP *&soap,
86                                            char *charset,
87                                            const char *stylesheet) const;
88             bool z3950_build_query(mp::odr &odr_en, Z_Query *z_query, 
89                                    const SRW_query &query, 
90                                    SRW_query_type query_type) const;
91             bool z3950_init_request(mp::Package &package, 
92                                          const std::string 
93                                          &database = "Default") const;
94             bool z3950_close_request(mp::Package &package) const;
95             bool z3950_search_request(mp::Package &package,
96                                       mp::odr &odr_en,
97                                       Z_SRW_PDU *sru_pdu_res,
98                                       Z_SRW_searchRetrieveRequest 
99                                           const *sr_req) const;
100                                       //const std::string &database, 
101                                       //const std::string &query, 
102                                       //int query_type) const;
103             bool z3950_present_request(mp::Package &package,
104                                        mp::odr &odr_en,
105                                        Z_SRW_PDU *sru_pdu_res,
106                                        Z_SRW_searchRetrieveRequest 
107                                        const *sr_req) const;
108             //unsigned int start_position,
109             //unsigned int records_requested) const;
110             bool z3950_scan_request(mp::Package &package,
111                                     mp::odr &odr_en,
112                                     Z_SRW_PDU *sru_pdu_res,
113                                     Z_SRW_scanRequest 
114                                     const *sr_req) const;
115             //const std::string &database, 
116             //const std::string &query, 
117             //int query_type) const;
118         };
119     }
120 }
121
122 yf::SRUtoZ3950::SRUtoZ3950() : m_p(new Rep)
123 {
124 }
125
126 yf::SRUtoZ3950::~SRUtoZ3950()
127 {  // must have a destructor because of boost::scoped_ptr
128 }
129
130 void yf::SRUtoZ3950::configure(const xmlNode *xmlnode)
131 {
132     m_p->configure(xmlnode);
133 }
134
135 void yf::SRUtoZ3950::process(mp::Package &package) const
136 {
137     m_p->process(package);
138 }
139
140 void yf::SRUtoZ3950::Rep::configure(const xmlNode *xmlnode)
141 {
142 }
143
144 void yf::SRUtoZ3950::Rep::process(mp::Package &package) const
145 {
146     Z_GDU *zgdu_req = package.request().get();
147
148     // ignoring all non HTTP_Request packages
149     if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
150         package.move();
151         return;
152     }
153     
154     // only working on  HTTP_Request packages now
155
156
157     // TODO: Z3950 response parsing and translation to SRU package
158     bool ok = true;    
159
160     Z_SRW_PDU *sru_pdu_req = 0;
161     mp::odr odr_de(ODR_DECODE);
162
163     Z_SRW_PDU *sru_pdu_res = 0;
164     mp::odr odr_en(ODR_ENCODE);
165
166     Z_SOAP *soap = 0;
167     char *charset = 0;
168     const char *stylesheet = 0;
169
170     if (! (sru_pdu_req = decode_sru_request(package, odr_de, soap, 
171                                             charset, stylesheet)))
172     {
173         sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response);
174         std::cout << "TODO: correct error when SRW package could not be"
175             " parsed\n";
176         //build_sru_debug_package(package);
177         build_sru_response(package, odr_en, soap, 
178                            sru_pdu_res, charset, stylesheet);
179         return;
180     }
181     
182     
183     // SRU request package translation to Z3950 package
184     if (sru_pdu_req)
185         std::cout << *sru_pdu_req << "\n";
186     else
187         std::cout << "SRU empty\n";
188     
189
190     // explain
191     if (sru_pdu_req && sru_pdu_req->which == Z_SRW_explain_request)
192     {
193         //Z_SRW_searchRetrieveRequest *sr_req = sru_pdu_req->u.request;
194         sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response);
195         std::cout << "TODO: implement explain response";
196         
197     }
198     
199
200     // searchRetrieve
201     if (sru_pdu_req && sru_pdu_req->which == Z_SRW_searchRetrieve_request)
202     {
203         Z_SRW_searchRetrieveRequest *sr_req = sru_pdu_req->u.request;   
204         
205         sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_searchRetrieve_response);
206
207         // TODO: checking of unsupported operations and proper diagnostic setup
208
209         // recordXPath unsupported.
210         //if (sr_req->recordXPath)
211         //    yaz_add_srw_diagnostic(odr_decode(),
212         //                           &diag, &num_diags, 72, 0);
213         // sort unsupported
214         //    if (sr_req->sort_type != Z_SRW_sort_type_none)
215         //        yaz_add_srw_diagnostic(odr_decode(),
216         //                               &diag, &num_diags, 80, 0);
217
218
219         if (z3950_init_request(package))
220         {
221             {
222                 ok = z3950_search_request(package, odr_en,
223                                           sru_pdu_res, sr_req);
224
225                 if (ok && sru_pdu_res->u.response->numberOfRecords
226                     && *(sru_pdu_res->u.response->numberOfRecords))
227                     
228                     ok = z3950_present_request(package, odr_en,
229                                                sru_pdu_res,
230                                                sr_req);
231                 z3950_close_request(package);
232             }
233         }
234     }
235
236     // scan
237     else if (sru_pdu_req && sru_pdu_req->which == Z_SRW_scan_request)
238     {
239         Z_SRW_scanRequest  *sr_req = sru_pdu_req->u.scan_request;   
240
241         sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_scan_response);
242         
243         if (z3950_init_request(package))
244         {
245             z3950_scan_request(package, odr_en, sru_pdu_res, sr_req);    
246             z3950_close_request(package);
247         }        
248     }
249     else
250     {
251         std::cout << "SRU OPERATION NOT SUPPORTED \n";
252         sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response);
253         
254         // TODO: make nice diagnostic return package 
255         package.session().close();
256         return;
257     }
258
259     //build_sru_debug_package(package);
260     build_sru_response(package, odr_en, soap, 
261                        sru_pdu_res, charset, stylesheet);
262     return;
263
264
265
266
267
268
269
270 }
271
272 bool yf::SRUtoZ3950::Rep::build_sru_debug_package(mp::Package &package) const
273 {
274     Z_GDU *zgdu_req = package.request().get();
275     if  (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
276     {    
277         Z_HTTP_Request* http_req =  zgdu_req->u.HTTP_Request;
278         std::string content = debug_http(*http_req);
279         int http_code = 400;    
280         http_response(package, content, http_code);
281         return true;
282     }
283     package.session().close();
284     return false;
285 }
286
287
288 bool yf::SRUtoZ3950::Rep::build_sru_response(mp::Package &package, 
289                                              mp::odr &odr_en,
290                                              Z_SOAP *soap,
291                                              const Z_SRW_PDU *sru_pdu_res,
292                                              char *charset,
293                                              const char *stylesheet) 
294     const
295 {
296
297     // SRU request package translation to Z3950 package
298     if (sru_pdu_res)
299         std::cout << *(const_cast<Z_SRW_PDU *>(sru_pdu_res)) << "\n";
300     else
301         std::cout << "SRU empty\n";
302
303     
304     Z_GDU *zgdu_req = package.request().get();
305     if  (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
306     {    
307         Z_GDU *zgdu_res //= z_get_HTTP_Response(odr_en, 200);
308             = odr_en.create_HTTP_Response(package.session(), 
309                                           zgdu_req->u.HTTP_Request, 
310                                           200);
311           Z_HTTP_Response * http_res = zgdu_res->u.HTTP_Response;
312
313           static Z_SOAP_Handler soap_handlers[4] = {
314               {"http://www.loc.gov/zing/srw/", 0,
315                (Z_SOAP_fun) yaz_srw_codec},
316               {"http://www.loc.gov/zing/srw/v1.0/", 0,
317                (Z_SOAP_fun) yaz_srw_codec},
318               {"http://www.loc.gov/zing/srw/update/", 0,
319                (Z_SOAP_fun) yaz_ucp_codec},
320               {0, 0, 0}
321           };
322
323           //if (!stylesheet && assoc->server)
324           //stylesheet = assoc->server->stylesheet;
325
326           /* empty stylesheet means NO stylesheet */
327           //if (stylesheet && *stylesheet == '\0')
328           //    stylesheet = 0;
329           //ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
330           //&hres->content_buf, &hres->content_len,
331           //                             soap_handlers, charset, stylesheet);
332
333           // encoding SRU package
334
335          soap->u.generic->p  = (void*) sru_pdu_res;         
336          //int ret = 
337          z_soap_codec_enc_xsl(odr_en, &soap, 
338                               &http_res->content_buf, &http_res->content_len,
339                               soap_handlers, charset, 0);
340
341          package.response() = zgdu_res;
342          return true;
343     }
344     package.session().close();
345     return false;
346 }
347
348
349
350  Z_SRW_PDU * yf::SRUtoZ3950::Rep::decode_sru_request(mp::Package &package,
351                                                      mp::odr &odr_de,
352                                                      Z_SOAP *&soap,
353                                                      char *charset,
354                                                      const char *stylesheet) 
355      const
356 {
357     Z_GDU *zgdu_req = package.request().get();
358     Z_SRW_PDU *sru_pdu_req = 0;
359
360     // ignoring all non HTTP_Request packages
361     if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
362         return 0;
363     }
364     
365     Z_HTTP_Request* http_req =  zgdu_req->u.HTTP_Request;
366     if (! http_req)
367         return 0;
368
369     Z_SRW_diagnostic *diag = 0;
370     int num_diags = 0;
371     
372     if (0 == yaz_sru_decode(http_req, &sru_pdu_req, &soap, 
373                             odr_de, &charset, &diag, &num_diags))
374     {
375         if (num_diags)
376         {
377             std::cout << "SRU DECODE DIAGNOSTICS " << num_diags << "\n";
378             // TODO: make nice diagnostic return package 
379             //Z_SRW_PDU *srw_pdu_res =
380             //            yaz_srw_get(odr(ODR_ENCODE),
381             //                        Z_SRW_searchRetrieve_response);
382             //        Z_SRW_searchRetrieveResponse *srw_res = srw_pdu_res->u.response;
383             
384             //        srw_res->diagnostics = diagnostic;
385             //        srw_res->num_diagnostics = num_diagnostic;
386             //        send_srw_response(srw_pdu_res);
387             //        return;
388             
389             // package.session().close();
390             //return 0;
391         }
392         return sru_pdu_req;
393     }
394     else if (0 == yaz_srw_decode(http_req, &sru_pdu_req, &soap, 
395                                  odr_de, &charset))
396         return sru_pdu_req;
397     else 
398     {
399         //std::cout << "SRU DECODING ERROR - SHOULD NEVER HAPPEN\n";
400         package.session().close();
401         return 0;
402     }
403     return 0;
404 }
405
406 bool 
407 yf::SRUtoZ3950::Rep::z3950_init_request(mp::Package &package, 
408                                              const std::string &database) const
409 {
410     // prepare Z3950 package
411     //Session s;
412     //Package z3950_package(s, package.origin());
413     Package z3950_package(package.session(), package.origin());
414     z3950_package.copy_filter(package);
415
416     // set initRequest APDU
417     mp::odr odr_en(ODR_ENCODE);
418     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_initRequest);
419     Z_InitRequest *init_req = apdu->u.initRequest;
420     //TODO: add user name in apdu
421     //TODO: add user passwd in apdu
422     //init_req->idAuthentication = org_init->idAuthentication;
423     //init_req->implementationId = "IDxyz";
424     //init_req->implementationName = "NAMExyz";
425     //init_req->implementationVersion = "VERSIONxyz";
426
427     ODR_MASK_SET(init_req->options, Z_Options_search);
428     ODR_MASK_SET(init_req->options, Z_Options_present);
429     ODR_MASK_SET(init_req->options, Z_Options_namedResultSets);
430     ODR_MASK_SET(init_req->options, Z_Options_scan);
431
432     ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_1);
433     ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_2);
434     ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_3);
435
436     z3950_package.request() = apdu;
437
438     // send Z3950 package
439     // std::cout << "z3950_init_request " << *apdu <<"\n";
440     z3950_package.move();
441
442     // dead Z3950 backend detection
443     if (z3950_package.session().is_closed()){
444         package.session().close();
445         return false;
446     }
447
448     // check successful initResponse
449     Z_GDU *z3950_gdu = z3950_package.response().get();
450
451     if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 
452         && z3950_gdu->u.z3950->which == Z_APDU_initResponse)
453          return true;
454  
455     return false;
456 }
457
458 bool 
459 yf::SRUtoZ3950::Rep::z3950_close_request(mp::Package &package) const
460 {
461     // prepare Z3950 package 
462     Package z3950_package(package.session(), package.origin());
463     z3950_package.copy_filter(package);
464     z3950_package.session().close();
465
466     // set close APDU
467     //mp::odr odr_en(ODR_ENCODE);
468     //Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_close);
469     //z3950_package.request() = apdu;
470
471     z3950_package.move();
472
473     // check successful close response
474     //Z_GDU *z3950_gdu = z3950_package.response().get();
475     //if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 
476     //    && z3950_gdu->u.z3950->which == Z_APDU_close)
477     //    return true;
478
479     if (z3950_package.session().is_closed()){
480         //package.session().close();
481         return true;
482     }
483     return false;
484 }
485
486 bool 
487 yf::SRUtoZ3950::Rep::z3950_search_request(mp::Package &package,  
488                                           mp::odr &odr_en,
489                                           Z_SRW_PDU *sru_pdu_res,
490                                           Z_SRW_searchRetrieveRequest 
491                                           const *sr_req) const
492 {
493     Package z3950_package(package.session(), package.origin());
494     z3950_package.copy_filter(package); 
495     //mp::odr odr_en(ODR_ENCODE);
496     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_searchRequest);
497
498     //add stuff in z3950 apdu
499     Z_SearchRequest *z_searchRequest = apdu->u.searchRequest;
500
501     // z3950'fy database
502     z_searchRequest->num_databaseNames = 1;
503     z_searchRequest->databaseNames = (char**)
504         odr_malloc(odr_en, sizeof(char *));
505     if (sr_req->database)
506         z_searchRequest->databaseNames[0] 
507             = odr_strdup(odr_en, const_cast<char *>(sr_req->database));
508     else
509         z_searchRequest->databaseNames[0] 
510             = odr_strdup(odr_en, "Default");
511
512
513     // z3950'fy query
514     Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
515     z_searchRequest->query = z_query;
516  
517     if (!z3950_build_query(odr_en, z_query, 
518                            (const SRW_query&)sr_req->query, 
519                            sr_req->query_type))
520     {    
521         //send_to_srw_client_error(7, "query");
522         return false;
523     }
524
525     z3950_package.request() = apdu;
526     //std::cout << "z3950_search_request " << *apdu << "\n";
527         
528     z3950_package.move();
529
530     //TODO: check success condition
531
532     //int yaz_diag_bib1_to_srw (int bib1_code);
533     //int yaz_diag_srw_to_bib1(int srw_code);
534     //Se kode i src/seshigh.c (srw_bend_search, srw_bend_init).
535
536     Z_GDU *z3950_gdu = z3950_package.response().get();
537     //std::cout << "z3950_search_request " << *z3950_gdu << "\n";
538
539     if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 
540         && z3950_gdu->u.z3950->which == Z_APDU_searchResponse
541         && z3950_gdu->u.z3950->u.searchResponse->searchStatus)
542     {
543
544         Z_SearchResponse *sr = z3950_gdu->u.z3950->u.searchResponse;
545         if (sr)
546         {
547             // srw'fy number of records
548             sru_pdu_res->u.response->numberOfRecords 
549                 = (int *) odr_malloc(odr_en, sizeof(int *));
550             *(sru_pdu_res->u.response->numberOfRecords) = *(sr->resultCount);
551         }
552
553         return true;
554     }
555     
556     return false;
557 }
558
559 bool 
560 yf::SRUtoZ3950::Rep::z3950_present_request(mp::Package &package, 
561                                            mp::odr &odr_en,
562                                            Z_SRW_PDU *sru_pdu_res,
563                                            Z_SRW_searchRetrieveRequest 
564                                            const *sr_req)
565     const
566 {
567
568     if (!sr_req)
569         return false;
570
571     
572     // no need to work if nobody wants records seen ..
573     if (!(sr_req->maximumRecords) || 0 == *(sr_req->maximumRecords))
574         return true;
575
576     // creating Z3950 package
577     Package z3950_package(package.session(), package.origin());
578     z3950_package.copy_filter(package); 
579     //mp::odr odr_en(ODR_ENCODE);
580     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_presentRequest);
581
582     //TODO: add stuff in apdu
583     assert(apdu->u.presentRequest);
584
585     // z3950'fy start record position
586     if (sr_req->startRecord)
587         *(apdu->u.presentRequest->resultSetStartPoint) 
588             = *(sr_req->startRecord);
589     else 
590         *(apdu->u.presentRequest->resultSetStartPoint) = 1;
591     
592     // z3950'fy number of records requested 
593     if (sr_req->maximumRecords)
594         *(apdu->u.presentRequest->numberOfRecordsRequested) 
595             = *(sr_req->maximumRecords);
596      
597     // TODO: z3950'fy record schema
598     //if (sr_req->recordSchema)
599     //    *(apdu->u.presentRequest->preferredRecordSyntax) 
600     //        = *(sr_req->recordSchema);  
601
602     z3950_package.request() = apdu;
603
604     //std::cout << "z3950_present_request " << *apdu << "\n";   
605     z3950_package.move();
606
607     //TODO: check success condition
608     Z_GDU *z3950_gdu = z3950_package.response().get();
609     if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 
610         && z3950_gdu->u.z3950->which == Z_APDU_presentResponse)
611
612     {
613         //std::cout << "z3950_present_request OK\n";
614
615         Z_PresentResponse *pr = z3950_gdu->u.z3950->u.presentResponse;
616         if (pr)
617         {
618
619             // srw'fy number of returned records
620             //sru_pdu_res->u.response->num_records 
621             //    = *(pr->numberOfRecordsReturned);
622             //= (int *) odr_malloc(odr_en, sizeof(int *));
623             //*(sru_pdu_res->u.response->num_records) 
624             //    = *(pr->numberOfRecordsReturned);
625
626             // srw'fy nextRecordPosition
627             sru_pdu_res->u.response->nextRecordPosition 
628                 = (int *) odr_malloc(odr_en, sizeof(int *));
629             *(sru_pdu_res->u.response->nextRecordPosition) 
630                 = *(pr->nextResultSetPosition);
631         }
632         return true;
633     }
634
635     return false;
636 }
637
638 bool 
639 yf::SRUtoZ3950::Rep::z3950_scan_request(mp::Package &package,
640                                         mp::odr &odr_en,
641                                         Z_SRW_PDU *sru_pdu_res,
642                                         Z_SRW_scanRequest const *sr_req) const 
643 {
644     Package z3950_package(package.session(), package.origin());
645     z3950_package.copy_filter(package); 
646     //mp::odr odr_en(ODR_ENCODE);
647     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_scanRequest);
648
649     //TODO: add stuff in apdu
650     Z_ScanRequest *z_scanRequest = apdu->u.scanRequest;
651
652     // database repackaging
653     z_scanRequest->num_databaseNames = 1;
654     z_scanRequest->databaseNames = (char**)
655         odr_malloc(odr_en, sizeof(char *));
656     if (sr_req->database)
657         z_scanRequest->databaseNames[0] 
658             = odr_strdup(odr_en, const_cast<char *>(sr_req->database));
659     else
660         z_scanRequest->databaseNames[0] 
661             = odr_strdup(odr_en, "Default");
662
663
664     // query repackaging
665     // CQL or XCQL scan is not possible in Z3950, flagging a diagnostic
666     if (sr_req->query_type != Z_SRW_query_type_pqf)
667     {        
668         //send_to_srw_client_error(7, "query");
669         return false;
670     }
671
672     // PQF query repackaging
673     // need to use Z_AttributesPlusTerm structure, not Z_Query
674     // this can be digget out of a 
675     // Z_query->type1(Z_RPNQuery)->RPNStructure(Z_RPNStructure)
676     //   ->u.simple(Z_Operand)->u.attributesPlusTerm(Z_AttributesPlusTerm )
677
678     //Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
679     //z_searchRequest->query = z_query;
680
681     //if (!z3950_build_query(odr_en, z_query, 
682     //                       (const SRW_query&)sr_req->query, 
683     //                       sr_req->query_type))
684     //{    
685         //send_to_srw_client_error(7, "query");
686     //    return false;
687     //}
688
689     // TODO: 
690
691     z3950_package.request() = apdu;
692     std::cout << "z3950_scan_request " << *apdu << "\n";   
693
694     z3950_package.move();
695     //TODO: check success condition
696     return true;
697     return false;
698 }
699
700 bool yf::SRUtoZ3950::Rep::z3950_build_query(mp::odr &odr_en, Z_Query *z_query, 
701                                             const SRW_query &query, 
702                                             SRW_query_type query_type) const
703 {        
704     if (query_type == Z_SRW_query_type_cql)
705     {
706         Z_External *ext = (Z_External *) 
707             odr_malloc(odr_en, sizeof(*ext));
708         ext->direct_reference = 
709             odr_getoidbystr(odr_en, "1.2.840.10003.16.2");
710         ext->indirect_reference = 0;
711         ext->descriptor = 0;
712         ext->which = Z_External_CQL;
713         ext->u.cql = const_cast<char *>(query.cql);
714         
715         z_query->which = Z_Query_type_104;
716         z_query->u.type_104 =  ext;
717         return true;
718     }
719
720     if (query_type == Z_SRW_query_type_pqf)
721     {
722         Z_RPNQuery *RPNquery;
723         YAZ_PQF_Parser pqf_parser;
724         
725         pqf_parser = yaz_pqf_create ();
726         
727         RPNquery = yaz_pqf_parse (pqf_parser, odr_en, query.pqf);
728         if (!RPNquery)
729         {
730             std::cout << "TODO: Handeling of bad PQF\n";
731             std::cout << "TODO: Diagnostic to be send\n";
732         }
733         z_query->which = Z_Query_type_1;
734         z_query->u.type_1 =  RPNquery;
735         
736         yaz_pqf_destroy(pqf_parser);
737         return true;
738     }
739     return false;
740 }
741
742
743 std::string 
744 yf::SRUtoZ3950::Rep::sru_protocol(const Z_HTTP_Request &http_req) const
745 {
746     const std::string mime_urlencoded("application/x-www-form-urlencoded");
747     const std::string mime_text_xml("text/xml");
748     const std::string mime_soap_xml("application/soap+xml");
749
750     const std::string http_method(http_req.method);
751     const std::string http_type 
752         =  http_header_value(http_req.headers, "Content-Type");
753
754     if (http_method == "GET")
755         return "SRU GET";
756
757     if (http_method == "POST"
758               && http_type  == mime_urlencoded)
759         return "SRU POST";
760     
761     if ( http_method == "POST"
762          && (http_type  == mime_text_xml
763              || http_type  == mime_soap_xml))
764         return "SRU SOAP";
765
766     return "HTTP";
767 }
768
769 std::string 
770 yf::SRUtoZ3950::Rep::debug_http(const Z_HTTP_Request &http_req) const
771 {
772     std::string message("<html>\n<body>\n<h1>"
773                         "Metaproxy SRUtoZ3950 filter"
774                         "</h1>\n");
775     
776     message += "<h3>HTTP Info</h3><br/>\n";
777     message += "<p>\n";
778     message += "<b>Method: </b> " + std::string(http_req.method) + "<br/>\n";
779     message += "<b>Version:</b> " + std::string(http_req.version) + "<br/>\n";
780     message += "<b>Path:   </b> " + std::string(http_req.path) + "<br/>\n";
781
782     message += "<b>Content-Type:</b>"
783         + http_header_value(http_req.headers, "Content-Type")
784         + "<br/>\n";
785     message += "<b>Content-Length:</b>"
786         + http_header_value(http_req.headers, "Content-Length")
787         + "<br/>\n";
788     message += "</p>\n";    
789     
790     message += "<h3>Headers</h3><br/>\n";
791     message += "<p>\n";    
792     Z_HTTP_Header* header = http_req.headers;
793     while (header){
794         message += "<b>Header: </b> <i>" 
795             + std::string(header->name) + ":</i> "
796             + std::string(header->value) + "<br/>\n";
797         header = header->next;
798     }
799     message += "</p>\n";    
800     message += "</body>\n</html>\n";
801     return message;
802 }
803
804 void yf::SRUtoZ3950::Rep::http_response(metaproxy_1::Package &package, 
805                                         const std::string &content, 
806                                         int http_code) const
807 {
808
809     Z_GDU *zgdu_req = package.request().get(); 
810     Z_GDU *zgdu_res = 0; 
811     mp::odr odr;
812     zgdu_res 
813        = odr.create_HTTP_Response(package.session(), 
814                                   zgdu_req->u.HTTP_Request, 
815                                   http_code);
816         
817     zgdu_res->u.HTTP_Response->content_len = content.size();
818     zgdu_res->u.HTTP_Response->content_buf 
819         = (char*) odr_malloc(odr, zgdu_res->u.HTTP_Response->content_len);
820     
821     strncpy(zgdu_res->u.HTTP_Response->content_buf, 
822             content.c_str(),  zgdu_res->u.HTTP_Response->content_len);
823     
824     //z_HTTP_header_add(odr, &hres->headers,
825     //                  "Content-Type", content_type.c_str());
826     package.response() = zgdu_res;
827 }
828
829
830
831
832 static mp::filter::Base* filter_creator()
833 {
834     return new mp::filter::SRUtoZ3950;
835 }
836
837 extern "C" {
838     struct metaproxy_1_filter_struct metaproxy_1_filter_sru_to_z3950 = {
839         0,
840         "SRUtoZ3950",
841         filter_creator
842     };
843 }
844
845
846 /*
847  * Local variables:
848  * c-basic-offset: 4
849  * indent-tabs-mode: nil
850  * c-file-style: "stroustrup"
851  * End:
852  * vim: shiftwidth=4 tabstop=8 expandtab
853  */