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

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

Added some flags so we don't connect to the z-server as often as we were...
z3950proto::filter is called 8 times for a get document request!!!!!
Actually, this also fixed a problem I was having connecting to a particular
zserver, as the server was returning an error on about the 7th call to filter()

  • Property svn:keywords set to Author Date Id Revision
File size: 9.2 KB
Line 
1/**********************************************************************
2 *
3 * z3950server.cpp --
4 * Copyright (C) 2000 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "z3950server.h"
27#include "comtypes.h"
28#include <stdio.h>
29// z39.50 yaz stuff
30
31extern "C" {
32#include "yaz/yaz_zclient.h"
33}
34
35/***
36 each z39.50 server+database pair is a GSDL collection.
37***/
38
39z3950_server::z3950_server() {
40 info=NULL;
41 connected=false;
42 titles=NULL;
43 gotsinglerecord=false;
44 // for now, assume that all records will have text associated with them.
45 meta["hastxt"]="1";
46 // for now, assume we don't want ANY DocumentButtons.
47 format["DocumentButtons"]="";
48}
49
50z3950_server::~z3950_server() {
51}
52
53void z3950_server::setMeta(const text_t &key, const text_t &value) {
54 meta[key]=value;
55}
56
57void z3950_server::setName(const text_t &newname) {
58 title=newname;
59 meta["collectionname"]=newname;
60}
61
62void z3950_server::addcfgAbout(const text_t &lang, const text_t &abouttext) {
63 about[lang]=abouttext;
64}
65
66bool z3950_server::getcfgAbout(const text_t &lang, text_t &abouttxt) {
67 text_tmap::iterator it;
68 it=about.find(lang);
69 if (it==about.end()) return (false);
70 abouttxt=((*it).second);
71 return (true);
72}
73
74
75// now functions that actually talk over the tcp connection.
76
77// create a tcp connection to the associated target. Currently, this will
78// re-initialise if we are already connected.
79bool z3950_server::connect() {
80 text_t server_and_port;
81 char *zserverinfo;
82
83 server_and_port=info->host+":"+info->port;
84 // remember that info.name is the database name
85
86 z_initialize();
87
88 if (z_cmd_open(server_and_port.getcstr(),info->name.getcstr())==1)
89 // we got a connection error
90 return false;
91
92 // get initialisation response.
93 z_getnextAPDU();
94 zserverinfo=z_get_initResponse();
95 if (zserverinfo!=NULL) {
96 z_initstr.appendcstr(zserverinfo);
97 }
98 free(zserverinfo);
99
100 connected=true;
101 return true;
102}
103
104void z3950_server::parseQuery(const text_t &query,
105 const text_t &fields,
106 text_t &parsed_query) {
107 /****** FIXME *****/
108 // We need to format the query string into RPN -
109 // by just passing it like this, it will only work for simple queries.
110 // This will require us to actually come up with a query syntax and
111 // a parser. For now, we'll just do an "AND" query for all terms
112
113 // we need to count number of terms separated by a space
114 char *ptr=query.getcstr();
115 int strlength=strlen(ptr);
116 bool inword=false;
117 int num_terms=0;
118 for (int i=0;i<strlength;i++) {
119 if (*(ptr+i)!=' ') {
120 if (inword==false) {
121 inword=true;
122 num_terms++;
123 }
124 }
125 else { // ptr+i is a space
126 inword=false;
127 }
128 }
129
130 // set the field(s) to search on - main ones (that I've found) include:
131 // 1016 => Any
132 // 1 => (Personal) Name
133 // 4 => Title
134 // 21 => Subject Heading
135 // 45 => Subject precis
136 // Note I have no idea how these actually work - I think some servers
137 // only have limited fields, and map all subject-type requests into that
138 // subject field, etc.
139
140 parsed_query="@attr 1=";
141 if (fields==".author")
142 parsed_query+="1 ";
143 else if (fields==".title")
144 parsed_query+="4 ";
145 else // fields==".any"
146 parsed_query+="1016 ";
147
148 // append "@and" for each term after the first
149 for (int i=1;i<num_terms;i++)
150 parsed_query+="@and ";
151 // append the actual query
152 parsed_query+=query;
153
154}
155
156text_tarray *z3950_server::getrecordTitles(const text_t &query,
157 const text_t &fields,
158 int first, int count,
159 int *nummatches, comerror_t &err) {
160 /* NOTE!!!!!! Because this code currently only works in cgi-bin mode,
161 we only ever do one request. Therefore, it is CURRENTLY OK to store
162 (cache) the retrieved titles, because if this function is ever called
163 more than once, the arguments will be the same each time.
164 (I think :)
165 */
166
167 char **c_str_titles;
168 int i;
169 int last;
170
171 if (gotsinglerecord==true) {
172 /* If true, then this whole execution was done to retrieve a single
173 document. Therefore, the list of titles of all records matching the
174 query isn't actually required. It's just that for some reason our
175 filter (z3950proto::filter) gets called at least 7 times, with the
176 7th being a "QueryFilter" for some reason... */
177 nummatches=0;
178 return NULL; /* shouldn't really return NULL, but nummatches is checked
179 first (I hope) */
180 }
181
182 // if (titles!=NULL) delete (titles);
183 if (titles!=NULL) return titles;
184 titles=new text_tarray;
185
186 /* check if connected */
187 if (connected==false)
188 if (connect()==false) {
189 // we could not connect.
190 err=protocolError;
191 return (NULL);
192 }
193
194
195 text_t expanded_query="";
196 parseQuery(query,fields,expanded_query);
197
198 // following functions defined in yaz_zclient.c
199 *nummatches=z_cmd_dosearch(expanded_query.getcstr()); // returns # found, -1 on err.
200 if (*nummatches<=0) {
201 if (*nummatches==0) {
202 // no matches
203 return (NULL);
204 } else if (*nummatches==-1) {
205 // prefix query error
206 err=protocolError;
207 return (NULL);
208 } else if (*nummatches==-2) {
209 // sendsearchRequest not answered by searchResponse
210 err=protocolError;
211 return (NULL);
212 }
213 }
214 // could do a sort eventually, eg on date, title, etc.
215 // (non-existent function) z_sort(field, asc|desc);
216 /* min of (count, first + (*nummatches) ) */
217 // z_getrecordTitles ( first, howmany )
218 c_str_titles=z_getrecordTitles(first,min(count,*nummatches-first+1));
219 if (c_str_titles==NULL) {
220 // an error occurred. we need a logout/err as an arg
221 return (NULL);
222 }
223 if (c_str_titles[0]==0) {
224 // no matches.
225 return (NULL);
226 }
227 last=(int)c_str_titles[0];
228 for (i=1;i<=last;i++) {
229 titles->push_back(c_str_titles[i]);
230 free(c_str_titles[i]);
231 }
232 free(c_str_titles);
233 return (titles);
234
235}
236
237bool z3950_server::getfullrecord(const text_t &query, const text_t &fields,
238 const int ID,
239 text_t &rettitle,
240 text_t &rettext, comerror_t &err) {
241
242 static char **c_str_titles=NULL;
243 static char *fulltext=NULL;
244 /* NOTE!!!!!! Because this code currently only works in cgi-bin mode,
245 we only ever do one request. Therefore, it is CURRENTLY OK to store
246 (cache) the retrieved titles, because if this function is ever called
247 more than once, the arguments will be the same each time.
248 (I think :)
249 */
250
251 gotsinglerecord=true; // well, not yet, but we've been called...
252
253 if (connected==false) {
254 if (connect()==false) {
255 // error connecting...
256 err=protocolError;
257 return (false);
258 }
259 // since we have just re-connected, we need to do the
260 // query again.
261
262 text_t expanded_query="";
263 parseQuery(query,fields,expanded_query);
264
265 int returned=z_cmd_dosearch(expanded_query.getcstr());
266 if (returned<=0) {
267 // 0 => none.
268 // <0 => error
269 err=protocolError;
270 return (false);
271 }
272 }
273
274 if (c_str_titles==NULL)
275 c_str_titles=z_getrecordTitles(ID,1); // check this return value.
276
277 if (rettitle!="unneeded") {
278 //int dummy;
279 if (c_str_titles!=NULL && (int)c_str_titles[0]==1) {
280 rettitle.setcstr(c_str_titles[1]); // and check this
281 ////// free (c_str_titles); - we want to "cache" it
282 } else {
283 // we didn't get something....
284 rettitle="Nothing Returned...";
285 }
286 }
287
288 if (fulltext==NULL)
289 // get the text
290 fulltext=z_getfullRecord(ID);
291
292 if (rettext!="unneeded") {
293 rettext.setcstr(fulltext);
294 }
295 return (true);
296 }
297
298text_t &z3950_server::getzAbout() {
299 text_t zserverresp;
300
301 // Assume we have not yet connected, so that must be done here.
302 if (connected==true)
303 return (z_initstr);
304
305 // we need to create the tcp connection to the target (server)
306 // z_initstr=new text_t;
307
308 if (connect()==false) {
309 z_initstr.setcstr("<H2>Server offline</H2>Error - could not connect to server <B>");
310 z_initstr += info->host.getcstr();
311 z_initstr += "</B> on port ";
312 z_initstr += info->port;
313 z_initstr += "\n";
314 return (z_initstr);
315 }
316
317 // z_initstr currently contains the target's response. We want to
318 // PREPEND the following information.
319 zserverresp=z_initstr;
320 z_initstr="Internet server: <b>";
321 z_initstr+=info->host;
322 z_initstr+="</b> on port ";
323 z_initstr+=info->port;
324 z_initstr+=".<br>\n";
325 z_initstr+=zserverresp;
326
327 // should close /******* WHAT IF DOING A QUERY!??!?!? ********/
328 // z_cmd_close(0);
329 // connected=false;
330 return (z_initstr);
331}
332
Note: See TracBrowser for help on using the repository browser.