source: branches/z3950-branch/gsdl/src/recpt/z3950proto.cpp@ 1174

Last change on this file since 1174 was 1174, checked in by johnmcp, 24 years ago

checkpoint - can now connect and get status information from a z39.50 server.
Still need to get queries and data retrieval working.

  • Property svn:keywords set to Author Date Id Revision
File size: 13.9 KB
Line 
1
2#ifndef Z3950PROTO_H
3#define Z3050PROTO_H
4
5#include "z3950proto.h"
6#include "comtypes.h"
7#include <stdio.h>
8// z39.50 yaz stuff
9
10
11// config file parsing stuff
12#include "z3950cfg.h" // for reading in config files -
13// defines "struct z3950cfg *zserver_list" as the head of the list.
14extern FILE *yyin;
15extern "C" {
16 extern int zconfigparse();
17}
18
19z3950proto::z3950proto() {
20 zserver_count=0;
21}
22
23z3950proto::~z3950proto() {
24}
25
26void z3950proto::add_server (const z3950_server& zserver) {
27
28 // append the new server
29 zserver_count++;
30 zservers.push_back(zserver);
31}
32
33void z3950proto::read_config_file(const text_t &filename) {
34 struct z3950cfg *here;
35 struct z3950cfg *oldhere;
36 z3950_server *zserver;
37 ShortColInfo_t *tempinfo;
38
39 // zconfigparse() is defined in zparse.tab.c,
40 // which is the bison output of zparse.y
41
42 yyin=fopen(filename.getcstr(),"r");
43 if (yyin==NULL) {
44 cerr << "Could not open "<<filename.getcstr()<<" for reading.\n";
45 }
46 zconfigparse();
47 // we now have the config files in the ptr zserver_list
48 if (zserver_list==NULL)
49 return; // no valid servers found in the config file - note that
50 // the parser will have already spat out any errors.
51
52 // now create z3950servers for each structure in server_list
53 here=zserver_list;
54 while (here!=NULL) {
55 zserver=new z3950_server;
56 tempinfo=new ShortColInfo_t;
57
58 tempinfo->host.setcstr(here->hostname);
59 tempinfo->port=here->port;
60 tempinfo->name.setcstr(here->dbname);
61 zserver->setInfo(tempinfo);
62 zserver->setName(here->shortname);
63 // now collection metadata.
64 zserver->setMeta("collectionname",here->longname);
65 if (here->icon!=NULL)
66 zserver->setMeta("iconcollection",here->icon);
67 if (here->smallicon!=NULL)
68 zserver->setMeta("iconcollectionsmall",here->smallicon);
69 if (0) {
70 cerr << "creating metadata:\n\tcolname is " << here->longname
71 << "\n\ticoncollection is " << here->icon
72 << "\n and\ticoncollectionsmall is " << here->smallicon
73 << "\n";
74 }
75
76 // About list
77 if (here->about!=NULL) {
78 struct z3950aboutlist *about_here=here->about;
79 struct z3950aboutlist *oldabout;
80
81 while (about_here!=NULL) {
82 // problem with default lang (null):
83 if (about_here->lang==NULL)
84 zserver->addAbout("en",about_here->text);
85 else
86 zserver->addAbout(about_here->lang, about_here->text);
87 oldabout=about_here;
88 about_here=about_here->next;
89 free(oldabout->lang);
90 free(oldabout->text);
91 free(oldabout);
92 }
93 }
94
95 oldhere=here;
96 here=here->next;
97 free(oldhere->shortname);
98 free(oldhere->hostname);
99 free(oldhere->dbname);
100 free(oldhere->longname);
101 free(oldhere->icon);
102 free(oldhere->smallicon);
103 free(oldhere);
104
105
106 add_server(*zserver);
107 /* assume that the push_back operator creates a copy.
108 BUT: doesn't create copies of structures pointed to... only
109 creates a copy of the pointer (to the same location!) */
110 } // end of while loop.
111
112}
113
114void z3950proto::configure (const text_t &key,
115 const text_tarray &cfgline) {
116
117 // this is called for each line in the gsdlsite.cfg file
118
119 if (0)
120 cerr << "z3950proto::configure called:"
121 << "key is " << key.getcstr()
122 << "\n1st line is " << cfgline[0].getcstr() << endl;
123
124}
125
126
127bool z3950proto::init (ostream &/*logout*/) {
128 // set up tcp connection to server here?
129 // we might also read in the config file here (instead of librarymain.cpp)
130
131 //
132
133 // logout goes to initout.txt
134 // logout <<"zdebug:init:Number of z3950 servers: "<< zserver_count << "\n";
135 //logout << "\t1st server name: " << zservers[0].getName().getcstr() << "\n";
136 return true;
137
138}
139
140/*text_t z3950proto::get_protocol_name () {
141 return "z3950proto";
142}
143*/
144
145void z3950proto::get_collection_list (text_tarray &collist,
146 comerror_t &/*err*/,
147 ostream &/*logout*/) {
148 // logout here DOESN'T go to initout.txt
149 // logout << "zdebug: get_collection_list called:\n";
150
151 /** *** for now, we are assuming that each SERVER is a GSDL collection,
152 as opposed to each DATABASE on the servers.
153 */
154 z3950_server_array::iterator here = zservers.begin();
155 z3950_server_array::iterator end = zservers.end();
156 while (here != end) {
157 collist.push_back(here->getName());
158 //const ShortColInfo_t *info=here->getInfo();
159 //collist.push_back(info->name);
160 here++;
161 }
162}
163
164void z3950proto::has_collection (const text_t &collection, bool &hascollection,
165 comerror_t &/*err*/, ostream &/*logout*/) {
166 z3950_server_array::iterator here = zservers.begin();
167 z3950_server_array::iterator end = zservers.end();
168 while (here != end) {
169 if(here->getName()==collection) {
170 hascollection=true;
171 return;
172 }
173 here++;
174 }
175 hascollection=false;
176}
177
178void z3950proto::ping (const text_t &/*collection*/, bool &wassuccess,
179 comerror_t &/*err*/, ostream &/*logout*/) {
180 // should we just ping the server, or actually create a connection
181 // to the z39.50 server process on the machine ?
182 wassuccess = true;
183}
184
185void z3950proto::get_collectinfo (const text_t &collection,
186 ColInfoResponse_t &collectinfo,
187 comerror_t &err, ostream &logout) {
188
189 // set err to protocolError if something goes wrong...
190
191 z3950_server_array::iterator here = zservers.begin();
192 z3950_server_array::iterator end = zservers.end();
193 while (here != end) {
194 if(here->getName()==collection) {
195 break;
196 }
197 here++;
198 }
199
200 // is this right? ie does end refer to the last element, or AFTER the
201 // last element?
202 if (here==end) {
203 err=protocolError;
204 logout << "z39.50: couldn't find collection"
205 << collection.getcstr()
206 << endl;
207 return;
208 }
209
210 const ShortColInfo_t *colinfo=here->getInfo();
211 collectinfo.shortInfo.name=colinfo->name;
212 collectinfo.shortInfo.host=colinfo->host;
213 collectinfo.shortInfo.port=colinfo->port;
214
215 collectinfo.isPublic=true;
216 // don't use beta field
217 /*collectinfo.isBeta=false;*/
218 collectinfo.buildDate=1;
219 // leave ccsCols empty (no cross-coll. searching - for now)
220 /*collectinfo.ccsCols=(text_tarray);*/ //not like this!!!
221 // This info is available from the config file -- johnmcp */
222 collectinfo.languages.push_back("en");
223 collectinfo.languages.push_back("fr");
224 collectinfo.numDocs=0;
225 collectinfo.numWords=0;
226 collectinfo.numBytes=0;
227 // copy the text maps over.
228 // collectinfo.collectionmeta; // text_tmap
229 collectinfo.collectionmeta=*(here->getMeta());
230 /* collectinfo.format; //text_tmap
231 collectinfo.building; //text_tmap
232 */
233
234 ////collectinfo.receptionist="z3950";
235 /* for now... this is a url, relative to .../cgi-bin.
236 NOTE: if this is empty, it defaults to _gwcgi_?a=p&p=about&c=<colname>
237 */
238}
239
240void z3950proto::get_filterinfo (const text_t &/*collection*/,
241 InfoFiltersResponse_t &/*response*/,
242 comerror_t &/*err*/, ostream &/*logout*/) {
243
244}
245
246void z3950proto::filter (const text_t &collection,
247 FilterRequest_t &request,
248 FilterResponse_t &response,
249 comerror_t &err, ostream &logout) {
250 // this function is called when:
251 // * creating the title page,(looking for iconcoll* & collectname metadata)
252 // * creating the about page (looking for "Title" metadata)
253 // * doing the query - (note that a request for metadata comes first, then
254 // filterOptions = FRmetadata | FROID | FRtermFreq (64+4+1)
255
256 // metadata-only requests have filterName="NullFilter", else "QueryFilter".
257 // For the title page, we should not create a connection to the target
258 // (target means the actual z39.50 server, origin means us), but
259 // for the about page and query pages, we need to get information from the
260 // origin. (eg for the about page, we will print out some info such as ID,
261 // name and version.
262
263 // cerr now goes to errout.txt in etc directory
264
265 // get relevant "collection"
266 z3950_server_array::iterator zserver = zservers.begin();
267 z3950_server_array::iterator zend = zservers.end();
268 while (zserver != zend) {
269 if(zserver->getName()==collection) {
270 break;
271 }
272 zserver++;
273 }
274 // now have collection in zserver.
275
276 // ColInfoResponse_t *info = new ColInfoResponse_t;
277 ColInfoResponse_t info;
278 ResultDocInfo_t *docInfo=new ResultDocInfo_t;
279
280
281 // leave response.termInfo empty
282 // leave response.docInfo empty
283 /* got the following for first query:
284 request.filterResultOptions=FRmetadata;
285 request.getParents=getParents
286 request.fields=metadata
287 request.docSet (includes OID);
288 */
289
290 // response.termInfo.push_back(""); ??????? (should be empty if not req.)
291
292
293 // See if this is for a query action
294 /*** johnmcp **********
295 this is not enough, as FROID is set for the about action,
296 and furthermore, the number of docInfo's (+1?) seems to imply the number
297 of search methods.
298 ** ABOUT ACTION
299 * OIDtools.get_children()
300 . FRmetadata, FilterOptions ParentNode=''
301 * OIDtools.get_info()
302 . FRmetadata
303 ** QUERY ACTION
304 * OIDtools.get_info() <- receptionist.define_general_macros()
305 . FRmetadata, no OptionValues
306 * queryaction.search_single_collection
307 . FRmetadata | FROID | FRtermFreq, fltrOps Term/QueryType/Casefold/..
308 */
309 if (request.filterResultOptions & /*FROID*/FRtermFreq) {
310 // Pretty bad hack: this is assuming
311 // FRtermFreq is only set for query action, not about action.
312
313 // what about:
314 // OptionValue_tarray filterOptions
315 // docSet
316 // requestParams
317 // refParams
318 // fields -- requested metadata fields.
319 /*
320 if (!request.requestParams.empty())
321 cout << "RequestParams: " << request.requestParams.getcstr() << "\n";
322 if (!request.refParams.empty())
323 cout << "RefParams: " << request.refParams.getcstr() << "\n";
324 */ OptionValue_tarray::iterator ov_here=request.filterOptions.begin();
325 OptionValue_tarray::iterator ov_end=request.filterOptions.end();
326 while (ov_here != ov_end) {
327 cout << "OV pair: `" << ov_here->name.getcstr() << "'=`"
328 << ov_here->value.getcstr() << "'\n";
329 ov_here++;
330 }/*
331 cout << "end\n\n";
332 */
333
334 /* Sample OptionValue pairs
335 `StartResults'=`1'
336 `EndResults'=`20'
337 `Term'=`firstword secondword' (term is just whatever the user typed in)
338 `QueryType'=`ranked' => 'OR' (cgiarg t=1)
339 `QueryType' = `boolean' => 'AND' (cgiarg t=0)
340 `Casefold'=`true'
341 `Stem'=`false'
342 `Maxdocs'=`50'
343 */
344 docInfo->metadata["Title"].values.push_back("dummy title");
345 docInfo->result_num=1;
346
347 if (request.filterResultOptions & FRtermFreq) {
348 response.numDocs=2;
349 response.isApprox=Exact; // Exact | Approximate | MoreThan
350 }
351
352 response.docInfo.push_back(*docInfo);
353 // create a 2nd dummy record
354 docInfo=new ResultDocInfo_t;
355 docInfo->metadata["Title"].values.push_back("another title");
356 docInfo->result_num=2;
357 response.docInfo.push_back(*docInfo);
358
359 } // end of if (... & FROID)
360 else {
361 // this wasn't a query action
362
363 if (request.filterOptions.size()>0 &&
364 request.filterOptions[0].name=="ParentNode") {
365 // don't want to return anything
366 //delete (docInfo);
367 } else {
368 // in case we need to return only metadata
369 response.docInfo.push_back(*docInfo);
370 }
371 }
372
373 // Fill in metadata for each response.docInfo (if wanted)
374 if (request.filterResultOptions & FRmetadata) {
375 get_collectinfo (collection, info, err, logout);
376 // should check err returned here....
377 /* In the absence of any other information, (eg commented code),
378 assuming that if the request.fields is empty, then we should return
379 all metadata, otherwise return only the requested fields */
380 /**** comtypes.h has: "text_tset fields; // empty if not used" ****/
381
382 if (!request.fields.empty()) {
383 // loop on each document being returned
384 ResultDocInfo_tarray::iterator docs_here=response.docInfo.begin();
385 ResultDocInfo_tarray::iterator docs_end=response.docInfo.end();
386 while (docs_here!=docs_end) {
387
388 // loop on all the metadata fields in request.fields (type text_tset)
389 text_tset::iterator fields_here=request.fields.begin();
390 text_tset::iterator fields_end=request.fields.end();
391 text_tmap::iterator it;
392 while (fields_here!=fields_end) {
393 it=info.collectionmeta.find(*fields_here);
394 ////////// cerr << "filter: getting " << (*fields_here).getcstr();
395 if (it!=info.collectionmeta.end())
396 docs_here->metadata[*fields_here].values.push_back((*it).second);
397 else {
398 docs_here->metadata[*fields_here].values.push_back("");
399 /////// cerr << " (not found)";
400 }
401 ////////cerr << "\n";
402 fields_here++;
403 } // end of inner while loop
404 docs_here++;
405 } // end of outer while loop
406 } // end of if (!request.fields.empty())
407
408 else { // request.fields empty: return all metadata for about page or query
409 // we'll only put it in the first docInfo.
410 text_tmap::iterator colmeta_here=info.collectionmeta.begin();
411 text_tmap::iterator colmeta_end=info.collectionmeta.end();
412 while (colmeta_here!=colmeta_end) {
413 response.docInfo[0].metadata[(*colmeta_here).first].
414 values.push_back((*colmeta_here).second);
415 /////cerr << "\t" << (*colmeta_here).first.getcstr() << "\n";
416 colmeta_here++;
417 }
418 // get data from target.
419 // check if "collectionextra" metadata is set. If it isn't, we should
420 // create connection to target to get it.
421 if (info.collectionmeta.find("collectionextra")==colmeta_end) {
422 // it doesn't exist.
423 text_t *abouttext;
424 // this gets the server's name and id, plus MOTD, etc.
425 abouttext=zserver->connect_getAbout();
426 // add in the text we read in from config file.
427 // how do we incorporate multi-lingual metadata?
428 (*abouttext)+="<P>\n";
429 (*abouttext)+=zserver->getAbout("en");
430 zserver->setMeta("collectionextra",*abouttext);
431 response.docInfo[0].metadata["collectionextra"].values.push_back(*abouttext);
432 delete (abouttext);
433 }
434 } // end of else
435
436 } //end of if (... & FRmetadata) ...
437
438
439
440 err=noError;
441}
442
443void z3950proto::get_document (const text_t &/*collection*/,
444 const DocumentRequest_t &/*request*/,
445 DocumentResponse_t &/*response*/,
446 comerror_t &err, ostream &logout) {
447
448 if (0) {
449 err=protocolError;
450 logout << "Some error\n";
451 }
452}
453
454
455#endif
Note: See TracBrowser for help on using the repository browser.