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

Revision 22452, 27.4 KB (checked in by kjdon, 10 years ago)

added a variable to store the default format, so can change it easily. Still have to recompile though. Maybe one day I'll have it read in from a file or somewhere.

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// change the default format here - these two must match
58int default_marc_format_d2m_ = USMARC; // USMARC, UNIMARC, DANMARC, FINMARC, NORMARC, SWEMARC
59oid_value default_marc_format_yaz_ = VAL_USMARC; // VAL_USMARC, VAL_UNIMARC, VAL_DANMARC, VAL_FINMARC, VAL_NORMARC, VAL_SWEMARC
60
61// *** initialize things here ***
62bend_initresult *bend_init(bend_initrequest *q)
63{
64  // *** called when client connects to the server ***
65  if (z3950_verbosity_ > 1) {
66    cerr << "Entering bend_init" << endl;
67  }
68
69  Protocol = new nullproto(); 
70  Cservers = new collectset(gsdlhome, collecthome);
71  Protocol->set_collectset(Cservers);
72 
73  cerr << "Starting Z39.50 Server ..." << endl;
74 
75  Server = new z3950Server(Protocol, gsdlhome);
76  cerr << "Server constructed" << endl;
77 
78  const bool status = Server->initialise();
79  cerr << "Initialised server: return status = " << status << endl;
80 
81  text_tarray collist;
82  comerror_t err;
83  Protocol->get_collection_list( collist, err, cout );
84
85  // display the list of available Greenstone collections
86  text_tarray::iterator cols_here=collist.begin();
87  text_tarray::iterator cols_end=collist.end();
88  while (cols_here != cols_end) {
89    gsdlCollection tmpcol(*cols_here, gsdlhome);
90   
91    Collection_map[*cols_here] = tmpcol;
92   
93    if (tmpcol.z3950Capeable()) {
94      cerr << "  " << tmpcol.getName() << "\tis Z39.50 capable" << endl;
95    }
96    cols_here++;
97  }
98
99   
100  bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
101  //static char *dummy = "Hej fister"; // what's this for?
102 
103  r->errcode = 0;
104  r->errstring = 0;
105  r->handle = Protocol;
106  q->bend_sort = ztest_sort;       /* register sort handler */
107  q->bend_search = ztest_search;   /* register search handler */
108  q->bend_present = ztest_present; /* register present handle */
109  q->bend_esrequest = ztest_esrequest;
110  q->bend_delete = ztest_delete;
111  q->bend_fetch = ztest_fetch;
112  q->bend_scan = ztest_scan;
113
114  return r;
115}
116
117// *** perform query, get number of hits ***
118int ztest_search (void *handle, bend_search_rr *rr)
119{
120  // *** called when client issues a "find" command
121  if (z3950_verbosity_>1) {
122    cerr << "Entering ztest_search" << endl;
123  }
124
125  Response_tlist.clear();
126  Response_tlist_colnames.clear();
127  Response_tlist_sizes.clear();
128 
129  comerror_t err;
130  FilterRequest_t request;
131
132  request.filterName = "QueryFilter";
133  request.filterResultOptions = FROID | FRtermFreq | FRmetadata; 
134
135  OptionValue_t option;
136
137  // how many results to get. grouping all results together into
138  // one set instead of breaking up into "pages".
139  // note: see if Z39.50 has a concept of pages.
140  option.name = "StartResults";
141  option.value = "1";
142  request.filterOptions.push_back (option);
143  option.name = "EndResults";
144  option.value = MAXHITS;
145  request.filterOptions.push_back (option);
146  option.name = "Maxdocs";
147  option.value = MAXHITS;
148  request.filterOptions.push_back (option);
149
150  text_t GSQuery = ZQueryToGSQuery(rr);
151  option.name = "Term";
152  option.value = GSQuery;
153  request.filterOptions.push_back (option);
154  Resultsets[Resultsets.size()+1] = GSQuery;
155
156  option.name = "QueryType";
157  option.value = "boolean";
158  request.filterOptions.push_back (option);
159
160  option.name = "MatchMode";
161  option.value = "all";
162  request.filterOptions.push_back (option);
163
164  option.name = "Casefold";
165  option.value = "true";
166  request.filterOptions.push_back (option);
167
168  option.name = "Stem";
169  option.value = "false";
170  request.filterOptions.push_back (option);
171
172  option.name = "AccentFold";
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
492bool get_sutrs_record (int recnum, text_t &MetadataResult, text_t &CollectionName)
493{
494  if (z3950_verbosity_>1) {
495    cerr << "Entering get_sutrs_record" << endl;
496  }
497  int total_records = 0;
498
499  list<FilterResponse_t>::iterator RESPONSE_here = Response_tlist.begin();
500  list<FilterResponse_t>::iterator RESPONSE_end = Response_tlist.end();
501  list<text_t>::iterator RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
502  list<text_t>::iterator RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
503  list<int>::iterator RESPONSE_SIZES_here = Response_tlist_sizes.begin();
504  list<int>::iterator RESPONSE_SIZES_end = Response_tlist_sizes.end();
505
506  RESPONSE_here = Response_tlist.begin();
507  RESPONSE_end = Response_tlist.end();
508  while (RESPONSE_here != RESPONSE_end) {
509    total_records += (*RESPONSE_here).numDocs;
510    RESPONSE_here++;
511  }
512
513  // check that the index is within bounds
514  if (recnum < 1 || recnum > total_records) {
515    cerr << "get_sutrs_record failed" << endl;
516    return false; // failed
517  } else {
518    FilterResponse_t response;
519    // iterate through Response_tlist to find the right response
520    RESPONSE_here = Response_tlist.begin();
521    RESPONSE_end = Response_tlist.end();
522    RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
523    RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
524    RESPONSE_SIZES_here = Response_tlist_sizes.begin();
525    RESPONSE_SIZES_end = Response_tlist_sizes.end();
526    int n = 0;
527
528    while (RESPONSE_here != RESPONSE_end) {
529      n += *RESPONSE_SIZES_here;
530      if (n >= recnum) {
531    response = *RESPONSE_here;
532    CollectionName = *RESPONSE_COLNAMES_here;
533    recnum = *RESPONSE_SIZES_here - (n - recnum);
534    break;
535      }
536      // these should all have the same number of elements,
537      // so only need to check that one is within bounds.
538      // may want to combine these into a larger data structure later.
539      RESPONSE_here++;
540      RESPONSE_COLNAMES_here++;
541      RESPONSE_SIZES_here++;
542    }
543
544    // locate the desired record in the response
545   
546    MetadataInfo_tmap::iterator METAFIELD_here = response.docInfo[recnum-1].metadata.begin();
547    MetadataInfo_tmap::iterator METAFIELD_end = response.docInfo[recnum-1].metadata.end();
548
549    while (METAFIELD_here!=METAFIELD_end) {
550      text_tarray::iterator METAVALUE_here = METAFIELD_here->second.values.begin();
551      text_tarray::iterator METAVALUE_end = METAFIELD_here->second.values.end();
552      while (METAVALUE_here!=METAVALUE_end) {
553    // construct a text_t containing the record:
554    // there are multiple metadata fields,
555    // each field can have multiple values.
556    /*
557    // don't include fields starting with a lowercase letter,
558    // these are system fields.
559    // later: include these anyway, since Explain fields start with lowercase letters
560    if (METAFIELD_here->first[0] >= 'A' &&
561        METAFIELD_here->first[0] <= 'Z') {
562    */
563      MetadataResult += METAFIELD_here->first; // field name
564      MetadataResult += " ";
565      MetadataResult += *METAVALUE_here; // field contents
566      MetadataResult += "\n";
567      //}
568    METAVALUE_here++;
569      }
570      METAFIELD_here++;
571    }
572    return true; // succeeded
573  }
574}
575
576bool get_marc_record (int recnum, list<metatag*> &Metatag_list, text_t &CollectionName)
577{
578  if (z3950_verbosity_>1) {
579    cerr << "Entering get_marc_record" << endl;
580  }
581  int total_records = 0;
582
583  list<FilterResponse_t>::iterator RESPONSE_here = Response_tlist.begin();
584  list<FilterResponse_t>::iterator RESPONSE_end = Response_tlist.end();
585  list<text_t>::iterator RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
586  list<text_t>::iterator RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
587  list<int>::iterator RESPONSE_SIZES_here = Response_tlist_sizes.begin();
588  list<int>::iterator RESPONSE_SIZES_end = Response_tlist_sizes.end();
589
590  RESPONSE_here = Response_tlist.begin();
591  RESPONSE_end = Response_tlist.end();
592  while (RESPONSE_here != RESPONSE_end) {
593    total_records += (*RESPONSE_here).numDocs;
594    RESPONSE_here++;
595  }
596
597  // check that the index is within bounds
598  if (recnum < 1 || recnum > total_records) {
599    cerr << "get_marc_record failed" << endl;
600    return false; // failed
601  }
602   
603  FilterResponse_t response;
604  // iterate through Response_tlist to find the right response
605  RESPONSE_here = Response_tlist.begin();
606  RESPONSE_end = Response_tlist.end();
607  RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
608  RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
609  RESPONSE_SIZES_here = Response_tlist_sizes.begin();
610  RESPONSE_SIZES_end = Response_tlist_sizes.end();
611  int n = 0;
612  while (RESPONSE_here != RESPONSE_end) {
613    n += *RESPONSE_SIZES_here;
614    if (n >= recnum) {
615      response = *RESPONSE_here;
616      CollectionName = *RESPONSE_COLNAMES_here;
617      recnum = *RESPONSE_SIZES_here - (n - recnum);
618      break;
619    }
620    // these should all have the same number of elements,
621    // so only need to check that one is within bounds.
622    // may want to combine these into a larger data structure later.
623    RESPONSE_here++;
624    RESPONSE_COLNAMES_here++;
625    RESPONSE_SIZES_here++;
626  }
627
628  // locate the desired record in the response and gather all the metadata
629   
630  MetadataInfo_tmap::iterator METAFIELD_here = response.docInfo[recnum-1].metadata.begin();
631  MetadataInfo_tmap::iterator METAFIELD_end = response.docInfo[recnum-1].metadata.end();
632 
633  while (METAFIELD_here!=METAFIELD_end) {
634    text_t meta_name = METAFIELD_here->first;
635    text_t::const_iterator pos = findchar(meta_name.begin(), meta_name.end(), '.');
636    // strip off namespace and subfield
637    if (pos != meta_name.end()) {
638      meta_name = substr(pos+1, meta_name.end());
639    }
640    pos = findchar(meta_name.begin(), meta_name.end(), '^');
641    if (pos != meta_name.end()) {
642      meta_name = substr(meta_name.begin(), pos);
643    }
644    if (meta_name[0] >= 'A' &&
645    meta_name[0] <= 'Z') {
646      text_tarray::iterator METAVALUE_here = METAFIELD_here->second.values.begin();
647      text_tarray::iterator METAVALUE_end = METAFIELD_here->second.values.end();
648      while (METAVALUE_here!=METAVALUE_end) {
649   
650    metatag *tmptag = new metatag();
651    tmptag->name = meta_name.getcstr();
652    tmptag->type = "";
653    tmptag->scheme = "";
654    tmptag->value = (*METAVALUE_here).getcstr();
655    Metatag_list.push_back(tmptag);
656   
657    METAVALUE_here++;
658      }
659    }
660   
661    METAFIELD_here++;
662  }
663  return true; // succeeded
664
665}
666
667// *** implement this ***
668int ztest_fetch(void *handle, bend_fetch_rr *r)
669{
670  // *** called when client issues a "show" command, 2nd of 5
671    if (z3950_verbosity_>1) {
672      cerr << "Entering ztest_fetch" << endl;
673    }
674    char *cp;
675    r->errstring = 0;
676    r->last_in_set = 0;
677    r->basename = "DUMMY"; // this is set below
678    r->output_format = r->request_format;
679
680    // simple unstructured text
681    if (r->request_format == VAL_SUTRS)
682    {
683      // copies record into r, errcode will be 13 if fails
684      text_t MetadataResult;
685      text_t CollectionName;
686      if (!get_sutrs_record(r->number, MetadataResult, CollectionName)) {
687    r->errcode = 13;
688    return 0;
689      } else {         
690    r->len = MetadataResult.size();
691    r->record = (char*) odr_malloc(r->stream, r->len+1);
692    char *tmptxt = MetadataResult.getcstr();
693    strcpy(r->record, tmptxt);
694    delete tmptxt;
695    r->basename = (char*) odr_malloc(r->stream, CollectionName.size()+1);
696    tmptxt = CollectionName.getcstr();
697    strcpy(r->basename, tmptxt);
698    delete tmptxt;
699      }
700    }
701    // *** do we want to use this format? ***
702    else if (r->request_format == VAL_GRS1)
703    {
704      // bail out, since we don't support grs (yet?)
705      r->errcode = 107; // "Query type not supported"
706      return 0;
707     
708    }
709    // assume that here on in is some sort of MARC format
710    else {
711      marcrec *mrec = new marcrec;
712
713      mrec = (marcrec*) malloc(sizeof(*mrec));
714     
715      mrec->marcline = (char*) malloc(100000);
716      mrec->partitle = (char*) malloc(10000);
717      mrec->subtitle = (char*) malloc(10000);
718      mrec->year     = (char*) malloc(1000);
719      mrec->url      = (char*) malloc(1000);
720      mrec->fmat     = (char*) malloc(1000);
721      mrec->s008     = (char*) malloc(41);
722     
723      mrec->ncreators = 0;
724      mrec->ntitles   = 0;
725      *mrec->marcline = 0;
726      *mrec->subtitle = 0;
727      *mrec->partitle = 0;
728      *mrec->year     = 0;
729      *mrec->url      = 0;
730      *mrec->fmat     = 0;
731      strcpy(mrec->s008, "                                        ");
732
733      text_t CollectionName;
734      list<metatag*> Metatag_list;
735
736      if (!get_marc_record(r->number, Metatag_list, CollectionName)) {
737    r->errcode = 13;
738    return 0;
739      }
740
741      // work out the d2m format number
742      int record_format;
743      switch(r->request_format) {
744      case VAL_DANMARC:
745    record_format = DANMARC;
746    break;
747      case VAL_FINMARC:
748    record_format = FINMARC;
749    break;
750      case VAL_NORMARC:
751    record_format = NORMARC;
752    break;
753      case VAL_SWEMARC:
754    record_format = SWEMARC;
755    break;
756      case VAL_UNIMARC:
757    record_format = UNIMARC;
758    break;
759      default:
760    // we don;t know any other format, so assume usMARC
761    record_format = default_marc_format_d2m_;
762    // set above to be request_format, but this may change it
763    r->output_format = default_marc_format_yaz_;
764      }
765     
766     
767
768      list<metatag*>::iterator METATAG_here = Metatag_list.begin();
769      list<metatag*>::iterator METATAG_end = Metatag_list.end();
770      while (METATAG_here != METATAG_end) {
771    //usMARC(*METATAG_here, mrec);
772    MARCmake(*METATAG_here, mrec, record_format);
773    METATAG_here++;
774      }
775
776      // set the date in the marc record to the current date
777      char today[32];
778      time_t d;
779      struct tm *time_struct;
780      //putenv("TZ=NFT-1DFT");
781      d = time(NULL);
782      time_struct = localtime(&d);
783      strftime(today, 16, "%y%m%d", time_struct);
784      put008(mrec->s008, today, F008_DATE_ENTERED);
785      put008(mrec->s008, "s", F008_TYPE_OF_DATE);
786
787      // to do: make this safer + more efficient
788      cp = new char[1000000];
789      char *cp2 = new char[1000000];
790   
791      MARCtidy(mrec, cp, record_format);
792   
793      sprintf(cp2, "%s", (char*) MARC2709(cp, 0, 6, 'n', 'm', ' '));
794      r->len = strlen(cp2);
795      r->record = (char*) odr_malloc(r->stream, r->len+1);
796      strcpy(r->record, cp2);     
797      r->basename = (char*) odr_malloc(r->stream, CollectionName.size()+1);
798      char *tmptxt;
799      tmptxt = CollectionName.getcstr();
800      strcpy(r->basename, tmptxt);
801      delete tmptxt;
802      delete cp2;     
803      cerr << "dumping record:`" << cp << "'" << endl;
804      delete cp;
805     
806    }
807
808    r->errcode = 0;
809    return 0;
810}
811
812/*
813 * silly dummy-scan what reads words from a file.
814 */
815int ztest_scan(void *handle, bend_scan_rr *q)
816{
817  // *** called when client issues a "scan" command
818  if (z3950_verbosity_>1) {
819    cerr << "Entering ztest_scan" << endl;
820  }
821   
822  // bail out, since we don't support scan (yet?)
823  q->errcode = 107; // "Query type not supported"
824  return 0;
825
826    static FILE *f = 0;
827    static struct scan_entry list[200];
828    static char entries[200][80];
829    int hits[200];
830    char term[80], *p;
831    int i, pos;
832    int term_position_req = q->term_position;
833    int num_entries_req = q->num_entries;
834
835    q->errcode = 0;
836    q->errstring = 0;
837    q->entries = list;
838    q->status = BEND_SCAN_SUCCESS;
839    if (!f && !(f = fopen("dummy-words", "r")))
840    {
841    perror("dummy-words");
842    exit(1);
843    }
844    if (q->term->term->which != Z_Term_general)
845    {
846        q->errcode = 229; /* unsupported term type */
847    return 0;
848    }
849    if (*q->step_size != 0)
850    {
851    q->errcode = 205; /*Only zero step size supported for Scan */
852    return 0;
853    }
854    if (q->term->term->u.general->len >= 80)
855    {
856        q->errcode = 11; /* term too long */
857    return 0;
858    }
859    if (q->num_entries > 200)
860    {
861        q->errcode = 31;
862    return 0;
863    }
864    memcpy(term, q->term->term->u.general->buf, q->term->term->u.general->len);
865    term[q->term->term->u.general->len] = '\0';
866    for (p = term; *p; p++)
867        if (islower(*p))
868        *p = toupper(*p);
869
870    fseek(f, 0, SEEK_SET);
871    q->num_entries = 0;
872
873    for (i = 0, pos = 0; fscanf(f, " %79[^:]:%d", entries[pos], &hits[pos]) == 2;
874    i++, pos < 199 ? pos++ : (pos = 0))
875    {
876        if (!q->num_entries && strcmp(entries[pos], term) >= 0) /* s-point fnd */
877    {
878        if ((q->term_position = term_position_req) > i + 1)
879        {
880            q->term_position = i + 1;
881        q->status = BEND_SCAN_PARTIAL;
882        }
883        for (; q->num_entries < q->term_position; q->num_entries++)
884        {
885            int po;
886
887        po = pos - q->term_position + q->num_entries+1; /* find pos */
888        if (po < 0)
889            po += 200;
890
891        if (!strcmp (term, "SD") && q->num_entries == 2)
892        {
893            list[q->num_entries].term = entries[pos];
894            list[q->num_entries].occurrences = -1;
895            list[q->num_entries].errcode = 233;
896            list[q->num_entries].errstring = "SD for Scan Term";
897        }
898        else
899        {
900            list[q->num_entries].term = entries[po];
901            list[q->num_entries].occurrences = hits[po];
902        }
903        }
904    }
905    else if (q->num_entries)
906    {
907        list[q->num_entries].term = entries[pos];
908        list[q->num_entries].occurrences = hits[pos];
909        q->num_entries++;
910    }
911    if (q->num_entries >= num_entries_req)
912        break;
913    }
914    if (feof(f))
915        q->status = BEND_SCAN_PARTIAL;
916    return 0;
917}
918
919
920
921void bend_close(void *handle)
922{
923  if (z3950_verbosity_>1) {
924    cerr << "Entering bend_close" << endl;
925  }
926  delete Server;
927  delete Cservers;
928  delete Protocol;
929  if (z3950_verbosity_>1) {
930    cerr << "heap cleaned up, exiting bend_close" << endl;
931  }
932  return;
933}
934
935int main (int argc, char *argv[])
936{
937 
938  const int statserv_var =  statserv_main(argc, argv, bend_init, bend_close);
939  cerr << "statserv_main returns: " << statserv_var << endl;
940  return statserv_var;
941 
942  return 0;
943}
944
945
Note: See TracBrowser for help on using the browser.