#include "z3950server.h" #include "comtypes.h" #include // z39.50 yaz stuff extern "C" { #include "yaz/client/yaz_zclient.h" } /*** each z39.50 server+database pair is a GSDL collection. ***/ z3950_server::z3950_server() { info=NULL; connected=false; titles=NULL; // for now, assume that all records will have text associated with them. meta["hastxt"]="1"; // for now, assume we don't want ANY DocumentButtons. format["DocumentButtons"]=""; } z3950_server::~z3950_server() { } void z3950_server::setMeta(const text_t &key, const text_t &value) { meta[key]=value; } void z3950_server::setName(const text_t &newname) { title=newname; meta["collectionname"]=newname; } void z3950_server::addcfgAbout(const text_t &lang, const text_t &abouttext) { about[lang]=abouttext; } bool z3950_server::getcfgAbout(const text_t &lang, text_t &abouttxt) { text_tmap::iterator it; it=about.find(lang); if (it==about.end()) return (false); abouttxt=((*it).second); return (true); } // now functions that actually talk over the tcp connection. // create a tcp connection to the associated target. Currently, this will // re-initialise if we are already connected. bool z3950_server::connect() { text_t server_and_port; char *zserverinfo; server_and_port=info->host+":"+info->port; // remember that info.name is the database name z_initialize(); if (z_cmd_open(server_and_port.getcstr(),info->name.getcstr())==1) // we got a connection error return false; // get initialisation response. z_getnextAPDU(); zserverinfo=z_get_initResponse(); if (zserverinfo!=NULL) { z_initstr.appendcstr(zserverinfo); } free(zserverinfo); connected=true; return true; } void z3950_server::parseQuery(const text_t &query, const text_t &fields, text_t &parsed_query) { /****** FIXME *****/ // We need to format the query string into RPN - // by just passing it like this, it will only work for simple queries. // This will require us to actually come up with a query syntax and // a parser. For now, we'll just do an "AND" query for all terms // we need to count number of terms separated by a space char *ptr=query.getcstr(); int strlength=strlen(ptr); bool inword=false; int num_terms=0; for (int i=0;i Any // 1 => (Personal) Name // 4 => Title // 21 => Subject Heading // 45 => Subject precis // Note I have no idea how these actually work - I think some servers // only have limited fields, and map all subject-type requests into that // subject field, etc. parsed_query="@attr 1="; if (fields==".author") parsed_query+="1 "; else if (fields==".title") parsed_query+="4 "; else // fields==".any" parsed_query+="1016 "; // append "@and" for each term after the first for (int i=1;ipush_back(c_str_titles[i]); free(c_str_titles[i]); } free(c_str_titles); return (titles); } bool z3950_server::getfullrecord(const text_t &query, const text_t &fields, const int ID, text_t &rettitle, text_t &rettext, comerror_t &err) { if (connected==false) { if (connect()==false) { // error connecting... err=protocolError; return (false); } // since we have just re-connected, we need to do the // query again. text_t expanded_query=""; parseQuery(query,fields,expanded_query); int returned=z_cmd_dosearch(expanded_query.getcstr()); if (returned<=0) { // 0 => none. // <0 => error err=protocolError; return (false); } } if (rettitle!="unneeded") { char **c_str_titles; //int dummy; c_str_titles=z_getrecordTitles(ID,1); // check this return value. if (c_str_titles!=NULL && (int)c_str_titles[0]==1) { rettitle.setcstr(c_str_titles[1]); // and check this free (c_str_titles); // rettitle="Dummy Title"; } else { // we didn't get something.... rettitle="Nothing Returned..."; } } if (rettext!="unneeded") { // get the text rettext.setcstr(z_getfullRecord(ID)); } return (true); } text_t &z3950_server::getzAbout() { text_t zserverresp; // Assume we have not yet connected, so that must be done here. if (connected==true) return (z_initstr); // we need to create the tcp connection to the target (server) // z_initstr=new text_t; if (connect()==false) { z_initstr.setcstr("

Server offline

Error - could not connect to server "); z_initstr += info->host.getcstr(); z_initstr += " on port "; z_initstr += info->port; z_initstr += "\n"; return (z_initstr); } // z_initstr currently contains the target's response. We want to // PREPEND the following information. zserverresp=z_initstr; z_initstr="Internet server: "; z_initstr+=info->host; z_initstr+=" on port "; z_initstr+=info->port; z_initstr+=".
\n"; z_initstr+=zserverresp; // should close /******* WHAT IF DOING A QUERY!??!?!? ********/ // z_cmd_close(0); // connected=false; return (z_initstr); }