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