+void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only)
+{
+ for (ptr = ptr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type != XML_ELEMENT_NODE)
+ continue;
+ else if (!strcmp((const char *) ptr->name, "torus"))
+ {
+ const struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ {
+ if (!strcmp((const char *) attr->name, "url"))
+ torus_url = mp::xml::get_text(attr->children);
+ else if (!strcmp((const char *) attr->name, "xsldir"))
+ xsldir = mp::xml::get_text(attr->children);
+ else
+ throw mp::filter::FilterException(
+ "Bad attribute " + std::string((const char *)
+ attr->name));
+ }
+ }
+ else if (!strcmp((const char *) ptr->name, "fieldmap"))
+ {
+ const struct _xmlAttr *attr;
+ std::string ccl_field;
+ std::string cql_field;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ {
+ if (!strcmp((const char *) attr->name, "ccl"))
+ ccl_field = mp::xml::get_text(attr->children);
+ else if (!strcmp((const char *) attr->name, "cql"))
+ cql_field = mp::xml::get_text(attr->children);
+ else
+ throw mp::filter::FilterException(
+ "Bad attribute " + std::string((const char *)
+ attr->name));
+ }
+ if (ccl_field.length() && cql_field.length())
+ fieldmap[cql_field] = ccl_field;
+ }
+ else if (!strcmp((const char *) ptr->name, "records"))
+ {
+ yaz_log(YLOG_WARN, "records ignored!");
+ }
+ else
+ {
+ throw mp::filter::FilterException
+ ("Bad element "
+ + std::string((const char *) ptr->name)
+ + " in zoom filter");
+ }
+ }
+}
+
+yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
+ std::string &database, int *error, const char **addinfo)
+{
+ std::list<BackendPtr>::const_iterator map_it;
+ if (m_backend && m_backend->m_frontend_database == database)
+ return m_backend;
+
+ xmlDoc *doc = mp::get_searchable(m_p->torus_url, database);
+ if (!doc)
+ {
+ *error = YAZ_BIB1_DATABASE_DOES_NOT_EXIST;
+ *addinfo = database.c_str();
+ BackendPtr b;
+ return b;
+ }
+ SearchablePtr sptr = m_p->parse_torus(xmlDocGetRootElement(doc));
+ xmlFreeDoc(doc);
+ if (!sptr)
+ {
+ *error = YAZ_BIB1_DATABASE_DOES_NOT_EXIST;
+ *addinfo = database.c_str();
+ BackendPtr b;
+ return b;
+ }
+
+ xsltStylesheetPtr xsp = 0;
+ if (sptr->transform_xsl_fname.length())
+ {
+ std::string fname;
+
+ if (m_p->xsldir.length())
+ fname = m_p->xsldir + "/" + sptr->transform_xsl_fname;
+ else
+ fname = sptr->transform_xsl_fname;
+ xmlDoc *xsp_doc = xmlParseFile(fname.c_str());
+ if (!xsp_doc)
+ {
+ *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
+ *addinfo = "xmlParseFile failed";
+ BackendPtr b;
+ return b;
+ }
+ xsp = xsltParseStylesheetDoc(xsp_doc);
+ if (!xsp)
+ {
+ *error = YAZ_BIB1_DATABASE_DOES_NOT_EXIST;
+ *addinfo = "xsltParseStylesheetDoc failed";
+ BackendPtr b;
+ xmlFreeDoc(xsp_doc);
+ return b;
+ }
+ }
+
+ m_backend.reset();
+
+ BackendPtr b(new Backend(sptr));
+
+ std::string cf_parm;
+ b->xsp = xsp;
+ b->m_frontend_database = database;
+ std::string authentication = sptr->authentication;
+
+ if (sptr->query_encoding.length())
+ b->set_option("rpnCharset", sptr->query_encoding.c_str());
+
+ if (sptr->cfAuth.length())
+ {
+ b->set_option("user", sptr->cfAuth.c_str());
+ if (authentication.length())
+ {
+ size_t found = authentication.find('/');
+ if (found != std::string::npos)
+ {
+ cf_parm += "user=" + mp::util::uri_encode(authentication.substr(0, found))
+ + "&password=" + mp::util::uri_encode(authentication.substr(found+1));
+ }
+ else
+ cf_parm += "user=" + mp::util::uri_encode(authentication);
+ }
+ }
+ else if (authentication.length())
+ b->set_option("user", authentication.c_str());
+
+ if (sptr->cfProxy.length())
+ {
+ if (cf_parm.length())
+ cf_parm += "&";
+ cf_parm += "proxy=" + mp::util::uri_encode(sptr->cfProxy);
+ }
+ if (sptr->cfSubDb.length())
+ {
+ if (cf_parm.length())
+ cf_parm += "&";
+ cf_parm += "subdatabase=" + mp::util::uri_encode(sptr->cfSubDb);
+ }
+
+ std::string url;
+ if (sptr->sru.length())
+ {
+ url = "http://" + sptr->target;
+ b->set_option("sru", sptr->sru.c_str());
+ }
+ else
+ {
+ url = sptr->target;
+ }
+ if (cf_parm.length())
+ {
+ url += "," + cf_parm;
+ }
+ b->connect(url, error, addinfo);
+ if (*error == 0)
+ {
+ m_backend = b;
+ }
+ return b;
+}
+
+Z_Records *yf::Zoom::Frontend::get_records(Odr_int start,
+ Odr_int number_to_present,
+ int *error,
+ const char **addinfo,
+ Odr_int *number_of_records_returned,
+ ODR odr,
+ BackendPtr b,
+ Odr_oid *preferredRecordSyntax,
+ const char *element_set_name)
+{
+ *number_of_records_returned = 0;
+ Z_Records *records = 0;
+ bool enable_pz2_transform = false;
+
+ if (start < 0 || number_to_present <= 0)
+ return records;
+
+ if (number_to_present > 10000)
+ number_to_present = 10000;
+
+ ZOOM_record *recs = (ZOOM_record *)
+ odr_malloc(odr, number_to_present * sizeof(*recs));
+
+ char oid_name_str[OID_STR_MAX];
+ const char *syntax_name = 0;
+
+ if (preferredRecordSyntax)
+ {
+ if (!oid_oidcmp(preferredRecordSyntax, yaz_oid_recsyn_xml)
+ && element_set_name &&
+ !strcmp(element_set_name, "pz2"))
+ {
+ if (b->sptr->request_syntax.length())
+ {
+ syntax_name = b->sptr->request_syntax.c_str();
+ enable_pz2_transform = true;
+ }
+ }
+ else
+ {
+ syntax_name =
+ yaz_oid_to_string_buf(preferredRecordSyntax, 0, oid_name_str);
+ }
+ }
+
+ b->set_option("preferredRecordSyntax", syntax_name);
+
+ if (enable_pz2_transform)
+ {
+ element_set_name = "F";
+ if (b->sptr->element_set.length())
+ element_set_name = b->sptr->element_set.c_str();
+ }
+
+ b->set_option("elementSetName", element_set_name);
+
+ b->present(start, number_to_present, recs, error, addinfo);
+
+ Odr_int i = 0;
+ if (!*error)
+ {
+ for (i = 0; i < number_to_present; i++)
+ if (!recs[i])
+ break;
+ }
+ if (i > 0)
+ { // only return records if no error and at least one record
+ char *odr_database = odr_strdup(odr,
+ b->m_frontend_database.c_str());
+ Z_NamePlusRecordList *npl = (Z_NamePlusRecordList *)
+ odr_malloc(odr, sizeof(*npl));
+ *number_of_records_returned = i;
+ npl->num_records = i;
+ npl->records = (Z_NamePlusRecord **)
+ odr_malloc(odr, i * sizeof(*npl->records));
+ for (i = 0; i < number_to_present; i++)
+ {
+ Z_NamePlusRecord *npr = 0;
+ const char *addinfo;
+ int sur_error = ZOOM_record_error(recs[i], 0 /* msg */,
+ &addinfo, 0 /* diagset */);
+
+ if (sur_error)
+ {
+ npr = zget_surrogateDiagRec(odr, odr_database, sur_error,
+ addinfo);
+ }
+ else if (enable_pz2_transform)
+ {
+ char rec_type_str[100];
+
+ strcpy(rec_type_str, b->sptr->use_turbomarc ?
+ "txml" : "xml");
+
+ // prevent buffer overflow ...
+ if (b->sptr->record_encoding.length() > 0 &&
+ b->sptr->record_encoding.length() <
+ (sizeof(rec_type_str)-20))
+ {
+ strcat(rec_type_str, "; charset=");
+ strcat(rec_type_str, b->sptr->record_encoding.c_str());
+ }
+
+ int rec_len;
+ const char *rec_buf = ZOOM_record_get(recs[i], rec_type_str,
+ &rec_len);
+ if (rec_buf && b->xsp)
+ {
+ xmlDoc *rec_doc = xmlParseMemory(rec_buf, rec_len);
+ if (rec_doc)
+ {
+ xmlDoc *rec_res;
+ rec_res = xsltApplyStylesheet(b->xsp, rec_doc, 0);
+
+ if (rec_res)
+ xsltSaveResultToString((xmlChar **) &rec_buf, &rec_len,
+ rec_res, b->xsp);
+ }
+ }
+
+ if (rec_buf)
+ {
+ npr = (Z_NamePlusRecord *) odr_malloc(odr, sizeof(*npr));
+ npr->databaseName = odr_database;
+ npr->which = Z_NamePlusRecord_databaseRecord;
+ npr->u.databaseRecord =
+ z_ext_record_xml(odr, rec_buf, rec_len);
+ }
+ else
+ {
+ npr = zget_surrogateDiagRec(
+ odr, odr_database,
+ YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
+ rec_type_str);
+ }
+ }
+ else
+ {
+ Z_External *ext =
+ (Z_External *) ZOOM_record_get(recs[i], "ext", 0);
+ if (ext)
+ {
+ npr = (Z_NamePlusRecord *) odr_malloc(odr, sizeof(*npr));
+ npr->databaseName = odr_database;
+ npr->which = Z_NamePlusRecord_databaseRecord;
+ npr->u.databaseRecord = ext;
+ }
+ else
+ {
+ npr = zget_surrogateDiagRec(
+ odr, odr_database,
+ YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
+ "ZOOM_record, type ext");
+ }
+ }
+ npl->records[i] = npr;
+ }
+ records = (Z_Records*) odr_malloc(odr, sizeof(*records));
+ records->which = Z_Records_DBOSD;
+ records->u.databaseOrSurDiagnostics = npl;
+ }
+ return records;
+}
+
+struct cql_node *yf::Zoom::Impl::convert_cql_fields(struct cql_node *cn,
+ ODR odr)
+{
+ struct cql_node *r = 0;
+ if (!cn)
+ return 0;
+ switch (cn->which)
+ {
+ case CQL_NODE_ST:
+ if (cn->u.st.index)
+ {
+ std::map<std::string,std::string>::const_iterator it;
+ it = fieldmap.find(cn->u.st.index);
+ if (it == fieldmap.end())
+ return cn;
+ cn->u.st.index = odr_strdup(odr, it->second.c_str());
+ }
+ break;
+ case CQL_NODE_BOOL:
+ r = convert_cql_fields(cn->u.boolean.left, odr);
+ if (!r)
+ r = convert_cql_fields(cn->u.boolean.right, odr);
+ break;
+ case CQL_NODE_SORT:
+ r = convert_cql_fields(cn->u.sort.search, odr);
+ break;
+ }
+ return r;
+}
+
+void yf::Zoom::Frontend::handle_search(mp::Package &package)