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

Last change on this file since 9934 was 9926, checked in by davidb, 19 years ago

Introduction of Z39.50 Server code for Greenstone. Based on the work of
Chris Martin (2001 approx). Updated to work with newer version of YAZ
library.

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