root/main/trunk/greenstone2/runtime-src/src/z3950/z3950server.cpp @ 22400

Revision 22400, 27.2 KB (checked in by kjdon, 10 years ago)

some code formatting changes, major change is the call to MARCtidy instead of usMARC, allowing for different output formats, including the new uniMARC

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      }
737
738      // work out the d2m format number
739      int record_format;
740      switch(r->request_format) {
741      case VAL_DANMARC:
742    record_format = DANMARC;
743    break;
744      case VAL_FINMARC:
745    record_format = FINMARC;
746    break;
747      case VAL_NORMARC:
748    record_format = NORMARC;
749    break;
750      case VAL_SWEMARC:
751    record_format = SWEMARC;
752    break;
753      case VAL_UNIMARC:
754    record_format = UNIMARC;
755    break;
756      default:
757    // we don;t know any other format, so assume usMARC
758    record_format = USMARC;
759    // set above to be request_format, but this may change it
760    r->output_format = VAL_USMARC;
761      }
762     
763     
764
765      list<metatag*>::iterator METATAG_here = Metatag_list.begin();
766      list<metatag*>::iterator METATAG_end = Metatag_list.end();
767      while (METATAG_here != METATAG_end) {
768    //usMARC(*METATAG_here, mrec);
769    MARCmake(*METATAG_here, mrec, record_format);
770    METATAG_here++;
771      }
772
773      // set the date in the marc record to the current date
774      char today[32];
775      time_t d;
776      struct tm *time_struct;
777      //putenv("TZ=NFT-1DFT");
778      d = time(NULL);
779      time_struct = localtime(&d);
780      strftime(today, 16, "%y%m%d", time_struct);
781      put008(mrec->s008, today, F008_DATE_ENTERED);
782      put008(mrec->s008, "s", F008_TYPE_OF_DATE);
783
784      // to do: make this safer + more efficient
785      cp = new char[1000000];
786      char *cp2 = new char[1000000];
787   
788      MARCtidy(mrec, cp, record_format);
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 browser.