1 /* This file is part of Metaproxy.
2 Copyright (C) Index Data
4 Metaproxy is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
9 Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 // make std::min actually work on Windows
23 #include <metaproxy/package.hpp>
24 #include <metaproxy/util.hpp>
25 #include "gduutil.hpp"
26 #include "sru_util.hpp"
27 #include "filter_sru_to_z3950.hpp"
30 #include <yaz/pquery.h>
31 #include <yaz/oid_db.h>
33 #include <yaz/otherinfo.h>
34 #if YAZ_VERSIONL >= 0x50000
35 #include <yaz/facet.h>
38 #include <boost/thread/mutex.hpp>
39 #include <boost/thread/condition.hpp>
46 namespace mp = metaproxy_1;
47 namespace mp_util = metaproxy_1::util;
48 namespace yf = mp::filter;
50 namespace metaproxy_1 {
52 class SRUtoZ3950::Frontend : boost::noncopyable {
59 class SRUtoZ3950::Impl {
61 void configure(const xmlNode *xmlnode);
62 void process(metaproxy_1::Package &package);
64 FrontendPtr get_frontend(mp::Package &package);
65 void release_frontend(mp::Package &package);
66 std::map<std::string, const xmlNode *> m_database_explain;
67 std::string default_stylesheet;
69 typedef std::map<std::string, int> ActiveUrlMap;
71 boost::mutex m_url_mutex;
72 boost::condition m_cond_url_ready;
73 ActiveUrlMap m_active_urls;
76 boost::mutex m_mutex_session;
77 boost::condition m_cond_session_ready;
78 std::map<mp::Session, FrontendPtr> m_clients;
80 void sru(metaproxy_1::Package &package, Z_GDU *zgdu_req);
81 int z3950_build_query(
82 mp::odr &odr_en, Z_Query *z_query,
83 const Z_SRW_searchRetrieveRequest *req
86 bool z3950_init_request(
90 Z_SRW_PDU *sru_pdu_res,
91 const Z_SRW_PDU *sru_pdu_req
94 bool z3950_close_request(mp::Package &package) const;
96 bool z3950_search_request(
98 mp::Package &z3950_package,
100 Z_SRW_PDU *sru_pdu_res,
101 Z_SRW_searchRetrieveRequest const *sr_req,
103 std::string db_append
106 bool z3950_present_request(
107 mp::Package &package,
109 Z_SRW_PDU *sru_pdu_res,
110 Z_SRW_searchRetrieveRequest const *sr_req
113 bool z3950_to_srw_diagnostics_ok(
115 Z_SRW_searchRetrieveResponse *srw_res,
119 int z3950_to_srw_diag(
121 Z_SRW_searchRetrieveResponse *srw_res,
122 Z_DefaultDiagFormat *ddf
129 yf::SRUtoZ3950::SRUtoZ3950() : m_p(new Impl)
133 yf::SRUtoZ3950::~SRUtoZ3950()
134 { // must have a destructor because of boost::scoped_ptr
137 void yf::SRUtoZ3950::configure(const xmlNode *xmlnode, bool test_only,
140 m_p->configure(xmlnode);
143 void yf::SRUtoZ3950::process(mp::Package &package) const
145 m_p->process(package);
148 void yf::SRUtoZ3950::Impl::configure(const xmlNode *confignode)
150 const xmlNode * dbnode;
152 for (dbnode = confignode->children; dbnode; dbnode = dbnode->next)
154 if (dbnode->type != XML_ELEMENT_NODE)
157 if (!strcmp((const char *) dbnode->name, "database"))
159 std::string database;
161 for (struct _xmlAttr *attr = dbnode->properties;
162 attr; attr = attr->next)
164 mp::xml::check_attribute(attr, "", "name");
165 database = mp::xml::get_text(attr);
167 const xmlNode *explainnode;
168 for (explainnode = dbnode->children;
169 explainnode; explainnode = explainnode->next)
171 if (explainnode->type == XML_ELEMENT_NODE)
173 m_database_explain.insert(
174 std::make_pair(database, explainnode));
180 else if (!strcmp((const char *) dbnode->name, "stylesheet"))
182 default_stylesheet = mp::xml::get_text(dbnode);
186 throw mp::filter::FilterException
188 + std::string((const char *) dbnode->name)
195 void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req)
199 mp::odr odr_de(ODR_DECODE);
200 Z_SRW_PDU *sru_pdu_req = 0;
202 mp::odr odr_en(ODR_ENCODE);
203 Z_SRW_PDU *sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response);
205 // determine database with the HTTP header information only
206 mp_util::SRUServerInfo sruinfo = mp_util::get_sru_server_info(package);
207 std::map<std::string, const xmlNode *>::iterator idbexp;
208 idbexp = m_database_explain.find(sruinfo.database);
210 // assign explain config XML DOM node if database is known
211 const xmlNode *explainnode = 0;
212 if (idbexp != m_database_explain.end())
214 explainnode = idbexp->second;
217 // decode SRU request
220 const char *stylesheet = 0;
222 // filter acts as sink for non-valid SRU requests
223 if (! (sru_pdu_req = mp_util::decode_sru_request(package, odr_de, odr_en,
229 mp_util::build_sru_explain(package, odr_en, sru_pdu_res,
230 sruinfo, explainnode);
231 mp_util::build_sru_response(package, odr_en, soap,
232 sru_pdu_res, charset, stylesheet);
236 metaproxy_1::odr odr;
238 odr.create_HTTP_Response(package.session(),
239 zgdu_req->u.HTTP_Request, 400);
240 package.response() = zgdu_res;
245 bool enable_package_log = false;
248 Z_SRW_extra_arg *arg;
250 for ( arg = sru_pdu_req->extra_args; arg; arg = arg->next)
251 if (!strcmp(arg->name, "x-target"))
253 zurl = std::string(arg->value);
255 else if (!strcmp(arg->name, "x-max-sockets"))
257 package.origin().set_max_sockets(atoi(arg->value));
259 else if (!strcmp(arg->name, "x-session-id"))
261 package.origin().set_custom_session(arg->value);
263 else if (!strcmp(arg->name, "x-log-enable"))
265 if (*arg->value == '1')
267 enable_package_log = true;
268 package.log_enable();
271 else if (!strncmp(arg->name, "x-client-", 9) && arg->value)
275 dbargs += mp_util::uri_encode(arg->name + 9);
277 dbargs += mp_util::uri_encode(arg->value);
282 Package z3950_package(package.session(), package.origin());
283 z3950_package.copy_filter(package);
285 // filter acts as sink for SRU explain requests
286 if (sru_pdu_req->which == Z_SRW_explain_request)
288 Z_SRW_explainRequest *er_req = sru_pdu_req->u.explain_request;
289 stylesheet = er_req->stylesheet;
291 mp_util::build_sru_explain(package, odr_en, sru_pdu_res,
292 sruinfo, explainnode, er_req);
294 else if (sru_pdu_req->which == Z_SRW_searchRetrieve_request
295 && sru_pdu_req->u.request)
297 Z_SRW_searchRetrieveRequest *sr_req = sru_pdu_req->u.request;
298 stylesheet = sr_req->stylesheet;
300 sru_pdu_res = yaz_srw_get_pdu(odr_en, Z_SRW_searchRetrieve_response,
301 sru_pdu_req->srw_version);
303 // checking that we have a query
304 ok = mp_util::check_sru_query_exists(package, odr_en,
305 sru_pdu_res, sr_req);
307 if (ok && z3950_init_request(package, odr_en,
308 zurl, sru_pdu_res, sru_pdu_req))
310 ok = z3950_search_request(package, z3950_package, odr_en,
311 sru_pdu_res, sr_req, zurl, dbargs);
314 && sru_pdu_res->u.response->numberOfRecords
315 && *(sru_pdu_res->u.response->numberOfRecords))
317 ok = z3950_present_request(package, odr_en,
320 z3950_close_request(package);
325 else if (sru_pdu_req->which == Z_SRW_scan_request
326 && sru_pdu_req->u.scan_request)
328 sru_pdu_res = yaz_srw_get_pdu(odr_en, Z_SRW_scan_response,
329 sru_pdu_req->srw_version);
330 stylesheet = sru_pdu_req->u.scan_request->stylesheet;
332 // we do not do scan at the moment, therefore issuing a diagnostic
333 yaz_add_srw_diagnostic(odr_en,
334 &(sru_pdu_res->u.scan_response->diagnostics),
335 &(sru_pdu_res->u.scan_response->num_diagnostics),
336 YAZ_SRW_UNSUPP_OPERATION, "scan");
340 sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response);
342 yaz_add_srw_diagnostic(odr_en,
343 &(sru_pdu_res->u.explain_response->diagnostics),
344 &(sru_pdu_res->u.explain_response->num_diagnostics),
345 YAZ_SRW_UNSUPP_OPERATION, "unknown");
348 if (enable_package_log)
351 package.log_reset(l);
356 wrbuf_puts(w, "<log>\n");
357 wrbuf_xmlputs(w, l.c_str());
358 wrbuf_puts(w, "</log>");
360 sru_pdu_res->extraResponseData_len = w.len();
361 sru_pdu_res->extraResponseData_buf =
362 odr_strdup(odr_en, wrbuf_cstr(w));
365 if (!stylesheet && default_stylesheet.length())
366 stylesheet = default_stylesheet.c_str();
368 // build and send SRU response
369 mp_util::build_sru_response(package, odr_en, soap,
370 sru_pdu_res, charset, stylesheet);
374 yf::SRUtoZ3950::Frontend::Frontend() : m_in_use(true)
378 yf::SRUtoZ3950::Frontend::~Frontend()
383 yf::SRUtoZ3950::FrontendPtr yf::SRUtoZ3950::Impl::get_frontend(
384 mp::Package &package)
386 boost::mutex::scoped_lock lock(m_mutex_session);
388 std::map<mp::Session,yf::SRUtoZ3950::FrontendPtr>::iterator it;
392 it = m_clients.find(package.session());
393 if (it == m_clients.end())
396 if (!it->second->m_in_use)
398 it->second->m_in_use = true;
401 m_cond_session_ready.wait(lock);
403 FrontendPtr f(new Frontend);
404 m_clients[package.session()] = f;
409 void yf::SRUtoZ3950::Impl::release_frontend(mp::Package &package)
411 boost::mutex::scoped_lock lock(m_mutex_session);
412 std::map<mp::Session,FrontendPtr>::iterator it;
414 it = m_clients.find(package.session());
415 if (it != m_clients.end())
417 if (package.session().is_closed())
423 it->second->m_in_use = false;
425 m_cond_session_ready.notify_all();
429 void yf::SRUtoZ3950::Impl::process(mp::Package &package)
431 FrontendPtr f = get_frontend(package);
433 Z_GDU *zgdu_req = package.request().get();
435 if (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
437 if (zgdu_req->u.HTTP_Request->content_len == 0)
439 const char *path = zgdu_req->u.HTTP_Request->path;
440 boost::mutex::scoped_lock lock(m_url_mutex);
443 ActiveUrlMap::iterator it = m_active_urls.find(path);
444 if (it == m_active_urls.end())
446 m_active_urls[path] = 1;
449 yaz_log(YLOG_LOG, "Waiting for %s to complete", path);
450 m_cond_url_ready.wait(lock);
453 sru(package, zgdu_req);
454 if (zgdu_req && zgdu_req->u.HTTP_Request->content_len == 0)
456 const char *path = zgdu_req->u.HTTP_Request->path;
457 boost::mutex::scoped_lock lock(m_url_mutex);
459 ActiveUrlMap::iterator it = m_active_urls.find(path);
461 m_active_urls.erase(it);
462 m_cond_url_ready.notify_all();
469 release_frontend(package);
473 yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package,
476 Z_SRW_PDU *sru_pdu_res,
477 const Z_SRW_PDU *sru_pdu_req) const
479 // prepare Z3950 package
480 Package z3950_package(package.session(), package.origin());
481 z3950_package.copy_filter(package);
483 // set initRequest APDU
484 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_initRequest);
485 Z_InitRequest *init_req = apdu->u.initRequest;
487 Z_IdAuthentication *auth = NULL;
488 if (sru_pdu_req->username && !sru_pdu_req->password)
490 auth = (Z_IdAuthentication *) odr_malloc(odr_en, sizeof(Z_IdAuthentication));
491 auth->which = Z_IdAuthentication_open;
492 auth->u.open = odr_strdup(odr_en, sru_pdu_req->username);
494 else if (sru_pdu_req->username && sru_pdu_req->password)
496 auth = (Z_IdAuthentication *) odr_malloc(odr_en, sizeof(Z_IdAuthentication));
497 auth->which = Z_IdAuthentication_idPass;
498 auth->u.idPass = (Z_IdPass *) odr_malloc(odr_en, sizeof(Z_IdPass));
499 auth->u.idPass->groupId = NULL;
500 auth->u.idPass->password = odr_strdup(odr_en, sru_pdu_req->password);
501 auth->u.idPass->userId = odr_strdup(odr_en, sru_pdu_req->username);
504 init_req->idAuthentication = auth;
506 *init_req->preferredMessageSize = 10*1024*1024;
507 *init_req->maximumRecordSize = 10*1024*1024;
509 ODR_MASK_SET(init_req->options, Z_Options_search);
510 ODR_MASK_SET(init_req->options, Z_Options_present);
511 ODR_MASK_SET(init_req->options, Z_Options_namedResultSets);
512 ODR_MASK_SET(init_req->options, Z_Options_scan);
514 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_1);
515 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_2);
516 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_3);
521 std::list<std::string> dblist;
522 mp_util::split_zurl(zurl, host, dblist);
523 mp_util::set_vhost_otherinfo(&init_req->otherInfo, odr_en, host, 1);
526 Z_GDU *zgdu_req = package.request().get();
527 if (zgdu_req->which == Z_GDU_HTTP_Request)
529 Z_HTTP_Request *hreq = zgdu_req->u.HTTP_Request;
530 const char *peer_name =
531 z_HTTP_header_lookup(hreq->headers, "X-Forwarded-For");
534 yaz_oi_set_string_oid(&init_req->otherInfo, odr_en,
535 yaz_oid_userinfo_client_ip, 1, peer_name);
539 z3950_package.request() = apdu;
541 // send Z3950 package
542 z3950_package.move();
544 // check successful initResponse
545 Z_GDU *z3950_gdu = z3950_package.response().get();
547 int error = YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE;
548 const char *addinfo = 0;
549 if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950
550 && z3950_gdu->u.z3950->which == Z_APDU_initResponse)
552 Z_InitResponse *initrs = z3950_gdu->u.z3950->u.initResponse;
558 Z_DefaultDiagFormat *df = yaz_decode_init_diag(no, initrs);
562 yaz_add_srw_diagnostic(odr_en,
563 &(sru_pdu_res->u.response->diagnostics),
564 &(sru_pdu_res->u.response->num_diagnostics),
565 yaz_diag_bib1_to_srw(*df->condition),
570 return false; // got least one diagnostic from init
572 // we just have result=false.
573 error = YAZ_SRW_AUTHENTICATION_ERROR;
576 addinfo = "sru_z3950: expected initResponse";
577 yaz_add_srw_diagnostic(odr_en,
578 &(sru_pdu_res->u.response->diagnostics),
579 &(sru_pdu_res->u.response->num_diagnostics),
584 bool yf::SRUtoZ3950::Impl::z3950_close_request(mp::Package &package) const
586 Package z3950_package(package.session(), package.origin());
587 z3950_package.copy_filter(package);
588 z3950_package.session().close();
590 z3950_package.move();
592 if (z3950_package.session().is_closed())
599 bool yf::SRUtoZ3950::Impl::z3950_search_request(mp::Package &package,
600 mp::Package &z3950_package,
602 Z_SRW_PDU *sru_pdu_res,
603 Z_SRW_searchRetrieveRequest
606 std::string dbappend) const
609 assert(sru_pdu_res->u.response);
611 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_searchRequest);
612 Z_SearchRequest *z_searchRequest = apdu->u.searchRequest;
614 // RecordSyntax will always be XML
615 z_searchRequest->preferredRecordSyntax
616 = odr_oiddup(odr_en, yaz_oid_recsyn_xml);
618 if (!mp_util::set_databases_from_zurl(odr_en, zurl,
619 &z_searchRequest->num_databaseNames,
620 &z_searchRequest->databaseNames))
624 if (sr_req->database)
625 db = sr_req->database;
629 if (dbappend.length())
634 z_searchRequest->num_databaseNames = 1;
635 z_searchRequest->databaseNames = (char**)
636 odr_malloc(odr_en, sizeof(char *));
637 z_searchRequest->databaseNames[0] = odr_strdup(odr_en, db.c_str());
639 #if YAZ_VERSIONL >= 0x50000
640 // yaz_oi_set_facetlist not public in YAZ 4.2.66
641 if (sr_req->facetList)
643 Z_OtherInformation **oi = &z_searchRequest->otherInfo;
644 yaz_oi_set_facetlist(oi, odr_en, sr_req->facetList);
648 Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
649 z_searchRequest->query = z_query;
651 int sru_diagnostic = z3950_build_query(odr_en, z_query, sr_req);
654 yaz_add_srw_diagnostic(odr_en,
655 &(sru_pdu_res->u.response->diagnostics),
656 &(sru_pdu_res->u.response->num_diagnostics),
662 z3950_package.request() = apdu;
664 z3950_package.move();
666 Z_GDU *z3950_gdu = z3950_package.response().get();
668 if (!z3950_gdu || z3950_gdu->which != Z_GDU_Z3950
669 || z3950_gdu->u.z3950->which != Z_APDU_searchResponse
670 || !z3950_gdu->u.z3950->u.searchResponse
671 || !z3950_gdu->u.z3950->u.searchResponse->searchStatus)
673 yaz_add_srw_diagnostic(odr_en,
674 &(sru_pdu_res->u.response->diagnostics),
675 &(sru_pdu_res->u.response->num_diagnostics),
676 YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE, 0);
680 Z_SearchResponse *sr = z3950_gdu->u.z3950->u.searchResponse;
682 if (!z3950_to_srw_diagnostics_ok(odr_en, sru_pdu_res->u.response,
687 #if YAZ_VERSIONL >= 0x50000
688 Z_FacetList *fl = yaz_oi_get_facetlist(&sr->additionalSearchInfo);
690 fl = yaz_oi_get_facetlist(&sr->otherInfo);
691 sru_pdu_res->u.response->facetList = fl;
693 sru_pdu_res->u.response->numberOfRecords
694 = odr_intdup(odr_en, *sr->resultCount);
698 bool yf::SRUtoZ3950::Impl::z3950_present_request(
699 mp::Package &package,
701 Z_SRW_PDU *sru_pdu_res,
702 const Z_SRW_searchRetrieveRequest *sr_req)
705 assert(sru_pdu_res->u.response);
712 if (sr_req->maximumRecords)
713 max_recs = *sr_req->maximumRecords;
714 if (sr_req->startRecord)
715 start = *sr_req->startRecord;
717 // no need to work if nobody wants record ..
721 bool send_z3950_present = true;
723 // recordXPath unsupported.
724 if (sr_req->recordXPath)
726 send_z3950_present = false;
727 yaz_add_srw_diagnostic(odr_en,
728 &(sru_pdu_res->u.response->diagnostics),
729 &(sru_pdu_res->u.response->num_diagnostics),
730 YAZ_SRW_XPATH_RETRIEVAL_UNSUPP, 0);
733 // resultSetTTL unsupported.
734 // resultSetIdleTime in response
735 if (sr_req->resultSetTTL)
737 send_z3950_present = false;
738 yaz_add_srw_diagnostic(odr_en,
739 &(sru_pdu_res->u.response->diagnostics),
740 &(sru_pdu_res->u.response->num_diagnostics),
741 YAZ_SRW_RESULT_SETS_UNSUPP, 0);
745 if (sr_req->sort_type != Z_SRW_sort_type_none)
747 send_z3950_present = false;
748 yaz_add_srw_diagnostic(odr_en,
749 &(sru_pdu_res->u.response->diagnostics),
750 &(sru_pdu_res->u.response->num_diagnostics),
751 YAZ_SRW_SORT_UNSUPP, 0);
754 // start record requested negative, or larger than number of records
755 if (start < 0 || start > *sru_pdu_res->u.response->numberOfRecords)
757 send_z3950_present = false;
758 yaz_add_srw_diagnostic(odr_en,
759 &(sru_pdu_res->u.response->diagnostics),
760 &(sru_pdu_res->u.response->num_diagnostics),
761 YAZ_SRW_FIRST_RECORD_POSITION_OUT_OF_RANGE, 0);
764 // maximumRecords requested negative
767 send_z3950_present = false;
768 yaz_add_srw_diagnostic(odr_en,
769 &(sru_pdu_res->u.response->diagnostics),
770 &(sru_pdu_res->u.response->num_diagnostics),
771 YAZ_SRW_UNSUPP_PARAMETER_VALUE,
775 // exit on all these above diagnostics
776 if (!send_z3950_present)
779 if (max_recs > *sru_pdu_res->u.response->numberOfRecords - start)
780 max_recs = *sru_pdu_res->u.response->numberOfRecords - start + 1;
782 Z_SRW_searchRetrieveResponse *sru_res = sru_pdu_res->u.response;
783 sru_res->records = (Z_SRW_record *)
784 odr_malloc(odr_en, max_recs * sizeof(Z_SRW_record));
786 while (num < max_recs)
788 // now packaging the z3950 present request
789 Package z3950_package(package.session(), package.origin());
790 z3950_package.copy_filter(package);
791 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_presentRequest);
793 assert(apdu->u.presentRequest);
795 *apdu->u.presentRequest->resultSetStartPoint = start + num;
796 *apdu->u.presentRequest->numberOfRecordsRequested = max_recs - num;
798 // set response packing to be same as "request" packing..
799 int record_packing = Z_SRW_recordPacking_XML;
800 if (sr_req->recordPacking && 's' == *(sr_req->recordPacking))
801 record_packing = Z_SRW_recordPacking_string;
803 // RecordSyntax will always be XML
804 apdu->u.presentRequest->preferredRecordSyntax
805 = odr_oiddup(odr_en, yaz_oid_recsyn_xml);
807 // z3950'fy record schema
808 if (sr_req->recordSchema)
810 apdu->u.presentRequest->recordComposition
811 = (Z_RecordComposition *)
812 odr_malloc(odr_en, sizeof(Z_RecordComposition));
813 apdu->u.presentRequest->recordComposition->which
814 = Z_RecordComp_simple;
815 apdu->u.presentRequest->recordComposition->u.simple
816 = mp_util::build_esn_from_schema(odr_en,
818 sr_req->recordSchema);
821 // attaching Z3950 package to filter chain
822 z3950_package.request() = apdu;
824 // sending Z30.50 present request
825 z3950_package.move();
827 //check successful Z3950 present response
828 Z_GDU *z3950_gdu = z3950_package.response().get();
829 if (!z3950_gdu || z3950_gdu->which != Z_GDU_Z3950
830 || z3950_gdu->u.z3950->which != Z_APDU_presentResponse
831 || !z3950_gdu->u.z3950->u.presentResponse)
834 yaz_add_srw_diagnostic(odr_en,
835 &(sru_pdu_res->u.response->diagnostics),
836 &(sru_pdu_res->u.response->num_diagnostics),
837 YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE, 0);
840 // everything fine, continuing
842 Z_PresentResponse *pr = z3950_gdu->u.z3950->u.presentResponse;
844 // checking non surrogate diagnostics in Z3950 present response package
845 if (!z3950_to_srw_diagnostics_ok(odr_en, sru_pdu_res->u.response,
849 // if anything but database or surrogate diagnostics, stop
850 if (!pr->records || pr->records->which != Z_Records_DBOSD)
854 // inserting all records
856 pr->records->u.databaseOrSurDiagnostics->num_records;
857 for (int i = 0; i < returned_recs; i++)
859 int position = i + *apdu->u.presentRequest->resultSetStartPoint;
860 Z_NamePlusRecord *npr
861 = pr->records->u.databaseOrSurDiagnostics->records[i];
863 sru_res->records[i + num].recordPacking = record_packing;
865 if (npr->which == Z_NamePlusRecord_surrogateDiagnostic)
867 Z_DiagRec *p = npr->u.surrogateDiagnostic;
868 if (p->which == Z_DiagRec_defaultFormat)
870 Z_DefaultDiagFormat *df = p->u.defaultFormat;
871 int c = yaz_diag_bib1_to_srw(*df->condition);
873 yaz_mk_sru_surrogate(
874 odr_en, sru_res->records + i + num, position,
879 yaz_mk_sru_surrogate(
880 odr_en, sru_res->records + i + num, position,
881 YAZ_SRW_RECORD_TEMPORARILY_UNAVAILABLE, 0);
884 else if (npr->which == Z_NamePlusRecord_databaseRecord &&
885 npr->u.databaseRecord->direct_reference
886 && !oid_oidcmp(npr->u.databaseRecord->direct_reference,
889 // got XML record back
890 Z_External *r = npr->u.databaseRecord;
891 sru_res->records[i + num].recordPosition =
892 odr_intdup(odr_en, position);
893 sru_res->records[i + num].recordSchema = sr_req->recordSchema;
894 sru_res->records[i + num].recordData_buf
895 = odr_strdupn(odr_en,
896 (const char *)r->u.octet_aligned->buf,
897 r->u.octet_aligned->len);
898 sru_res->records[i + num].recordData_len
899 = r->u.octet_aligned->len;
903 // not XML or no database record at all
904 yaz_mk_sru_surrogate(
905 odr_en, sru_res->records + i + num, position,
906 YAZ_SRW_RECORD_NOT_AVAILABLE_IN_THIS_SCHEMA, 0);
909 num += returned_recs;
912 sru_res->num_records = num;
913 if (start - 1 + num < *sru_pdu_res->u.response->numberOfRecords)
914 sru_res->nextRecordPosition =
915 odr_intdup(odr_en, start + num);
919 int yf::SRUtoZ3950::Impl::z3950_build_query(
920 mp::odr &odr_en, Z_Query *z_query,
921 const Z_SRW_searchRetrieveRequest *req
925 #ifdef Z_SRW_query_type_cql
926 req->query_type == Z_SRW_query_type_cql
928 !strcmp(req->queryType, "cql")
932 Z_External *ext = (Z_External *)
933 odr_malloc(odr_en, sizeof(*ext));
934 ext->direct_reference =
935 odr_getoidbystr(odr_en, "1.2.840.10003.16.2");
936 ext->indirect_reference = 0;
938 ext->which = Z_External_CQL;
939 ext->u.cql = odr_strdup(odr_en,
940 #ifdef Z_SRW_query_type_cql
947 z_query->which = Z_Query_type_104;
948 z_query->u.type_104 = ext;
953 #ifdef Z_SRW_query_type_pqf
954 req->query_type == Z_SRW_query_type_pqf
956 !strcmp(req->queryType, "pqf")
960 Z_RPNQuery *RPNquery;
961 YAZ_PQF_Parser pqf_parser;
963 pqf_parser = yaz_pqf_create ();
965 RPNquery = yaz_pqf_parse (pqf_parser, odr_en,
966 #ifdef Z_SRW_query_type_pqf
972 yaz_pqf_destroy(pqf_parser);
975 return YAZ_SRW_QUERY_SYNTAX_ERROR;
977 z_query->which = Z_Query_type_1;
978 z_query->u.type_1 = RPNquery;
982 return YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED;
985 bool yf::SRUtoZ3950::Impl::z3950_to_srw_diagnostics_ok(
987 Z_SRW_searchRetrieveResponse
989 Z_Records *records) const
991 // checking non surrogate diagnostics in Z3950 present response package
993 && records->which == Z_Records_NSD
994 && records->u.nonSurrogateDiagnostic)
996 z3950_to_srw_diag(odr_en, sru_res,
997 records->u.nonSurrogateDiagnostic);
1003 int yf::SRUtoZ3950::Impl::z3950_to_srw_diag(
1005 Z_SRW_searchRetrieveResponse *sru_res,
1006 Z_DefaultDiagFormat *ddf) const
1008 int bib1_code = *ddf->condition;
1009 sru_res->num_diagnostics = 1;
1010 sru_res->diagnostics = (Z_SRW_diagnostic *)
1011 odr_malloc(odr_en, sizeof(*sru_res->diagnostics));
1012 yaz_mk_std_diagnostic(odr_en, sru_res->diagnostics,
1013 yaz_diag_bib1_to_srw(bib1_code),
1018 static mp::filter::Base* filter_creator()
1020 return new mp::filter::SRUtoZ3950;
1024 struct metaproxy_1_filter_struct metaproxy_1_filter_sru_z3950 = {
1035 * c-file-style: "Stroustrup"
1036 * indent-tabs-mode: nil
1038 * vim: shiftwidth=4 tabstop=8 expandtab