X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=src%2Ffilter_sru_to_z3950.cpp;h=75c0da4be22bdf56a483e88a583b712eac939a6d;hb=0e655a16ff31347f31878649bb0cf9bc6420469b;hp=328188d7124bd36b93bf972a3994a3be246614fe;hpb=09ce8a48eb9d2947cd019f9b8adb6513941c2211;p=metaproxy-moved-to-github.git diff --git a/src/filter_sru_to_z3950.cpp b/src/filter_sru_to_z3950.cpp index 328188d..75c0da4 100644 --- a/src/filter_sru_to_z3950.cpp +++ b/src/filter_sru_to_z3950.cpp @@ -1,5 +1,5 @@ /* This file is part of Metaproxy. - Copyright (C) 2005-2008 Index Data + Copyright (C) 2005-2012 Index Data Metaproxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -16,10 +16,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +// make std::min actually work on Windows +#define NOMINMAX 1 + #include "config.hpp" -#include "filter.hpp" -#include "package.hpp" -#include "util.hpp" +#include +#include #include "gduutil.hpp" #include "sru_util.hpp" #include "filter_sru_to_z3950.hpp" @@ -37,7 +39,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include -#include +/* #include */ #include namespace mp = metaproxy_1; @@ -46,30 +48,46 @@ namespace yf = mp::filter; namespace metaproxy_1 { namespace filter { + class SRUtoZ3950::Frontend : boost::noncopyable { + friend class Impl; + bool m_in_use; + public: + Frontend(); + ~Frontend(); + }; class SRUtoZ3950::Impl { public: void configure(const xmlNode *xmlnode); void process(metaproxy_1::Package &package); private: - union SRW_query {char * cql; char * xcql; char * pqf;}; - typedef const int& SRW_query_type; + FrontendPtr get_frontend(mp::Package &package); + void release_frontend(mp::Package &package); std::map m_database_explain; typedef std::map ActiveUrlMap; - boost::mutex m_mutex; + boost::mutex m_url_mutex; boost::condition m_cond_url_ready; ActiveUrlMap m_active_urls; + + + boost::mutex m_mutex_session; + boost::condition m_cond_session_ready; + std::map m_clients; private: void sru(metaproxy_1::Package &package, Z_GDU *zgdu_req); - bool z3950_build_query(mp::odr &odr_en, Z_Query *z_query, - const SRW_query &query, - SRW_query_type query_type) const; - - bool z3950_init_request(mp::Package &package, - mp::odr &odr_en, - std::string zurl, - Z_SRW_PDU *sru_pdu_res) const; + int z3950_build_query( + mp::odr &odr_en, Z_Query *z_query, + const Z_SRW_searchRetrieveRequest *req + ) const; + + bool z3950_init_request( + mp::Package &package, + mp::odr &odr_en, + std::string zurl, + Z_SRW_PDU *sru_pdu_res, + const Z_SRW_PDU *sru_pdu_req + ) const; bool z3950_close_request(mp::Package &package) const; @@ -78,28 +96,27 @@ namespace metaproxy_1 { mp::odr &odr_en, Z_SRW_PDU *sru_pdu_res, Z_SRW_searchRetrieveRequest const *sr_req, - std::string zurl) const; + std::string zurl + ) const; bool z3950_present_request( mp::Package &package, mp::odr &odr_en, Z_SRW_PDU *sru_pdu_res, - Z_SRW_searchRetrieveRequest const *sr_req) const; - - bool z3950_scan_request(mp::Package &package, - mp::odr &odr_en, - Z_SRW_PDU *sru_pdu_res, - Z_SRW_scanRequest - const *sr_req) const; - - bool z3950_to_srw_diagnostics_ok(mp::odr &odr_en, - Z_SRW_searchRetrieveResponse *srw_res, - Z_Records *records) const; - - int z3950_to_srw_diag(mp::odr &odr_en, - Z_SRW_searchRetrieveResponse *srw_res, - Z_DefaultDiagFormat *ddf) const; - + Z_SRW_searchRetrieveRequest const *sr_req + ) const; + + bool z3950_to_srw_diagnostics_ok( + mp::odr &odr_en, + Z_SRW_searchRetrieveResponse *srw_res, + Z_Records *records + ) const; + + int z3950_to_srw_diag( + mp::odr &odr_en, + Z_SRW_searchRetrieveResponse *srw_res, + Z_DefaultDiagFormat *ddf + ) const; }; } @@ -113,7 +130,8 @@ yf::SRUtoZ3950::~SRUtoZ3950() { // must have a destructor because of boost::scoped_ptr } -void yf::SRUtoZ3950::configure(const xmlNode *xmlnode, bool test_only) +void yf::SRUtoZ3950::configure(const xmlNode *xmlnode, bool test_only, + const char *path) { m_p->configure(xmlnode); } @@ -127,7 +145,8 @@ void yf::SRUtoZ3950::Impl::configure(const xmlNode *confignode) { const xmlNode * dbnode; - for (dbnode = confignode->children; dbnode; dbnode = dbnode->next){ + for (dbnode = confignode->children; dbnode; dbnode = dbnode->next) + { if (dbnode->type != XML_ELEMENT_NODE) continue; @@ -135,14 +154,16 @@ void yf::SRUtoZ3950::Impl::configure(const xmlNode *confignode) mp::xml::check_element_mp(dbnode, "database"); for (struct _xmlAttr *attr = dbnode->properties; - attr; attr = attr->next){ + attr; attr = attr->next) + { mp::xml::check_attribute(attr, "", "name"); database = mp::xml::get_text(attr); const xmlNode *explainnode; for (explainnode = dbnode->children; - explainnode; explainnode = explainnode->next){ + explainnode; explainnode = explainnode->next) + { if (explainnode->type != XML_ELEMENT_NODE) continue; if (explainnode) @@ -150,7 +171,7 @@ void yf::SRUtoZ3950::Impl::configure(const xmlNode *confignode) } // assigning explain node to database name - no check yet m_database_explain.insert(std::make_pair(database, explainnode)); - } + } } } @@ -171,15 +192,10 @@ void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req) // assign explain config XML DOM node if database is known const xmlNode *explainnode = 0; - if (idbexp != m_database_explain.end()){ + if (idbexp != m_database_explain.end()) + { explainnode = idbexp->second; } - // just moving package if database is not known - else { - package.move(); - return; - } - // decode SRU request Z_SOAP *soap = 0; @@ -188,8 +204,8 @@ void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req) // filter acts as sink for non-valid SRU requests if (! (sru_pdu_req = mp_util::decode_sru_request(package, odr_de, odr_en, - sru_pdu_res, &soap, - charset, stylesheet))) + sru_pdu_res, &soap, + charset, stylesheet))) { if (soap) { @@ -209,6 +225,7 @@ void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req) return; } + bool enable_package_log = false; std::string zurl; Z_SRW_extra_arg *arg; @@ -221,20 +238,29 @@ void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req) { package.origin().set_max_sockets(atoi(arg->value)); } - + else if (!strcmp(arg->name, "x-session-id")) + { + package.origin().set_custom_session(arg->value); + } + else if (!strcmp(arg->name, "x-log-enable")) + { + if (*arg->value == '1') + { + enable_package_log = true; + package.log_enable(); + } + } + assert(sru_pdu_req); // filter acts as sink for SRU explain requests - if (sru_pdu_req && sru_pdu_req->which == Z_SRW_explain_request) + if (sru_pdu_req->which == Z_SRW_explain_request) { Z_SRW_explainRequest *er_req = sru_pdu_req->u.explain_request; - //mp_util::build_simple_explain(package, odr_en, sru_pdu_res, - // sruinfo, er_req); mp_util::build_sru_explain(package, odr_en, sru_pdu_res, sruinfo, explainnode, er_req); } - else if (sru_pdu_req - && sru_pdu_req->which == Z_SRW_searchRetrieve_request - && sru_pdu_req->u.request) + else if (sru_pdu_req->which == Z_SRW_searchRetrieve_request + && sru_pdu_req->u.request) { // searchRetrieve Z_SRW_searchRetrieveRequest *sr_req = sru_pdu_req->u.request; @@ -244,17 +270,16 @@ void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req) ok = mp_util::check_sru_query_exists(package, odr_en, sru_pdu_res, sr_req); - if (ok && z3950_init_request(package, odr_en, zurl, sru_pdu_res)) + if (ok && z3950_init_request(package, odr_en, + zurl, sru_pdu_res, sru_pdu_req)) { ok = z3950_search_request(package, odr_en, sru_pdu_res, sr_req, zurl); if (ok && sru_pdu_res->u.response->numberOfRecords - && *(sru_pdu_res->u.response->numberOfRecords) - && sr_req->maximumRecords - && *(sr_req->maximumRecords)) - + && *(sru_pdu_res->u.response->numberOfRecords)) + ok = z3950_present_request(package, odr_en, sru_pdu_res, sr_req); @@ -263,12 +288,9 @@ void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req) } // scan - else if (sru_pdu_req - && sru_pdu_req->which == Z_SRW_scan_request + else if (sru_pdu_req->which == Z_SRW_scan_request && sru_pdu_req->u.scan_request) { - Z_SRW_scanRequest *sr_req = sru_pdu_req->u.scan_request; - sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_scan_response); // we do not do scan at the moment, therefore issuing a diagnostic @@ -276,78 +298,141 @@ void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req) &(sru_pdu_res->u.scan_response->diagnostics), &(sru_pdu_res->u.scan_response->num_diagnostics), YAZ_SRW_UNSUPP_OPERATION, "scan"); - - // to be used when we do scan - if (false && z3950_init_request(package, odr_en, zurl, sru_pdu_res)) - { - z3950_scan_request(package, odr_en, sru_pdu_res, sr_req); - z3950_close_request(package); - } } else { - //std::cout << "SRU OPERATION NOT SUPPORTED \n"; sru_pdu_res = yaz_srw_get(odr_en, Z_SRW_explain_response); - // TODO: make nice diagnostic return package - return; + yaz_add_srw_diagnostic(odr_en, + &(sru_pdu_res->u.explain_response->diagnostics), + &(sru_pdu_res->u.explain_response->num_diagnostics), + YAZ_SRW_UNSUPP_OPERATION, "unknown"); } + if (enable_package_log) + { + std::string l; + package.log_reset(l); + if (l.length()) + { + mp::wrbuf w; + + wrbuf_puts(w, "\n"); + wrbuf_xmlputs(w, l.c_str()); + wrbuf_puts(w, ""); + + sru_pdu_res->extraResponseData_len = w.len(); + sru_pdu_res->extraResponseData_buf = + odr_strdup(odr_en, wrbuf_cstr(w)); + } + } + // build and send SRU response mp_util::build_sru_response(package, odr_en, soap, sru_pdu_res, charset, stylesheet); } -void yf::SRUtoZ3950::Impl::process(mp::Package &package) +yf::SRUtoZ3950::Frontend::Frontend() : m_in_use(true) { - Z_GDU *zgdu_req = package.request().get(); +} - // ignoring all non HTTP_Request packages - if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){ - package.move(); - return; - } - - // only working on HTTP_Request packages now +yf::SRUtoZ3950::Frontend::~Frontend() +{ +} - // see if HTTP request is already being executed.. - // we consider only the SRU - GET case.. - if (zgdu_req->u.HTTP_Request->content_len == 0) + +yf::SRUtoZ3950::FrontendPtr yf::SRUtoZ3950::Impl::get_frontend( + mp::Package &package) +{ + boost::mutex::scoped_lock lock(m_mutex_session); + + std::map::iterator it; + + while (true) { - const char *path = zgdu_req->u.HTTP_Request->path; - boost::mutex::scoped_lock lock(m_mutex); - while (1) + it = m_clients.find(package.session()); + if (it == m_clients.end()) + break; + + if (!it->second->m_in_use) { - ActiveUrlMap::iterator it = m_active_urls.find(path); - if (it == m_active_urls.end()) - { - m_active_urls[path] = 1; - break; - } - yaz_log(YLOG_LOG, "Waiting for %s to complete", path); - m_cond_url_ready.wait(lock); + it->second->m_in_use = true; + return it->second; } + m_cond_session_ready.wait(lock); } - sru(package, zgdu_req); - if (zgdu_req->u.HTTP_Request->content_len == 0) + FrontendPtr f(new Frontend); + m_clients[package.session()] = f; + f->m_in_use = true; + return f; +} + +void yf::SRUtoZ3950::Impl::release_frontend(mp::Package &package) +{ + boost::mutex::scoped_lock lock(m_mutex_session); + std::map::iterator it; + + it = m_clients.find(package.session()); + if (it != m_clients.end()) { - const char *path = zgdu_req->u.HTTP_Request->path; - boost::mutex::scoped_lock lock(m_mutex); + if (package.session().is_closed()) + { + m_clients.erase(it); + } + else + { + it->second->m_in_use = false; + } + m_cond_session_ready.notify_all(); + } +} + +void yf::SRUtoZ3950::Impl::process(mp::Package &package) +{ + FrontendPtr f = get_frontend(package); - ActiveUrlMap::iterator it = m_active_urls.find(path); + Z_GDU *zgdu_req = package.request().get(); - m_active_urls.erase(it); - m_cond_url_ready.notify_all(); + if (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request) + { + if (zgdu_req->u.HTTP_Request->content_len == 0) + { + const char *path = zgdu_req->u.HTTP_Request->path; + boost::mutex::scoped_lock lock(m_url_mutex); + while (1) + { + ActiveUrlMap::iterator it = m_active_urls.find(path); + if (it == m_active_urls.end()) + { + m_active_urls[path] = 1; + break; + } + yaz_log(YLOG_LOG, "Waiting for %s to complete", path); + m_cond_url_ready.wait(lock); + } + } + sru(package, zgdu_req); + if (zgdu_req && zgdu_req->u.HTTP_Request->content_len == 0) + { + const char *path = zgdu_req->u.HTTP_Request->path; + boost::mutex::scoped_lock lock(m_url_mutex); + + ActiveUrlMap::iterator it = m_active_urls.find(path); + + m_active_urls.erase(it); + m_cond_url_ready.notify_all(); + } } + release_frontend(package); } - bool yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package, mp::odr &odr_en, std::string zurl, - Z_SRW_PDU *sru_pdu_res) const + Z_SRW_PDU *sru_pdu_res, + const Z_SRW_PDU *sru_pdu_req) const { // prepare Z3950 package Package z3950_package(package.session(), package.origin()); @@ -356,13 +441,29 @@ yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package, // set initRequest APDU Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_initRequest); Z_InitRequest *init_req = apdu->u.initRequest; - //TODO: add user name in apdu - //TODO: add user passwd in apdu - //init_req->idAuthentication = org_init->idAuthentication; - //init_req->implementationId = "IDxyz"; - //init_req->implementationName = "NAMExyz"; - //init_req->implementationVersion = "VERSIONxyz"; + Z_IdAuthentication *auth = NULL; + if (sru_pdu_req->username && !sru_pdu_req->password) + { + auth = (Z_IdAuthentication *) odr_malloc(odr_en, sizeof(Z_IdAuthentication)); + auth->which = Z_IdAuthentication_open; + auth->u.open = odr_strdup(odr_en, sru_pdu_req->username); + } + else if (sru_pdu_req->username && sru_pdu_req->password) + { + auth = (Z_IdAuthentication *) odr_malloc(odr_en, sizeof(Z_IdAuthentication)); + auth->which = Z_IdAuthentication_idPass; + auth->u.idPass = (Z_IdPass *) odr_malloc(odr_en, sizeof(Z_IdPass)); + auth->u.idPass->groupId = NULL; + auth->u.idPass->password = odr_strdup(odr_en, sru_pdu_req->password); + auth->u.idPass->userId = odr_strdup(odr_en, sru_pdu_req->username); + } + + init_req->idAuthentication = auth; + + *init_req->preferredMessageSize = 10*1024*1024; + *init_req->maximumRecordSize = 10*1024*1024; + ODR_MASK_SET(init_req->options, Z_Options_search); ODR_MASK_SET(init_req->options, Z_Options_present); ODR_MASK_SET(init_req->options, Z_Options_namedResultSets); @@ -386,7 +487,8 @@ yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package, z3950_package.move(); // dead Z3950 backend detection - if (z3950_package.session().is_closed()){ + if (z3950_package.session().is_closed()) + { yaz_add_srw_diagnostic(odr_en, &(sru_pdu_res->u.response->diagnostics), &(sru_pdu_res->u.response->num_diagnostics), @@ -400,7 +502,7 @@ yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package, if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 && z3950_gdu->u.z3950->which == Z_APDU_initResponse && *z3950_gdu->u.z3950->u.initResponse->result) - return true; + return true; yaz_add_srw_diagnostic(odr_en, &(sru_pdu_res->u.response->diagnostics), @@ -409,28 +511,16 @@ yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package, return false; } -bool -yf::SRUtoZ3950::Impl::z3950_close_request(mp::Package &package) const +bool yf::SRUtoZ3950::Impl::z3950_close_request(mp::Package &package) const { - // prepare and close Z3950 package Package z3950_package(package.session(), package.origin()); z3950_package.copy_filter(package); z3950_package.session().close(); - // set close APDU - //mp::odr odr_en(ODR_ENCODE); - //Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_close); - //z3950_package.request() = apdu; - z3950_package.move(); - // check successful close response - //Z_GDU *z3950_gdu = z3950_package.response().get(); - //if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950 - // && z3950_gdu->u.z3950->which == Z_APDU_close) - // return true; - - if (z3950_package.session().is_closed()){ + if (z3950_package.session().is_closed()) + { return true; } return false; @@ -449,14 +539,16 @@ bool yf::SRUtoZ3950::Impl::z3950_search_request(mp::Package &package, Package z3950_package(package.session(), package.origin()); z3950_package.copy_filter(package); - //add stuff in z3950 apdu Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_searchRequest); Z_SearchRequest *z_searchRequest = apdu->u.searchRequest; + // RecordSyntax will always be XML + z_searchRequest->preferredRecordSyntax + = odr_oiddup(odr_en, yaz_oid_recsyn_xml); if (!mp_util::set_databases_from_zurl(odr_en, zurl, - &z_searchRequest->num_databaseNames, - &z_searchRequest->databaseNames)) + &z_searchRequest->num_databaseNames, + &z_searchRequest->databaseNames)) { z_searchRequest->num_databaseNames = 1; z_searchRequest->databaseNames = (char**) @@ -467,37 +559,29 @@ bool yf::SRUtoZ3950::Impl::z3950_search_request(mp::Package &package, = odr_strdup(odr_en, const_cast(sr_req->database)); else z_searchRequest->databaseNames[0] - = odr_strdup(odr_en, "Default"); + = odr_strdup(odr_en, "Default"); } - // z3950'fy query Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query)); z_searchRequest->query = z_query; - if (!z3950_build_query(odr_en, z_query, - (const SRW_query&)sr_req->query, - sr_req->query_type)) + int sru_diagnostic = z3950_build_query(odr_en, z_query, sr_req); + if (sru_diagnostic) { yaz_add_srw_diagnostic(odr_en, &(sru_pdu_res->u.response->diagnostics), &(sru_pdu_res->u.response->num_diagnostics), - 7, "query"); + sru_diagnostic, + "query"); return false; } z3950_package.request() = apdu; - // send Z39.50 package off to backend z3950_package.move(); - Z_GDU *z3950_gdu = z3950_package.response().get(); - //TODO: check success condition - //int yaz_diag_bib1_to_srw (int bib1_code); - //int yaz_diag_srw_to_bib1(int srw_code); - //Se kode i src/seshigh.c (srw_bend_search, srw_bend_init). - if (!z3950_gdu || z3950_gdu->which != Z_GDU_Z3950 || z3950_gdu->u.z3950->which != Z_APDU_searchResponse || !z3950_gdu->u.z3950->u.searchResponse @@ -506,39 +590,28 @@ bool yf::SRUtoZ3950::Impl::z3950_search_request(mp::Package &package, yaz_add_srw_diagnostic(odr_en, &(sru_pdu_res->u.response->diagnostics), &(sru_pdu_res->u.response->num_diagnostics), - 2, 0); + YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE, 0); return false; } - // everything fine, continuing Z_SearchResponse *sr = z3950_gdu->u.z3950->u.searchResponse; - // checking non surrogate diagnostics in Z3950 search response package if (!z3950_to_srw_diagnostics_ok(odr_en, sru_pdu_res->u.response, sr->records)) { return false; } - // Finally, roll on and srw'fy number of records - sru_pdu_res->u.response->numberOfRecords - = (int *) odr_malloc(odr_en, sizeof(int *)); - *(sru_pdu_res->u.response->numberOfRecords) = *(sr->resultCount); - - // srw'fy nextRecordPosition - //sru_pdu_res->u.response->nextRecordPosition - // = (int *) odr_malloc(odr_en, sizeof(int *)); - //*(sru_pdu_res->u.response->nextRecordPosition) = 1; - + sru_pdu_res->u.response->numberOfRecords + = odr_intdup(odr_en, *sr->resultCount); return true; } -bool -yf::SRUtoZ3950::Impl::z3950_present_request(mp::Package &package, - mp::odr &odr_en, - Z_SRW_PDU *sru_pdu_res, - Z_SRW_searchRetrieveRequest - const *sr_req) +bool yf::SRUtoZ3950::Impl::z3950_present_request( + mp::Package &package, + mp::odr &odr_en, + Z_SRW_PDU *sru_pdu_res, + const Z_SRW_searchRetrieveRequest *sr_req) const { assert(sru_pdu_res->u.response); @@ -614,213 +687,134 @@ yf::SRUtoZ3950::Impl::z3950_present_request(mp::Package &package, // exit on all these above diagnostics if (!send_z3950_present) return false; - - // now packaging the z3950 present request - Package z3950_package(package.session(), package.origin()); - z3950_package.copy_filter(package); - Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_presentRequest); - - assert(apdu->u.presentRequest); - - // z3950'fy start record position - *apdu->u.presentRequest->resultSetStartPoint = start; - - // z3950'fy number of records requested - // protect against requesting records out of range - *apdu->u.presentRequest->numberOfRecordsRequested - = std::min(max_recs, - *sru_pdu_res->u.response->numberOfRecords - start + 1); - - // z3950'fy recordPacking - int record_packing = Z_SRW_recordPacking_XML; - if (sr_req->recordPacking && 's' == *(sr_req->recordPacking)) - record_packing = Z_SRW_recordPacking_string; - // RecordSyntax will always be XML - apdu->u.presentRequest->preferredRecordSyntax - = odr_oiddup(odr_en, yaz_oid_recsyn_xml); - - // z3950'fy record schema - if (sr_req->recordSchema) - { - apdu->u.presentRequest->recordComposition - = (Z_RecordComposition *) - odr_malloc(odr_en, sizeof(Z_RecordComposition)); - apdu->u.presentRequest->recordComposition->which - = Z_RecordComp_simple; - apdu->u.presentRequest->recordComposition->u.simple - = mp_util::build_esn_from_schema(odr_en, - (const char *) - sr_req->recordSchema); - } - - // z3950'fy time to live - flagged as diagnostics above - //if (sr_req->resultSetTTL) - - // attaching Z3950 package to filter chain - z3950_package.request() = apdu; - - // sending Z30.50 present request - z3950_package.move(); - - //check successful Z3950 present response - Z_GDU *z3950_gdu = z3950_package.response().get(); - if (!z3950_gdu || z3950_gdu->which != Z_GDU_Z3950 - || z3950_gdu->u.z3950->which != Z_APDU_presentResponse - || !z3950_gdu->u.z3950->u.presentResponse) + if (max_recs > *sru_pdu_res->u.response->numberOfRecords - start) + max_recs = *sru_pdu_res->u.response->numberOfRecords - start + 1; - { - yaz_add_srw_diagnostic(odr_en, - &(sru_pdu_res->u.response->diagnostics), - &(sru_pdu_res->u.response->num_diagnostics), - YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE, 0); - return false; - } - - - // everything fine, continuing - - Z_PresentResponse *pr = z3950_gdu->u.z3950->u.presentResponse; Z_SRW_searchRetrieveResponse *sru_res = sru_pdu_res->u.response; - - - // checking non surrogate diagnostics in Z3950 present response package - if (!z3950_to_srw_diagnostics_ok(odr_en, sru_pdu_res->u.response, - pr->records)) - return false; - - - - // copy all records if existing - if (pr->records && pr->records->which == Z_Records_DBOSD) + sru_res->records = (Z_SRW_record *) + odr_malloc(odr_en, max_recs * sizeof(Z_SRW_record)); + int num = 0; + while (num < max_recs) { - // srw'fy number of returned records - sru_res->num_records - = pr->records->u.databaseOrSurDiagnostics->num_records; + // now packaging the z3950 present request + Package z3950_package(package.session(), package.origin()); + z3950_package.copy_filter(package); + Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_presentRequest); - sru_res->records - = (Z_SRW_record *) odr_malloc(odr_en, - sru_res->num_records - * sizeof(Z_SRW_record)); + assert(apdu->u.presentRequest); - - // srw'fy nextRecordPosition - // next position never zero or behind the last z3950 record - if (pr->nextResultSetPosition - && *(pr->nextResultSetPosition) > 0 - && *(pr->nextResultSetPosition) - <= *(sru_pdu_res->u.response->numberOfRecords)) - sru_res->nextRecordPosition - = odr_intdup(odr_en, *(pr->nextResultSetPosition)); + *apdu->u.presentRequest->resultSetStartPoint = start + num; + *apdu->u.presentRequest->numberOfRecordsRequested = max_recs - num; - // inserting all records - for (int i = 0; i < sru_res->num_records; i++) + // set response packing to be same as "request" packing.. + int record_packing = Z_SRW_recordPacking_XML; + if (sr_req->recordPacking && 's' == *(sr_req->recordPacking)) + record_packing = Z_SRW_recordPacking_string; + + // RecordSyntax will always be XML + apdu->u.presentRequest->preferredRecordSyntax + = odr_oiddup(odr_en, yaz_oid_recsyn_xml); + + // z3950'fy record schema + if (sr_req->recordSchema) { - int position = i + *apdu->u.presentRequest->resultSetStartPoint; - Z_NamePlusRecord *npr - = pr->records->u.databaseOrSurDiagnostics->records[i]; - - sru_res->records[i].recordPacking = record_packing; + apdu->u.presentRequest->recordComposition + = (Z_RecordComposition *) + odr_malloc(odr_en, sizeof(Z_RecordComposition)); + apdu->u.presentRequest->recordComposition->which + = Z_RecordComp_simple; + apdu->u.presentRequest->recordComposition->u.simple + = mp_util::build_esn_from_schema(odr_en, + (const char *) + sr_req->recordSchema); + } + + // attaching Z3950 package to filter chain + z3950_package.request() = apdu; + + // sending Z30.50 present request + z3950_package.move(); + + //check successful Z3950 present response + Z_GDU *z3950_gdu = z3950_package.response().get(); + if (!z3950_gdu || z3950_gdu->which != Z_GDU_Z3950 + || z3950_gdu->u.z3950->which != Z_APDU_presentResponse + || !z3950_gdu->u.z3950->u.presentResponse) - if (npr->which == Z_NamePlusRecord_databaseRecord && - npr->u.databaseRecord->direct_reference - && !oid_oidcmp(npr->u.databaseRecord->direct_reference, - yaz_oid_recsyn_xml)) - { - // got XML record back - Z_External *r = npr->u.databaseRecord; - sru_res->records[i].recordPosition = - odr_intdup(odr_en, position); - sru_res->records[i].recordSchema = sr_req->recordSchema; - sru_res->records[i].recordData_buf - = odr_strdupn(odr_en, - (const char *)r->u.octet_aligned->buf, - r->u.octet_aligned->len); - sru_res->records[i].recordData_len - = r->u.octet_aligned->len; - } - else + { + yaz_add_srw_diagnostic(odr_en, + &(sru_pdu_res->u.response->diagnostics), + &(sru_pdu_res->u.response->num_diagnostics), + YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE, 0); + return false; + } + // everything fine, continuing + + Z_PresentResponse *pr = z3950_gdu->u.z3950->u.presentResponse; + + // checking non surrogate diagnostics in Z3950 present response package + if (!z3950_to_srw_diagnostics_ok(odr_en, sru_pdu_res->u.response, + pr->records)) + return false; + + // if anything but database or surrogate diagnostics, stop + if (!pr->records || pr->records->which != Z_Records_DBOSD) + break; + else + { + // inserting all records + int returned_recs = + pr->records->u.databaseOrSurDiagnostics->num_records; + for (int i = 0; i < returned_recs; i++) { - // not XML or no database record at all - yaz_mk_sru_surrogate( - odr_en, sru_res->records + i, position, - YAZ_SRW_RECORD_NOT_AVAILABLE_IN_THIS_SCHEMA, 0); + int position = i + *apdu->u.presentRequest->resultSetStartPoint; + Z_NamePlusRecord *npr + = pr->records->u.databaseOrSurDiagnostics->records[i]; + + sru_res->records[i + num].recordPacking = record_packing; + + if (npr->which == Z_NamePlusRecord_databaseRecord && + npr->u.databaseRecord->direct_reference + && !oid_oidcmp(npr->u.databaseRecord->direct_reference, + yaz_oid_recsyn_xml)) + { + // got XML record back + Z_External *r = npr->u.databaseRecord; + sru_res->records[i + num].recordPosition = + odr_intdup(odr_en, position); + sru_res->records[i + num].recordSchema = sr_req->recordSchema; + sru_res->records[i + num].recordData_buf + = odr_strdupn(odr_en, + (const char *)r->u.octet_aligned->buf, + r->u.octet_aligned->len); + sru_res->records[i + num].recordData_len + = r->u.octet_aligned->len; + } + else + { + // not XML or no database record at all + yaz_mk_sru_surrogate( + odr_en, sru_res->records + i + num, position, + YAZ_SRW_RECORD_NOT_AVAILABLE_IN_THIS_SCHEMA, 0); + } } + num += returned_recs; } } - - return true; -} - -bool -yf::SRUtoZ3950::Impl::z3950_scan_request(mp::Package &package, - mp::odr &odr_en, - Z_SRW_PDU *sru_pdu_res, - Z_SRW_scanRequest const *sr_req) const -{ - assert(sru_pdu_res->u.scan_response); - - Package z3950_package(package.session(), package.origin()); - z3950_package.copy_filter(package); - //mp::odr odr_en(ODR_ENCODE); - Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_scanRequest); - - //TODO: add stuff in apdu - Z_ScanRequest *z_scanRequest = apdu->u.scanRequest; - - // database repackaging - z_scanRequest->num_databaseNames = 1; - z_scanRequest->databaseNames = (char**) - odr_malloc(odr_en, sizeof(char *)); - if (sr_req->database) - z_scanRequest->databaseNames[0] - = odr_strdup(odr_en, const_cast(sr_req->database)); - else - z_scanRequest->databaseNames[0] - = odr_strdup(odr_en, "Default"); - - - // query repackaging - // CQL or XCQL scan is not possible in Z3950, flagging a diagnostic - if (sr_req->query_type != Z_SRW_query_type_pqf) - { - //send_to_srw_client_error(7, "query"); - return false; - } - - // PQF query repackaging - // need to use Z_AttributesPlusTerm structure, not Z_Query - // this can be digget out of a - // Z_query->type1(Z_RPNQuery)->RPNStructure(Z_RPNStructure) - // ->u.simple(Z_Operand)->u.attributesPlusTerm(Z_AttributesPlusTerm ) - - //Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query)); - //z_searchRequest->query = z_query; - - //if (!z3950_build_query(odr_en, z_query, - // (const SRW_query&)sr_req->query, - // sr_req->query_type)) - //{ - //send_to_srw_client_error(7, "query"); - // return false; - //} - - // TODO: - - z3950_package.request() = apdu; - std::cout << "z3950_scan_request " << *apdu << "\n"; - - z3950_package.move(); - //TODO: check success condition + sru_res->num_records = num; + if (start - 1 + num < *sru_pdu_res->u.response->numberOfRecords) + sru_res->nextRecordPosition = + odr_intdup(odr_en, start + num); return true; - return false; } -bool yf::SRUtoZ3950::Impl::z3950_build_query(mp::odr &odr_en, Z_Query *z_query, - const SRW_query &query, - SRW_query_type query_type) const +int yf::SRUtoZ3950::Impl::z3950_build_query( + mp::odr &odr_en, Z_Query *z_query, + const Z_SRW_searchRetrieveRequest *req + ) const { - if (query_type == Z_SRW_query_type_cql) + if (req->query_type == Z_SRW_query_type_cql) { Z_External *ext = (Z_External *) odr_malloc(odr_en, sizeof(*ext)); @@ -829,41 +823,40 @@ bool yf::SRUtoZ3950::Impl::z3950_build_query(mp::odr &odr_en, Z_Query *z_query, ext->indirect_reference = 0; ext->descriptor = 0; ext->which = Z_External_CQL; - ext->u.cql = const_cast(query.cql); + ext->u.cql = odr_strdup(odr_en, req->query.cql); z_query->which = Z_Query_type_104; z_query->u.type_104 = ext; - return true; + return 0; } - if (query_type == Z_SRW_query_type_pqf) + if (req->query_type == Z_SRW_query_type_pqf) { Z_RPNQuery *RPNquery; YAZ_PQF_Parser pqf_parser; pqf_parser = yaz_pqf_create (); - RPNquery = yaz_pqf_parse (pqf_parser, odr_en, query.pqf); + RPNquery = yaz_pqf_parse (pqf_parser, odr_en, req->query.pqf); + + yaz_pqf_destroy(pqf_parser); + if (!RPNquery) - { - std::cout << "TODO: Handeling of bad PQF\n"; - std::cout << "TODO: Diagnostic to be send\n"; - } + return YAZ_SRW_QUERY_SYNTAX_ERROR; + z_query->which = Z_Query_type_1; z_query->u.type_1 = RPNquery; - yaz_pqf_destroy(pqf_parser); - return true; + return 0; } - return false; + return YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED; } - -bool -yf::SRUtoZ3950::Impl::z3950_to_srw_diagnostics_ok(mp::odr &odr_en, - Z_SRW_searchRetrieveResponse - *sru_res, - Z_Records *records) const +bool yf::SRUtoZ3950::Impl::z3950_to_srw_diagnostics_ok( + mp::odr &odr_en, + Z_SRW_searchRetrieveResponse + *sru_res, + Z_Records *records) const { // checking non surrogate diagnostics in Z3950 present response package if (records @@ -877,11 +870,10 @@ yf::SRUtoZ3950::Impl::z3950_to_srw_diagnostics_ok(mp::odr &odr_en, return true; } - -int -yf::SRUtoZ3950::Impl::z3950_to_srw_diag(mp::odr &odr_en, - Z_SRW_searchRetrieveResponse *sru_res, - Z_DefaultDiagFormat *ddf) const +int yf::SRUtoZ3950::Impl::z3950_to_srw_diag( + mp::odr &odr_en, + Z_SRW_searchRetrieveResponse *sru_res, + Z_DefaultDiagFormat *ddf) const { int bib1_code = *ddf->condition; sru_res->num_diagnostics = 1; @@ -893,8 +885,6 @@ yf::SRUtoZ3950::Impl::z3950_to_srw_diag(mp::odr &odr_en, return 0; } - - static mp::filter::Base* filter_creator() { return new mp::filter::SRUtoZ3950; @@ -912,8 +902,9 @@ extern "C" { /* * Local variables: * c-basic-offset: 4 + * c-file-style: "Stroustrup" * indent-tabs-mode: nil - * c-file-style: "stroustrup" * End: * vim: shiftwidth=4 tabstop=8 expandtab */ +