source: trunk/gsdl/src/colservr/z3950server.cpp@ 11188

Last change on this file since 11188 was 10436, checked in by kjdon, 19 years ago

moved the yaz headers to the top or teh include list to avoid namespace conflicts

  • Property svn:keywords set to Author Date Id Revision
File size: 27.2 KB
Line 
1
2// YAZ headers
3#include <yaz/backend.h>
4#include <yaz/log.h>
5#ifdef ASN_COMPILED
6#include <yaz/ill.h>
7#endif
8
9
10// Standard headers
11
12#if defined(GSDL_USE_OBJECTSPACE)
13# include <ospace\std\iostream>
14# include <ospace\std\fstream>
15# include <ospace\std\sstream>
16#elif defined(GSDL_USE_IOS_H)
17# include <iostream.h>
18# include <fstream.h>
19# include <strstream.h>
20#else
21# include <iostream>
22# include <fstream>
23# include <sstream>
24#endif
25
26#include <string>
27#include <list>
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <ctype.h>
32#include <time.h>
33
34// Greenstone headers
35#include "fileutil.h"
36#include "comtypes.h"
37#include "recptproto.h"
38#include "nullproto.h"
39
40
41// Z39.50 server headers
42#include "z3950parser.h"
43#include "z3950explain.h"
44
45#include "z3950server.h"
46
47// Dublin Core -> MARC (d2m) headers and source files
48#include "d2m4gs.h"
49
50// these globals are local to each thread,
51// one Z39.50 connection = one thread.
52text_t gsdlhome; // this is specified externally when Greenstone is installed
53list<FilterResponse_t> Response_tlist; // list of response sets
54list<text_t> Response_tlist_colnames; // collection names for the above
55list<int> Response_tlist_sizes; // sizes (number of records) for the above
56z3950Server *Server = NULL;
57collectset *Cservers = NULL;
58nullproto *Protocol = NULL;
59
60map<text_t, gsdlCollection> Collection_map; // info and tools for collections
61map<text_t, text_t> Resultsets; // mapping from ResultSetId to GSQuery
62
63int z3950_verbosity_ = 3;
64
65// *** initialize things here ***
66bend_initresult *bend_init(bend_initrequest *q)
67{
68 // *** called when client connects to the server ***
69 if (z3950_verbosity_ > 1) {
70 cerr << "Entering bend_init" << endl;
71 }
72
73 Protocol = new nullproto();
74 Cservers = new collectset(gsdlhome);
75 Protocol->set_collectset(Cservers);
76
77 cerr << "Starting Z39.50 Server ..." << endl;
78
79 Server = new z3950Server(Protocol, gsdlhome);
80 cerr << "Server constructed" << endl;
81
82 const bool status = Server->initialise();
83 cerr << "Initialised server: return status = " << status << endl;
84
85 text_tarray collist;
86 comerror_t err;
87 Protocol->get_collection_list( collist, err, cout );
88
89 // display the list of available Greenstone collections
90 text_tarray::iterator cols_here=collist.begin();
91 text_tarray::iterator cols_end=collist.end();
92 while (cols_here != cols_end) {
93 gsdlCollection tmpcol(*cols_here, gsdlhome);
94
95 Collection_map[*cols_here] = tmpcol;
96
97 if (tmpcol.z3950Capeable()) {
98 cerr << " " << tmpcol.getName() << "\tis Z39.50 capable" << endl;
99 }
100 cols_here++;
101 }
102
103
104 bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
105 //static char *dummy = "Hej fister"; // what's this for?
106
107 r->errcode = 0;
108 r->errstring = 0;
109 r->handle = Protocol;
110 q->bend_sort = ztest_sort; /* register sort handler */
111 q->bend_search = ztest_search; /* register search handler */
112 q->bend_present = ztest_present; /* register present handle */
113 q->bend_esrequest = ztest_esrequest;
114 q->bend_delete = ztest_delete;
115 q->bend_fetch = ztest_fetch;
116 q->bend_scan = ztest_scan;
117
118 return r;
119}
120
121// *** perform query, get number of hits ***
122int ztest_search (void *handle, bend_search_rr *rr)
123{
124 // *** called when client issues a "find" command
125 if (z3950_verbosity_>1) {
126 cerr << "Entering ztest_search" << endl;
127 }
128
129 Response_tlist.clear();
130 Response_tlist_colnames.clear();
131 Response_tlist_sizes.clear();
132
133 comerror_t err;
134 FilterRequest_t request;
135
136 request.filterName = "QueryFilter";
137 request.filterResultOptions = FROID | FRtermFreq | FRmetadata;
138
139 OptionValue_t option;
140
141 // how many results to get. grouping all results together into
142 // one set instead of breaking up into "pages".
143 // note: see if Z39.50 has a concept of pages.
144 option.name = "StartResults";
145 option.value = "1";
146 request.filterOptions.push_back (option);
147 option.name = "EndResults";
148 option.value = MAXHITS;
149 request.filterOptions.push_back (option);
150 option.name = "Maxdocs";
151 option.value = MAXHITS;
152 request.filterOptions.push_back (option);
153
154 text_t GSQuery = ZQueryToGSQuery(rr);
155 option.name = "Term";
156 option.value = GSQuery;
157 request.filterOptions.push_back (option);
158 Resultsets[Resultsets.size()+1] = GSQuery;
159
160 option.name = "QueryType";
161 option.value = "boolean";
162 request.filterOptions.push_back (option);
163
164 option.name = "MatchMode";
165 option.value = "all";
166 request.filterOptions.push_back (option);
167
168 option.name = "Casefold";
169 option.value = "true";
170 request.filterOptions.push_back (option);
171
172 option.name = "Stem";
173 option.value = "false";
174 request.filterOptions.push_back (option);
175
176 // MG queries don't need this, MGPP queries do.
177 // doesn't do any harm to include it anyway.
178 // note: not all collections have document-level granularity...
179 option.name = "Level";
180 option.value = "Doc";
181 request.filterOptions.push_back (option);
182
183 // Z39.50 supports the searching of multiple databases
184 rr->hits = 0;
185 for (int i = 0; i < rr->num_bases; i++) {
186 FilterResponse_t response;
187 cerr << "Searching basename = " << rr->basenames[i] << endl;
188 // intercept Explain requests
189 if (strcmp(rr->basenames[i], "IR-Explain-1")==0) {
190 //ColInfoResponse_t collectinfo;
191 //Protocol->get_collectinfo("csbib", collectinfo, err, cerr);
192 //response.numDocs = 1;
193 //ResultDocInfo_t docinfo;
194 //docinfo.metadata["foo"].values.push_back("bar");
195 getExplainInfo(rr, response, err);
196 //response.docInfo.push_back(docinfo);
197 } else {
198 cerr << "calling filter..." << endl;
199 Protocol->filter(rr->basenames[i], request, response, err, cerr);
200 cerr << "returned from filter." << endl;
201 if (response.numDocs > MAXHITS) {
202 response.numDocs = MAXHITS;
203 }
204 }
205 rr->hits += response.numDocs;
206 Response_tlist.push_back(response);
207 text_t basename = rr->basenames[i];
208 Response_tlist_colnames.push_back(basename);
209 Response_tlist_sizes.push_back(response.numDocs);
210 cerr << "search complete." << endl;
211 }
212
213 if (rr->hits > MAXHITS) rr->hits = MAXHITS;
214 return 0;
215}
216
217// *** extra code for showing results, not needed ***
218int ztest_present (void *handle, bend_present_rr *rr)
219{
220 // *** called when client issues a "show" command, 1st of 5
221 if (z3950_verbosity_>1) {
222 cerr << "entering ztest_present" << endl;
223 }
224 return 0;
225}
226
227int ztest_esrequest (void *handle, bend_esrequest_rr *rr)
228{
229
230 if (z3950_verbosity_>1) {
231 cerr << "Entering ztest_esrequest" << endl;
232 }
233 yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
234 if (rr->esr->packageName)
235 yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
236 yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
237
238 if (!rr->esr->taskSpecificParameters)
239 {
240 yaz_log (LOG_WARN, "No task specific parameters");
241 }
242 else if (rr->esr->taskSpecificParameters->which == Z_External_itemOrder)
243 {
244 Z_ItemOrder *it = rr->esr->taskSpecificParameters->u.itemOrder;
245 yaz_log (LOG_LOG, "Received ItemOrder");
246 switch (it->which)
247 {
248#ifdef ASN_COMPILED
249 case Z_IOItemOrder_esRequest:
250#else
251 case Z_ItemOrder_esRequest:
252#endif
253 {
254 Z_IORequest *ir = it->u.esRequest;
255 Z_IOOriginPartToKeep *k = ir->toKeep;
256 Z_IOOriginPartNotToKeep *n = ir->notToKeep;
257
258 if (k && k->contact)
259 {
260 if (k->contact->name)
261 yaz_log(LOG_LOG, "contact name %s", k->contact->name);
262 if (k->contact->phone)
263 yaz_log(LOG_LOG, "contact phone %s", k->contact->phone);
264 if (k->contact->email)
265 yaz_log(LOG_LOG, "contact email %s", k->contact->email);
266 }
267 if (k->addlBilling)
268 {
269 yaz_log(LOG_LOG, "Billing info (not shown)");
270 }
271
272 if (n->resultSetItem)
273 {
274 yaz_log(LOG_LOG, "resultsetItem");
275 yaz_log(LOG_LOG, "setId: %s", n->resultSetItem->resultSetId);
276 yaz_log(LOG_LOG, "item: %d", *n->resultSetItem->item);
277 }
278#ifdef ASN_COMPILED
279 if (n->itemRequest)
280 {
281 Z_External *r = (Z_External*) n->itemRequest;
282 ILL_ItemRequest *item_req = 0;
283 ILL_Request *ill_req = 0;
284 if (r->direct_reference)
285 {
286 oident *ent = oid_getentbyoid(r->direct_reference);
287 if (ent)
288 yaz_log(LOG_LOG, "OID %s", ent->desc);
289 if (ent && ent->value == VAL_ISO_ILL_1)
290 {
291 yaz_log (LOG_LOG, "ItemRequest");
292 if (r->which == ODR_EXTERNAL_single)
293 {
294 odr_setbuf(rr->decode,
295 (char*)(r->u.single_ASN1_type->buf),
296 r->u.single_ASN1_type->len, 0);
297
298 if (!ill_ItemRequest (rr->decode, &item_req, 0, 0))
299 {
300 yaz_log (LOG_LOG,
301 "Couldn't decode ItemRequest %s near %d",
302 odr_errmsg(odr_geterror(rr->decode)),
303 odr_offset(rr->decode));
304 yaz_log(LOG_LOG, "PDU dump:");
305 odr_dumpBER(yaz_log_file(),
306 (const char*)(r->u.single_ASN1_type->buf),
307 r->u.single_ASN1_type->len);
308 }
309 if (rr->print)
310 {
311 ill_ItemRequest (rr->print, &item_req, 0,
312 "ItemRequest");
313 odr_reset (rr->print);
314 }
315 }
316 if (!item_req && r->which == ODR_EXTERNAL_single)
317 {
318 yaz_log (LOG_LOG, "ILLRequest");
319 odr_setbuf(rr->decode,
320 (char*)(r->u.single_ASN1_type->buf),
321 r->u.single_ASN1_type->len, 0);
322
323 if (!ill_Request (rr->decode, &ill_req, 0, 0))
324 {
325 yaz_log (LOG_LOG,
326 "Couldn't decode ILLRequest %s near %d",
327 odr_errmsg(odr_geterror(rr->decode)),
328 odr_offset(rr->decode));
329 yaz_log(LOG_LOG, "PDU dump:");
330 odr_dumpBER(yaz_log_file(),
331 (const char*)(r->u.single_ASN1_type->buf),
332 r->u.single_ASN1_type->len);
333 }
334 if (rr->print)
335 {
336 ill_Request (rr->print, &ill_req, 0,
337 "ILLRequest");
338 odr_reset (rr->print);
339 }
340 }
341 }
342 }
343 if (item_req)
344 {
345 yaz_log (LOG_LOG, "ILL protocol version = %d",
346 *item_req->protocol_version_num);
347 }
348 }
349#endif
350 }
351 break;
352 }
353 }
354 else if (rr->esr->taskSpecificParameters->which == Z_External_update)
355 {
356 Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
357 yaz_log (LOG_LOG, "Received DB Update");
358 if (up->which == Z_IUUpdate_esRequest)
359 {
360 Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
361 Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
362 Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
363
364 yaz_log (LOG_LOG, "action");
365 if (toKeep->action)
366 {
367 switch (*toKeep->action)
368 {
369 case Z_IUOriginPartToKeep_recordInsert:
370 yaz_log (LOG_LOG, " recordInsert");
371 break;
372 case Z_IUOriginPartToKeep_recordReplace:
373 yaz_log (LOG_LOG, " recordUpdate");
374 break;
375 case Z_IUOriginPartToKeep_recordDelete:
376 yaz_log (LOG_LOG, " recordDelete");
377 break;
378 case Z_IUOriginPartToKeep_elementUpdate:
379 yaz_log (LOG_LOG, " elementUpdate");
380 break;
381 case Z_IUOriginPartToKeep_specialUpdate:
382 yaz_log (LOG_LOG, " specialUpdate");
383 break;
384 default:
385 yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
386 }
387 }
388 if (toKeep->databaseName)
389 {
390 yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
391 if (!strcmp(toKeep->databaseName, "fault"))
392 {
393 rr->errcode = 109;
394 rr->errstring = toKeep->databaseName;
395 }
396 if (!strcmp(toKeep->databaseName, "accept"))
397 rr->errcode = -1;
398 }
399 if (notToKeep)
400 {
401 int i;
402 for (i = 0; i < notToKeep->num; i++)
403 {
404 Z_External *rec = notToKeep->elements[i]->record;
405
406 if (rec->direct_reference)
407 {
408 struct oident *oident;
409 oident = oid_getentbyoid(rec->direct_reference);
410 if (oident)
411 yaz_log (LOG_LOG, "record %d type %s", i,
412 oident->desc);
413 }
414 switch (rec->which)
415 {
416 case Z_External_sutrs:
417 if (rec->u.octet_aligned->len > 170)
418 yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
419 rec->u.sutrs->len,
420 rec->u.sutrs->buf);
421 else
422 yaz_log (LOG_LOG, "%d bytes:\n%s",
423 rec->u.sutrs->len,
424 rec->u.sutrs->buf);
425 break;
426 case Z_External_octet :
427 if (rec->u.octet_aligned->len > 170)
428 yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
429 rec->u.octet_aligned->len,
430 rec->u.octet_aligned->buf);
431 else
432 yaz_log (LOG_LOG, "%d bytes\n%s",
433 rec->u.octet_aligned->len,
434 rec->u.octet_aligned->buf);
435 }
436 }
437 }
438 }
439 }
440 else
441 {
442 yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
443 rr->esr->taskSpecificParameters->which);
444
445 }
446 return 0;
447}
448
449int ztest_delete (void *handle, bend_delete_rr *rr)
450{
451 // *** called when client issues a "delete" command
452 if (z3950_verbosity_>1) {
453 cerr << "Entering ztest_delete" << endl;
454 }
455 if (rr->num_setnames == 1 && !strcmp (rr->setnames[0], "1"))
456 rr->delete_status = Z_DeleteStatus_success;
457 else
458 rr->delete_status = Z_DeleteStatus_resultSetDidNotExist;
459 return 0;
460}
461
462// *** do we want to sort the results? ***
463/* Our sort handler really doesn't sort... */
464int ztest_sort (void *handle, bend_sort_rr *rr)
465{
466 if (z3950_verbosity_>1) {
467 cerr << "entering ztest_sort" << endl;
468 }
469 rr->errcode = 0;
470 rr->sort_status = Z_SortStatus_success;
471 return 0;
472}
473
474static int atoin (const char *buf, int n)
475{
476 // *** called when client issues a "show" command, 5th of 5
477 // *** NOT called if the "show" command has an invalid argument
478 if (z3950_verbosity_>1) {
479 cerr << "Entering atoin" << endl;
480 }
481 int val = 0;
482 while (--n >= 0)
483 {
484 if (isdigit(*buf))
485 val = val*10 + (*buf - '0');
486 buf++;
487 }
488 return val;
489}
490
491// *** don't think we want this ***
492static Z_GenericRecord *dummy_grs_record (int num, ODR o)
493{
494 if (z3950_verbosity_>1) {
495 cerr << "Entering dummy_grs_record" << endl;
496 }
497
498 FILE *f = fopen("dummy-grs", "r");
499 char line[512];
500 Z_GenericRecord *r = 0;
501 int n;
502
503 if (!f)
504 return 0;
505 while (fgets(line, 512, f))
506 if (*line == '#' && sscanf(line, "#%d", &n) == 1 && n == num)
507 {
508 r = read_grs1(f, o);
509 break;
510 }
511 fclose(f);
512 return r;
513}
514
515bool get_sutrs_record (int recnum, text_t &MetadataResult, text_t &CollectionName)
516{
517 if (z3950_verbosity_>1) {
518 cerr << "Entering get_sutrs_record" << endl;
519 }
520 int total_records = 0;
521
522 list<FilterResponse_t>::iterator RESPONSE_here = Response_tlist.begin();
523 list<FilterResponse_t>::iterator RESPONSE_end = Response_tlist.end();
524 list<text_t>::iterator RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
525 list<text_t>::iterator RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
526 list<int>::iterator RESPONSE_SIZES_here = Response_tlist_sizes.begin();
527 list<int>::iterator RESPONSE_SIZES_end = Response_tlist_sizes.end();
528
529 RESPONSE_here = Response_tlist.begin();
530 RESPONSE_end = Response_tlist.end();
531 while (RESPONSE_here != RESPONSE_end) {
532 total_records += (*RESPONSE_here).numDocs;
533 RESPONSE_here++;
534 }
535
536 // check that the index is within bounds
537 if (recnum < 1 || recnum > total_records) {
538 cerr << "get_sutrs_record failed" << endl;
539 return false; // failed
540 } else {
541 FilterResponse_t response;
542 // iterate through Response_tlist to find the right response
543 RESPONSE_here = Response_tlist.begin();
544 RESPONSE_end = Response_tlist.end();
545 RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
546 RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
547 RESPONSE_SIZES_here = Response_tlist_sizes.begin();
548 RESPONSE_SIZES_end = Response_tlist_sizes.end();
549 int n = 0;
550
551 while (RESPONSE_here != RESPONSE_end) {
552 n += *RESPONSE_SIZES_here;
553 if (n >= recnum) {
554 response = *RESPONSE_here;
555 CollectionName = *RESPONSE_COLNAMES_here;
556 recnum = *RESPONSE_SIZES_here - (n - recnum);
557 break;
558 }
559 // these should all have the same number of elements,
560 // so only need to check that one is within bounds.
561 // may want to combine these into a larger data structure later.
562 RESPONSE_here++;
563 RESPONSE_COLNAMES_here++;
564 RESPONSE_SIZES_here++;
565 }
566
567 // locate the desired record in the response
568
569 MetadataInfo_tmap::iterator METAFIELD_here = response.docInfo[recnum-1].metadata.begin();
570 MetadataInfo_tmap::iterator METAFIELD_end = response.docInfo[recnum-1].metadata.end();
571
572 while (METAFIELD_here!=METAFIELD_end) {
573 text_tarray::iterator METAVALUE_here = METAFIELD_here->second.values.begin();
574 text_tarray::iterator METAVALUE_end = METAFIELD_here->second.values.end();
575 while (METAVALUE_here!=METAVALUE_end) {
576 // construct a text_t containing the record:
577 // there are multiple metadata fields,
578 // each field can have multiple values.
579 /*
580 // don't include fields starting with a lowercase letter,
581 // these are system fields.
582 // later: include these anyway, since Explain fields start with lowercase letters
583 if (METAFIELD_here->first[0] >= 'A' &&
584 METAFIELD_here->first[0] <= 'Z') {
585 */
586 MetadataResult += METAFIELD_here->first; // field name
587 MetadataResult += " ";
588 MetadataResult += *METAVALUE_here; // field contents
589 MetadataResult += "\n";
590 //}
591 METAVALUE_here++;
592 }
593 METAFIELD_here++;
594 }
595 return true; // succeeded
596 }
597}
598
599bool get_marc_record (int recnum, list<metatag*> &Metatag_list, text_t &CollectionName)
600{
601 if (z3950_verbosity_>1) {
602 cerr << "Entering get_marc_record" << endl;
603 }
604 int total_records = 0;
605
606 list<FilterResponse_t>::iterator RESPONSE_here = Response_tlist.begin();
607 list<FilterResponse_t>::iterator RESPONSE_end = Response_tlist.end();
608 list<text_t>::iterator RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
609 list<text_t>::iterator RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
610 list<int>::iterator RESPONSE_SIZES_here = Response_tlist_sizes.begin();
611 list<int>::iterator RESPONSE_SIZES_end = Response_tlist_sizes.end();
612
613 RESPONSE_here = Response_tlist.begin();
614 RESPONSE_end = Response_tlist.end();
615 while (RESPONSE_here != RESPONSE_end) {
616 total_records += (*RESPONSE_here).numDocs;
617 RESPONSE_here++;
618 }
619
620 // check that the index is within bounds
621 if (recnum < 1 || recnum > total_records) {
622 cerr << "get_marc_record failed" << endl;
623 return false; // failed
624 } else {
625 FilterResponse_t response;
626 // iterate through Response_tlist to find the right response
627 RESPONSE_here = Response_tlist.begin();
628 RESPONSE_end = Response_tlist.end();
629 RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
630 RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
631 RESPONSE_SIZES_here = Response_tlist_sizes.begin();
632 RESPONSE_SIZES_end = Response_tlist_sizes.end();
633 int n = 0;
634 while (RESPONSE_here != RESPONSE_end) {
635 n += *RESPONSE_SIZES_here;
636 if (n >= recnum) {
637 response = *RESPONSE_here;
638 CollectionName = *RESPONSE_COLNAMES_here;
639 recnum = *RESPONSE_SIZES_here - (n - recnum);
640 break;
641 }
642 // these should all have the same number of elements,
643 // so only need to check that one is within bounds.
644 // may want to combine these into a larger data structure later.
645 RESPONSE_here++;
646 RESPONSE_COLNAMES_here++;
647 RESPONSE_SIZES_here++;
648 }
649
650 // locate the desired record in the response
651
652 MetadataInfo_tmap::iterator METAFIELD_here = response.docInfo[recnum-1].metadata.begin();
653 MetadataInfo_tmap::iterator METAFIELD_end = response.docInfo[recnum-1].metadata.end();
654
655 while (METAFIELD_here!=METAFIELD_end) {
656 text_tarray::iterator METAVALUE_here = METAFIELD_here->second.values.begin();
657 text_tarray::iterator METAVALUE_end = METAFIELD_here->second.values.end();
658 while (METAVALUE_here!=METAVALUE_end) {
659 if (METAFIELD_here->first[0] >= 'A' &&
660 METAFIELD_here->first[0] <= 'Z') {
661 metatag *tmptag = new metatag();
662 tmptag->name = METAFIELD_here->first.getcstr();
663 tmptag->type = "";
664 tmptag->scheme = "";
665 tmptag->value = (*METAVALUE_here).getcstr();
666 Metatag_list.push_back(tmptag);
667 }
668 METAVALUE_here++;
669 }
670 METAFIELD_here++;
671 }
672 return true; // succeeded
673 }
674}
675
676// *** implement this ***
677int ztest_fetch(void *handle, bend_fetch_rr *r)
678{
679 // *** called when client issues a "show" command, 2nd of 5
680 if (z3950_verbosity_>1) {
681 cerr << "Entering ztest_fetch" << endl;
682 }
683 char *cp;
684 r->errstring = 0;
685 r->last_in_set = 0;
686 r->basename = "DUMMY"; // this is set below
687 r->output_format = r->request_format;
688
689 // *** use this until found a good way of mapping Greenstone
690 // *** metadata fields to USMARC fields
691 if (r->request_format == VAL_SUTRS)
692 {
693 // copies record into r, errcode will be 13 if fails
694 text_t MetadataResult;
695 text_t CollectionName;
696 if (!get_sutrs_record(r->number, MetadataResult, CollectionName)) {
697 r->errcode = 13;
698 return 0;
699 } else {
700 r->len = MetadataResult.size();
701 r->record = (char*) odr_malloc(r->stream, r->len+1);
702 char *tmptxt = MetadataResult.getcstr();
703 strcpy(r->record, tmptxt);
704 delete tmptxt;
705 r->basename = (char*) odr_malloc(r->stream, CollectionName.size()+1);
706 tmptxt = CollectionName.getcstr();
707 strcpy(r->basename, tmptxt);
708 delete tmptxt;
709 }
710 }
711 // *** do we want to use this format? ***
712 else if (r->request_format == VAL_GRS1)
713 {
714 // bail out, since we don't support grs (yet?)
715 r->errcode = 107; // "Query type not supported"
716 return 0;
717
718 }
719 // assume that here on in is some sort of MARC format
720 else {
721 marcrec *mrec = new marcrec;
722
723 mrec = (marcrec*) malloc(sizeof(*mrec));
724
725 mrec->marcline = (char*) malloc(100000);
726 mrec->partitle = (char*) malloc(10000);
727 mrec->subtitle = (char*) malloc(10000);
728 mrec->year = (char*) malloc(1000);
729 mrec->url = (char*) malloc(1000);
730 mrec->fmat = (char*) malloc(1000);
731 mrec->s008 = (char*) malloc(41);
732
733 mrec->ncreators = 0;
734 mrec->ntitles = 0;
735 *mrec->marcline = 0;
736 *mrec->subtitle = 0;
737 *mrec->partitle = 0;
738 *mrec->year = 0;
739 *mrec->url = 0;
740 *mrec->fmat = 0;
741 strcpy(mrec->s008, " ");
742
743 text_t CollectionName;
744 list<metatag*> Metatag_list;
745
746 if (!get_marc_record(r->number, Metatag_list, CollectionName)) {
747 r->errcode = 13;
748 return 0;
749 } else {
750 list<metatag*>::iterator METATAG_here = Metatag_list.begin();
751 list<metatag*>::iterator METATAG_end = Metatag_list.end();
752 while (METATAG_here != METATAG_end) {
753 usMARC(*METATAG_here, mrec);
754 METATAG_here++;
755 }
756
757 // set the date in the marc record to the current date
758 char today[32];
759 time_t d;
760 struct tm *time_struct;
761 //putenv("TZ=NFT-1DFT");
762 d = time(NULL);
763 time_struct = localtime(&d);
764 strftime(today, 16, "%y%m%d", time_struct);
765 put008(mrec->s008, today, F008_DATE_ENTERED);
766 put008(mrec->s008, "s", F008_TYPE_OF_DATE);
767
768 // to do: make this safer + more efficient
769 cp = new char[1000000];
770 char *cp2 = new char[1000000];
771
772 switch(r->request_format) {
773 case VAL_DANMARC: {
774 MARCtidy(mrec, cp, DANMARC);
775 r->output_format = VAL_DANMARC;
776 break; }
777 case VAL_FINMARC: {
778 MARCtidy(mrec, cp, FINMARC);
779 r->output_format = VAL_FINMARC;
780 break; }
781 // YAZ doesn't know about ISMARC
782 /*
783 case VAL_ISMARC: {
784 put008(mrec->s008, "k", F008_FORM_OF_PUBLICATION);
785 MARCtidy(mrec, cp, ISMARC);
786 r->output_format = VAL_ISMARC;
787 break; }
788 */
789 case VAL_NORMARC: {
790 MARCtidy(mrec, cp, NORMARC);
791 r->output_format = VAL_NORMARC;
792 break; }
793 case VAL_SWEMARC: {
794 MARCtidy(mrec, cp, SWEMARC);
795 r->output_format = VAL_SWEMARC;
796 break; }
797 default: {
798 MARCtidy(mrec, cp, USMARC);
799 r->output_format = VAL_USMARC;
800 break; }
801 }
802
803 sprintf(cp2, "%s", (char*) MARC2709(cp, 0, 6, 'n', 'm', ' '));
804 r->len = strlen(cp2);
805 r->record = (char*) odr_malloc(r->stream, r->len+1);
806 strcpy(r->record, cp2);
807 r->basename = (char*) odr_malloc(r->stream, CollectionName.size()+1);
808 char *tmptxt;
809 tmptxt = CollectionName.getcstr();
810 strcpy(r->basename, tmptxt);
811 delete tmptxt;
812 delete cp2;
813 cerr << "dumping record:`" << cp << "'" << endl;
814 delete cp;
815 }
816 }
817
818 r->errcode = 0;
819 return 0;
820}
821
822/*
823 * silly dummy-scan what reads words from a file.
824 */
825int ztest_scan(void *handle, bend_scan_rr *q)
826{
827 // *** called when client issues a "scan" command
828 if (z3950_verbosity_>1) {
829 cerr << "Entering ztest_scan" << endl;
830 }
831
832 // bail out, since we don't support scan (yet?)
833 q->errcode = 107; // "Query type not supported"
834 return 0;
835
836 static FILE *f = 0;
837 static struct scan_entry list[200];
838 static char entries[200][80];
839 int hits[200];
840 char term[80], *p;
841 int i, pos;
842 int term_position_req = q->term_position;
843 int num_entries_req = q->num_entries;
844
845 q->errcode = 0;
846 q->errstring = 0;
847 q->entries = list;
848 q->status = BEND_SCAN_SUCCESS;
849 if (!f && !(f = fopen("dummy-words", "r")))
850 {
851 perror("dummy-words");
852 exit(1);
853 }
854 if (q->term->term->which != Z_Term_general)
855 {
856 q->errcode = 229; /* unsupported term type */
857 return 0;
858 }
859 if (*q->step_size != 0)
860 {
861 q->errcode = 205; /*Only zero step size supported for Scan */
862 return 0;
863 }
864 if (q->term->term->u.general->len >= 80)
865 {
866 q->errcode = 11; /* term too long */
867 return 0;
868 }
869 if (q->num_entries > 200)
870 {
871 q->errcode = 31;
872 return 0;
873 }
874 memcpy(term, q->term->term->u.general->buf, q->term->term->u.general->len);
875 term[q->term->term->u.general->len] = '\0';
876 for (p = term; *p; p++)
877 if (islower(*p))
878 *p = toupper(*p);
879
880 fseek(f, 0, SEEK_SET);
881 q->num_entries = 0;
882
883 for (i = 0, pos = 0; fscanf(f, " %79[^:]:%d", entries[pos], &hits[pos]) == 2;
884 i++, pos < 199 ? pos++ : (pos = 0))
885 {
886 if (!q->num_entries && strcmp(entries[pos], term) >= 0) /* s-point fnd */
887 {
888 if ((q->term_position = term_position_req) > i + 1)
889 {
890 q->term_position = i + 1;
891 q->status = BEND_SCAN_PARTIAL;
892 }
893 for (; q->num_entries < q->term_position; q->num_entries++)
894 {
895 int po;
896
897 po = pos - q->term_position + q->num_entries+1; /* find pos */
898 if (po < 0)
899 po += 200;
900
901 if (!strcmp (term, "SD") && q->num_entries == 2)
902 {
903 list[q->num_entries].term = entries[pos];
904 list[q->num_entries].occurrences = -1;
905 list[q->num_entries].errcode = 233;
906 list[q->num_entries].errstring = "SD for Scan Term";
907 }
908 else
909 {
910 list[q->num_entries].term = entries[po];
911 list[q->num_entries].occurrences = hits[po];
912 }
913 }
914 }
915 else if (q->num_entries)
916 {
917 list[q->num_entries].term = entries[pos];
918 list[q->num_entries].occurrences = hits[pos];
919 q->num_entries++;
920 }
921 if (q->num_entries >= num_entries_req)
922 break;
923 }
924 if (feof(f))
925 q->status = BEND_SCAN_PARTIAL;
926 return 0;
927}
928
929
930
931void bend_close(void *handle)
932{
933 if (z3950_verbosity_>1) {
934 cerr << "Entering bend_close" << endl;
935 }
936 delete Server;
937 delete Cservers;
938 delete Protocol;
939 if (z3950_verbosity_>1) {
940 cerr << "heap cleaned up, exiting bend_close" << endl;
941 }
942 return;
943}
944
945int main (int argc, char *argv[])
946{
947
948 const int statserv_var = statserv_main(argc, argv, bend_init, bend_close);
949 cerr << "statserv_main returns: " << statserv_var << endl;
950 return statserv_var;
951
952 return 0;
953}
954
955
Note: See TracBrowser for help on using the repository browser.