more work on SRU explain filters
[metaproxy-moved-to-github.git] / src / filter_sru_to_z3950.cpp
1 /* $Id: filter_sru_to_z3950.cpp,v 1.25 2007-01-07 00:41:18 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 "sru_util.hpp"
13 #include "filter_sru_to_z3950.hpp"
14
15 #include <yaz/zgdu.h>
16 #include <yaz/z-core.h>
17 #include <yaz/srw.h>
18 #include <yaz/pquery.h>
19
20 #include <boost/thread/mutex.hpp>
21
22 #include <iostream>
23 #include <sstream>
24 #include <string>
25 #include <algorithm>
26
27 namespace mp = metaproxy_1;
28 namespace mp_util = metaproxy_1::util;
29 namespace yf = mp::filter;
30
31
32 namespace metaproxy_1 {
33     namespace filter {
34         class SRUtoZ3950::Impl {
35         public:
36             void configure(const xmlNode *xmlnode);
37             void process(metaproxy_1::Package &package) const;
38         private:
39             union SRW_query {char * cql; char * xcql; char * pqf;};
40             typedef const int& SRW_query_type;
41         private:
42
43             bool z3950_build_query(mp::odr &odr_en, Z_Query *z_query, 
44                                    const SRW_query &query, 
45                                    SRW_query_type query_type) const;
46
47             bool z3950_init_request(mp::Package &package, 
48                                          const std::string 
49                                          &database = "Default") const;
50
51             bool z3950_close_request(mp::Package &package) const;
52
53             bool z3950_search_request(mp::Package &package,
54                                       mp::odr &odr_en,
55                                       Z_SRW_PDU *sru_pdu_res,
56                                       Z_SRW_searchRetrieveRequest 
57                                           const *sr_req) const;
58
59             bool z3950_present_request(mp::Package &package,
60                                        mp::odr &odr_en,
61                                        Z_SRW_PDU *sru_pdu_res,
62                                        Z_SRW_searchRetrieveRequest 
63                                        const *sr_req) const;
64
65             bool z3950_scan_request(mp::Package &package,
66                                     mp::odr &odr_en,
67                                     Z_SRW_PDU *sru_pdu_res,
68                                     Z_SRW_scanRequest 
69                                     const *sr_req) const;
70
71
72             int z3950_to_srw_diag(mp::odr &odr_en, 
73                                   Z_SRW_searchRetrieveResponse *srw_res,
74                                   Z_DefaultDiagFormat *ddf) const;
75         };
76     }
77 }
78
79 yf::SRUtoZ3950::SRUtoZ3950() : m_p(new Impl)
80 {
81 }
82
83 yf::SRUtoZ3950::~SRUtoZ3950()
84 {  // must have a destructor because of boost::scoped_ptr
85 }
86
87 void yf::SRUtoZ3950::configure(const xmlNode *xmlnode)
88 {
89     m_p->configure(xmlnode);
90 }
91
92 void yf::SRUtoZ3950::process(mp::Package &package) const
93 {
94     m_p->process(package);
95 }
96
97 void yf::SRUtoZ3950::Impl::configure(const xmlNode *xmlnode)
98 {
99 }
100
101 void yf::SRUtoZ3950::Impl::process(mp::Package &package) const
102 {
103     Z_GDU *zgdu_req = package.request().get();
104
105     // ignoring all non HTTP_Request packages
106     if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
107         package.move();
108         return;
109     }
110     
111     // only working on  HTTP_Request packages now
112
113
114     // TODO: Z3950 response parsing and translation to SRU package
115     bool ok = true;    
116
117     mp::odr odr_de(ODR_DECODE);
118     Z_SRW_PDU *sru_pdu_req = 0;
119
120     mp::odr odr_en(ODR_ENCODE);
121     //Z_SRW_PDU *sru_pdu_res = 0;
122     Z_SRW_PDU *sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response);
123
124     Z_SOAP *soap = 0;
125     char *charset = 0;
126     char *stylesheet = 0;
127
128     mp_util::SRUServerInfo sruinfo = mp_util::get_sru_server_info(package);
129
130
131     if (! (sru_pdu_req = mp_util::decode_sru_request(package, odr_de, odr_en, 
132                                             sru_pdu_res, soap,
133                                             charset, stylesheet)))
134     {
135         //mp_util::build_simple_explain(package, odr_en, sru_pdu_res, sruinfo);
136         //mp_util::build_sru_response(package, odr_en, soap, 
137         //                   sru_pdu_res, charset, stylesheet);
138         //package.session().close();
139         package.move();
140         return;
141     }
142     
143     // explain
144     if (sru_pdu_req && sru_pdu_req->which == Z_SRW_explain_request)
145     {
146         //Z_SRW_explainRequest *er_req = sru_pdu_req->u.explain_request;
147         //sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response);
148
149         //mp_util::build_simple_explain(package, odr_en, sru_pdu_res, 
150         //                              sruinfo, er_req);
151         package.move();
152         return;
153     }
154
155     // searchRetrieve
156     else if (sru_pdu_req 
157         && sru_pdu_req->which == Z_SRW_searchRetrieve_request
158         && sru_pdu_req->u.request)
159     {
160         Z_SRW_searchRetrieveRequest *sr_req = sru_pdu_req->u.request;   
161         
162         sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_searchRetrieve_response);
163
164         // checking that we have a query
165         ok = mp_util::check_sru_query_exists(package, odr_en, 
166                                              sru_pdu_res, sr_req);
167
168         if (ok && z3950_init_request(package))
169         {
170             {
171                 ok = z3950_search_request(package, odr_en,
172                                           sru_pdu_res, sr_req);
173
174                 if (ok 
175                     && sru_pdu_res->u.response->numberOfRecords
176                     && *(sru_pdu_res->u.response->numberOfRecords)
177                     && sr_req->maximumRecords
178                     && *(sr_req->maximumRecords))
179                     
180                     ok = z3950_present_request(package, odr_en,
181                                                sru_pdu_res,
182                                                sr_req);
183                 z3950_close_request(package);
184             }
185         }
186     }
187
188     // scan
189     else if (sru_pdu_req 
190              && sru_pdu_req->which == Z_SRW_scan_request
191              && sru_pdu_req->u.scan_request)
192     {
193         Z_SRW_scanRequest  *sr_req = sru_pdu_req->u.scan_request;   
194
195         sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_scan_response);
196         
197         // we do not do scan at the moment, therefore issuing a diagnostic
198         yaz_add_srw_diagnostic(odr_en,
199                                &(sru_pdu_res->u.scan_response->diagnostics), 
200                                &(sru_pdu_res->u.scan_response->num_diagnostics), 
201                                4, "scan");
202  
203         // to be used when we do scan
204         if (false && z3950_init_request(package))
205         {
206             z3950_scan_request(package, odr_en, sru_pdu_res, sr_req);    
207             z3950_close_request(package);
208         }        
209     }
210     else
211     {
212         //std::cout << "SRU OPERATION NOT SUPPORTED \n";
213         sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response);
214         
215         // TODO: make nice diagnostic return package 
216         package.session().close();
217         return;
218     }
219
220     //mp_util::build_sru_debug_package(package);
221     mp_util::build_sru_response(package, odr_en, soap, 
222                                 sru_pdu_res, charset, stylesheet);
223     return;
224 }
225
226
227
228 bool 
229 yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package, 
230                                              const std::string &database) const
231 {
232     // prepare Z3950 package
233     //Session s;
234     //Package z3950_package(s, package.origin());
235     Package z3950_package(package.session(), package.origin());
236     z3950_package.copy_filter(package);
237
238     // set initRequest APDU
239     mp::odr odr_en(ODR_ENCODE);
240     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_initRequest);
241     Z_InitRequest *init_req = apdu->u.initRequest;
242     //TODO: add user name in apdu
243     //TODO: add user passwd in apdu
244     //init_req->idAuthentication = org_init->idAuthentication;
245     //init_req->implementationId = "IDxyz";
246     //init_req->implementationName = "NAMExyz";
247     //init_req->implementationVersion = "VERSIONxyz";
248
249     ODR_MASK_SET(init_req->options, Z_Options_search);
250     ODR_MASK_SET(init_req->options, Z_Options_present);
251     ODR_MASK_SET(init_req->options, Z_Options_namedResultSets);
252     ODR_MASK_SET(init_req->options, Z_Options_scan);
253
254     ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_1);
255     ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_2);
256     ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_3);
257
258     z3950_package.request() = apdu;
259
260     // send Z3950 package
261     // std::cout << "z3950_init_request " << *apdu <<"\n";
262     z3950_package.move();
263
264     // dead Z3950 backend detection
265     if (z3950_package.session().is_closed()){
266         package.session().close();
267         return false;
268     }
269
270     // check successful initResponse
271     Z_GDU *z3950_gdu = z3950_package.response().get();
272
273     if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 
274         && z3950_gdu->u.z3950->which == Z_APDU_initResponse)
275          return true;
276  
277     return false;
278 }
279
280 bool 
281 yf::SRUtoZ3950::Impl::z3950_close_request(mp::Package &package) const
282 {
283     // close SRU package
284     package.session().close();
285
286     // prepare and close Z3950 package 
287     Package z3950_package(package.session(), package.origin());
288     z3950_package.copy_filter(package);
289     z3950_package.session().close();
290
291     // set close APDU
292     //mp::odr odr_en(ODR_ENCODE);
293     //Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_close);
294     //z3950_package.request() = apdu;
295
296     z3950_package.move();
297
298     // check successful close response
299     //Z_GDU *z3950_gdu = z3950_package.response().get();
300     //if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 
301     //    && z3950_gdu->u.z3950->which == Z_APDU_close)
302     //    return true;
303
304     if (z3950_package.session().is_closed()){
305         return true;
306     }
307     return false;
308 }
309
310 bool 
311 yf::SRUtoZ3950::Impl::z3950_search_request(mp::Package &package,  
312                                           mp::odr &odr_en,
313                                           Z_SRW_PDU *sru_pdu_res,
314                                           Z_SRW_searchRetrieveRequest 
315                                           const *sr_req) const
316 {
317
318     assert(sru_pdu_res->u.response);
319
320     Package z3950_package(package.session(), package.origin());
321     z3950_package.copy_filter(package);
322
323     //add stuff in z3950 apdu
324     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_searchRequest);
325     Z_SearchRequest *z_searchRequest = apdu->u.searchRequest;
326
327     // z3950'fy database
328     z_searchRequest->num_databaseNames = 1;
329     z_searchRequest->databaseNames = (char**)
330         odr_malloc(odr_en, sizeof(char *));
331
332     if (sr_req->database)
333         z_searchRequest->databaseNames[0] 
334             = odr_strdup(odr_en, const_cast<char *>(sr_req->database));
335     else
336         z_searchRequest->databaseNames[0] 
337             = odr_strdup(odr_en, "Default");
338
339
340     // z3950'fy query
341     Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
342     z_searchRequest->query = z_query;
343  
344     if (!z3950_build_query(odr_en, z_query, 
345                            (const SRW_query&)sr_req->query, 
346                            sr_req->query_type))
347     {    
348         yaz_add_srw_diagnostic(odr_en,
349                                &(sru_pdu_res->u.response->diagnostics), 
350                                &(sru_pdu_res->u.response->num_diagnostics), 
351                                7, "query");
352         return false;
353     }
354
355     z3950_package.request() = apdu;
356     //std::cout << "z3950_search_request " << *apdu << "\n";
357         
358     z3950_package.move();
359
360
361     Z_GDU *z3950_gdu = z3950_package.response().get();
362     //std::cout << "z3950_search_request " << *z3950_gdu << "\n";
363
364     //TODO: check success condition
365
366     //int yaz_diag_bib1_to_srw (int bib1_code);
367     //int yaz_diag_srw_to_bib1(int srw_code);
368     //Se kode i src/seshigh.c (srw_bend_search, srw_bend_init).
369
370     if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 
371         && z3950_gdu->u.z3950->which == Z_APDU_searchResponse
372         && z3950_gdu->u.z3950->u.searchResponse->searchStatus)
373     {
374
375         Z_SearchResponse *sr = z3950_gdu->u.z3950->u.searchResponse;
376         if (sr)
377         {
378             // srw'fy number of records
379             sru_pdu_res->u.response->numberOfRecords 
380                 = (int *) odr_malloc(odr_en, sizeof(int *));
381             *(sru_pdu_res->u.response->numberOfRecords) = *(sr->resultCount);
382
383             // srw'fy nextRecordPosition
384             //sru_pdu_res->u.response->nextRecordPosition 
385             //    = (int *) odr_malloc(odr_en, sizeof(int *));
386             //*(sru_pdu_res->u.response->nextRecordPosition) = 1;
387
388         }
389
390         return true;
391     }
392     
393     return false;
394 }
395
396 bool 
397 yf::SRUtoZ3950::Impl::z3950_present_request(mp::Package &package, 
398                                            mp::odr &odr_en,
399                                            Z_SRW_PDU *sru_pdu_res,
400                                            Z_SRW_searchRetrieveRequest 
401                                            const *sr_req)
402     const
403 {
404     assert(sru_pdu_res->u.response);
405
406     if (!sr_req)
407         return false;
408
409     
410     // no need to work if nobody wants record ..
411     if (!(sr_req->maximumRecords) || 0 == *(sr_req->maximumRecords))
412         return true;
413
414     bool send_z3950_present = true;
415
416     // recordXPath unsupported.
417     if (sr_req->recordXPath)
418     {
419         send_z3950_present = false;
420         yaz_add_srw_diagnostic(odr_en,
421                                &(sru_pdu_res->u.response->diagnostics), 
422                                &(sru_pdu_res->u.response->num_diagnostics), 
423                                72, 0);
424     }
425     
426     // resultSetTTL unsupported.
427     // resultSetIdleTime in response
428     if (sr_req->resultSetTTL)
429     {
430         send_z3950_present = false;
431         yaz_add_srw_diagnostic(odr_en,
432                                &(sru_pdu_res->u.response->diagnostics), 
433                                &(sru_pdu_res->u.response->num_diagnostics), 
434                                50, 0);
435     }
436     
437     // sort unsupported
438     if (sr_req->sort_type != Z_SRW_sort_type_none)
439     {
440         send_z3950_present = false;
441         yaz_add_srw_diagnostic(odr_en,
442                                &(sru_pdu_res->u.response->diagnostics), 
443                                &(sru_pdu_res->u.response->num_diagnostics), 
444                                80, 0);
445     }
446     
447     // start record requested negative, or larger than number of records
448     if (sr_req->startRecord 
449         && 
450         ((*(sr_req->startRecord) < 0)       // negative
451          ||
452          (sru_pdu_res->u.response->numberOfRecords  //out of range
453           && *(sr_req->startRecord) 
454           > *(sru_pdu_res->u.response->numberOfRecords))
455         ))
456     {
457         send_z3950_present = false;
458         yaz_add_srw_diagnostic(odr_en,
459                                &(sru_pdu_res->u.response->diagnostics), 
460                                &(sru_pdu_res->u.response->num_diagnostics), 
461                                61, 0);
462     }    
463
464     // maximumRecords requested negative
465     if (sr_req->maximumRecords
466         && *(sr_req->maximumRecords) < 0) 
467           
468     {
469         send_z3950_present = false;
470         yaz_add_srw_diagnostic(odr_en,
471                                &(sru_pdu_res->u.response->diagnostics), 
472                                &(sru_pdu_res->u.response->num_diagnostics), 
473                                6, "maximumRecords");
474     }    
475
476     // exit on all these above diagnostics
477     if (!send_z3950_present)
478         return false;
479
480     // now packaging the z3950 present request
481     Package z3950_package(package.session(), package.origin());
482     z3950_package.copy_filter(package); 
483     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_presentRequest);
484
485     assert(apdu->u.presentRequest);
486
487     // z3950'fy start record position
488     if (sr_req->startRecord)
489         *(apdu->u.presentRequest->resultSetStartPoint) 
490             = *(sr_req->startRecord);
491     else 
492         *(apdu->u.presentRequest->resultSetStartPoint) = 1;
493     
494     // z3950'fy number of records requested 
495     // protect against requesting records out of range
496     if (sr_req->maximumRecords)
497         *(apdu->u.presentRequest->numberOfRecordsRequested) 
498             = std::min(*(sr_req->maximumRecords), 
499                   *(sru_pdu_res->u.response->numberOfRecords)
500                   - *(apdu->u.presentRequest->resultSetStartPoint)
501                   + 1);
502      
503     // z3950'fy recordPacking
504     int record_packing = Z_SRW_recordPacking_XML;
505     if (sr_req->recordPacking && 's' == *(sr_req->recordPacking))
506         record_packing = Z_SRW_recordPacking_string;
507
508     // RecordSyntax will always be XML
509     (apdu->u.presentRequest->preferredRecordSyntax)
510         = yaz_oidval_to_z3950oid (odr_en, CLASS_RECSYN, VAL_TEXT_XML);
511
512     // z3950'fy record schema
513      if (sr_req->recordSchema)
514      {
515          apdu->u.presentRequest->recordComposition 
516              = (Z_RecordComposition *) 
517                odr_malloc(odr_en, sizeof(Z_RecordComposition));
518          apdu->u.presentRequest->recordComposition->which 
519              = Z_RecordComp_simple;
520          apdu->u.presentRequest->recordComposition->u.simple 
521              = mp_util::build_esn_from_schema(odr_en,
522                                       (const char *) sr_req->recordSchema); 
523      }
524
525     // z3950'fy time to live - flagged as diagnostics above
526     //if (sr_req->resultSetTTL)
527
528     // attaching Z3950 package to filter chain
529     z3950_package.request() = apdu;
530
531     //std::cout << "z3950_present_request " << *apdu << "\n";   
532     z3950_package.move();
533
534     //check successful Z3950 present response
535     Z_GDU *z3950_gdu = z3950_package.response().get();
536     if (!z3950_gdu || z3950_gdu->which != Z_GDU_Z3950 
537         || z3950_gdu->u.z3950->which != Z_APDU_presentResponse
538         || !z3950_gdu->u.z3950->u.presentResponse)
539
540     {
541         yaz_add_srw_diagnostic(odr_en,
542                                &(sru_pdu_res->u.response->diagnostics), 
543                                &(sru_pdu_res->u.response->num_diagnostics), 
544                                2, 0);
545         package.session().close();
546         return false;
547     }
548     
549
550     // everything fine, continuing
551     //std::cout << "z3950_present_request OK\n";
552
553     Z_PresentResponse *pr = z3950_gdu->u.z3950->u.presentResponse;
554     Z_SRW_searchRetrieveResponse *sru_res = sru_pdu_res->u.response;
555         
556     // checking non surrogate dioagnostics in Z3950 present response package
557     if (pr->records 
558         && pr->records->which == Z_Records_NSD
559         && pr->records->u.nonSurrogateDiagnostic)
560     {
561         //int http_code =
562         z3950_to_srw_diag(odr_en, sru_res, 
563                           pr->records->u.nonSurrogateDiagnostic);
564         return false;
565     }
566     
567     // copy all records if existing
568     if (pr->records && pr->records->which == Z_Records_DBOSD)
569     {
570         // srw'fy number of returned records
571         sru_res->num_records
572             = pr->records->u.databaseOrSurDiagnostics->num_records;
573         
574         sru_res->records 
575             = (Z_SRW_record *) odr_malloc(odr_en, 
576                                           sru_res->num_records 
577                                              * sizeof(Z_SRW_record));
578         
579
580         // srw'fy nextRecordPosition
581         // next position never zero or behind the last z3950 record 
582         if (pr->nextResultSetPosition
583             && *(pr->nextResultSetPosition) > 0 
584             && *(pr->nextResultSetPosition) 
585                <= *(sru_pdu_res->u.response->numberOfRecords))
586             sru_res->nextRecordPosition 
587                 = odr_intdup(odr_en, *(pr->nextResultSetPosition));
588         
589         // inserting all records
590         for (int i = 0; i < sru_res->num_records; i++)
591         {
592             Z_NamePlusRecord *npr 
593                 = pr->records->u.databaseOrSurDiagnostics->records[i];
594             
595             sru_res->records[i].recordPosition 
596                 = odr_intdup(odr_en, 
597                              i + *(apdu->u.presentRequest->resultSetStartPoint));
598             
599             sru_res->records[i].recordPacking = record_packing;
600             
601             if (npr->which != Z_NamePlusRecord_databaseRecord)
602             {
603                 sru_res->records[i].recordSchema = "diagnostic";
604                 sru_res->records[i].recordData_buf = "67";
605                 sru_res->records[i].recordData_len = 2;
606             }
607             else
608             {
609                 Z_External *r = npr->u.databaseRecord;
610                 oident *ent = oid_getentbyoid(r->direct_reference);
611                 if (r->which == Z_External_octet 
612                     && ent->value == VAL_TEXT_XML)
613                 {
614                     sru_res->records[i].recordSchema = "dc";
615                     sru_res->records[i].recordData_buf
616                         = odr_strdupn(odr_en, 
617                                       (const char *)r->u.octet_aligned->buf, 
618                                       r->u.octet_aligned->len);
619                     sru_res->records[i].recordData_len 
620                         = r->u.octet_aligned->len;
621                 }
622                 else
623                 {
624                     sru_res->records[i].recordSchema = "diagnostic";
625                     sru_res->records[i].recordData_buf = "67";
626                     sru_res->records[i].recordData_len = 2;
627                 }
628             }   
629         }    
630     }
631     
632     return true;
633 }
634
635 bool 
636 yf::SRUtoZ3950::Impl::z3950_scan_request(mp::Package &package,
637                                         mp::odr &odr_en,
638                                         Z_SRW_PDU *sru_pdu_res,
639                                         Z_SRW_scanRequest const *sr_req) const 
640 {
641     assert(sru_pdu_res->u.scan_response);
642
643     Package z3950_package(package.session(), package.origin());
644     z3950_package.copy_filter(package); 
645     //mp::odr odr_en(ODR_ENCODE);
646     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_scanRequest);
647
648     //TODO: add stuff in apdu
649     Z_ScanRequest *z_scanRequest = apdu->u.scanRequest;
650
651     // database repackaging
652     z_scanRequest->num_databaseNames = 1;
653     z_scanRequest->databaseNames = (char**)
654         odr_malloc(odr_en, sizeof(char *));
655     if (sr_req->database)
656         z_scanRequest->databaseNames[0] 
657             = odr_strdup(odr_en, const_cast<char *>(sr_req->database));
658     else
659         z_scanRequest->databaseNames[0] 
660             = odr_strdup(odr_en, "Default");
661
662
663     // query repackaging
664     // CQL or XCQL scan is not possible in Z3950, flagging a diagnostic
665     if (sr_req->query_type != Z_SRW_query_type_pqf)
666     {        
667         //send_to_srw_client_error(7, "query");
668         return false;
669     }
670
671     // PQF query repackaging
672     // need to use Z_AttributesPlusTerm structure, not Z_Query
673     // this can be digget out of a 
674     // Z_query->type1(Z_RPNQuery)->RPNStructure(Z_RPNStructure)
675     //   ->u.simple(Z_Operand)->u.attributesPlusTerm(Z_AttributesPlusTerm )
676
677     //Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
678     //z_searchRequest->query = z_query;
679
680     //if (!z3950_build_query(odr_en, z_query, 
681     //                       (const SRW_query&)sr_req->query, 
682     //                       sr_req->query_type))
683     //{    
684         //send_to_srw_client_error(7, "query");
685     //    return false;
686     //}
687
688     // TODO: 
689
690     z3950_package.request() = apdu;
691     std::cout << "z3950_scan_request " << *apdu << "\n";   
692
693     z3950_package.move();
694     //TODO: check success condition
695     return true;
696     return false;
697 }
698
699 bool yf::SRUtoZ3950::Impl::z3950_build_query(mp::odr &odr_en, Z_Query *z_query, 
700                                             const SRW_query &query, 
701                                             SRW_query_type query_type) const
702 {        
703     if (query_type == Z_SRW_query_type_cql)
704     {
705         Z_External *ext = (Z_External *) 
706             odr_malloc(odr_en, sizeof(*ext));
707         ext->direct_reference = 
708             odr_getoidbystr(odr_en, "1.2.840.10003.16.2");
709         ext->indirect_reference = 0;
710         ext->descriptor = 0;
711         ext->which = Z_External_CQL;
712         ext->u.cql = const_cast<char *>(query.cql);
713         
714         z_query->which = Z_Query_type_104;
715         z_query->u.type_104 =  ext;
716         return true;
717     }
718
719     if (query_type == Z_SRW_query_type_pqf)
720     {
721         Z_RPNQuery *RPNquery;
722         YAZ_PQF_Parser pqf_parser;
723         
724         pqf_parser = yaz_pqf_create ();
725         
726         RPNquery = yaz_pqf_parse (pqf_parser, odr_en, query.pqf);
727         if (!RPNquery)
728         {
729             std::cout << "TODO: Handeling of bad PQF\n";
730             std::cout << "TODO: Diagnostic to be send\n";
731         }
732         z_query->which = Z_Query_type_1;
733         z_query->u.type_1 =  RPNquery;
734         
735         yaz_pqf_destroy(pqf_parser);
736         return true;
737     }
738     return false;
739 }
740
741
742
743 int 
744 yf::SRUtoZ3950::Impl::z3950_to_srw_diag(mp::odr &odr_en, 
745                                        Z_SRW_searchRetrieveResponse *sru_res,
746                                        Z_DefaultDiagFormat *ddf) const
747 {
748     int bib1_code = *ddf->condition;
749     if (bib1_code == 109)
750         return 404;
751     sru_res->num_diagnostics = 1;
752     sru_res->diagnostics = (Z_SRW_diagnostic *)
753         odr_malloc(odr_en, sizeof(*sru_res->diagnostics));
754     yaz_mk_std_diagnostic(odr_en, sru_res->diagnostics,
755                           yaz_diag_bib1_to_srw(*ddf->condition), 
756                           ddf->u.v2Addinfo);
757     return 0;
758 }
759
760
761
762 static mp::filter::Base* filter_creator()
763 {
764     return new mp::filter::SRUtoZ3950;
765 }
766
767 extern "C" {
768     struct metaproxy_1_filter_struct metaproxy_1_filter_sru_to_z3950 = {
769         0,
770         "sru_z3950",
771         filter_creator
772     };
773 }
774
775
776 /*
777  * Local variables:
778  * c-basic-offset: 4
779  * indent-tabs-mode: nil
780  * c-file-style: "stroustrup"
781  * End:
782  * vim: shiftwidth=4 tabstop=8 expandtab
783  */