source: gsdl/trunk/runtime-src/src/z3950/z3950server.cpp@ 19591

Last change on this file since 19591 was 19591, checked in by kjdon, 12 years ago

strip off namespace and subfield when creating metatags, as the d2m mappings don't allow them

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