source: trunk/gsdl/src/recpt/z3950server.cpp@ 1349

Last change on this file since 1349 was 1349, checked in by jrm21, 24 years ago

moved yaz/client/yaz_zclient.h into yaz/include/yaz.

  • Property svn:keywords set to Author Date Id Revision
File size: 6.8 KB
Line 
1#include "z3950server.h"
2#include "comtypes.h"
3#include <stdio.h>
4// z39.50 yaz stuff
5
6extern "C" {
7#include "yaz/yaz_zclient.h"
8}
9
10/***
11 each z39.50 server+database pair is a GSDL collection.
12***/
13
14z3950_server::z3950_server() {
15 info=NULL;
16 connected=false;
17 titles=NULL;
18 // for now, assume that all records will have text associated with them.
19 meta["hastxt"]="1";
20 // for now, assume we don't want ANY DocumentButtons.
21 format["DocumentButtons"]="";
22}
23
24z3950_server::~z3950_server() {
25}
26
27void z3950_server::setMeta(const text_t &key, const text_t &value) {
28 meta[key]=value;
29}
30
31void z3950_server::setName(const text_t &newname) {
32 title=newname;
33 meta["collectionname"]=newname;
34}
35
36void z3950_server::addcfgAbout(const text_t &lang, const text_t &abouttext) {
37 about[lang]=abouttext;
38}
39
40bool z3950_server::getcfgAbout(const text_t &lang, text_t &abouttxt) {
41 text_tmap::iterator it;
42 it=about.find(lang);
43 if (it==about.end()) return (false);
44 abouttxt=((*it).second);
45 return (true);
46}
47
48
49// now functions that actually talk over the tcp connection.
50
51// create a tcp connection to the associated target. Currently, this will
52// re-initialise if we are already connected.
53bool z3950_server::connect() {
54 text_t server_and_port;
55 char *zserverinfo;
56
57 server_and_port=info->host+":"+info->port;
58 // remember that info.name is the database name
59
60 z_initialize();
61
62 if (z_cmd_open(server_and_port.getcstr(),info->name.getcstr())==1)
63 // we got a connection error
64 return false;
65
66 // get initialisation response.
67 z_getnextAPDU();
68 zserverinfo=z_get_initResponse();
69 if (zserverinfo!=NULL) {
70 z_initstr.appendcstr(zserverinfo);
71 }
72 free(zserverinfo);
73
74 connected=true;
75 return true;
76}
77
78void z3950_server::parseQuery(const text_t &query,
79 const text_t &fields,
80 text_t &parsed_query) {
81 /****** FIXME *****/
82 // We need to format the query string into RPN -
83 // by just passing it like this, it will only work for simple queries.
84 // This will require us to actually come up with a query syntax and
85 // a parser. For now, we'll just do an "AND" query for all terms
86
87 // we need to count number of terms separated by a space
88 char *ptr=query.getcstr();
89 int strlength=strlen(ptr);
90 bool inword=false;
91 int num_terms=0;
92 for (int i=0;i<strlength;i++) {
93 if (*(ptr+i)!=' ') {
94 if (inword==false) {
95 inword=true;
96 num_terms++;
97 }
98 }
99 else { // ptr+i is a space
100 inword=false;
101 }
102 }
103
104 // set the field(s) to search on - main ones (that I've found) include:
105 // 1016 => Any
106 // 1 => (Personal) Name
107 // 4 => Title
108 // 21 => Subject Heading
109 // 45 => Subject precis
110 // Note I have no idea how these actually work - I think some servers
111 // only have limited fields, and map all subject-type requests into that
112 // subject field, etc.
113
114 parsed_query="@attr 1=";
115 if (fields==".author")
116 parsed_query+="1 ";
117 else if (fields==".title")
118 parsed_query+="4 ";
119 else // fields==".any"
120 parsed_query+="1016 ";
121
122 // append "@and" for each term after the first
123 for (int i=1;i<num_terms;i++)
124 parsed_query+="@and ";
125 // append the actual query
126 parsed_query+=query;
127
128}
129
130text_tarray *z3950_server::getrecordTitles(const text_t &query,
131 const text_t &fields,
132 int first, int count,
133 int *nummatches, comerror_t &err) {
134 char **c_str_titles;
135 int i;
136 int last;
137 if (titles!=NULL) delete (titles);
138 titles=new text_tarray;
139
140 /* check if connected */
141 if (connected==false)
142 if (connect()==false) {
143 // we could not connect.
144 err=protocolError;
145 return (NULL);
146 }
147
148
149 text_t expanded_query="";
150 parseQuery(query,fields,expanded_query);
151
152 // following functions defined in yaz_zclient.c
153 *nummatches=z_cmd_dosearch(expanded_query.getcstr()); // returns # found, -1 on err.
154 if (*nummatches<=0) {
155 if (*nummatches==0) {
156 // no matches
157 return (NULL);
158 } else if (*nummatches==-1) {
159 // prefix query error
160 err=protocolError;
161 return (NULL);
162 } else if (*nummatches==-2) {
163 // sendsearchRequest not answered by searchResponse
164 err=protocolError;
165 return (NULL);
166 }
167 }
168 // could do a sort eventually, eg on date, title, etc.
169 // (non-existent function) z_sort(field, asc|desc);
170 /* min of (count, first + (*nummatches) ) */
171 // z_getrecordTitles ( first, howmany )
172 c_str_titles=z_getrecordTitles(first,min(count,*nummatches-first+1));
173 if (c_str_titles==NULL) {
174 // an error occurred. we need a logout/err as an arg
175 return (NULL);
176 }
177 if (c_str_titles[0]==0) {
178 // no matches.
179 return (NULL);
180 }
181 last=(int)c_str_titles[0];
182 for (i=1;i<=last;i++) {
183 titles->push_back(c_str_titles[i]);
184 free(c_str_titles[i]);
185 }
186 free(c_str_titles);
187 return (titles);
188
189}
190
191bool z3950_server::getfullrecord(const text_t &query, const text_t &fields,
192 const int ID,
193 text_t &rettitle,
194 text_t &rettext, comerror_t &err) {
195 if (connected==false) {
196 if (connect()==false) {
197 // error connecting...
198 err=protocolError;
199 return (false);
200 }
201 // since we have just re-connected, we need to do the
202 // query again.
203
204 text_t expanded_query="";
205 parseQuery(query,fields,expanded_query);
206
207 int returned=z_cmd_dosearch(expanded_query.getcstr());
208 if (returned<=0) {
209 // 0 => none.
210 // <0 => error
211 err=protocolError;
212 return (false);
213 }
214 }
215
216 if (rettitle!="unneeded") {
217 char **c_str_titles;
218 //int dummy;
219 c_str_titles=z_getrecordTitles(ID,1); // check this return value.
220 if (c_str_titles!=NULL && (int)c_str_titles[0]==1) {
221 rettitle.setcstr(c_str_titles[1]); // and check this
222 free (c_str_titles);
223 // rettitle="Dummy Title";
224 } else {
225 // we didn't get something....
226 rettitle="Nothing Returned...";
227 }
228 }
229
230 if (rettext!="unneeded") {
231 // get the text
232 rettext.setcstr(z_getfullRecord(ID));
233 }
234 return (true);
235 }
236
237text_t &z3950_server::getzAbout() {
238 text_t zserverresp;
239
240 // Assume we have not yet connected, so that must be done here.
241 if (connected==true)
242 return (z_initstr);
243
244 // we need to create the tcp connection to the target (server)
245 // z_initstr=new text_t;
246
247 if (connect()==false) {
248 z_initstr.setcstr("<H2>Server offline</H2>Error - could not connect to server <B>");
249 z_initstr += info->host.getcstr();
250 z_initstr += "</B> on port ";
251 z_initstr += info->port;
252 z_initstr += "\n";
253 return (z_initstr);
254 }
255
256 // z_initstr currently contains the target's response. We want to
257 // PREPEND the following information.
258 zserverresp=z_initstr;
259 z_initstr="Internet server: <b>";
260 z_initstr+=info->host;
261 z_initstr+="</b> on port ";
262 z_initstr+=info->port;
263 z_initstr+=".<br>\n";
264 z_initstr+=zserverresp;
265
266 // should close /******* WHAT IF DOING A QUERY!??!?!? ********/
267 // z_cmd_close(0);
268 // connected=false;
269 return (z_initstr);
270}
271
Note: See TracBrowser for help on using the repository browser.