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);
204 // determine database with the HTTP header information only
205 mp_util::SRUServerInfo sruinfo = mp_util::get_sru_server_info(package);
206 std::map<std::string, const xmlNode *>::iterator idbexp;
207 idbexp = m_database_explain.find(sruinfo.database);
209 // assign explain config XML DOM node if database is known
210 const xmlNode *explainnode = 0;
211 if (idbexp != m_database_explain.end())
213 explainnode = idbexp->second;
216 // decode SRU request
219 const char *stylesheet = 0;
220 Z_SRW_diagnostic *diagnostic = 0;
221 int num_diagnostic = 0;
223 // filter acts as sink for non-valid SRU requests
224 if (! (sru_pdu_req = mp_util::decode_sru_request(package, odr_de, odr_en,
226 &num_diagnostic, &soap,
231 Z_SRW_PDU *sru_pdu_res = yaz_srw_get(odr_en,
232 Z_SRW_explain_response);
233 sru_pdu_res->u.explain_response->diagnostics = diagnostic;
234 sru_pdu_res->u.explain_response->num_diagnostics = num_diagnostic;
235 mp_util::build_sru_explain(package, odr_en, sru_pdu_res,
236 sruinfo, explainnode);
237 mp_util::build_sru_response(package, odr_en, soap,
238 sru_pdu_res, charset, stylesheet);
242 metaproxy_1::odr odr;
244 odr.create_HTTP_Response(package.session(),
245 zgdu_req->u.HTTP_Request, 400);
246 package.response() = zgdu_res;
251 bool enable_package_log = false;
254 Z_SRW_extra_arg *arg;
256 for ( arg = sru_pdu_req->extra_args; arg; arg = arg->next)
257 if (!strcmp(arg->name, "x-target"))
259 zurl = std::string(arg->value);
261 else if (!strcmp(arg->name, "x-max-sockets"))
263 package.origin().set_max_sockets(atoi(arg->value));
265 else if (!strcmp(arg->name, "x-session-id"))
267 package.origin().set_custom_session(arg->value);
269 else if (!strcmp(arg->name, "x-log-enable"))
271 if (*arg->value == '1')
273 enable_package_log = true;
274 package.log_enable();
277 else if (!strncmp(arg->name, "x-client-", 9) && arg->value)
281 dbargs += mp_util::uri_encode(arg->name + 9);
283 dbargs += mp_util::uri_encode(arg->value);
288 Package z3950_package(package.session(), package.origin());
289 z3950_package.copy_filter(package);
291 Z_SRW_PDU *sru_pdu_res = 0;
292 if (sru_pdu_req->which == Z_SRW_explain_request)
294 Z_SRW_explainRequest *er_req = sru_pdu_req->u.explain_request;
295 stylesheet = er_req->stylesheet;
296 sru_pdu_res = yaz_srw_get_pdu_e(odr_en, Z_SRW_explain_response,
298 sru_pdu_res->u.explain_response->diagnostics = diagnostic;
299 sru_pdu_res->u.explain_response->num_diagnostics = num_diagnostic;
300 mp_util::build_sru_explain(package, odr_en, sru_pdu_res,
301 sruinfo, explainnode, er_req);
303 else if (sru_pdu_req->which == Z_SRW_searchRetrieve_request)
305 Z_SRW_searchRetrieveRequest *sr_req = sru_pdu_req->u.request;
306 stylesheet = sr_req->stylesheet;
307 sru_pdu_res = yaz_srw_get_pdu_e(odr_en, Z_SRW_searchRetrieve_response,
309 sru_pdu_res->u.response->diagnostics = diagnostic;
310 sru_pdu_res->u.response->num_diagnostics = num_diagnostic;
312 // checking that we have a query
313 ok = mp_util::check_sru_query_exists(package, odr_en,
314 sru_pdu_res, sr_req);
316 if (ok && z3950_init_request(package, odr_en,
317 zurl, sru_pdu_res, sru_pdu_req))
319 ok = z3950_search_request(package, z3950_package, odr_en,
320 sru_pdu_res, sr_req, zurl, dbargs);
323 && sru_pdu_res->u.response->numberOfRecords
324 && *(sru_pdu_res->u.response->numberOfRecords))
326 ok = z3950_present_request(package, odr_en,
329 z3950_close_request(package);
332 else if (sru_pdu_req->which == Z_SRW_scan_request)
334 stylesheet = sru_pdu_req->u.scan_request->stylesheet;
335 sru_pdu_res = yaz_srw_get_pdu_e(odr_en, Z_SRW_scan_response,
337 sru_pdu_res->u.scan_response->diagnostics = diagnostic;
338 sru_pdu_res->u.scan_response->num_diagnostics = num_diagnostic;
340 // we do not do scan at the moment, therefore issuing a diagnostic
341 yaz_add_srw_diagnostic(odr_en,
342 &sru_pdu_res->u.scan_response->diagnostics,
343 &sru_pdu_res->u.scan_response->num_diagnostics,
344 YAZ_SRW_UNSUPP_OPERATION, "scan");
349 yaz_srw_get_pdu_e(odr_en, Z_SRW_explain_response, sru_pdu_req);
350 sru_pdu_res->u.explain_response->diagnostics = diagnostic;
351 sru_pdu_res->u.explain_response->num_diagnostics = num_diagnostic;
352 yaz_add_srw_diagnostic(odr_en, &diagnostic, &num_diagnostic,
353 YAZ_SRW_UNSUPP_OPERATION, "unknown");
355 if (enable_package_log)
358 package.log_reset(l);
363 wrbuf_puts(w, "<log>\n");
364 wrbuf_xmlputs(w, l.c_str());
365 wrbuf_puts(w, "</log>");
367 sru_pdu_res->extraResponseData_len = w.len();
368 sru_pdu_res->extraResponseData_buf =
369 odr_strdup(odr_en, wrbuf_cstr(w));
372 if (!stylesheet && default_stylesheet.length())
373 stylesheet = default_stylesheet.c_str();
375 // build and send SRU response
376 mp_util::build_sru_response(package, odr_en, soap,
377 sru_pdu_res, charset, stylesheet);
381 yf::SRUtoZ3950::Frontend::Frontend() : m_in_use(true)
385 yf::SRUtoZ3950::Frontend::~Frontend()
390 yf::SRUtoZ3950::FrontendPtr yf::SRUtoZ3950::Impl::get_frontend(
391 mp::Package &package)
393 boost::mutex::scoped_lock lock(m_mutex_session);
395 std::map<mp::Session,yf::SRUtoZ3950::FrontendPtr>::iterator it;
399 it = m_clients.find(package.session());
400 if (it == m_clients.end())
403 if (!it->second->m_in_use)
405 it->second->m_in_use = true;
408 m_cond_session_ready.wait(lock);
410 FrontendPtr f(new Frontend);
411 m_clients[package.session()] = f;
416 void yf::SRUtoZ3950::Impl::release_frontend(mp::Package &package)
418 boost::mutex::scoped_lock lock(m_mutex_session);
419 std::map<mp::Session,FrontendPtr>::iterator it;
421 it = m_clients.find(package.session());
422 if (it != m_clients.end())
424 if (package.session().is_closed())
430 it->second->m_in_use = false;
432 m_cond_session_ready.notify_all();
436 void yf::SRUtoZ3950::Impl::process(mp::Package &package)
438 FrontendPtr f = get_frontend(package);
440 Z_GDU *zgdu_req = package.request().get();
442 if (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
444 if (zgdu_req->u.HTTP_Request->content_len == 0)
446 const char *path = zgdu_req->u.HTTP_Request->path;
447 boost::mutex::scoped_lock lock(m_url_mutex);
450 ActiveUrlMap::iterator it = m_active_urls.find(path);
451 if (it == m_active_urls.end())
453 m_active_urls[path] = 1;
456 yaz_log(YLOG_LOG, "Waiting for %s to complete", path);
457 m_cond_url_ready.wait(lock);
460 sru(package, zgdu_req);
461 if (zgdu_req && zgdu_req->u.HTTP_Request->content_len == 0)
463 const char *path = zgdu_req->u.HTTP_Request->path;
464 boost::mutex::scoped_lock lock(m_url_mutex);
466 ActiveUrlMap::iterator it = m_active_urls.find(path);
468 m_active_urls.erase(it);
469 m_cond_url_ready.notify_all();
476 release_frontend(package);
480 yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package,
483 Z_SRW_PDU *sru_pdu_res,
484 const Z_SRW_PDU *sru_pdu_req) const
486 // prepare Z3950 package
487 Package z3950_package(package.session(), package.origin());
488 z3950_package.copy_filter(package);
490 // set initRequest APDU
491 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_initRequest);
492 Z_InitRequest *init_req = apdu->u.initRequest;
494 Z_IdAuthentication *auth = NULL;
495 if (sru_pdu_req->username && !sru_pdu_req->password)
497 auth = (Z_IdAuthentication *) odr_malloc(odr_en, sizeof(Z_IdAuthentication));
498 auth->which = Z_IdAuthentication_open;
499 auth->u.open = odr_strdup(odr_en, sru_pdu_req->username);
501 else if (sru_pdu_req->username && sru_pdu_req->password)
503 auth = (Z_IdAuthentication *) odr_malloc(odr_en, sizeof(Z_IdAuthentication));
504 auth->which = Z_IdAuthentication_idPass;
505 auth->u.idPass = (Z_IdPass *) odr_malloc(odr_en, sizeof(Z_IdPass));
506 auth->u.idPass->groupId = NULL;
507 auth->u.idPass->password = odr_strdup(odr_en, sru_pdu_req->password);
508 auth->u.idPass->userId = odr_strdup(odr_en, sru_pdu_req->username);
511 init_req->idAuthentication = auth;
513 *init_req->preferredMessageSize = 10*1024*1024;
514 *init_req->maximumRecordSize = 10*1024*1024;
516 ODR_MASK_SET(init_req->options, Z_Options_search);
517 ODR_MASK_SET(init_req->options, Z_Options_present);
518 ODR_MASK_SET(init_req->options, Z_Options_namedResultSets);
519 ODR_MASK_SET(init_req->options, Z_Options_scan);
521 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_1);
522 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_2);
523 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_3);
528 std::list<std::string> dblist;
529 mp_util::split_zurl(zurl, host, dblist);
530 mp_util::set_vhost_otherinfo(&init_req->otherInfo, odr_en, host, 1);
533 Z_GDU *zgdu_req = package.request().get();
534 if (zgdu_req->which == Z_GDU_HTTP_Request)
536 Z_HTTP_Request *hreq = zgdu_req->u.HTTP_Request;
537 const char *peer_name =
538 z_HTTP_header_lookup(hreq->headers, "X-Forwarded-For");
541 yaz_oi_set_string_oid(&init_req->otherInfo, odr_en,
542 yaz_oid_userinfo_client_ip, 1, peer_name);
546 z3950_package.request() = apdu;
548 // send Z3950 package
549 z3950_package.move();
551 // check successful initResponse
552 Z_GDU *z3950_gdu = z3950_package.response().get();
554 int error = YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE;
555 const char *addinfo = 0;
556 if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950
557 && z3950_gdu->u.z3950->which == Z_APDU_initResponse)
559 Z_InitResponse *initrs = z3950_gdu->u.z3950->u.initResponse;
565 Z_DefaultDiagFormat *df = yaz_decode_init_diag(no, initrs);
569 yaz_add_srw_diagnostic(odr_en,
570 &(sru_pdu_res->u.response->diagnostics),
571 &(sru_pdu_res->u.response->num_diagnostics),
572 yaz_diag_bib1_to_srw(*df->condition),
577 return false; // got least one diagnostic from init
579 // we just have result=false.
580 error = YAZ_SRW_AUTHENTICATION_ERROR;
583 addinfo = "sru_z3950: expected initResponse";
584 yaz_add_srw_diagnostic(odr_en,
585 &(sru_pdu_res->u.response->diagnostics),
586 &(sru_pdu_res->u.response->num_diagnostics),
591 bool yf::SRUtoZ3950::Impl::z3950_close_request(mp::Package &package) const
593 Package z3950_package(package.session(), package.origin());
594 z3950_package.copy_filter(package);
595 z3950_package.session().close();
597 z3950_package.move();
599 if (z3950_package.session().is_closed())
606 bool yf::SRUtoZ3950::Impl::z3950_search_request(mp::Package &package,
607 mp::Package &z3950_package,
609 Z_SRW_PDU *sru_pdu_res,
610 Z_SRW_searchRetrieveRequest
613 std::string dbappend) const
616 assert(sru_pdu_res->u.response);
618 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_searchRequest);
619 Z_SearchRequest *z_searchRequest = apdu->u.searchRequest;
621 // RecordSyntax will always be XML
622 z_searchRequest->preferredRecordSyntax
623 = odr_oiddup(odr_en, yaz_oid_recsyn_xml);
625 if (!mp_util::set_databases_from_zurl(odr_en, zurl,
626 &z_searchRequest->num_databaseNames,
627 &z_searchRequest->databaseNames))
631 if (sr_req->database)
632 db = sr_req->database;
636 if (dbappend.length())
641 z_searchRequest->num_databaseNames = 1;
642 z_searchRequest->databaseNames = (char**)
643 odr_malloc(odr_en, sizeof(char *));
644 z_searchRequest->databaseNames[0] = odr_strdup(odr_en, db.c_str());
646 #if YAZ_VERSIONL >= 0x50000
647 // yaz_oi_set_facetlist not public in YAZ 4.2.66
648 if (sr_req->facetList)
650 Z_OtherInformation **oi = &z_searchRequest->additionalSearchInfo;
651 yaz_oi_set_facetlist(oi, odr_en, sr_req->facetList);
655 Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
656 z_searchRequest->query = z_query;
658 int sru_diagnostic = z3950_build_query(odr_en, z_query, sr_req);
661 yaz_add_srw_diagnostic(odr_en,
662 &(sru_pdu_res->u.response->diagnostics),
663 &(sru_pdu_res->u.response->num_diagnostics),
669 z3950_package.request() = apdu;
671 z3950_package.move();
673 Z_GDU *z3950_gdu = z3950_package.response().get();
675 if (!z3950_gdu || z3950_gdu->which != Z_GDU_Z3950
676 || z3950_gdu->u.z3950->which != Z_APDU_searchResponse
677 || !z3950_gdu->u.z3950->u.searchResponse
678 || !z3950_gdu->u.z3950->u.searchResponse->searchStatus)
680 yaz_add_srw_diagnostic(odr_en,
681 &(sru_pdu_res->u.response->diagnostics),
682 &(sru_pdu_res->u.response->num_diagnostics),
683 YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE, 0);
687 Z_SearchResponse *sr = z3950_gdu->u.z3950->u.searchResponse;
689 if (!z3950_to_srw_diagnostics_ok(odr_en, sru_pdu_res->u.response,
694 #if YAZ_VERSIONL >= 0x50000
695 Z_FacetList *fl = yaz_oi_get_facetlist(&sr->additionalSearchInfo);
697 fl = yaz_oi_get_facetlist(&sr->otherInfo);
698 sru_pdu_res->u.response->facetList = fl;
700 sru_pdu_res->u.response->numberOfRecords
701 = odr_intdup(odr_en, *sr->resultCount);
705 bool yf::SRUtoZ3950::Impl::z3950_present_request(
706 mp::Package &package,
708 Z_SRW_PDU *sru_pdu_res,
709 const Z_SRW_searchRetrieveRequest *sr_req)
712 assert(sru_pdu_res->u.response);
719 if (sr_req->maximumRecords)
720 max_recs = *sr_req->maximumRecords;
721 if (sr_req->startRecord)
722 start = *sr_req->startRecord;
724 // no need to work if nobody wants record ..
728 bool send_z3950_present = true;
730 // recordXPath unsupported.
731 if (sr_req->recordXPath)
733 send_z3950_present = false;
734 yaz_add_srw_diagnostic(odr_en,
735 &(sru_pdu_res->u.response->diagnostics),
736 &(sru_pdu_res->u.response->num_diagnostics),
737 YAZ_SRW_XPATH_RETRIEVAL_UNSUPP, 0);
740 // resultSetTTL unsupported.
741 // resultSetIdleTime in response
742 if (sr_req->resultSetTTL)
744 send_z3950_present = false;
745 yaz_add_srw_diagnostic(odr_en,
746 &(sru_pdu_res->u.response->diagnostics),
747 &(sru_pdu_res->u.response->num_diagnostics),
748 YAZ_SRW_RESULT_SETS_UNSUPP, 0);
752 if (sr_req->sort_type != Z_SRW_sort_type_none)
754 send_z3950_present = false;
755 yaz_add_srw_diagnostic(odr_en,
756 &(sru_pdu_res->u.response->diagnostics),
757 &(sru_pdu_res->u.response->num_diagnostics),
758 YAZ_SRW_SORT_UNSUPP, 0);
761 // start record requested negative, or larger than number of records
762 if (start < 0 || start > *sru_pdu_res->u.response->numberOfRecords)
764 send_z3950_present = false;
765 yaz_add_srw_diagnostic(odr_en,
766 &(sru_pdu_res->u.response->diagnostics),
767 &(sru_pdu_res->u.response->num_diagnostics),
768 YAZ_SRW_FIRST_RECORD_POSITION_OUT_OF_RANGE, 0);
771 // maximumRecords requested negative
774 send_z3950_present = false;
775 yaz_add_srw_diagnostic(odr_en,
776 &(sru_pdu_res->u.response->diagnostics),
777 &(sru_pdu_res->u.response->num_diagnostics),
778 YAZ_SRW_UNSUPP_PARAMETER_VALUE,
782 // exit on all these above diagnostics
783 if (!send_z3950_present)
786 if (max_recs > *sru_pdu_res->u.response->numberOfRecords - start)
787 max_recs = *sru_pdu_res->u.response->numberOfRecords - start + 1;
789 Z_SRW_searchRetrieveResponse *sru_res = sru_pdu_res->u.response;
790 sru_res->records = (Z_SRW_record *)
791 odr_malloc(odr_en, max_recs * sizeof(Z_SRW_record));
793 while (num < max_recs)
795 // now packaging the z3950 present request
796 Package z3950_package(package.session(), package.origin());
797 z3950_package.copy_filter(package);
798 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_presentRequest);
800 assert(apdu->u.presentRequest);
802 *apdu->u.presentRequest->resultSetStartPoint = start + num;
803 *apdu->u.presentRequest->numberOfRecordsRequested = max_recs - num;
805 // set response packing to be same as "request" packing..
806 int record_packing = Z_SRW_recordPacking_XML;
807 if (sr_req->recordPacking && 's' == *(sr_req->recordPacking))
808 record_packing = Z_SRW_recordPacking_string;
810 // RecordSyntax will always be XML
811 apdu->u.presentRequest->preferredRecordSyntax
812 = odr_oiddup(odr_en, yaz_oid_recsyn_xml);
814 // z3950'fy record schema
815 if (sr_req->recordSchema)
817 apdu->u.presentRequest->recordComposition
818 = (Z_RecordComposition *)
819 odr_malloc(odr_en, sizeof(Z_RecordComposition));
820 apdu->u.presentRequest->recordComposition->which
821 = Z_RecordComp_simple;
822 apdu->u.presentRequest->recordComposition->u.simple
823 = mp_util::build_esn_from_schema(odr_en,
825 sr_req->recordSchema);
828 // attaching Z3950 package to filter chain
829 z3950_package.request() = apdu;
831 // sending Z30.50 present request
832 z3950_package.move();
834 //check successful Z3950 present response
835 Z_GDU *z3950_gdu = z3950_package.response().get();
836 if (!z3950_gdu || z3950_gdu->which != Z_GDU_Z3950
837 || z3950_gdu->u.z3950->which != Z_APDU_presentResponse
838 || !z3950_gdu->u.z3950->u.presentResponse)
841 yaz_add_srw_diagnostic(odr_en,
842 &(sru_pdu_res->u.response->diagnostics),
843 &(sru_pdu_res->u.response->num_diagnostics),
844 YAZ_SRW_SYSTEM_TEMPORARILY_UNAVAILABLE, 0);
847 // everything fine, continuing
849 Z_PresentResponse *pr = z3950_gdu->u.z3950->u.presentResponse;
851 // checking non surrogate diagnostics in Z3950 present response package
852 if (!z3950_to_srw_diagnostics_ok(odr_en, sru_pdu_res->u.response,
856 // if anything but database or surrogate diagnostics, stop
857 if (!pr->records || pr->records->which != Z_Records_DBOSD)
861 // inserting all records
863 pr->records->u.databaseOrSurDiagnostics->num_records;
864 for (int i = 0; i < returned_recs; i++)
866 int position = i + *apdu->u.presentRequest->resultSetStartPoint;
867 Z_NamePlusRecord *npr
868 = pr->records->u.databaseOrSurDiagnostics->records[i];
870 sru_res->records[i + num].recordPacking = record_packing;
872 if (npr->which == Z_NamePlusRecord_surrogateDiagnostic)
874 Z_DiagRec *p = npr->u.surrogateDiagnostic;
875 if (p->which == Z_DiagRec_defaultFormat)
877 Z_DefaultDiagFormat *df = p->u.defaultFormat;
878 int c = yaz_diag_bib1_to_srw(*df->condition);
880 yaz_mk_sru_surrogate(
881 odr_en, sru_res->records + i + num, position,
886 yaz_mk_sru_surrogate(
887 odr_en, sru_res->records + i + num, position,
888 YAZ_SRW_RECORD_TEMPORARILY_UNAVAILABLE, 0);
891 else if (npr->which == Z_NamePlusRecord_databaseRecord &&
892 npr->u.databaseRecord->direct_reference
893 && !oid_oidcmp(npr->u.databaseRecord->direct_reference,
896 // got XML record back
897 Z_External *r = npr->u.databaseRecord;
898 sru_res->records[i + num].recordPosition =
899 odr_intdup(odr_en, position);
900 sru_res->records[i + num].recordSchema = sr_req->recordSchema;
901 sru_res->records[i + num].recordData_buf
902 = odr_strdupn(odr_en,
903 (const char *)r->u.octet_aligned->buf,
904 r->u.octet_aligned->len);
905 sru_res->records[i + num].recordData_len
906 = r->u.octet_aligned->len;
910 // not XML or no database record at all
911 yaz_mk_sru_surrogate(
912 odr_en, sru_res->records + i + num, position,
913 YAZ_SRW_RECORD_NOT_AVAILABLE_IN_THIS_SCHEMA, 0);
916 num += returned_recs;
919 sru_res->num_records = num;
920 if (start - 1 + num < *sru_pdu_res->u.response->numberOfRecords)
921 sru_res->nextRecordPosition =
922 odr_intdup(odr_en, start + num);
926 int yf::SRUtoZ3950::Impl::z3950_build_query(
927 mp::odr &odr_en, Z_Query *z_query,
928 const Z_SRW_searchRetrieveRequest *req
932 #ifdef Z_SRW_query_type_cql
933 req->query_type == Z_SRW_query_type_cql
935 !strcmp(req->queryType, "cql")
939 Z_External *ext = (Z_External *)
940 odr_malloc(odr_en, sizeof(*ext));
941 ext->direct_reference =
942 odr_getoidbystr(odr_en, "1.2.840.10003.16.2");
943 ext->indirect_reference = 0;
945 ext->which = Z_External_CQL;
946 ext->u.cql = odr_strdup(odr_en,
947 #ifdef Z_SRW_query_type_cql
954 z_query->which = Z_Query_type_104;
955 z_query->u.type_104 = ext;
960 #ifdef Z_SRW_query_type_pqf
961 req->query_type == Z_SRW_query_type_pqf
963 !strcmp(req->queryType, "pqf")
967 Z_RPNQuery *RPNquery;
968 YAZ_PQF_Parser pqf_parser;
970 pqf_parser = yaz_pqf_create ();
972 RPNquery = yaz_pqf_parse (pqf_parser, odr_en,
973 #ifdef Z_SRW_query_type_pqf
979 yaz_pqf_destroy(pqf_parser);
982 return YAZ_SRW_QUERY_SYNTAX_ERROR;
984 z_query->which = Z_Query_type_1;
985 z_query->u.type_1 = RPNquery;
989 return YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED;
992 bool yf::SRUtoZ3950::Impl::z3950_to_srw_diagnostics_ok(
994 Z_SRW_searchRetrieveResponse
996 Z_Records *records) const
998 // checking non surrogate diagnostics in Z3950 present response package
1000 && records->which == Z_Records_NSD
1001 && records->u.nonSurrogateDiagnostic)
1003 z3950_to_srw_diag(odr_en, sru_res,
1004 records->u.nonSurrogateDiagnostic);
1010 int yf::SRUtoZ3950::Impl::z3950_to_srw_diag(
1012 Z_SRW_searchRetrieveResponse *sru_res,
1013 Z_DefaultDiagFormat *ddf) const
1015 int bib1_code = *ddf->condition;
1016 sru_res->num_diagnostics = 1;
1017 sru_res->diagnostics = (Z_SRW_diagnostic *)
1018 odr_malloc(odr_en, sizeof(*sru_res->diagnostics));
1019 yaz_mk_std_diagnostic(odr_en, sru_res->diagnostics,
1020 yaz_diag_bib1_to_srw(bib1_code),
1025 static mp::filter::Base* filter_creator()
1027 return new mp::filter::SRUtoZ3950;
1031 struct metaproxy_1_filter_struct metaproxy_1_filter_sru_z3950 = {
1042 * c-file-style: "Stroustrup"
1043 * indent-tabs-mode: nil
1045 * vim: shiftwidth=4 tabstop=8 expandtab