Index: /gsdl/trunk/src/colservr/Makefile.in
===================================================================
--- /gsdl/trunk/src/colservr/Makefile.in	(revision 15424)
+++ /gsdl/trunk/src/colservr/Makefile.in	(revision 15425)
@@ -96,5 +96,4 @@
 
 USE_CORBA = @USE_CORBA@
-USE_Z3950 = @USE_Z3950@
 
 RANLIB = @RANLIB@
@@ -140,14 +139,4 @@
 endif
 
-ifeq ($(USE_Z3950), 1)
-INCLUDES += -I../../packages/yaz/include -I../../packages/d2m
-Z3950HEADERS = 
-Z3950SOURCES = z3950parser.cpp z3950explain.cpp z3950_to_gsdl.cpp z3950server.cpp
-Z3950OBJECTS = z3950parser.o   z3950explain.o   z3950_to_gsdl.o   z3950server.o
-else
-Z3950HEADERS = 
-Z3950SOURCES = 
-Z3950OBJECTS = 
-endif
 
 # following objects need both mg and mgpp stuff - jrm21
@@ -173,5 +162,5 @@
 
 all : $(OBJECTS)
-	$(MAKE) USE_MGPP=1 $(MGPP_OBJECTS) $(Z3950OBJECTS)
+	$(MAKE) USE_MGPP=1 $(MGPP_OBJECTS)
 
 distclean:
Index: dl/trunk/src/colservr/z3950_to_gsdl.cpp
===================================================================
--- /gsdl/trunk/src/colservr/z3950_to_gsdl.cpp	(revision 15424)
+++ 	(revision )
@@ -1,345 +1,0 @@
-/**********************************************************************
- *
- * z3950_to_gsdl.cpp --
- * Copyright (C) 2000  The New Zealand Digital Library Project
- *
- * A component of the Greenstone digital library software
- * from the New Zealand Digital Library Project at the
- * University of Waikato, New Zealand.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *********************************************************************/
-
-#include "z3950parser.h"
-#include "z3950server.h"
-#include "z3950_to_gsdl.h"
-
-// converts a char* to uppercase, I wouldn't be
-// writing this if I could find an existing
-// function to do it
-void toUpperString(char *&text)
-{
-  for (int i = 0; text[i] != '\0'; i++) {
-    text[i] = toupper(text[i]);
-  }
-}
-
-
-text_t gsdlCollection::getName() 
-{
-  return name;
-}
-
-bool gsdlCollection::z3950Capeable() const
-{
-  return z3950ready;
-}
-
-
-bool gsdlCollection::bib1_to_dc_mapping(text_t& filename)
-{
-    ifstream inFile;
-    int input_Bib1;
-    text_t input_DCES;
-    text_t input_Short;
-
-    char* filename_cstr = filename.getcstr();
-    inFile.open(filename_cstr, ios::in);
-    delete [] filename_cstr;
-
-    if (!inFile) {
-      return false;
-    }
-
-    const int BUFFERSIZE = 1024;
-    char buffer[BUFFERSIZE];
-
-    // read in pairs of values (mappings from Bib-1 to DCES)
-    while (!inFile.eof()) {
-      char input_DCES_tmp[BUFFERSIZE];
-
-      inFile.getline(buffer, BUFFERSIZE, '\n');
-      if (buffer[0] == '#') {
-	// ignore comments (# ...)
-	continue;
-      }
-
-      sscanf(buffer,"%d %s",&input_Bib1, input_DCES_tmp);
-
-      input_DCES = input_DCES_tmp;
-
-      Bib1_to_DCES[input_Bib1] = input_DCES;
-
-      if (z3950_verbosity_>2) {
-	cerr << "(" << input_Bib1 << "/" << input_DCES << ") ";
-      }
-    }
-
-    if (z3950_verbosity_>2) {
-      cerr << endl;
-    }
-    inFile.close();
-
-    return true;
-}
-
-
-bool gsdlCollection::dc_to_short_mapping(text_t& filename, 
-					 text_t& collectionName) 
-{
-    ifstream inFileBuild;
-    text_t input_DCES;
-    text_t input_Short;
-  
-    char* filename_cstr = filename.getcstr();
-    inFileBuild.open(filename_cstr, ios::in);
-    delete [] filename_cstr;
-
-    if (!inFileBuild) {
-      if (z3950_verbosity_>2) {
-	cerr << "Warning: Unable to open: " << filename << endl;
-	cerr << "         Collection " << collectionName << " might not be built" << endl;
-      }
-      return false;
-    }
-
-    const int BUFFERSIZE = 1024;
-    char buffer[BUFFERSIZE];
-
-    // find the indexfieldmap line
-    do {
-      inFileBuild >> buffer;
-      if (inFileBuild.eof()) {
-	if (z3950_verbosity_>1) {
-	  cerr << "Warning: Did not find indexfieldmap in build.cfg for " 
-	       << collectionName << endl;
-	}
-	return false;
-      }
-    } while (strcmp(buffer, "indexfieldmap") != 0);
-
-    // at this stage, buffer contains "indexfieldmap",
-    // if the file didn't contain it, would have returned above
-    inFileBuild >> buffer;
-    while (strstr(buffer, "->") != NULL) {
-      // buffer contains a DCES->Short mapping
-      input_DCES.clear();
-      input_Short.clear();
-
-      // copy in DCES
-      int i;
-      for (i = 0; buffer[i] != '-'; i++) {
-	input_DCES.appendcarr(&(buffer[i]), 1);
-      }
-
-      // skip over "->"
-      i+=2;
-
-      // copy in Short
-      for (; isalpha(buffer[i]); i++) {
-	input_Short.appendcarr(&(buffer[i]), 1);
-      }
-
-      // add to map
-      DCES_to_Short[input_DCES] = input_Short;
-
-      if (z3950_verbosity_>1) {
-	cerr << "<" << input_DCES << "/" << input_Short << "> ";
-      }
-
-      inFileBuild >> buffer;
-    }
-
-    inFileBuild.close();
-
-    if (z3950_verbosity_>1) {
-      cerr << endl;
-    }
-
-    return true;
-}    
-
-
-
-
-  // converts a Bib1 field number to a short index name,
-  // returns true if a mapping existed, false otherwise
-bool gsdlCollection::getFieldArg(int Bib1, text_t &Short) 
-{
-    if (Bib1_to_DCES.count(Bib1) < 1) return false;
-    if (DCES_to_Short.count(Bib1_to_DCES[Bib1]) < 1) return false;
-    Short = DCES_to_Short[Bib1_to_DCES[Bib1]];
-    return true;
-}
-  
-gsdlCollection::~gsdlCollection(void) 
-{
-    //cerr << "gsdlCollection destructor called" << endl;
-}
-
-gsdlCollection::gsdlCollection(void) 
-{
-    //cerr << "gsdlCollection void constructor called" << endl;
-}
- 
-gsdlCollection::gsdlCollection(text_t collectionName, text_t gsdlhome) 
-{
-
-    //char *filename_cstr;
-    //ifstream inFile;
-    //int inFileSize = 0;
-    z3950ready = true;
-
-    // int input_Bib1;
-    //text_t input_DCES;
-    //text_t input_Short;
-
-    name = collectionName;
-
-    // read in the cfg file for Bib1_to_DCES
-    text_t col_filename = gsdlhome;
-    col_filename.appendcstr("/collect/");
-    col_filename.append(collectionName);
-    col_filename.appendcstr("/etc/bib1_to_dces.cfg");
-
-    if (!bib1_to_dc_mapping(col_filename)) {
-      text_t site_filename = gsdlhome;
-      site_filename.appendcstr("/etc/bib1_to_dces.cfg");
-
-      if (!bib1_to_dc_mapping(site_filename)) {
-	cerr << "Unable to find bib1->dublin core mapping for " 
-	     << collectionName << endl;
-	cerr << "Looked for:\n  " << col_filename << "\n  " 
-	     << site_filename << endl;
-	z3950ready = false;
-	return;
-      }
-    }
-
-    // read in the cfg file for mapping Dublin Core to Short (internal name)
-    text_t build_filename = gsdlhome;
-    build_filename.appendcstr("/collect/");
-    build_filename.append(collectionName);
-    build_filename.appendcstr("/index/build.cfg");
-
-    if (!dc_to_short_mapping(build_filename,collectionName)) {
-      // explicitly check for error (in case in future more work is done after
-      // this
-      z3950ready = false;
-      return;
-    }
-
-}
-
-
-void z3950Server::openLogfile(text_t extension, ofstream &out)
-{
-    char *cfilename;
-    text_t filename;
-
-    filename = filename_cat(gsdlhome, extension);
-    cfilename = filename.getcstr();
-
-    out.open(cfilename);
-    delete cfilename;
-}
-
-z3950Server::z3950Server(nullproto *protocol, text_t home)
-{ 
-
-    text_t dirname;
-    char * cdirname;
-    if (home.empty()) {
-      cerr  << "Z3950Server Error: gsdlhome not set. \nPlease make sure"
-	    << " you have a valid gsdlsite.cfg file in the directory \n"
-	    << "you are running z3950server\n";
-      cerr << "Exiting..."<<endl;
-      exit(1);
-    } 
-    cerr << "Z3950Server: gsdlhome = " << home << endl;
-
-    this->gsdlhome = home;
-    //cerr << gsdlhome.getcstr() << endl;
-    dirname = filename_cat(gsdlhome, "/collect");
-    cdirname = dirname.getcstr();
-    if (!read_dir (cdirname, collections)) { 
-      cerr << "Z3950Server Error: could not read directory "<<cdirname<<endl;
-      cerr << "Exiting..."<<endl;
-      exit (1);
-    }
-    delete cdirname;
-
-    cerr << "Constructing set list server" << endl;
-    this->protocol = protocol;
-
-    // initialise Yaz stuff for z39.50 server 
-}
-  
-bool z3950Server::initialise() 
-{
-      ofstream      logout;
-      int           reply;
-      comerror_t    error = noError;
-
-      this->openLogfile("/etc/z3950out.txt", logout);
-      reply = protocol->init(error, logout);
-      logout.close();
-      return (reply != 0 ? 1 : 0);
-}
-
-void z3950Server::configure(const text_t &key, const text_tarray &cfgline, 
-			    comerror_t &err)
-{
-      err = noError;
-
-      // ****
-      cerr << "Recieved " << key << " = ";
-      for (int unsigned i=0; i<cfgline.size(); i++)
-	{
-	  cout << cfgline[i] << " ";
-	}
-      cout << endl;
-
-      // DB // ****
-      if (key=="gsdlhome")
-	{  
-	  text_tarray cfgline;
-	  cfgline.push_back (gsdlhome);
-	  cerr << "Changing gsdlhome to " << gsdlhome << endl;
-	  protocol->configure(key, cfgline, err);
-	}
-      else if (key=="httpdomain")
-	{
-	  // Only let gsdlhome through !!!! // ****
-	  cerr << "Supressing httpdomain" << endl;
-	}
-      else if (key=="httpprefix")
-	{
-	  cerr << "Supressing httpprefix" << endl;
-	}
-      else
-	{ 
-	  protocol->configure(key, cfgline,err);
-	}
-}
-
-int z3950Server::run_z3950( int argc, char **argv ) 
-{
-
-    const int statserv_var =  statserv_main(argc, argv, bend_init, bend_close);
-    cerr << "statserv_main returns: " << statserv_var << endl;
-    return statserv_var;
-}
Index: dl/trunk/src/colservr/z3950_to_gsdl.h
===================================================================
--- /gsdl/trunk/src/colservr/z3950_to_gsdl.h	(revision 15424)
+++ 	(revision )
@@ -1,87 +1,0 @@
-/**********************************************************************
- *
- * z3950_to_gsdl.h --
- * Copyright (C) 2000  The New Zealand Digital Library Project
- *
- * A component of the Greenstone digital library software
- * from the New Zealand Digital Library Project at the
- * University of Waikato, New Zealand.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *********************************************************************/
-
-#ifndef Z3950_TO_GSDL_H
-#define Z3950_TO_GSDL_H
-
-
-void toUpperString(char *&text);
-
-class gsdlCollection
-{
- public:
-  gsdlCollection(); 
-  gsdlCollection(text_t collectionName, text_t gsdlhome);
-  ~gsdlCollection(void);
-
-  bool z3950Capeable() const;
-
-  // converts a Bib1 field number to a short index name,
-  // returns true if a mapping existed, false otherwise
-  bool getFieldArg(int Bib1, text_t &Short);
-
-  text_t getName(); // returns the name of the collection in short form
-  
- protected:
-
-
-  bool bib1_to_dc_mapping(text_t& filename);
-  bool dc_to_short_mapping(text_t& filename, text_t& collectionName);
-
- protected:
-  text_t name;
-  map<int, text_t>    Bib1_to_DCES;  // Bib-1 to DC metadata names
-  map<text_t, text_t> DCES_to_Short; // DC to short (2-3 letter) internal name
-
-  bool z3950ready; // is the collection Z39.50-ready ?
-                   // (i.e. does it have the cfg files for mappings)
-
-
-};
-
-class z3950Server 
-{
-protected:
-  text_tarray collections;
-  nullproto *protocol;
-  text_t      gsdlhome;
-
-  // save particular YAZ variables ...
-
-  void openLogfile(text_t extension, ofstream &out);
-
-
-public:
-  z3950Server(nullproto *protocol, text_t home);
-  
-  bool initialise();
-
-  void configure(const text_t &key, const text_tarray &cfgline, comerror_t &err);
-
-  int run_z3950( int argc, char **argv );
-
-};
-
-#endif
Index: dl/trunk/src/colservr/z3950explain.cpp
===================================================================
--- /gsdl/trunk/src/colservr/z3950explain.cpp	(revision 15424)
+++ 	(revision )
@@ -1,209 +1,0 @@
-/**********************************************************************
- *
- * z3950explain.cpp --
- * Copyright (C) 2000  The New Zealand Digital Library Project
- *
- * A component of the Greenstone digital library software
- * from the New Zealand Digital Library Project at the
- * University of Waikato, New Zealand.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *********************************************************************/
-
-#include "z3950explain.h"
-
-void getExplainInfo(bend_search_rr *rr, FilterResponse_t &response, comerror_t &err)
-{
-  text_t GSQuery = ZQueryToGSQuery(rr);
-  char *GSQuery_char = GSQuery.getcstr(); 
-
-  int i;
-  if (strstr(GSQuery_char, "TargetInfo") != NULL) {
-    // should be one only
-    // real-life example:
-    /*
-      62
-      explain-category targetInfo
-      date-of-info Sep 22, 1999
-      language eng
-    */
-    ResultDocInfo_t docinfo;
-    docinfo.metadata["explain-category"].values.push_back("TargetInfo");
-    docinfo.metadata["name"].values.push_back("Greenstone");
-    docinfo.metadata["namedResultSets"].values.push_back("false");
-    docinfo.metadata["multipleDBsearch"].values.push_back("true");
-    docinfo.metadata["language"].values.push_back("eng");
-    response.docInfo.push_back(docinfo);
-    response.numDocs++;
-  }
-  if (strstr(GSQuery_char, "DatabaseInfo") != NULL) {
-    // should be one per collection
-    // real-life example:
-    /*
-      3
-      dbnum 0
-      explain-category DatabaseInfo
-      database-name.1 0
-      title Z39.50 EXPLAIN DB
-      database-name.2 ir-explain-1
-      date-of-info Sep 22, 1999
-      language eng
-      dbpath /usr/wald/z39.50root/explain
-      dbname explain
-    */
-    ResultDocInfo_t docinfo;
-    docinfo.metadata["explain-category"].values.push_back("DatabaseInfo");
-    docinfo.metadata["database-name"].values.push_back("IR-Explain-1");
-    docinfo.metadata["title"].values.push_back("Z39.50 EXPLAIN DB");
-    docinfo.metadata["language"].values.push_back("eng");
-    docinfo.metadata["dbname"].values.push_back("explain");
-    response.docInfo.push_back(docinfo);
-    response.numDocs++;
-    // now get the info for each collection
-    text_tarray collectlist;
-    Protocol->get_collection_list(collectlist, err, cerr);
-    text_tarray::iterator COLHERE = collectlist.begin();
-    text_tarray::iterator COLEND = collectlist.end();
-    while (COLHERE != COLEND) {
-      // don't include information for non-active collections
-      bool collection_active;
-      Protocol->ping(*COLHERE, collection_active, err, cerr);
-      if (collection_active != true) {
-	COLHERE++;
-	continue;
-      }
-      ColInfoResponse_t collectinfo;
-      Protocol->get_collectinfo(*COLHERE, collectinfo, err, cerr);
-      docinfo.clear();
-      docinfo.metadata["name"].values.push_back(collectinfo.shortInfo.name);
-      docinfo.metadata["host"].values.push_back(collectinfo.shortInfo.host);
-      if (collectinfo.isPublic) {
-	docinfo.metadata["isPublic"].values.push_back("true");
-      } else {
-	docinfo.metadata["isPublic"].values.push_back("false");
-      }
-      if (collectinfo.isBeta) {
-	docinfo.metadata["isBeta"].values.push_back("true");
-      } else {
-	docinfo.metadata["isBeta"].values.push_back("false");
-      }
-      if (collectinfo.useBook == true) {
-	docinfo.metadata["useBook"].values.push_back("true");
-      } else {
-	docinfo.metadata["useBook"].values.push_back("false");
-      }
-      docinfo.metadata["buildDate"].values.push_back(collectinfo.buildDate);
-      text_tarray::iterator TEXTT_HERE = collectinfo.ccsCols.begin();
-      text_tarray::iterator TEXTT_END = collectinfo.ccsCols.end();
-      for (i = 1; TEXTT_HERE != TEXTT_END; i++, TEXTT_HERE++) {
-	text_t tmp = "ccsCols.";
-	tmp.appendint(i);
-	docinfo.metadata[tmp].values.push_back(*TEXTT_HERE);
-      }
-      TEXTT_HERE = collectinfo.languages.begin();
-      TEXTT_END = collectinfo.languages.end();
-      for (i = 1; TEXTT_HERE != TEXTT_END; i++, TEXTT_HERE++) {
-	text_t tmp = "languages.";
-	tmp.appendint(i);
-	docinfo.metadata[tmp].values.push_back(*TEXTT_HERE);
-      }
-      docinfo.metadata["numDocs"].values.push_back(collectinfo.numDocs);
-      docinfo.metadata["numSections"].values.push_back(collectinfo.numSections);
-      docinfo.metadata["numWords"].values.push_back(collectinfo.numWords);
-      docinfo.metadata["numBytes"].values.push_back(collectinfo.numBytes);
-
-      collectionmeta_map::iterator COLLMETA_MAP_HERE = collectinfo.collectionmeta.begin();
-      collectionmeta_map::iterator COLLMETA_MAP_END = collectinfo.collectionmeta.end();
-      for (i = 1; COLLMETA_MAP_HERE != COLLMETA_MAP_END; i++, COLLMETA_MAP_HERE++) {
-	text_t tmp = "collectionmeta.";
-	tmp.appendint(i);
-	text_t tmp2 = COLLMETA_MAP_HERE->first;
-	tmp2.appendcstr(" -> ");
-	tmp2.append(COLLMETA_MAP_HERE->second[g_EmptyText]);
-	docinfo.metadata[tmp].values.push_back(tmp2);
-      }
-      text_tmap::iterator TEXTT_MAP_HERE;
-      text_tmap::iterator TEXTT_MAP_END;
-      // uncomment if you want to include this in the explain record,
-      // it's a bit messy to include by default
-      /*
-      TEXTT_MAP_HERE = collectinfo.format.begin();
-      TEXTT_MAP_END = collectinfo.format.end();
-      for (i = 1; TEXTT_MAP_HERE != TEXTT_MAP_END; i++, TEXTT_MAP_HERE++) {
-	text_t tmp = "format.";
-	tmp.appendint(i);
-	text_t tmp2 = TEXTT_MAP_HERE->first;
-	tmp2.appendcstr(" -> ");
-	tmp2.append(TEXTT_MAP_HERE->second);
-	docinfo.metadata[tmp].values.push_back(tmp2);
-      }
-      */
-      TEXTT_MAP_HERE = collectinfo.building.begin();
-      TEXTT_MAP_END = collectinfo.building.end();
-      for (i = 1; TEXTT_MAP_HERE != TEXTT_MAP_END; i++, TEXTT_MAP_HERE++) {
-	text_t tmp = "building.";
-	tmp.appendint(i);
-	text_t tmp2 = TEXTT_MAP_HERE->first;
-	tmp2.appendcstr(" -> ");
-	tmp2.append(TEXTT_MAP_HERE->second);
-	docinfo.metadata[tmp].values.push_back(tmp2);
-      }
-      docinfo.metadata["receptionist"].values.push_back(collectinfo.receptionist);
-      docinfo.metadata["buildType"].values.push_back(collectinfo.buildType);
-      response.docInfo.push_back(docinfo);
-      response.numDocs++;
-      COLHERE++;
-    }
-  }
-  if (strstr(GSQuery_char, "SchemaInfo") != NULL) {
-    // should be one per collection
-    // real-life example:
-    /*
-      10
-      dbnum 1
-      explain-category schemaInfo
-      database-name.1 1
-      database-name.2 books
-      database-name.3 default
-      database-name.4 cat
-      date-of-info Sep 22, 1999
-      language eng
-      schema.1 1.2.840.10003.13.1000.3.1
-      dbpath /usr/wald/z39.50root/books
-      dbname books
-     */
-  }
-  if (strstr(GSQuery_char, "AttributeSetInfo") != NULL) {
-    // should be one per collection
-    // real-life example:
-    /*
-      9
-      dbnum 1
-      explain-category AttributeSetInfo
-      database-name.1 1
-      database-name.2 books
-      database-name.3 default
-      database-name.4 cat
-      date-of-info Sep 22, 1999
-      language eng
-      attribute-set.1 1.2.840.10003.13.1000.3.1
-      dbpath /usr/wald/z39.50root/books
-      dbname books
-    */
-  }
-}
-
-
Index: dl/trunk/src/colservr/z3950explain.h
===================================================================
--- /gsdl/trunk/src/colservr/z3950explain.h	(revision 15424)
+++ 	(revision )
@@ -1,35 +1,0 @@
-/**********************************************************************
- *
- * z3950proto.h --
- * Copyright (C) 2000  The New Zealand Digital Library Project
- *
- * A component of the Greenstone digital library software
- * from the New Zealand Digital Library Project at the
- * University of Waikato, New Zealand.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *********************************************************************/
-
-#ifndef Z3950EXPLAIN_H
-#define Z3950EXPLAIN_H
-
-
-#include "z3950parser.h"
-
-void getExplainInfo(bend_search_rr *rr, FilterResponse_t &response, comerror_t &err);
-
-
-#endif
Index: dl/trunk/src/colservr/z3950parser.cpp
===================================================================
--- /gsdl/trunk/src/colservr/z3950parser.cpp	(revision 15424)
+++ 	(revision )
@@ -1,373 +1,0 @@
-
-#include "z3950parser.h"
-
-void Z_AttributeList_parse(bend_search_rr *rr, Z_AttributeList *Z, text_t &GSQuery)
-{
-  /*
-    struct Z_AttributeList {
-    int num_attributes;
-    Z_AttributeElement **attributes;
-    };
-  */
-
-  /*
-    struct Z_AttributeElement {
-    Z_AttributeSetId *attributeSet; // OPT
-    int *attributeType;
-    int which;
-    union {
-    int *numeric;
-    Z_ComplexAttribute *complex;
-    #define Z_AttributeValue_numeric 1
-    #define Z_AttributeValue_complex 2
-    } value;
-    };
-  */
-
-  
-
-}
-
-void Z_Term_parse(bend_search_rr *rr, Z_Term *Z, text_t &GSQuery)
-{
-  /*
-    struct Z_Term {
-    int which;
-    union {
-    Odr_oct *general;
-    int *numeric;
-    Z_InternationalString *characterString;
-    Odr_oid *oid;
-    char *dateTime;
-    Z_External *external;
-    Z_IntUnit *integerAndUnit;
-    Odr_null *null;
-    #define Z_Term_general 1
-    #define Z_Term_numeric 2
-    #define Z_Term_characterString 3
-    #define Z_Term_oid 4
-    #define Z_Term_dateTime 5
-    #define Z_Term_external 6
-    #define Z_Term_integerAndUnit 7
-    #define Z_Term_null 8
-    } u;
-    };
-  */
-
-  char *term;
-
-  switch(Z->which){
-  case Z_Term_general: {
-    // must copy no more than len bytes from buf, or else previous query terms may be included
-    int buflen = Z->u.general->len;
-    term = new char[buflen+1];
-    memset(term, '\0', buflen+1);
-    strncpy(term, (const char*)(Z->u.general->buf), buflen);
-    GSQuery += term;
-    break; }
-  case Z_Term_numeric:
-    GSQuery += *(Z->u.numeric); // int*
-    break;
-  case Z_Term_characterString:
-    GSQuery += Z->u.characterString; // what is this type?
-    break;
-  case Z_Term_oid:
-    GSQuery += *(Z->u.oid); // int*
-    break;
-  case Z_Term_dateTime:
-    GSQuery += Z->u.dateTime; // char*
-    break;
-  case Z_Term_external:
-    GSQuery += " "; // ignore this for now
-    break;
-  case Z_Term_integerAndUnit:
-    GSQuery += " "; // ignore this for now
-    break;
-  case Z_Term_null:
-    GSQuery += " "; // void
-    break;
-  default:
-    cerr << "Error in Z_Term_parse" << endl;
-    exit(1);
-  }
-}
-
-void Z_ProximityOperator_parse(bend_search_rr *rr, Z_ProximityOperator *Z, text_t &GSQuery)
-{
-  /*
-    struct Z_ProximityOperator {
-    bool_t *exclusion; // OPT
-    int *distance;
-    bool_t *ordered;
-    #define Z_ProximityOperator_Prox_lessThan 1
-    #define Z_ProximityOperator_Prox_lessThanOrEqual 2
-    #define Z_ProximityOperator_Prox_equal 3
-    #define Z_ProximityOperator_Prox_greaterThanOrEqual 4
-    #define Z_ProximityOperator_Prox_greaterThan 5
-    #define Z_ProximityOperator_Prox_notEqual 6
-    int *relationType;
-    int which;
-    union {
-    Z_ProxUnit *known;
-    int *zprivate;
-    #define Z_ProximityOperator_known 1
-    #define Z_ProximityOperator_private 2
-    } u;
-    };
-    
-    #define Z_ProxUnit_character 1
-    #define Z_ProxUnit_word 2
-    #define Z_ProxUnit_sentence 3
-    #define Z_ProxUnit_paragraph 4
-    #define Z_ProxUnit_section 5
-    #define Z_ProxUnit_chapter 6
-    #define Z_ProxUnit_document 7
-    #define Z_ProxUnit_element 8
-    #define Z_ProxUnit_subelement 9
-    #define Z_ProxUnit_elementType 10
-    #define Z_ProxUnit_byte 11
-  */
-
-  // Greenstone (actually mgpp) supports proximity, but only 
-  // to n words either side.
-  // A more complete implementation of proximity can be added
-  // by parsing the other fields in Z_ProximityOperator.
-  // Note: this only works properly with MGPP collections
-  
-  GSQuery += " NEAR"; 
-  GSQuery += *(Z->distance);
-  GSQuery += " ";
-}
-
-void Z_Operator_parse(bend_search_rr *rr, Z_Operator *Z, text_t &GSQuery)
-{
-  /*
-    struct Z_Operator {
-    int which;
-    union {
-    Odr_null *and;
-    Odr_null *or;
-    Odr_null *and_not;
-    Z_ProximityOperator *prox;
-    #define Z_Operator_and 1
-    #define Z_Operator_or 2
-    #define Z_Operator_and_not 3
-    #define Z_Operator_prox 4
-    } u;
-    };
-  */
-  
-  switch(Z->which){
-  case Z_Operator_and:
-    GSQuery += " & ";
-    break;
-  case Z_Operator_or:
-    GSQuery += " | ";
-    break;
-  case Z_Operator_and_not:
-    GSQuery += " ! ";
-    break;
-  case Z_Operator_prox:
-    Z_ProximityOperator_parse(rr, Z->u.prox, GSQuery);
-    break;
-  default:
-    cerr << "Error in Z_Operator_parse" << endl;
-    exit(1);
-  }
-}
-
-void Z_Operand_parse(bend_search_rr *rr, Z_Operand *Z, text_t &GSQuery)
-{
-    /*
-      struct Z_Operand {
-      int which;
-      union {
-      Z_AttributesPlusTerm *attributesPlusTerm;
-      Z_ResultSetId *resultSetId;
-      Z_ResultSetPlusAttributes *resultAttr;
-      #define Z_Operand_APT 1
-      #define Z_Operand_resultSetId 2
-      #define Z_Operand_resultAttr 3
-      } u;
-      };
-    */
-  
-  switch(Z->which) {
-  case Z_Operand_APT: {
-    /*
-      struct Z_AttributesPlusTerm {
-      Z_AttributeList *attributes;
-      Z_Term *term;
-      };
-    */
-    
-    /*
-      struct Z_AttributeList {
-      int num_attributes;
-      Z_AttributeElement **attributes;
-      };
-    */
-    
-    /*
-      struct Z_AttributeElement {
-      Z_AttributeSetId *attributeSet; // OPT
-      int *attributeType;
-      int which;
-      union {
-      int *numeric;
-      Z_ComplexAttribute *complex;
-      #define Z_AttributeValue_numeric 1
-      #define Z_AttributeValue_complex 2
-      } value;
-      };
-    */
-    
-    char *term;
-    
-    if (Z->u.attributesPlusTerm->attributes->num_attributes > 0) {
-      int Bib1_relation = *(Z->u.attributesPlusTerm->attributes->attributes[0]->attributeType);
-      int Bib1_use = *(Z->u.attributesPlusTerm->attributes->attributes[0]->value.numeric);
-
-      // if use value is 1010 ("Body of text"), is not a fielded search
-      if (Bib1_use == 1010) {
-	// if relation value is 6 ("not"), add a "not" to GSQuery
-	if (Bib1_relation == 6) {
-	  GSQuery += "! ";
-	}
-	Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
-      }
-      // for other use values, is a fielded search
-      else {
-	text_t Short;
-	// only add [ ]: if the index exists in the collection,
-	// note: only the index names in the first collection of a
-	// multi-collection search are used at the moment
-	if ((Collection_map[rr->basenames[0]]).getFieldArg(Bib1_use, Short)) {
-	  GSQuery += "[";
-	  cerr << "Supressing square brackets for the moment!\n";
-
-	  Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
-	  GSQuery += "]";
-	  GSQuery += ":";
-	  GSQuery += Short;
-	}
-	// if it doesn't, add it as an unfielded search term
-	else {
-	  cerr << "[" << rr->basenames[0] << "]: failed to find index" << endl;
-	  Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
-	}
-      }
-    }
-    else {
-      Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
-    }
-    break;
-  }
-  case Z_Operand_resultSetId: {
-    GSQuery += "(";
-    GSQuery += Resultsets[Z->u.resultSetId];
-    GSQuery += ")";
-    break; 
-  }
-  case Z_Operand_resultAttr:
-    GSQuery += " "; // ignore this for now
-    break;
-  default:
-    cerr << "Error in Z_Operand_parse" << endl;
-    exit(1);
-  } 
-}
-
-void Z_RPNStructure_parse(bend_search_rr *rr, Z_RPNStructure *Z, text_t &GSQuery)
-{
-  /*
-    struct Z_RPNStructure {
-    int which;
-    union {
-    Z_Operand *simple;
-    Z_Complex *complex;
-    #define Z_RPNStructure_simple 1
-    #define Z_RPNStructure_complex 2
-    } u;
-    };
-  */
-
-  switch(Z->which){
-  case Z_RPNStructure_simple:
-    Z_Operand_parse(rr, Z->u.simple, GSQuery);
-    break;
-  case Z_RPNStructure_complex:
-    GSQuery += "(";
-    Z_RPNStructure_parse(rr, Z->u.complex->s1, GSQuery);
-    Z_Operator_parse(rr, Z->u.complex->roperator, GSQuery);
-    Z_RPNStructure_parse(rr, Z->u.complex->s2, GSQuery);
-    GSQuery += ")";
-    break;
-  default:
-    cerr << "Error in Z_RPNStructure_parse" << endl;
-    exit(1);
-  }
-}
-
-text_t ZQueryToGSQuery(bend_search_rr *rr)
-{
-  text_t GSQuery;
-
-  switch(rr->query->which){
-  case Z_Query_type_0:
-    cerr << "querytype = 0" << endl;
-    // this is a void*, pretend it's a Greenstone-type query
-    GSQuery += (char*)(rr->query->u.type_0);
-    break;
-  case Z_Query_type_1: {
-    cerr << "querytype = 1" << endl;
-    /*
-      struct Z_RPNQuery {
-      Z_AttributeSetId *attributeSetId;
-      Z_RPNStructure *RPNStructure;
-      };
-    */
-    // parse attributeSetId
-    cerr << "attributeSetId = ";
-    int c, d = 0;
-    do {
-      c = rr->query->u.type_1->attributeSetId[d];
-      cerr << c;
-      d++;
-    } while (c >= 0);
-    cerr << endl;
-
-    Z_RPNStructure_parse(rr, rr->query->u.type_1->RPNStructure, GSQuery);
-    break; }
-  case Z_Query_type_2: {
-    cerr << "querytype = 2" << endl;
-    // this is just a buf (unsigned char*), pretend it's a Greenstone-type query
-    GSQuery += (char*)(rr->query->u.type_2->buf);
-    break; }
-  case Z_Query_type_100: {
-    cerr << "querytype = 100" << endl;
-     // this is just a buf (unsigned char*), pretend it's a Greenstone-type query
-    GSQuery += (char*)(rr->query->u.type_100->buf);
-    break; }
-  case Z_Query_type_101: {
-    cerr << "querytype = 101" << endl;
-    // check: is this really the same as a type 1 query?
-    Z_RPNStructure_parse(rr, rr->query->u.type_101->RPNStructure, GSQuery);
-    break; }
-  case Z_Query_type_102: {
-    cerr << "querytype = 102" << endl;
-     // this is just a buf (unsigned char*), pretend it's a Greenstone-type query
-    GSQuery += (char*)(rr->query->u.type_102->buf);
-    break; }
-  default: {
-    cerr << "Error in ZQueryToGSQuery" << endl;
-    exit(1); }
-  }
-
-  // override GSQuery (test code)
-  //GSQuery = "[the]:TX";
-
-  cerr << "GSQuery = `" << GSQuery << "'" << endl;
-  return GSQuery;
-}
-
Index: dl/trunk/src/colservr/z3950parser.h
===================================================================
--- /gsdl/trunk/src/colservr/z3950parser.h	(revision 15424)
+++ 	(revision )
@@ -1,77 +1,0 @@
-/**********************************************************************
- *
- * z3950parser.h -- convert Z39.50's RPN query syntax into Greenstone
- * Copyright (C) 2000  The New Zealand Digital Library Project
- *
- * A component of the Greenstone digital library software
- * from the New Zealand Digital Library Project at the
- * University of Waikato, New Zealand.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *********************************************************************/
-
-#ifndef Z3950PARSER_H
-#define Z3950PARSER_H
-
-
-#include <string>
-#include <list>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <time.h>
-
-// Greenstone headers
-#include "fileutil.h"
-#include "comtypes.h"
-#include "nullproto.h"
-#include "z3950_to_gsdl.h"
-
-// YAZ headers
-extern "C" {
-#include <yaz/backend.h>
-#include <yaz/log.h>
-#ifdef ASN_COMPILED
-#include <yaz/ill.h>
-#endif
-}
-
-extern text_t gsdlhome;
-extern list<FilterResponse_t> Response_tlist;
-extern list<text_t> Response_tlist_colnames;
-extern list<int> Response_tlist_sizes;
-extern z3950Server *Server;
-extern collectset *Cservers;
-extern nullproto *Protocol;
-extern map<text_t, gsdlCollection> Collection_map;
-extern map<text_t, text_t> Resultsets;
-
-void Z_AttributeList_parse(bend_search_rr *rr, Z_AttributeList *Z, text_t &GSQuery);
-
-void Z_Term_parse(bend_search_rr *rr, Z_Term *Z, text_t &GSQuery);
-
-void Z_ProximityOperator_parse(bend_search_rr *rr, Z_ProximityOperator *Z, text_t &GSQuery);
-
-void Z_Operator_parse(bend_search_rr *rr, Z_Operator *Z, text_t &GSQuery);
-
-void Z_Operand_parse(bend_search_rr *rr, Z_Operand *Z, text_t &GSQuery);
-
-void Z_RPNStructure_parse(bend_search_rr *rr, Z_RPNStructure *Z, text_t &GSQuery);
-
-text_t ZQueryToGSQuery(bend_search_rr *rr);
-
-#endif
Index: dl/trunk/src/colservr/z3950server.cpp
===================================================================
--- /gsdl/trunk/src/colservr/z3950server.cpp	(revision 15424)
+++ 	(revision )
@@ -1,927 +1,0 @@
-
-
-// Standard headers
-
-#if defined(GSDL_USE_OBJECTSPACE)
-#  include <ospace\std\iostream>
-#  include <ospace\std\fstream>
-#  include <ospace\std\sstream>
-#elif defined(GSDL_USE_IOS_H)
-#  include <iostream.h>
-#  include <fstream.h>
-#  include <strstream.h>
-#else
-#  include <iostream>
-#  include <fstream>
-#  include <sstream>
-#endif
-
-#include <string>
-#include <list>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <time.h>
-
-// Greenstone headers
-#include "fileutil.h"
-#include "comtypes.h"
-#include "nullproto.h"
-
-// Z39.50 server headers
-#include "z3950parser.h"
-#include "z3950explain.h"
-
-#include "z3950server.h"
-
-// Dublin Core -> MARC (d2m) headers and source files
-#include "d2m4gs.h"
-
-// these globals are local to each thread,
-// one Z39.50 connection = one thread.
-text_t gsdlhome; // this is specified externally when Greenstone is installed
-list<FilterResponse_t> Response_tlist; // list of response sets
-list<text_t> Response_tlist_colnames;  // collection names for the above
-list<int> Response_tlist_sizes;        // sizes (number of records) for the above
-z3950Server *Server   = NULL;
-collectset  *Cservers = NULL;
-nullproto   *Protocol = NULL;
-
-map<text_t, gsdlCollection> Collection_map; // info and tools for collections
-map<text_t, text_t> Resultsets;             // mapping from ResultSetId to GSQuery 
-
-int z3950_verbosity_ = 3;
-
-// *** initialize things here ***
-bend_initresult *bend_init(bend_initrequest *q)
-{
-  // *** called when client connects to the server ***
-  if (z3950_verbosity_ > 1) {
-    cerr << "Entering bend_init" << endl;
-  }
-
-  Protocol = new nullproto();  
-  Cservers = new collectset(gsdlhome);
-  Protocol->set_collectset(Cservers);
-  
-  cerr << "Starting Z39.50 Server ..." << endl;
-  
-  Server = new z3950Server(Protocol, gsdlhome);
-  cerr << "Server constructed" << endl;
-  
-  const bool status = Server->initialise();
-  cerr << "Initialised server: return status = " << status << endl;
-  
-  text_tarray collist;
-  comerror_t err;
-  Protocol->get_collection_list( collist, err, cout );
-
-  // display the list of available Greenstone collections
-  text_tarray::iterator cols_here=collist.begin();
-  text_tarray::iterator cols_end=collist.end();
-  while (cols_here != cols_end) {
-    gsdlCollection tmpcol(*cols_here, gsdlhome);
-    
-    Collection_map[*cols_here] = tmpcol;
-    
-    if (tmpcol.z3950Capeable()) {
-      cerr << "  " << tmpcol.getName() << "\tis Z39.50 capable" << endl;
-    }
-    cols_here++;
-  }
-
-    
-  bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
-  //static char *dummy = "Hej fister"; // what's this for?
-  
-  r->errcode = 0;
-  r->errstring = 0;
-  r->handle = Protocol;
-  q->bend_sort = ztest_sort;       /* register sort handler */
-  q->bend_search = ztest_search;   /* register search handler */
-  q->bend_present = ztest_present; /* register present handle */
-  q->bend_esrequest = ztest_esrequest;
-  q->bend_delete = ztest_delete;
-  q->bend_fetch = ztest_fetch;
-  q->bend_scan = ztest_scan;
-
-  return r;
-}
-
-// *** perform query, get number of hits ***
-int ztest_search (void *handle, bend_search_rr *rr)
-{
-  // *** called when client issues a "find" command
-  if (z3950_verbosity_>1) {
-    cerr << "Entering ztest_search" << endl;
-  }
-
-  Response_tlist.clear();
-  Response_tlist_colnames.clear();
-  Response_tlist_sizes.clear();
- 
-  comerror_t err;
-  FilterRequest_t request;
-
-  request.filterName = "QueryFilter";
-  request.filterResultOptions = FROID | FRtermFreq | FRmetadata;  
-
-  OptionValue_t option;
-
-  // how many results to get. grouping all results together into
-  // one set instead of breaking up into "pages". 
-  // note: see if Z39.50 has a concept of pages.
-  option.name = "StartResults";
-  option.value = "1";
-  request.filterOptions.push_back (option);
-  option.name = "EndResults";
-  option.value = MAXHITS;
-  request.filterOptions.push_back (option);
-  option.name = "Maxdocs";
-  option.value = MAXHITS;
-  request.filterOptions.push_back (option);
-
-  text_t GSQuery = ZQueryToGSQuery(rr);
-  option.name = "Term";
-  option.value = GSQuery;
-  request.filterOptions.push_back (option);
-  Resultsets[Resultsets.size()+1] = GSQuery;
-
-  option.name = "QueryType";
-  option.value = "boolean";
-  request.filterOptions.push_back (option);
-
-  option.name = "MatchMode";
-  option.value = "all";
-  request.filterOptions.push_back (option);
-
-  option.name = "Casefold";
-  option.value = "true";
-  request.filterOptions.push_back (option);
-
-  option.name = "Stem";
-  option.value = "false";
-  request.filterOptions.push_back (option);
-
-  option.name = "AccentFold";
-  option.value = "false";
-  request.filterOptions.push_back (option);
-  
-  // MG queries don't need this, MGPP queries do.
-  // doesn't do any harm to include it anyway.
-  // note: not all collections have document-level granularity...
-  option.name = "Level";
-  option.value = "Doc";
-  request.filterOptions.push_back (option);
-
-  // Z39.50 supports the searching of multiple databases
-  rr->hits = 0;
-  for (int i = 0; i < rr->num_bases; i++) {
-    FilterResponse_t response;
-    cerr << "Searching basename = " << rr->basenames[i] << endl;
-    // intercept Explain requests
-    if (strcmp(rr->basenames[i], "IR-Explain-1")==0) {
-      //ColInfoResponse_t collectinfo;
-      //Protocol->get_collectinfo("csbib", collectinfo, err, cerr);
-      //response.numDocs = 1;
-      //ResultDocInfo_t docinfo;
-      //docinfo.metadata["foo"].values.push_back("bar");
-      getExplainInfo(rr, response, err);
-      //response.docInfo.push_back(docinfo);
-    } else {
-      cerr << "calling filter..." << endl;
-      Protocol->filter(rr->basenames[i], request, response, err, cerr);
-      cerr << "returned from filter." << endl;
-      if (response.numDocs > MAXHITS) {
-	response.numDocs = MAXHITS;
-      }
-    }
-    rr->hits += response.numDocs;
-    Response_tlist.push_back(response);
-    text_t basename = rr->basenames[i];
-    Response_tlist_colnames.push_back(basename);
-    Response_tlist_sizes.push_back(response.numDocs);
-    cerr << "search complete." << endl;
-  }    
-
-  if (rr->hits > MAXHITS) rr->hits = MAXHITS;
-  return 0;
-}
-
-// *** extra code for showing results, not needed ***
-int ztest_present (void *handle, bend_present_rr *rr)
-{
-  // *** called when client issues a "show" command, 1st of 5
-  if (z3950_verbosity_>1) {
-    cerr << "entering ztest_present" << endl;
-  }
-  return 0;
-}
-
-int ztest_esrequest (void *handle, bend_esrequest_rr *rr)
-{
-
-    if (z3950_verbosity_>1) {
-      cerr << "Entering ztest_esrequest" << endl;
-    }
-    yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
-    if (rr->esr->packageName)
-    	yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
-    yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
-
-    if (!rr->esr->taskSpecificParameters)
-    {
-        yaz_log (LOG_WARN, "No task specific parameters");
-    }
-    else if (rr->esr->taskSpecificParameters->which == Z_External_itemOrder)
-    {
-    	Z_ItemOrder *it = rr->esr->taskSpecificParameters->u.itemOrder;
-	yaz_log (LOG_LOG, "Received ItemOrder");
-	switch (it->which)
-	{
-#ifdef ASN_COMPILED
-	case Z_IOItemOrder_esRequest:
-#else
-	case Z_ItemOrder_esRequest:
-#endif
-	{
-	    Z_IORequest *ir = it->u.esRequest;
-	    Z_IOOriginPartToKeep *k = ir->toKeep;
-	    Z_IOOriginPartNotToKeep *n = ir->notToKeep;
-	    
-	    if (k && k->contact)
-	    {
-	        if (k->contact->name)
-		    yaz_log(LOG_LOG, "contact name %s", k->contact->name);
-		if (k->contact->phone)
-		    yaz_log(LOG_LOG, "contact phone %s", k->contact->phone);
-		if (k->contact->email)
-		    yaz_log(LOG_LOG, "contact email %s", k->contact->email);
-	    }
-	    if (k->addlBilling)
-	    {
-	        yaz_log(LOG_LOG, "Billing info (not shown)");
-	    }
-	    
-	    if (n->resultSetItem)
-	    {
-	        yaz_log(LOG_LOG, "resultsetItem");
-		yaz_log(LOG_LOG, "setId: %s", n->resultSetItem->resultSetId);
-		yaz_log(LOG_LOG, "item: %d", *n->resultSetItem->item);
-	    }
-#ifdef ASN_COMPILED
-	    if (n->itemRequest)
-	    {
-		Z_External *r = (Z_External*) n->itemRequest;
-		ILL_ItemRequest *item_req = 0;
-		ILL_Request *ill_req = 0;
-		if (r->direct_reference)
-		{
-		    oident *ent = oid_getentbyoid(r->direct_reference);
-		    if (ent)
-			yaz_log(LOG_LOG, "OID %s", ent->desc);
-		    if (ent && ent->value == VAL_ISO_ILL_1)
-		    {
-			yaz_log (LOG_LOG, "ItemRequest");
-			if (r->which == ODR_EXTERNAL_single)
-			{
-			    odr_setbuf(rr->decode,
-				       (char*)(r->u.single_ASN1_type->buf),
-				       r->u.single_ASN1_type->len, 0);
-			    
-			    if (!ill_ItemRequest (rr->decode, &item_req, 0, 0))
-			    {
-				yaz_log (LOG_LOG,
-                                    "Couldn't decode ItemRequest %s near %d",
-                                       odr_errmsg(odr_geterror(rr->decode)),
-                                       odr_offset(rr->decode));
-                                yaz_log(LOG_LOG, "PDU dump:");
-                                odr_dumpBER(yaz_log_file(),
-                                     (const char*)(r->u.single_ASN1_type->buf),
-                                     r->u.single_ASN1_type->len);
-                            }
-			    if (rr->print)
-			    {
-				ill_ItemRequest (rr->print, &item_req, 0,
-                                    "ItemRequest");
-				odr_reset (rr->print);
- 			    }
-			}
-			if (!item_req && r->which == ODR_EXTERNAL_single)
-			{
-			    yaz_log (LOG_LOG, "ILLRequest");
-			    odr_setbuf(rr->decode,
-				       (char*)(r->u.single_ASN1_type->buf),
-				       r->u.single_ASN1_type->len, 0);
-			    
-			    if (!ill_Request (rr->decode, &ill_req, 0, 0))
-			    {
-				yaz_log (LOG_LOG,
-                                    "Couldn't decode ILLRequest %s near %d",
-                                       odr_errmsg(odr_geterror(rr->decode)),
-                                       odr_offset(rr->decode));
-                                yaz_log(LOG_LOG, "PDU dump:");
-                                odr_dumpBER(yaz_log_file(),
-                                     (const char*)(r->u.single_ASN1_type->buf),
-                                     r->u.single_ASN1_type->len);
-                            }
-			    if (rr->print)
-                            {
-				ill_Request (rr->print, &ill_req, 0,
-                                    "ILLRequest");
-				odr_reset (rr->print);
-			    }
-			}
-		    }
-		}
-		if (item_req)
-		{
-		    yaz_log (LOG_LOG, "ILL protocol version = %d",
-			     *item_req->protocol_version_num);
-		}
-	    }
-#endif
-	}
-	break;
-	}
-    }
-    else if (rr->esr->taskSpecificParameters->which == Z_External_update)
-    {
-    	Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
-	yaz_log (LOG_LOG, "Received DB Update");
-	if (up->which == Z_IUUpdate_esRequest)
-	{
-	    Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
-	    Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
-	    Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
-	    
-	    yaz_log (LOG_LOG, "action");
-	    if (toKeep->action)
-	    {
-		switch (*toKeep->action)
-		{
-		case Z_IUOriginPartToKeep_recordInsert:
-		    yaz_log (LOG_LOG, " recordInsert");
-		    break;
-		case Z_IUOriginPartToKeep_recordReplace:
-		    yaz_log (LOG_LOG, " recordUpdate");
-		    break;
-		case Z_IUOriginPartToKeep_recordDelete:
-		    yaz_log (LOG_LOG, " recordDelete");
-		    break;
-		case Z_IUOriginPartToKeep_elementUpdate:
-		    yaz_log (LOG_LOG, " elementUpdate");
-		    break;
-		case Z_IUOriginPartToKeep_specialUpdate:
-		    yaz_log (LOG_LOG, " specialUpdate");
-		    break;
-		default:
-		    yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
-		}
-	    }
-	    if (toKeep->databaseName)
-	    {
-		yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
-		if (!strcmp(toKeep->databaseName, "fault"))
-		{
-		    rr->errcode = 109;
-		    rr->errstring = toKeep->databaseName;
-		}
-		if (!strcmp(toKeep->databaseName, "accept"))
-		    rr->errcode = -1;
-	    }
-	    if (notToKeep)
-	    {
-		int i;
-		for (i = 0; i < notToKeep->num; i++)
-		{
-		    Z_External *rec = notToKeep->elements[i]->record;
-
-		    if (rec->direct_reference)
-		    {
-			struct oident *oident;
-			oident = oid_getentbyoid(rec->direct_reference);
-			if (oident)
-			    yaz_log (LOG_LOG, "record %d type %s", i,
-				     oident->desc);
-		    }
-		    switch (rec->which)
-		    {
-		    case Z_External_sutrs:
-			if (rec->u.octet_aligned->len > 170)
-			    yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
-				     rec->u.sutrs->len,
-				     rec->u.sutrs->buf);
-			else
-			    yaz_log (LOG_LOG, "%d bytes:\n%s",
-				     rec->u.sutrs->len,
-				     rec->u.sutrs->buf);
-                        break;
-		    case Z_External_octet        :
-			if (rec->u.octet_aligned->len > 170)
-			    yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
-				     rec->u.octet_aligned->len,
-				     rec->u.octet_aligned->buf);
-			else
-			    yaz_log (LOG_LOG, "%d bytes\n%s",
-				     rec->u.octet_aligned->len,
-				     rec->u.octet_aligned->buf);
-		    }
-		}
-	    }
-	}
-    }
-    else
-    {
-        yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
-		 rr->esr->taskSpecificParameters->which);
-	
-    }
-    return 0;
-}
-
-int ztest_delete (void *handle, bend_delete_rr *rr)
-{
-  // *** called when client issues a "delete" command
-  if (z3950_verbosity_>1) {
-    cerr << "Entering ztest_delete" << endl;
-  }
-  if (rr->num_setnames == 1 && !strcmp (rr->setnames[0], "1"))
-    rr->delete_status = Z_DeleteStatus_success;
-  else
-    rr->delete_status = Z_DeleteStatus_resultSetDidNotExist;
-  return 0;
-}
-
-// *** do we want to sort the results? ***
-/* Our sort handler really doesn't sort... */
-int ztest_sort (void *handle, bend_sort_rr *rr)
-{
-  if (z3950_verbosity_>1) {
-    cerr << "entering ztest_sort" << endl;
-  }
-  rr->errcode = 0;
-  rr->sort_status = Z_SortStatus_success;
-  return 0;
-}
-
-static int atoin (const char *buf, int n)
-{
-  // *** called when client issues a "show" command, 5th of 5
-  // *** NOT called if the "show" command has an invalid argument
-    if (z3950_verbosity_>1) {
-      cerr << "Entering atoin" << endl;
-    }
-    int val = 0;
-    while (--n >= 0)
-    {
-        if (isdigit(*buf))
-            val = val*10 + (*buf - '0');
-        buf++;
-    }
-    return val;
-}
-
-
-bool get_sutrs_record (int recnum, text_t &MetadataResult, text_t &CollectionName)
-{
-  if (z3950_verbosity_>1) {
-    cerr << "Entering get_sutrs_record" << endl;
-  }
-  int total_records = 0;
-
-  list<FilterResponse_t>::iterator RESPONSE_here = Response_tlist.begin();
-  list<FilterResponse_t>::iterator RESPONSE_end = Response_tlist.end();
-  list<text_t>::iterator RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
-  list<text_t>::iterator RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
-  list<int>::iterator RESPONSE_SIZES_here = Response_tlist_sizes.begin();
-  list<int>::iterator RESPONSE_SIZES_end = Response_tlist_sizes.end();
-
-  RESPONSE_here = Response_tlist.begin();
-  RESPONSE_end = Response_tlist.end();
-  while (RESPONSE_here != RESPONSE_end) {
-    total_records += (*RESPONSE_here).numDocs;
-    RESPONSE_here++;
-  }
-
-  // check that the index is within bounds
-  if (recnum < 1 || recnum > total_records) {
-    cerr << "get_sutrs_record failed" << endl;
-    return false; // failed
-  } else {
-    FilterResponse_t response;
-    // iterate through Response_tlist to find the right response
-    RESPONSE_here = Response_tlist.begin();
-    RESPONSE_end = Response_tlist.end();
-    RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
-    RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
-    RESPONSE_SIZES_here = Response_tlist_sizes.begin();
-    RESPONSE_SIZES_end = Response_tlist_sizes.end();
-    int n = 0;
-
-    while (RESPONSE_here != RESPONSE_end) {
-      n += *RESPONSE_SIZES_here;
-      if (n >= recnum) {
-	response = *RESPONSE_here;
-	CollectionName = *RESPONSE_COLNAMES_here;
-	recnum = *RESPONSE_SIZES_here - (n - recnum);
-	break;
-      }
-      // these should all have the same number of elements,
-      // so only need to check that one is within bounds.
-      // may want to combine these into a larger data structure later.
-      RESPONSE_here++;
-      RESPONSE_COLNAMES_here++;
-      RESPONSE_SIZES_here++;
-    }
-
-    // locate the desired record in the response 
-   
-    MetadataInfo_tmap::iterator METAFIELD_here = response.docInfo[recnum-1].metadata.begin();
-    MetadataInfo_tmap::iterator METAFIELD_end = response.docInfo[recnum-1].metadata.end();
-
-    while (METAFIELD_here!=METAFIELD_end) {
-      text_tarray::iterator METAVALUE_here = METAFIELD_here->second.values.begin();
-      text_tarray::iterator METAVALUE_end = METAFIELD_here->second.values.end();
-      while (METAVALUE_here!=METAVALUE_end) {
-	// construct a text_t containing the record:
-	// there are multiple metadata fields,
-	// each field can have multiple values.
-	/*
-	// don't include fields starting with a lowercase letter,
-	// these are system fields.
-	// later: include these anyway, since Explain fields start with lowercase letters
-	if (METAFIELD_here->first[0] >= 'A' &&
-	    METAFIELD_here->first[0] <= 'Z') {
-	*/
-	  MetadataResult += METAFIELD_here->first; // field name
-	  MetadataResult += " ";
-	  MetadataResult += *METAVALUE_here; // field contents
-	  MetadataResult += "\n";
-	  //}
-	METAVALUE_here++;
-      }
-      METAFIELD_here++;
-    }
-    return true; // succeeded
-  }
-}
-
-bool get_marc_record (int recnum, list<metatag*> &Metatag_list, text_t &CollectionName)
-{
-  if (z3950_verbosity_>1) {
-    cerr << "Entering get_marc_record" << endl;
-  }
-  int total_records = 0;
-
-  list<FilterResponse_t>::iterator RESPONSE_here = Response_tlist.begin();
-  list<FilterResponse_t>::iterator RESPONSE_end = Response_tlist.end();
-  list<text_t>::iterator RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
-  list<text_t>::iterator RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
-  list<int>::iterator RESPONSE_SIZES_here = Response_tlist_sizes.begin();
-  list<int>::iterator RESPONSE_SIZES_end = Response_tlist_sizes.end();
-
-  RESPONSE_here = Response_tlist.begin();
-  RESPONSE_end = Response_tlist.end();
-  while (RESPONSE_here != RESPONSE_end) {
-    total_records += (*RESPONSE_here).numDocs;
-    RESPONSE_here++;
-  }
-
-  // check that the index is within bounds
-  if (recnum < 1 || recnum > total_records) {
-    cerr << "get_marc_record failed" << endl;
-    return false; // failed
-  } else {
-    FilterResponse_t response;
-    // iterate through Response_tlist to find the right response
-    RESPONSE_here = Response_tlist.begin();
-    RESPONSE_end = Response_tlist.end();
-    RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
-    RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
-    RESPONSE_SIZES_here = Response_tlist_sizes.begin();
-    RESPONSE_SIZES_end = Response_tlist_sizes.end();
-    int n = 0;
-    while (RESPONSE_here != RESPONSE_end) {
-      n += *RESPONSE_SIZES_here;
-      if (n >= recnum) {
-	response = *RESPONSE_here;
-	CollectionName = *RESPONSE_COLNAMES_here;
-	recnum = *RESPONSE_SIZES_here - (n - recnum);
-	break;
-      }
-      // these should all have the same number of elements,
-      // so only need to check that one is within bounds.
-      // may want to combine these into a larger data structure later.
-      RESPONSE_here++;
-      RESPONSE_COLNAMES_here++;
-      RESPONSE_SIZES_here++;
-    }
-
-    // locate the desired record in the response
-    
-    MetadataInfo_tmap::iterator METAFIELD_here = response.docInfo[recnum-1].metadata.begin();
-    MetadataInfo_tmap::iterator METAFIELD_end = response.docInfo[recnum-1].metadata.end();
-    
-    while (METAFIELD_here!=METAFIELD_end) {
-      text_tarray::iterator METAVALUE_here = METAFIELD_here->second.values.begin();
-      text_tarray::iterator METAVALUE_end = METAFIELD_here->second.values.end();
-      while (METAVALUE_here!=METAVALUE_end) {
-	if (METAFIELD_here->first[0] >= 'A' &&
-	    METAFIELD_here->first[0] <= 'Z') {
-	  metatag *tmptag = new metatag();
-	  tmptag->name = METAFIELD_here->first.getcstr();
-	  tmptag->type = "";
-	  tmptag->scheme = "";
-	  tmptag->value = (*METAVALUE_here).getcstr();
-	  Metatag_list.push_back(tmptag);
-	}
-	METAVALUE_here++;
-      }
-      METAFIELD_here++;
-    }
-    return true; // succeeded
-  }
-}
-
-// *** implement this ***
-int ztest_fetch(void *handle, bend_fetch_rr *r)
-{
-  // *** called when client issues a "show" command, 2nd of 5
-    if (z3950_verbosity_>1) {
-      cerr << "Entering ztest_fetch" << endl;
-    }
-    char *cp;
-    r->errstring = 0;
-    r->last_in_set = 0;
-    r->basename = "DUMMY"; // this is set below
-    r->output_format = r->request_format;
-
-    // *** use this until found a good way of mapping Greenstone
-    // *** metadata fields to USMARC fields
-    if (r->request_format == VAL_SUTRS)
-    {
-      // copies record into r, errcode will be 13 if fails
-      text_t MetadataResult;
-      text_t CollectionName;
-      if (!get_sutrs_record(r->number, MetadataResult, CollectionName)) {
-	r->errcode = 13;
-	return 0;
-      } else {			
-	r->len = MetadataResult.size();
-	r->record = (char*) odr_malloc(r->stream, r->len+1);
-	char *tmptxt = MetadataResult.getcstr();
-	strcpy(r->record, tmptxt);
-	delete tmptxt;
-	r->basename = (char*) odr_malloc(r->stream, CollectionName.size()+1);
-	tmptxt = CollectionName.getcstr();
-	strcpy(r->basename, tmptxt);
-	delete tmptxt;
-      }
-    }
-    // *** do we want to use this format? ***
-    else if (r->request_format == VAL_GRS1)
-    {
-      // bail out, since we don't support grs (yet?)
-      r->errcode = 107; // "Query type not supported"
-      return 0;
-      
-    } 
-    // assume that here on in is some sort of MARC format
-    else {
-      marcrec *mrec = new marcrec;
-
-      mrec = (marcrec*) malloc(sizeof(*mrec));
-      
-      mrec->marcline = (char*) malloc(100000);
-      mrec->partitle = (char*) malloc(10000);
-      mrec->subtitle = (char*) malloc(10000);
-      mrec->year     = (char*) malloc(1000);
-      mrec->url      = (char*) malloc(1000);
-      mrec->fmat     = (char*) malloc(1000);
-      mrec->s008     = (char*) malloc(41);
-      
-      mrec->ncreators = 0;
-      mrec->ntitles   = 0;
-      *mrec->marcline = 0;
-      *mrec->subtitle = 0;
-      *mrec->partitle = 0;
-      *mrec->year     = 0;
-      *mrec->url      = 0;
-      *mrec->fmat     = 0;
-      strcpy(mrec->s008, "                                        ");
-
-      text_t CollectionName;
-      list<metatag*> Metatag_list;
-
-      if (!get_marc_record(r->number, Metatag_list, CollectionName)) {
-	r->errcode = 13;
-	return 0;
-      } else {
-	list<metatag*>::iterator METATAG_here = Metatag_list.begin();
-	list<metatag*>::iterator METATAG_end = Metatag_list.end();
-	while (METATAG_here != METATAG_end) {
-	  usMARC(*METATAG_here, mrec);
-	  METATAG_here++;
-	}
-
-	// set the date in the marc record to the current date
-	char today[32];
-	time_t d;
-	struct tm *time_struct;
-	//putenv("TZ=NFT-1DFT");
-	d = time(NULL);
-	time_struct = localtime(&d);
-	strftime(today, 16, "%y%m%d", time_struct);
-	put008(mrec->s008, today, F008_DATE_ENTERED);
-	put008(mrec->s008, "s", F008_TYPE_OF_DATE);
-
-	// to do: make this safer + more efficient
-	cp = new char[1000000];
-	char *cp2 = new char[1000000];
-	
-	switch(r->request_format) {
-	case VAL_DANMARC: {
-	  MARCtidy(mrec, cp, DANMARC);
-	  r->output_format = VAL_DANMARC;
-	  break; }
-	case VAL_FINMARC: {
-	  MARCtidy(mrec, cp, FINMARC);
-	  r->output_format = VAL_FINMARC;
-	  break; }
-	// YAZ doesn't know about ISMARC
-	/*
-	case VAL_ISMARC: {
-	  put008(mrec->s008, "k", F008_FORM_OF_PUBLICATION);
-	  MARCtidy(mrec, cp, ISMARC);
-	  r->output_format = VAL_ISMARC;
-	  break; }
-	*/
-	case VAL_NORMARC: {
-	  MARCtidy(mrec, cp, NORMARC);
-	  r->output_format = VAL_NORMARC;
-	  break; }
-	case VAL_SWEMARC: {
-	  MARCtidy(mrec, cp, SWEMARC);
-	  r->output_format = VAL_SWEMARC;
-	  break; }
-	default: {
-	  MARCtidy(mrec, cp, USMARC);
-	  r->output_format = VAL_USMARC;
-	  break; }
-	}
-	
-	sprintf(cp2, "%s", (char*) MARC2709(cp, 0, 6, 'n', 'm', ' '));
-	r->len = strlen(cp2);
-	r->record = (char*) odr_malloc(r->stream, r->len+1);
-	strcpy(r->record, cp2);     
-	r->basename = (char*) odr_malloc(r->stream, CollectionName.size()+1);
-	char *tmptxt;
-	tmptxt = CollectionName.getcstr();
-	strcpy(r->basename, tmptxt);
-	delete tmptxt;
-	delete cp2;      
-	cerr << "dumping record:`" << cp << "'" << endl;
-	delete cp;
-      }
-    }
-
-    r->errcode = 0;
-    return 0;
-}
-
-/*
- * silly dummy-scan what reads words from a file.
- */
-int ztest_scan(void *handle, bend_scan_rr *q)
-{
-  // *** called when client issues a "scan" command
-  if (z3950_verbosity_>1) {
-    cerr << "Entering ztest_scan" << endl;
-  }
-    
-  // bail out, since we don't support scan (yet?)
-  q->errcode = 107; // "Query type not supported"
-  return 0;
-
-    static FILE *f = 0;
-    static struct scan_entry list[200];
-    static char entries[200][80];
-    int hits[200];
-    char term[80], *p;
-    int i, pos;
-    int term_position_req = q->term_position;
-    int num_entries_req = q->num_entries;
-
-    q->errcode = 0;
-    q->errstring = 0;
-    q->entries = list;
-    q->status = BEND_SCAN_SUCCESS;
-    if (!f && !(f = fopen("dummy-words", "r")))
-    {
-	perror("dummy-words");
-	exit(1);
-    }
-    if (q->term->term->which != Z_Term_general)
-    {
-    	q->errcode = 229; /* unsupported term type */
-	return 0;
-    }
-    if (*q->step_size != 0)
-    {
-	q->errcode = 205; /*Only zero step size supported for Scan */
-	return 0;
-    }
-    if (q->term->term->u.general->len >= 80)
-    {
-    	q->errcode = 11; /* term too long */
-	return 0;
-    }
-    if (q->num_entries > 200)
-    {
-    	q->errcode = 31;
-	return 0;
-    }
-    memcpy(term, q->term->term->u.general->buf, q->term->term->u.general->len);
-    term[q->term->term->u.general->len] = '\0';
-    for (p = term; *p; p++)
-    	if (islower(*p))
-	    *p = toupper(*p);
-
-    fseek(f, 0, SEEK_SET);
-    q->num_entries = 0;
-
-    for (i = 0, pos = 0; fscanf(f, " %79[^:]:%d", entries[pos], &hits[pos]) == 2;
-	i++, pos < 199 ? pos++ : (pos = 0))
-    {
-    	if (!q->num_entries && strcmp(entries[pos], term) >= 0) /* s-point fnd */
-	{
-	    if ((q->term_position = term_position_req) > i + 1)
-	    {
-	    	q->term_position = i + 1;
-		q->status = BEND_SCAN_PARTIAL;
-	    }
-	    for (; q->num_entries < q->term_position; q->num_entries++)
-	    {
-	    	int po;
-
-		po = pos - q->term_position + q->num_entries+1; /* find pos */
-		if (po < 0)
-		    po += 200;
-
-		if (!strcmp (term, "SD") && q->num_entries == 2)
-		{
-		    list[q->num_entries].term = entries[pos];
-		    list[q->num_entries].occurrences = -1;
-		    list[q->num_entries].errcode = 233;
-		    list[q->num_entries].errstring = "SD for Scan Term";
-		}
-		else
-		{
-		    list[q->num_entries].term = entries[po];
-		    list[q->num_entries].occurrences = hits[po];
-		}
-	    }
-	}
-	else if (q->num_entries)
-	{
-	    list[q->num_entries].term = entries[pos];
-	    list[q->num_entries].occurrences = hits[pos];
-	    q->num_entries++;
-	}
-	if (q->num_entries >= num_entries_req)
-	    break;
-    }
-    if (feof(f))
-    	q->status = BEND_SCAN_PARTIAL;
-    return 0;
-}
-
-
-
-void bend_close(void *handle)
-{
-  if (z3950_verbosity_>1) {
-    cerr << "Entering bend_close" << endl;
-  }
-  delete Server;
-  delete Cservers;
-  delete Protocol;
-  if (z3950_verbosity_>1) {
-    cerr << "heap cleaned up, exiting bend_close" << endl;
-  }
-  return;
-}
-
-int main (int argc, char *argv[])
-{
-  
-  const int statserv_var =  statserv_main(argc, argv, bend_init, bend_close);
-  cerr << "statserv_main returns: " << statserv_var << endl;
-  return statserv_var;
-  
-  return 0;
-}
-
-
Index: dl/trunk/src/colservr/z3950server.h
===================================================================
--- /gsdl/trunk/src/colservr/z3950server.h	(revision 15424)
+++ 	(revision )
@@ -1,71 +1,0 @@
-/**********************************************************************
- *
- * z3950server.h --
- * Copyright (C) 2000  The New Zealand Digital Library Project
- *
- * A component of the Greenstone digital library software
- * from the New Zealand Digital Library Project at the
- * University of Waikato, New Zealand.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *********************************************************************/
-
-#ifndef Z3950SERVER_H
-#define Z3950ESRVER_H
-
-#include <string>
-#include <list>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <time.h>
-
-// Greenstone headers
-#include "fileutil.h"
-
-// the maximum number of hits allowed
-#define MAXHITS 10000
-
-// These globals are local to each thread: one Z39.50 connection = one thread.
-
-extern text_t gsdlhome; // this is specified externally when Greenstone is installed
-extern list<FilterResponse_t> Response_tlist; // list of response sets
-extern list<text_t> Response_tlist_colnames;  // collection names for the above
-extern list<int> Response_tlist_sizes;        // sizes (number of records) for the above
-extern z3950Server *Server;
-extern collectset *Cservers;
-extern nullproto *Protocol;
-extern map<text_t, gsdlCollection> Collection_map; // info and tools for collections
-extern map<text_t, text_t> Resultsets;             // mapping from ResultSetId to GSQuery 
-
-extern int z3950_verbosity_;
-
-bend_initresult *bend_init(bend_initrequest *q);
-void bend_close(void *handle);
-
-Z_GenericRecord *read_grs1(FILE *f, ODR o);
-
-int ztest_search (void *handle, bend_search_rr *rr);
-int ztest_sort (void *handle, bend_sort_rr *rr);
-int ztest_present (void *handle, bend_present_rr *rr);
-int ztest_esrequest (void *handle, bend_esrequest_rr *rr);
-int ztest_delete (void *handle, bend_delete_rr *rr);
-int ztest_fetch(void *handle, bend_fetch_rr *r);
-int ztest_scan(void *handle, bend_scan_rr *q);
-
-
-#endif
Index: /gsdl/trunk/src/recpt/Makefile.in
===================================================================
--- /gsdl/trunk/src/recpt/Makefile.in	(revision 15424)
+++ /gsdl/trunk/src/recpt/Makefile.in	(revision 15425)
@@ -278,5 +278,5 @@
 # if they don't need to include all the yaz headers
 z3950%.o: z3950%.cpp
-	$(COMPILE) -I$(YAZDIR)/include $<
+	$(COMPILE) -I$(YAZDIR)/include -I../../packages/d2m $<
 
 zparse.tab.c: zparse.y
@@ -394,9 +394,7 @@
 test:
 
-Z3950_OBJS = recptproto.o recptprototools.o \
-	 $(COLSERVROBJECTS) \
-    ../colservr/z3950parser.o ../colservr/z3950explain.o \
-    ../colservr/z3950_to_gsdl.o \
-    ../colservr/z3950server.o nullproto.o \
+Z3950_OBJECTS = z3950explain.o z3950parser.o z3950server.o z3950_to_gsdl.o
+
+Z3950_OBJS = $(Z3950_OBJECTS) recptproto.o recptprototools.o nullproto.o $(COLSERVROBJECTS) \
     ../../lib/gsdllib.a  \
     $(INDEXERS_DIR)/mg/src/text/libmgtext.a \
@@ -404,6 +402,6 @@
     $(FASTCGI_OBJS) \
     $(INDEXERS_DIR)/mgpp/text/libmgpptext.a \
-    $(INDEXERS_DIR)/mgpp/lib/libmgpplib.a ../../packages/yaz/lib/libyaz.a ../../packages/d2m/libd2m.a
-
+    $(INDEXERS_DIR)/mgpp/lib/libmgpplib.a \
+    ../../packages/yaz/lib/libyaz.a ../../packages/d2m/libd2m.a
 
 z3950server: $(Z3950_OBJS)
Index: /gsdl/trunk/src/recpt/z3950_to_gsdl.cpp
===================================================================
--- /gsdl/trunk/src/recpt/z3950_to_gsdl.cpp	(revision 15425)
+++ /gsdl/trunk/src/recpt/z3950_to_gsdl.cpp	(revision 15425)
@@ -0,0 +1,345 @@
+/**********************************************************************
+ *
+ * z3950_to_gsdl.cpp --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "z3950parser.h"
+#include "z3950server.h"
+#include "z3950_to_gsdl.h"
+
+// converts a char* to uppercase, I wouldn't be
+// writing this if I could find an existing
+// function to do it
+void toUpperString(char *&text)
+{
+  for (int i = 0; text[i] != '\0'; i++) {
+    text[i] = toupper(text[i]);
+  }
+}
+
+
+text_t gsdlCollection::getName() 
+{
+  return name;
+}
+
+bool gsdlCollection::z3950Capeable() const
+{
+  return z3950ready;
+}
+
+
+bool gsdlCollection::bib1_to_dc_mapping(text_t& filename)
+{
+    ifstream inFile;
+    int input_Bib1;
+    text_t input_DCES;
+    text_t input_Short;
+
+    char* filename_cstr = filename.getcstr();
+    inFile.open(filename_cstr, ios::in);
+    delete [] filename_cstr;
+
+    if (!inFile) {
+      return false;
+    }
+
+    const int BUFFERSIZE = 1024;
+    char buffer[BUFFERSIZE];
+
+    // read in pairs of values (mappings from Bib-1 to DCES)
+    while (!inFile.eof()) {
+      char input_DCES_tmp[BUFFERSIZE];
+
+      inFile.getline(buffer, BUFFERSIZE, '\n');
+      if (buffer[0] == '#') {
+	// ignore comments (# ...)
+	continue;
+      }
+
+      sscanf(buffer,"%d %s",&input_Bib1, input_DCES_tmp);
+
+      input_DCES = input_DCES_tmp;
+
+      Bib1_to_DCES[input_Bib1] = input_DCES;
+
+      if (z3950_verbosity_>2) {
+	cerr << "(" << input_Bib1 << "/" << input_DCES << ") ";
+      }
+    }
+
+    if (z3950_verbosity_>2) {
+      cerr << endl;
+    }
+    inFile.close();
+
+    return true;
+}
+
+
+bool gsdlCollection::dc_to_short_mapping(text_t& filename, 
+					 text_t& collectionName) 
+{
+    ifstream inFileBuild;
+    text_t input_DCES;
+    text_t input_Short;
+  
+    char* filename_cstr = filename.getcstr();
+    inFileBuild.open(filename_cstr, ios::in);
+    delete [] filename_cstr;
+
+    if (!inFileBuild) {
+      if (z3950_verbosity_>2) {
+	cerr << "Warning: Unable to open: " << filename << endl;
+	cerr << "         Collection " << collectionName << " might not be built" << endl;
+      }
+      return false;
+    }
+
+    const int BUFFERSIZE = 1024;
+    char buffer[BUFFERSIZE];
+
+    // find the indexfieldmap line
+    do {
+      inFileBuild >> buffer;
+      if (inFileBuild.eof()) {
+	if (z3950_verbosity_>1) {
+	  cerr << "Warning: Did not find indexfieldmap in build.cfg for " 
+	       << collectionName << endl;
+	}
+	return false;
+      }
+    } while (strcmp(buffer, "indexfieldmap") != 0);
+
+    // at this stage, buffer contains "indexfieldmap",
+    // if the file didn't contain it, would have returned above
+    inFileBuild >> buffer;
+    while (strstr(buffer, "->") != NULL) {
+      // buffer contains a DCES->Short mapping
+      input_DCES.clear();
+      input_Short.clear();
+
+      // copy in DCES
+      int i;
+      for (i = 0; buffer[i] != '-'; i++) {
+	input_DCES.appendcarr(&(buffer[i]), 1);
+      }
+
+      // skip over "->"
+      i+=2;
+
+      // copy in Short
+      for (; isalpha(buffer[i]); i++) {
+	input_Short.appendcarr(&(buffer[i]), 1);
+      }
+
+      // add to map
+      DCES_to_Short[input_DCES] = input_Short;
+
+      if (z3950_verbosity_>1) {
+	cerr << "<" << input_DCES << "/" << input_Short << "> ";
+      }
+
+      inFileBuild >> buffer;
+    }
+
+    inFileBuild.close();
+
+    if (z3950_verbosity_>1) {
+      cerr << endl;
+    }
+
+    return true;
+}    
+
+
+
+
+  // converts a Bib1 field number to a short index name,
+  // returns true if a mapping existed, false otherwise
+bool gsdlCollection::getFieldArg(int Bib1, text_t &Short) 
+{
+    if (Bib1_to_DCES.count(Bib1) < 1) return false;
+    if (DCES_to_Short.count(Bib1_to_DCES[Bib1]) < 1) return false;
+    Short = DCES_to_Short[Bib1_to_DCES[Bib1]];
+    return true;
+}
+  
+gsdlCollection::~gsdlCollection(void) 
+{
+    //cerr << "gsdlCollection destructor called" << endl;
+}
+
+gsdlCollection::gsdlCollection(void) 
+{
+    //cerr << "gsdlCollection void constructor called" << endl;
+}
+ 
+gsdlCollection::gsdlCollection(text_t collectionName, text_t gsdlhome) 
+{
+
+    //char *filename_cstr;
+    //ifstream inFile;
+    //int inFileSize = 0;
+    z3950ready = true;
+
+    // int input_Bib1;
+    //text_t input_DCES;
+    //text_t input_Short;
+
+    name = collectionName;
+
+    // read in the cfg file for Bib1_to_DCES
+    text_t col_filename = gsdlhome;
+    col_filename.appendcstr("/collect/");
+    col_filename.append(collectionName);
+    col_filename.appendcstr("/etc/bib1_to_dces.cfg");
+
+    if (!bib1_to_dc_mapping(col_filename)) {
+      text_t site_filename = gsdlhome;
+      site_filename.appendcstr("/etc/bib1_to_dces.cfg");
+
+      if (!bib1_to_dc_mapping(site_filename)) {
+	cerr << "Unable to find bib1->dublin core mapping for " 
+	     << collectionName << endl;
+	cerr << "Looked for:\n  " << col_filename << "\n  " 
+	     << site_filename << endl;
+	z3950ready = false;
+	return;
+      }
+    }
+
+    // read in the cfg file for mapping Dublin Core to Short (internal name)
+    text_t build_filename = gsdlhome;
+    build_filename.appendcstr("/collect/");
+    build_filename.append(collectionName);
+    build_filename.appendcstr("/index/build.cfg");
+
+    if (!dc_to_short_mapping(build_filename,collectionName)) {
+      // explicitly check for error (in case in future more work is done after
+      // this
+      z3950ready = false;
+      return;
+    }
+
+}
+
+
+void z3950Server::openLogfile(text_t extension, ofstream &out)
+{
+    char *cfilename;
+    text_t filename;
+
+    filename = filename_cat(gsdlhome, extension);
+    cfilename = filename.getcstr();
+
+    out.open(cfilename);
+    delete cfilename;
+}
+
+z3950Server::z3950Server(nullproto *protocol, text_t home)
+{ 
+
+    text_t dirname;
+    char * cdirname;
+    if (home.empty()) {
+      cerr  << "Z3950Server Error: gsdlhome not set. \nPlease make sure"
+	    << " you have a valid gsdlsite.cfg file in the directory \n"
+	    << "you are running z3950server\n";
+      cerr << "Exiting..."<<endl;
+      exit(1);
+    } 
+    cerr << "Z3950Server: gsdlhome = " << home << endl;
+
+    this->gsdlhome = home;
+    //cerr << gsdlhome.getcstr() << endl;
+    dirname = filename_cat(gsdlhome, "/collect");
+    cdirname = dirname.getcstr();
+    if (!read_dir (cdirname, collections)) { 
+      cerr << "Z3950Server Error: could not read directory "<<cdirname<<endl;
+      cerr << "Exiting..."<<endl;
+      exit (1);
+    }
+    delete cdirname;
+
+    cerr << "Constructing set list server" << endl;
+    this->protocol = protocol;
+
+    // initialise Yaz stuff for z39.50 server 
+}
+  
+bool z3950Server::initialise() 
+{
+      ofstream      logout;
+      int           reply;
+      comerror_t    error = noError;
+
+      this->openLogfile("/etc/z3950out.txt", logout);
+      reply = protocol->init(error, logout);
+      logout.close();
+      return (reply != 0 ? 1 : 0);
+}
+
+void z3950Server::configure(const text_t &key, const text_tarray &cfgline, 
+			    comerror_t &err)
+{
+      err = noError;
+
+      // ****
+      cerr << "Recieved " << key << " = ";
+      for (int unsigned i=0; i<cfgline.size(); i++)
+	{
+	  cout << cfgline[i] << " ";
+	}
+      cout << endl;
+
+      // DB // ****
+      if (key=="gsdlhome")
+	{  
+	  text_tarray cfgline;
+	  cfgline.push_back (gsdlhome);
+	  cerr << "Changing gsdlhome to " << gsdlhome << endl;
+	  protocol->configure(key, cfgline, err);
+	}
+      else if (key=="httpdomain")
+	{
+	  // Only let gsdlhome through !!!! // ****
+	  cerr << "Supressing httpdomain" << endl;
+	}
+      else if (key=="httpprefix")
+	{
+	  cerr << "Supressing httpprefix" << endl;
+	}
+      else
+	{ 
+	  protocol->configure(key, cfgline,err);
+	}
+}
+
+int z3950Server::run_z3950( int argc, char **argv ) 
+{
+
+    const int statserv_var =  statserv_main(argc, argv, bend_init, bend_close);
+    cerr << "statserv_main returns: " << statserv_var << endl;
+    return statserv_var;
+}
Index: /gsdl/trunk/src/recpt/z3950_to_gsdl.h
===================================================================
--- /gsdl/trunk/src/recpt/z3950_to_gsdl.h	(revision 15425)
+++ /gsdl/trunk/src/recpt/z3950_to_gsdl.h	(revision 15425)
@@ -0,0 +1,87 @@
+/**********************************************************************
+ *
+ * z3950_to_gsdl.h --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef Z3950_TO_GSDL_H
+#define Z3950_TO_GSDL_H
+
+
+void toUpperString(char *&text);
+
+class gsdlCollection
+{
+ public:
+  gsdlCollection(); 
+  gsdlCollection(text_t collectionName, text_t gsdlhome);
+  ~gsdlCollection(void);
+
+  bool z3950Capeable() const;
+
+  // converts a Bib1 field number to a short index name,
+  // returns true if a mapping existed, false otherwise
+  bool getFieldArg(int Bib1, text_t &Short);
+
+  text_t getName(); // returns the name of the collection in short form
+  
+ protected:
+
+
+  bool bib1_to_dc_mapping(text_t& filename);
+  bool dc_to_short_mapping(text_t& filename, text_t& collectionName);
+
+ protected:
+  text_t name;
+  map<int, text_t>    Bib1_to_DCES;  // Bib-1 to DC metadata names
+  map<text_t, text_t> DCES_to_Short; // DC to short (2-3 letter) internal name
+
+  bool z3950ready; // is the collection Z39.50-ready ?
+                   // (i.e. does it have the cfg files for mappings)
+
+
+};
+
+class z3950Server 
+{
+protected:
+  text_tarray collections;
+  nullproto *protocol;
+  text_t      gsdlhome;
+
+  // save particular YAZ variables ...
+
+  void openLogfile(text_t extension, ofstream &out);
+
+
+public:
+  z3950Server(nullproto *protocol, text_t home);
+  
+  bool initialise();
+
+  void configure(const text_t &key, const text_tarray &cfgline, comerror_t &err);
+
+  int run_z3950( int argc, char **argv );
+
+};
+
+#endif
Index: /gsdl/trunk/src/recpt/z3950explain.cpp
===================================================================
--- /gsdl/trunk/src/recpt/z3950explain.cpp	(revision 15425)
+++ /gsdl/trunk/src/recpt/z3950explain.cpp	(revision 15425)
@@ -0,0 +1,209 @@
+/**********************************************************************
+ *
+ * z3950explain.cpp --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "z3950explain.h"
+
+void getExplainInfo(bend_search_rr *rr, FilterResponse_t &response, comerror_t &err)
+{
+  text_t GSQuery = ZQueryToGSQuery(rr);
+  char *GSQuery_char = GSQuery.getcstr(); 
+
+  int i;
+  if (strstr(GSQuery_char, "TargetInfo") != NULL) {
+    // should be one only
+    // real-life example:
+    /*
+      62
+      explain-category targetInfo
+      date-of-info Sep 22, 1999
+      language eng
+    */
+    ResultDocInfo_t docinfo;
+    docinfo.metadata["explain-category"].values.push_back("TargetInfo");
+    docinfo.metadata["name"].values.push_back("Greenstone");
+    docinfo.metadata["namedResultSets"].values.push_back("false");
+    docinfo.metadata["multipleDBsearch"].values.push_back("true");
+    docinfo.metadata["language"].values.push_back("eng");
+    response.docInfo.push_back(docinfo);
+    response.numDocs++;
+  }
+  if (strstr(GSQuery_char, "DatabaseInfo") != NULL) {
+    // should be one per collection
+    // real-life example:
+    /*
+      3
+      dbnum 0
+      explain-category DatabaseInfo
+      database-name.1 0
+      title Z39.50 EXPLAIN DB
+      database-name.2 ir-explain-1
+      date-of-info Sep 22, 1999
+      language eng
+      dbpath /usr/wald/z39.50root/explain
+      dbname explain
+    */
+    ResultDocInfo_t docinfo;
+    docinfo.metadata["explain-category"].values.push_back("DatabaseInfo");
+    docinfo.metadata["database-name"].values.push_back("IR-Explain-1");
+    docinfo.metadata["title"].values.push_back("Z39.50 EXPLAIN DB");
+    docinfo.metadata["language"].values.push_back("eng");
+    docinfo.metadata["dbname"].values.push_back("explain");
+    response.docInfo.push_back(docinfo);
+    response.numDocs++;
+    // now get the info for each collection
+    text_tarray collectlist;
+    Protocol->get_collection_list(collectlist, err, cerr);
+    text_tarray::iterator COLHERE = collectlist.begin();
+    text_tarray::iterator COLEND = collectlist.end();
+    while (COLHERE != COLEND) {
+      // don't include information for non-active collections
+      bool collection_active;
+      Protocol->ping(*COLHERE, collection_active, err, cerr);
+      if (collection_active != true) {
+	COLHERE++;
+	continue;
+      }
+      ColInfoResponse_t collectinfo;
+      Protocol->get_collectinfo(*COLHERE, collectinfo, err, cerr);
+      docinfo.clear();
+      docinfo.metadata["name"].values.push_back(collectinfo.shortInfo.name);
+      docinfo.metadata["host"].values.push_back(collectinfo.shortInfo.host);
+      if (collectinfo.isPublic) {
+	docinfo.metadata["isPublic"].values.push_back("true");
+      } else {
+	docinfo.metadata["isPublic"].values.push_back("false");
+      }
+      if (collectinfo.isBeta) {
+	docinfo.metadata["isBeta"].values.push_back("true");
+      } else {
+	docinfo.metadata["isBeta"].values.push_back("false");
+      }
+      if (collectinfo.useBook == true) {
+	docinfo.metadata["useBook"].values.push_back("true");
+      } else {
+	docinfo.metadata["useBook"].values.push_back("false");
+      }
+      docinfo.metadata["buildDate"].values.push_back(collectinfo.buildDate);
+      text_tarray::iterator TEXTT_HERE = collectinfo.ccsCols.begin();
+      text_tarray::iterator TEXTT_END = collectinfo.ccsCols.end();
+      for (i = 1; TEXTT_HERE != TEXTT_END; i++, TEXTT_HERE++) {
+	text_t tmp = "ccsCols.";
+	tmp.appendint(i);
+	docinfo.metadata[tmp].values.push_back(*TEXTT_HERE);
+      }
+      TEXTT_HERE = collectinfo.languages.begin();
+      TEXTT_END = collectinfo.languages.end();
+      for (i = 1; TEXTT_HERE != TEXTT_END; i++, TEXTT_HERE++) {
+	text_t tmp = "languages.";
+	tmp.appendint(i);
+	docinfo.metadata[tmp].values.push_back(*TEXTT_HERE);
+      }
+      docinfo.metadata["numDocs"].values.push_back(collectinfo.numDocs);
+      docinfo.metadata["numSections"].values.push_back(collectinfo.numSections);
+      docinfo.metadata["numWords"].values.push_back(collectinfo.numWords);
+      docinfo.metadata["numBytes"].values.push_back(collectinfo.numBytes);
+
+      collectionmeta_map::iterator COLLMETA_MAP_HERE = collectinfo.collectionmeta.begin();
+      collectionmeta_map::iterator COLLMETA_MAP_END = collectinfo.collectionmeta.end();
+      for (i = 1; COLLMETA_MAP_HERE != COLLMETA_MAP_END; i++, COLLMETA_MAP_HERE++) {
+	text_t tmp = "collectionmeta.";
+	tmp.appendint(i);
+	text_t tmp2 = COLLMETA_MAP_HERE->first;
+	tmp2.appendcstr(" -> ");
+	tmp2.append(COLLMETA_MAP_HERE->second[g_EmptyText]);
+	docinfo.metadata[tmp].values.push_back(tmp2);
+      }
+      text_tmap::iterator TEXTT_MAP_HERE;
+      text_tmap::iterator TEXTT_MAP_END;
+      // uncomment if you want to include this in the explain record,
+      // it's a bit messy to include by default
+      /*
+      TEXTT_MAP_HERE = collectinfo.format.begin();
+      TEXTT_MAP_END = collectinfo.format.end();
+      for (i = 1; TEXTT_MAP_HERE != TEXTT_MAP_END; i++, TEXTT_MAP_HERE++) {
+	text_t tmp = "format.";
+	tmp.appendint(i);
+	text_t tmp2 = TEXTT_MAP_HERE->first;
+	tmp2.appendcstr(" -> ");
+	tmp2.append(TEXTT_MAP_HERE->second);
+	docinfo.metadata[tmp].values.push_back(tmp2);
+      }
+      */
+      TEXTT_MAP_HERE = collectinfo.building.begin();
+      TEXTT_MAP_END = collectinfo.building.end();
+      for (i = 1; TEXTT_MAP_HERE != TEXTT_MAP_END; i++, TEXTT_MAP_HERE++) {
+	text_t tmp = "building.";
+	tmp.appendint(i);
+	text_t tmp2 = TEXTT_MAP_HERE->first;
+	tmp2.appendcstr(" -> ");
+	tmp2.append(TEXTT_MAP_HERE->second);
+	docinfo.metadata[tmp].values.push_back(tmp2);
+      }
+      docinfo.metadata["receptionist"].values.push_back(collectinfo.receptionist);
+      docinfo.metadata["buildType"].values.push_back(collectinfo.buildType);
+      response.docInfo.push_back(docinfo);
+      response.numDocs++;
+      COLHERE++;
+    }
+  }
+  if (strstr(GSQuery_char, "SchemaInfo") != NULL) {
+    // should be one per collection
+    // real-life example:
+    /*
+      10
+      dbnum 1
+      explain-category schemaInfo
+      database-name.1 1
+      database-name.2 books
+      database-name.3 default
+      database-name.4 cat
+      date-of-info Sep 22, 1999
+      language eng
+      schema.1 1.2.840.10003.13.1000.3.1
+      dbpath /usr/wald/z39.50root/books
+      dbname books
+     */
+  }
+  if (strstr(GSQuery_char, "AttributeSetInfo") != NULL) {
+    // should be one per collection
+    // real-life example:
+    /*
+      9
+      dbnum 1
+      explain-category AttributeSetInfo
+      database-name.1 1
+      database-name.2 books
+      database-name.3 default
+      database-name.4 cat
+      date-of-info Sep 22, 1999
+      language eng
+      attribute-set.1 1.2.840.10003.13.1000.3.1
+      dbpath /usr/wald/z39.50root/books
+      dbname books
+    */
+  }
+}
+
+
Index: /gsdl/trunk/src/recpt/z3950explain.h
===================================================================
--- /gsdl/trunk/src/recpt/z3950explain.h	(revision 15425)
+++ /gsdl/trunk/src/recpt/z3950explain.h	(revision 15425)
@@ -0,0 +1,35 @@
+/**********************************************************************
+ *
+ * z3950proto.h --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef Z3950EXPLAIN_H
+#define Z3950EXPLAIN_H
+
+
+#include "z3950parser.h"
+
+void getExplainInfo(bend_search_rr *rr, FilterResponse_t &response, comerror_t &err);
+
+
+#endif
Index: /gsdl/trunk/src/recpt/z3950parser.cpp
===================================================================
--- /gsdl/trunk/src/recpt/z3950parser.cpp	(revision 15425)
+++ /gsdl/trunk/src/recpt/z3950parser.cpp	(revision 15425)
@@ -0,0 +1,373 @@
+
+#include "z3950parser.h"
+
+void Z_AttributeList_parse(bend_search_rr *rr, Z_AttributeList *Z, text_t &GSQuery)
+{
+  /*
+    struct Z_AttributeList {
+    int num_attributes;
+    Z_AttributeElement **attributes;
+    };
+  */
+
+  /*
+    struct Z_AttributeElement {
+    Z_AttributeSetId *attributeSet; // OPT
+    int *attributeType;
+    int which;
+    union {
+    int *numeric;
+    Z_ComplexAttribute *complex;
+    #define Z_AttributeValue_numeric 1
+    #define Z_AttributeValue_complex 2
+    } value;
+    };
+  */
+
+  
+
+}
+
+void Z_Term_parse(bend_search_rr *rr, Z_Term *Z, text_t &GSQuery)
+{
+  /*
+    struct Z_Term {
+    int which;
+    union {
+    Odr_oct *general;
+    int *numeric;
+    Z_InternationalString *characterString;
+    Odr_oid *oid;
+    char *dateTime;
+    Z_External *external;
+    Z_IntUnit *integerAndUnit;
+    Odr_null *null;
+    #define Z_Term_general 1
+    #define Z_Term_numeric 2
+    #define Z_Term_characterString 3
+    #define Z_Term_oid 4
+    #define Z_Term_dateTime 5
+    #define Z_Term_external 6
+    #define Z_Term_integerAndUnit 7
+    #define Z_Term_null 8
+    } u;
+    };
+  */
+
+  char *term;
+
+  switch(Z->which){
+  case Z_Term_general: {
+    // must copy no more than len bytes from buf, or else previous query terms may be included
+    int buflen = Z->u.general->len;
+    term = new char[buflen+1];
+    memset(term, '\0', buflen+1);
+    strncpy(term, (const char*)(Z->u.general->buf), buflen);
+    GSQuery += term;
+    break; }
+  case Z_Term_numeric:
+    GSQuery += *(Z->u.numeric); // int*
+    break;
+  case Z_Term_characterString:
+    GSQuery += Z->u.characterString; // what is this type?
+    break;
+  case Z_Term_oid:
+    GSQuery += *(Z->u.oid); // int*
+    break;
+  case Z_Term_dateTime:
+    GSQuery += Z->u.dateTime; // char*
+    break;
+  case Z_Term_external:
+    GSQuery += " "; // ignore this for now
+    break;
+  case Z_Term_integerAndUnit:
+    GSQuery += " "; // ignore this for now
+    break;
+  case Z_Term_null:
+    GSQuery += " "; // void
+    break;
+  default:
+    cerr << "Error in Z_Term_parse" << endl;
+    exit(1);
+  }
+}
+
+void Z_ProximityOperator_parse(bend_search_rr *rr, Z_ProximityOperator *Z, text_t &GSQuery)
+{
+  /*
+    struct Z_ProximityOperator {
+    bool_t *exclusion; // OPT
+    int *distance;
+    bool_t *ordered;
+    #define Z_ProximityOperator_Prox_lessThan 1
+    #define Z_ProximityOperator_Prox_lessThanOrEqual 2
+    #define Z_ProximityOperator_Prox_equal 3
+    #define Z_ProximityOperator_Prox_greaterThanOrEqual 4
+    #define Z_ProximityOperator_Prox_greaterThan 5
+    #define Z_ProximityOperator_Prox_notEqual 6
+    int *relationType;
+    int which;
+    union {
+    Z_ProxUnit *known;
+    int *zprivate;
+    #define Z_ProximityOperator_known 1
+    #define Z_ProximityOperator_private 2
+    } u;
+    };
+    
+    #define Z_ProxUnit_character 1
+    #define Z_ProxUnit_word 2
+    #define Z_ProxUnit_sentence 3
+    #define Z_ProxUnit_paragraph 4
+    #define Z_ProxUnit_section 5
+    #define Z_ProxUnit_chapter 6
+    #define Z_ProxUnit_document 7
+    #define Z_ProxUnit_element 8
+    #define Z_ProxUnit_subelement 9
+    #define Z_ProxUnit_elementType 10
+    #define Z_ProxUnit_byte 11
+  */
+
+  // Greenstone (actually mgpp) supports proximity, but only 
+  // to n words either side.
+  // A more complete implementation of proximity can be added
+  // by parsing the other fields in Z_ProximityOperator.
+  // Note: this only works properly with MGPP collections
+  
+  GSQuery += " NEAR"; 
+  GSQuery += *(Z->distance);
+  GSQuery += " ";
+}
+
+void Z_Operator_parse(bend_search_rr *rr, Z_Operator *Z, text_t &GSQuery)
+{
+  /*
+    struct Z_Operator {
+    int which;
+    union {
+    Odr_null *and;
+    Odr_null *or;
+    Odr_null *and_not;
+    Z_ProximityOperator *prox;
+    #define Z_Operator_and 1
+    #define Z_Operator_or 2
+    #define Z_Operator_and_not 3
+    #define Z_Operator_prox 4
+    } u;
+    };
+  */
+  
+  switch(Z->which){
+  case Z_Operator_and:
+    GSQuery += " & ";
+    break;
+  case Z_Operator_or:
+    GSQuery += " | ";
+    break;
+  case Z_Operator_and_not:
+    GSQuery += " ! ";
+    break;
+  case Z_Operator_prox:
+    Z_ProximityOperator_parse(rr, Z->u.prox, GSQuery);
+    break;
+  default:
+    cerr << "Error in Z_Operator_parse" << endl;
+    exit(1);
+  }
+}
+
+void Z_Operand_parse(bend_search_rr *rr, Z_Operand *Z, text_t &GSQuery)
+{
+    /*
+      struct Z_Operand {
+      int which;
+      union {
+      Z_AttributesPlusTerm *attributesPlusTerm;
+      Z_ResultSetId *resultSetId;
+      Z_ResultSetPlusAttributes *resultAttr;
+      #define Z_Operand_APT 1
+      #define Z_Operand_resultSetId 2
+      #define Z_Operand_resultAttr 3
+      } u;
+      };
+    */
+  
+  switch(Z->which) {
+  case Z_Operand_APT: {
+    /*
+      struct Z_AttributesPlusTerm {
+      Z_AttributeList *attributes;
+      Z_Term *term;
+      };
+    */
+    
+    /*
+      struct Z_AttributeList {
+      int num_attributes;
+      Z_AttributeElement **attributes;
+      };
+    */
+    
+    /*
+      struct Z_AttributeElement {
+      Z_AttributeSetId *attributeSet; // OPT
+      int *attributeType;
+      int which;
+      union {
+      int *numeric;
+      Z_ComplexAttribute *complex;
+      #define Z_AttributeValue_numeric 1
+      #define Z_AttributeValue_complex 2
+      } value;
+      };
+    */
+    
+    char *term;
+    
+    if (Z->u.attributesPlusTerm->attributes->num_attributes > 0) {
+      int Bib1_relation = *(Z->u.attributesPlusTerm->attributes->attributes[0]->attributeType);
+      int Bib1_use = *(Z->u.attributesPlusTerm->attributes->attributes[0]->value.numeric);
+
+      // if use value is 1010 ("Body of text"), is not a fielded search
+      if (Bib1_use == 1010) {
+	// if relation value is 6 ("not"), add a "not" to GSQuery
+	if (Bib1_relation == 6) {
+	  GSQuery += "! ";
+	}
+	Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
+      }
+      // for other use values, is a fielded search
+      else {
+	text_t Short;
+	// only add [ ]: if the index exists in the collection,
+	// note: only the index names in the first collection of a
+	// multi-collection search are used at the moment
+	if ((Collection_map[rr->basenames[0]]).getFieldArg(Bib1_use, Short)) {
+	  GSQuery += "[";
+	  cerr << "Supressing square brackets for the moment!\n";
+
+	  Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
+	  GSQuery += "]";
+	  GSQuery += ":";
+	  GSQuery += Short;
+	}
+	// if it doesn't, add it as an unfielded search term
+	else {
+	  cerr << "[" << rr->basenames[0] << "]: failed to find index" << endl;
+	  Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
+	}
+      }
+    }
+    else {
+      Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
+    }
+    break;
+  }
+  case Z_Operand_resultSetId: {
+    GSQuery += "(";
+    GSQuery += Resultsets[Z->u.resultSetId];
+    GSQuery += ")";
+    break; 
+  }
+  case Z_Operand_resultAttr:
+    GSQuery += " "; // ignore this for now
+    break;
+  default:
+    cerr << "Error in Z_Operand_parse" << endl;
+    exit(1);
+  } 
+}
+
+void Z_RPNStructure_parse(bend_search_rr *rr, Z_RPNStructure *Z, text_t &GSQuery)
+{
+  /*
+    struct Z_RPNStructure {
+    int which;
+    union {
+    Z_Operand *simple;
+    Z_Complex *complex;
+    #define Z_RPNStructure_simple 1
+    #define Z_RPNStructure_complex 2
+    } u;
+    };
+  */
+
+  switch(Z->which){
+  case Z_RPNStructure_simple:
+    Z_Operand_parse(rr, Z->u.simple, GSQuery);
+    break;
+  case Z_RPNStructure_complex:
+    GSQuery += "(";
+    Z_RPNStructure_parse(rr, Z->u.complex->s1, GSQuery);
+    Z_Operator_parse(rr, Z->u.complex->roperator, GSQuery);
+    Z_RPNStructure_parse(rr, Z->u.complex->s2, GSQuery);
+    GSQuery += ")";
+    break;
+  default:
+    cerr << "Error in Z_RPNStructure_parse" << endl;
+    exit(1);
+  }
+}
+
+text_t ZQueryToGSQuery(bend_search_rr *rr)
+{
+  text_t GSQuery;
+
+  switch(rr->query->which){
+  case Z_Query_type_0:
+    cerr << "querytype = 0" << endl;
+    // this is a void*, pretend it's a Greenstone-type query
+    GSQuery += (char*)(rr->query->u.type_0);
+    break;
+  case Z_Query_type_1: {
+    cerr << "querytype = 1" << endl;
+    /*
+      struct Z_RPNQuery {
+      Z_AttributeSetId *attributeSetId;
+      Z_RPNStructure *RPNStructure;
+      };
+    */
+    // parse attributeSetId
+    cerr << "attributeSetId = ";
+    int c, d = 0;
+    do {
+      c = rr->query->u.type_1->attributeSetId[d];
+      cerr << c;
+      d++;
+    } while (c >= 0);
+    cerr << endl;
+
+    Z_RPNStructure_parse(rr, rr->query->u.type_1->RPNStructure, GSQuery);
+    break; }
+  case Z_Query_type_2: {
+    cerr << "querytype = 2" << endl;
+    // this is just a buf (unsigned char*), pretend it's a Greenstone-type query
+    GSQuery += (char*)(rr->query->u.type_2->buf);
+    break; }
+  case Z_Query_type_100: {
+    cerr << "querytype = 100" << endl;
+     // this is just a buf (unsigned char*), pretend it's a Greenstone-type query
+    GSQuery += (char*)(rr->query->u.type_100->buf);
+    break; }
+  case Z_Query_type_101: {
+    cerr << "querytype = 101" << endl;
+    // check: is this really the same as a type 1 query?
+    Z_RPNStructure_parse(rr, rr->query->u.type_101->RPNStructure, GSQuery);
+    break; }
+  case Z_Query_type_102: {
+    cerr << "querytype = 102" << endl;
+     // this is just a buf (unsigned char*), pretend it's a Greenstone-type query
+    GSQuery += (char*)(rr->query->u.type_102->buf);
+    break; }
+  default: {
+    cerr << "Error in ZQueryToGSQuery" << endl;
+    exit(1); }
+  }
+
+  // override GSQuery (test code)
+  //GSQuery = "[the]:TX";
+
+  cerr << "GSQuery = `" << GSQuery << "'" << endl;
+  return GSQuery;
+}
+
Index: /gsdl/trunk/src/recpt/z3950parser.h
===================================================================
--- /gsdl/trunk/src/recpt/z3950parser.h	(revision 15425)
+++ /gsdl/trunk/src/recpt/z3950parser.h	(revision 15425)
@@ -0,0 +1,77 @@
+/**********************************************************************
+ *
+ * z3950parser.h -- convert Z39.50's RPN query syntax into Greenstone
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef Z3950PARSER_H
+#define Z3950PARSER_H
+
+
+#include <string>
+#include <list>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+
+// Greenstone headers
+#include "fileutil.h"
+#include "comtypes.h"
+#include "nullproto.h"
+#include "z3950_to_gsdl.h"
+
+// YAZ headers
+extern "C" {
+#include <yaz/backend.h>
+#include <yaz/log.h>
+#ifdef ASN_COMPILED
+#include <yaz/ill.h>
+#endif
+}
+
+extern text_t gsdlhome;
+extern list<FilterResponse_t> Response_tlist;
+extern list<text_t> Response_tlist_colnames;
+extern list<int> Response_tlist_sizes;
+extern z3950Server *Server;
+extern collectset *Cservers;
+extern nullproto *Protocol;
+extern map<text_t, gsdlCollection> Collection_map;
+extern map<text_t, text_t> Resultsets;
+
+void Z_AttributeList_parse(bend_search_rr *rr, Z_AttributeList *Z, text_t &GSQuery);
+
+void Z_Term_parse(bend_search_rr *rr, Z_Term *Z, text_t &GSQuery);
+
+void Z_ProximityOperator_parse(bend_search_rr *rr, Z_ProximityOperator *Z, text_t &GSQuery);
+
+void Z_Operator_parse(bend_search_rr *rr, Z_Operator *Z, text_t &GSQuery);
+
+void Z_Operand_parse(bend_search_rr *rr, Z_Operand *Z, text_t &GSQuery);
+
+void Z_RPNStructure_parse(bend_search_rr *rr, Z_RPNStructure *Z, text_t &GSQuery);
+
+text_t ZQueryToGSQuery(bend_search_rr *rr);
+
+#endif
Index: /gsdl/trunk/src/recpt/z3950server.cpp
===================================================================
--- /gsdl/trunk/src/recpt/z3950server.cpp	(revision 15425)
+++ /gsdl/trunk/src/recpt/z3950server.cpp	(revision 15425)
@@ -0,0 +1,927 @@
+
+
+// Standard headers
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#  include <ospace\std\fstream>
+#  include <ospace\std\sstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#  include <strstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#  include <sstream>
+#endif
+
+#include <string>
+#include <list>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+
+// Greenstone headers
+#include "fileutil.h"
+#include "comtypes.h"
+#include "nullproto.h"
+
+// Z39.50 server headers
+#include "z3950parser.h"
+#include "z3950explain.h"
+
+#include "z3950server.h"
+
+// Dublin Core -> MARC (d2m) headers and source files
+#include "d2m4gs.h"
+
+// these globals are local to each thread,
+// one Z39.50 connection = one thread.
+text_t gsdlhome; // this is specified externally when Greenstone is installed
+list<FilterResponse_t> Response_tlist; // list of response sets
+list<text_t> Response_tlist_colnames;  // collection names for the above
+list<int> Response_tlist_sizes;        // sizes (number of records) for the above
+z3950Server *Server   = NULL;
+collectset  *Cservers = NULL;
+nullproto   *Protocol = NULL;
+
+map<text_t, gsdlCollection> Collection_map; // info and tools for collections
+map<text_t, text_t> Resultsets;             // mapping from ResultSetId to GSQuery 
+
+int z3950_verbosity_ = 3;
+
+// *** initialize things here ***
+bend_initresult *bend_init(bend_initrequest *q)
+{
+  // *** called when client connects to the server ***
+  if (z3950_verbosity_ > 1) {
+    cerr << "Entering bend_init" << endl;
+  }
+
+  Protocol = new nullproto();  
+  Cservers = new collectset(gsdlhome);
+  Protocol->set_collectset(Cservers);
+  
+  cerr << "Starting Z39.50 Server ..." << endl;
+  
+  Server = new z3950Server(Protocol, gsdlhome);
+  cerr << "Server constructed" << endl;
+  
+  const bool status = Server->initialise();
+  cerr << "Initialised server: return status = " << status << endl;
+  
+  text_tarray collist;
+  comerror_t err;
+  Protocol->get_collection_list( collist, err, cout );
+
+  // display the list of available Greenstone collections
+  text_tarray::iterator cols_here=collist.begin();
+  text_tarray::iterator cols_end=collist.end();
+  while (cols_here != cols_end) {
+    gsdlCollection tmpcol(*cols_here, gsdlhome);
+    
+    Collection_map[*cols_here] = tmpcol;
+    
+    if (tmpcol.z3950Capeable()) {
+      cerr << "  " << tmpcol.getName() << "\tis Z39.50 capable" << endl;
+    }
+    cols_here++;
+  }
+
+    
+  bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
+  //static char *dummy = "Hej fister"; // what's this for?
+  
+  r->errcode = 0;
+  r->errstring = 0;
+  r->handle = Protocol;
+  q->bend_sort = ztest_sort;       /* register sort handler */
+  q->bend_search = ztest_search;   /* register search handler */
+  q->bend_present = ztest_present; /* register present handle */
+  q->bend_esrequest = ztest_esrequest;
+  q->bend_delete = ztest_delete;
+  q->bend_fetch = ztest_fetch;
+  q->bend_scan = ztest_scan;
+
+  return r;
+}
+
+// *** perform query, get number of hits ***
+int ztest_search (void *handle, bend_search_rr *rr)
+{
+  // *** called when client issues a "find" command
+  if (z3950_verbosity_>1) {
+    cerr << "Entering ztest_search" << endl;
+  }
+
+  Response_tlist.clear();
+  Response_tlist_colnames.clear();
+  Response_tlist_sizes.clear();
+ 
+  comerror_t err;
+  FilterRequest_t request;
+
+  request.filterName = "QueryFilter";
+  request.filterResultOptions = FROID | FRtermFreq | FRmetadata;  
+
+  OptionValue_t option;
+
+  // how many results to get. grouping all results together into
+  // one set instead of breaking up into "pages". 
+  // note: see if Z39.50 has a concept of pages.
+  option.name = "StartResults";
+  option.value = "1";
+  request.filterOptions.push_back (option);
+  option.name = "EndResults";
+  option.value = MAXHITS;
+  request.filterOptions.push_back (option);
+  option.name = "Maxdocs";
+  option.value = MAXHITS;
+  request.filterOptions.push_back (option);
+
+  text_t GSQuery = ZQueryToGSQuery(rr);
+  option.name = "Term";
+  option.value = GSQuery;
+  request.filterOptions.push_back (option);
+  Resultsets[Resultsets.size()+1] = GSQuery;
+
+  option.name = "QueryType";
+  option.value = "boolean";
+  request.filterOptions.push_back (option);
+
+  option.name = "MatchMode";
+  option.value = "all";
+  request.filterOptions.push_back (option);
+
+  option.name = "Casefold";
+  option.value = "true";
+  request.filterOptions.push_back (option);
+
+  option.name = "Stem";
+  option.value = "false";
+  request.filterOptions.push_back (option);
+
+  option.name = "AccentFold";
+  option.value = "false";
+  request.filterOptions.push_back (option);
+  
+  // MG queries don't need this, MGPP queries do.
+  // doesn't do any harm to include it anyway.
+  // note: not all collections have document-level granularity...
+  option.name = "Level";
+  option.value = "Doc";
+  request.filterOptions.push_back (option);
+
+  // Z39.50 supports the searching of multiple databases
+  rr->hits = 0;
+  for (int i = 0; i < rr->num_bases; i++) {
+    FilterResponse_t response;
+    cerr << "Searching basename = " << rr->basenames[i] << endl;
+    // intercept Explain requests
+    if (strcmp(rr->basenames[i], "IR-Explain-1")==0) {
+      //ColInfoResponse_t collectinfo;
+      //Protocol->get_collectinfo("csbib", collectinfo, err, cerr);
+      //response.numDocs = 1;
+      //ResultDocInfo_t docinfo;
+      //docinfo.metadata["foo"].values.push_back("bar");
+      getExplainInfo(rr, response, err);
+      //response.docInfo.push_back(docinfo);
+    } else {
+      cerr << "calling filter..." << endl;
+      Protocol->filter(rr->basenames[i], request, response, err, cerr);
+      cerr << "returned from filter." << endl;
+      if (response.numDocs > MAXHITS) {
+	response.numDocs = MAXHITS;
+      }
+    }
+    rr->hits += response.numDocs;
+    Response_tlist.push_back(response);
+    text_t basename = rr->basenames[i];
+    Response_tlist_colnames.push_back(basename);
+    Response_tlist_sizes.push_back(response.numDocs);
+    cerr << "search complete." << endl;
+  }    
+
+  if (rr->hits > MAXHITS) rr->hits = MAXHITS;
+  return 0;
+}
+
+// *** extra code for showing results, not needed ***
+int ztest_present (void *handle, bend_present_rr *rr)
+{
+  // *** called when client issues a "show" command, 1st of 5
+  if (z3950_verbosity_>1) {
+    cerr << "entering ztest_present" << endl;
+  }
+  return 0;
+}
+
+int ztest_esrequest (void *handle, bend_esrequest_rr *rr)
+{
+
+    if (z3950_verbosity_>1) {
+      cerr << "Entering ztest_esrequest" << endl;
+    }
+    yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
+    if (rr->esr->packageName)
+    	yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
+    yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
+
+    if (!rr->esr->taskSpecificParameters)
+    {
+        yaz_log (LOG_WARN, "No task specific parameters");
+    }
+    else if (rr->esr->taskSpecificParameters->which == Z_External_itemOrder)
+    {
+    	Z_ItemOrder *it = rr->esr->taskSpecificParameters->u.itemOrder;
+	yaz_log (LOG_LOG, "Received ItemOrder");
+	switch (it->which)
+	{
+#ifdef ASN_COMPILED
+	case Z_IOItemOrder_esRequest:
+#else
+	case Z_ItemOrder_esRequest:
+#endif
+	{
+	    Z_IORequest *ir = it->u.esRequest;
+	    Z_IOOriginPartToKeep *k = ir->toKeep;
+	    Z_IOOriginPartNotToKeep *n = ir->notToKeep;
+	    
+	    if (k && k->contact)
+	    {
+	        if (k->contact->name)
+		    yaz_log(LOG_LOG, "contact name %s", k->contact->name);
+		if (k->contact->phone)
+		    yaz_log(LOG_LOG, "contact phone %s", k->contact->phone);
+		if (k->contact->email)
+		    yaz_log(LOG_LOG, "contact email %s", k->contact->email);
+	    }
+	    if (k->addlBilling)
+	    {
+	        yaz_log(LOG_LOG, "Billing info (not shown)");
+	    }
+	    
+	    if (n->resultSetItem)
+	    {
+	        yaz_log(LOG_LOG, "resultsetItem");
+		yaz_log(LOG_LOG, "setId: %s", n->resultSetItem->resultSetId);
+		yaz_log(LOG_LOG, "item: %d", *n->resultSetItem->item);
+	    }
+#ifdef ASN_COMPILED
+	    if (n->itemRequest)
+	    {
+		Z_External *r = (Z_External*) n->itemRequest;
+		ILL_ItemRequest *item_req = 0;
+		ILL_Request *ill_req = 0;
+		if (r->direct_reference)
+		{
+		    oident *ent = oid_getentbyoid(r->direct_reference);
+		    if (ent)
+			yaz_log(LOG_LOG, "OID %s", ent->desc);
+		    if (ent && ent->value == VAL_ISO_ILL_1)
+		    {
+			yaz_log (LOG_LOG, "ItemRequest");
+			if (r->which == ODR_EXTERNAL_single)
+			{
+			    odr_setbuf(rr->decode,
+				       (char*)(r->u.single_ASN1_type->buf),
+				       r->u.single_ASN1_type->len, 0);
+			    
+			    if (!ill_ItemRequest (rr->decode, &item_req, 0, 0))
+			    {
+				yaz_log (LOG_LOG,
+                                    "Couldn't decode ItemRequest %s near %d",
+                                       odr_errmsg(odr_geterror(rr->decode)),
+                                       odr_offset(rr->decode));
+                                yaz_log(LOG_LOG, "PDU dump:");
+                                odr_dumpBER(yaz_log_file(),
+                                     (const char*)(r->u.single_ASN1_type->buf),
+                                     r->u.single_ASN1_type->len);
+                            }
+			    if (rr->print)
+			    {
+				ill_ItemRequest (rr->print, &item_req, 0,
+                                    "ItemRequest");
+				odr_reset (rr->print);
+ 			    }
+			}
+			if (!item_req && r->which == ODR_EXTERNAL_single)
+			{
+			    yaz_log (LOG_LOG, "ILLRequest");
+			    odr_setbuf(rr->decode,
+				       (char*)(r->u.single_ASN1_type->buf),
+				       r->u.single_ASN1_type->len, 0);
+			    
+			    if (!ill_Request (rr->decode, &ill_req, 0, 0))
+			    {
+				yaz_log (LOG_LOG,
+                                    "Couldn't decode ILLRequest %s near %d",
+                                       odr_errmsg(odr_geterror(rr->decode)),
+                                       odr_offset(rr->decode));
+                                yaz_log(LOG_LOG, "PDU dump:");
+                                odr_dumpBER(yaz_log_file(),
+                                     (const char*)(r->u.single_ASN1_type->buf),
+                                     r->u.single_ASN1_type->len);
+                            }
+			    if (rr->print)
+                            {
+				ill_Request (rr->print, &ill_req, 0,
+                                    "ILLRequest");
+				odr_reset (rr->print);
+			    }
+			}
+		    }
+		}
+		if (item_req)
+		{
+		    yaz_log (LOG_LOG, "ILL protocol version = %d",
+			     *item_req->protocol_version_num);
+		}
+	    }
+#endif
+	}
+	break;
+	}
+    }
+    else if (rr->esr->taskSpecificParameters->which == Z_External_update)
+    {
+    	Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
+	yaz_log (LOG_LOG, "Received DB Update");
+	if (up->which == Z_IUUpdate_esRequest)
+	{
+	    Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
+	    Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
+	    Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
+	    
+	    yaz_log (LOG_LOG, "action");
+	    if (toKeep->action)
+	    {
+		switch (*toKeep->action)
+		{
+		case Z_IUOriginPartToKeep_recordInsert:
+		    yaz_log (LOG_LOG, " recordInsert");
+		    break;
+		case Z_IUOriginPartToKeep_recordReplace:
+		    yaz_log (LOG_LOG, " recordUpdate");
+		    break;
+		case Z_IUOriginPartToKeep_recordDelete:
+		    yaz_log (LOG_LOG, " recordDelete");
+		    break;
+		case Z_IUOriginPartToKeep_elementUpdate:
+		    yaz_log (LOG_LOG, " elementUpdate");
+		    break;
+		case Z_IUOriginPartToKeep_specialUpdate:
+		    yaz_log (LOG_LOG, " specialUpdate");
+		    break;
+		default:
+		    yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
+		}
+	    }
+	    if (toKeep->databaseName)
+	    {
+		yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
+		if (!strcmp(toKeep->databaseName, "fault"))
+		{
+		    rr->errcode = 109;
+		    rr->errstring = toKeep->databaseName;
+		}
+		if (!strcmp(toKeep->databaseName, "accept"))
+		    rr->errcode = -1;
+	    }
+	    if (notToKeep)
+	    {
+		int i;
+		for (i = 0; i < notToKeep->num; i++)
+		{
+		    Z_External *rec = notToKeep->elements[i]->record;
+
+		    if (rec->direct_reference)
+		    {
+			struct oident *oident;
+			oident = oid_getentbyoid(rec->direct_reference);
+			if (oident)
+			    yaz_log (LOG_LOG, "record %d type %s", i,
+				     oident->desc);
+		    }
+		    switch (rec->which)
+		    {
+		    case Z_External_sutrs:
+			if (rec->u.octet_aligned->len > 170)
+			    yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
+				     rec->u.sutrs->len,
+				     rec->u.sutrs->buf);
+			else
+			    yaz_log (LOG_LOG, "%d bytes:\n%s",
+				     rec->u.sutrs->len,
+				     rec->u.sutrs->buf);
+                        break;
+		    case Z_External_octet        :
+			if (rec->u.octet_aligned->len > 170)
+			    yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
+				     rec->u.octet_aligned->len,
+				     rec->u.octet_aligned->buf);
+			else
+			    yaz_log (LOG_LOG, "%d bytes\n%s",
+				     rec->u.octet_aligned->len,
+				     rec->u.octet_aligned->buf);
+		    }
+		}
+	    }
+	}
+    }
+    else
+    {
+        yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
+		 rr->esr->taskSpecificParameters->which);
+	
+    }
+    return 0;
+}
+
+int ztest_delete (void *handle, bend_delete_rr *rr)
+{
+  // *** called when client issues a "delete" command
+  if (z3950_verbosity_>1) {
+    cerr << "Entering ztest_delete" << endl;
+  }
+  if (rr->num_setnames == 1 && !strcmp (rr->setnames[0], "1"))
+    rr->delete_status = Z_DeleteStatus_success;
+  else
+    rr->delete_status = Z_DeleteStatus_resultSetDidNotExist;
+  return 0;
+}
+
+// *** do we want to sort the results? ***
+/* Our sort handler really doesn't sort... */
+int ztest_sort (void *handle, bend_sort_rr *rr)
+{
+  if (z3950_verbosity_>1) {
+    cerr << "entering ztest_sort" << endl;
+  }
+  rr->errcode = 0;
+  rr->sort_status = Z_SortStatus_success;
+  return 0;
+}
+
+static int atoin (const char *buf, int n)
+{
+  // *** called when client issues a "show" command, 5th of 5
+  // *** NOT called if the "show" command has an invalid argument
+    if (z3950_verbosity_>1) {
+      cerr << "Entering atoin" << endl;
+    }
+    int val = 0;
+    while (--n >= 0)
+    {
+        if (isdigit(*buf))
+            val = val*10 + (*buf - '0');
+        buf++;
+    }
+    return val;
+}
+
+
+bool get_sutrs_record (int recnum, text_t &MetadataResult, text_t &CollectionName)
+{
+  if (z3950_verbosity_>1) {
+    cerr << "Entering get_sutrs_record" << endl;
+  }
+  int total_records = 0;
+
+  list<FilterResponse_t>::iterator RESPONSE_here = Response_tlist.begin();
+  list<FilterResponse_t>::iterator RESPONSE_end = Response_tlist.end();
+  list<text_t>::iterator RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
+  list<text_t>::iterator RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
+  list<int>::iterator RESPONSE_SIZES_here = Response_tlist_sizes.begin();
+  list<int>::iterator RESPONSE_SIZES_end = Response_tlist_sizes.end();
+
+  RESPONSE_here = Response_tlist.begin();
+  RESPONSE_end = Response_tlist.end();
+  while (RESPONSE_here != RESPONSE_end) {
+    total_records += (*RESPONSE_here).numDocs;
+    RESPONSE_here++;
+  }
+
+  // check that the index is within bounds
+  if (recnum < 1 || recnum > total_records) {
+    cerr << "get_sutrs_record failed" << endl;
+    return false; // failed
+  } else {
+    FilterResponse_t response;
+    // iterate through Response_tlist to find the right response
+    RESPONSE_here = Response_tlist.begin();
+    RESPONSE_end = Response_tlist.end();
+    RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
+    RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
+    RESPONSE_SIZES_here = Response_tlist_sizes.begin();
+    RESPONSE_SIZES_end = Response_tlist_sizes.end();
+    int n = 0;
+
+    while (RESPONSE_here != RESPONSE_end) {
+      n += *RESPONSE_SIZES_here;
+      if (n >= recnum) {
+	response = *RESPONSE_here;
+	CollectionName = *RESPONSE_COLNAMES_here;
+	recnum = *RESPONSE_SIZES_here - (n - recnum);
+	break;
+      }
+      // these should all have the same number of elements,
+      // so only need to check that one is within bounds.
+      // may want to combine these into a larger data structure later.
+      RESPONSE_here++;
+      RESPONSE_COLNAMES_here++;
+      RESPONSE_SIZES_here++;
+    }
+
+    // locate the desired record in the response 
+   
+    MetadataInfo_tmap::iterator METAFIELD_here = response.docInfo[recnum-1].metadata.begin();
+    MetadataInfo_tmap::iterator METAFIELD_end = response.docInfo[recnum-1].metadata.end();
+
+    while (METAFIELD_here!=METAFIELD_end) {
+      text_tarray::iterator METAVALUE_here = METAFIELD_here->second.values.begin();
+      text_tarray::iterator METAVALUE_end = METAFIELD_here->second.values.end();
+      while (METAVALUE_here!=METAVALUE_end) {
+	// construct a text_t containing the record:
+	// there are multiple metadata fields,
+	// each field can have multiple values.
+	/*
+	// don't include fields starting with a lowercase letter,
+	// these are system fields.
+	// later: include these anyway, since Explain fields start with lowercase letters
+	if (METAFIELD_here->first[0] >= 'A' &&
+	    METAFIELD_here->first[0] <= 'Z') {
+	*/
+	  MetadataResult += METAFIELD_here->first; // field name
+	  MetadataResult += " ";
+	  MetadataResult += *METAVALUE_here; // field contents
+	  MetadataResult += "\n";
+	  //}
+	METAVALUE_here++;
+      }
+      METAFIELD_here++;
+    }
+    return true; // succeeded
+  }
+}
+
+bool get_marc_record (int recnum, list<metatag*> &Metatag_list, text_t &CollectionName)
+{
+  if (z3950_verbosity_>1) {
+    cerr << "Entering get_marc_record" << endl;
+  }
+  int total_records = 0;
+
+  list<FilterResponse_t>::iterator RESPONSE_here = Response_tlist.begin();
+  list<FilterResponse_t>::iterator RESPONSE_end = Response_tlist.end();
+  list<text_t>::iterator RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
+  list<text_t>::iterator RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
+  list<int>::iterator RESPONSE_SIZES_here = Response_tlist_sizes.begin();
+  list<int>::iterator RESPONSE_SIZES_end = Response_tlist_sizes.end();
+
+  RESPONSE_here = Response_tlist.begin();
+  RESPONSE_end = Response_tlist.end();
+  while (RESPONSE_here != RESPONSE_end) {
+    total_records += (*RESPONSE_here).numDocs;
+    RESPONSE_here++;
+  }
+
+  // check that the index is within bounds
+  if (recnum < 1 || recnum > total_records) {
+    cerr << "get_marc_record failed" << endl;
+    return false; // failed
+  } else {
+    FilterResponse_t response;
+    // iterate through Response_tlist to find the right response
+    RESPONSE_here = Response_tlist.begin();
+    RESPONSE_end = Response_tlist.end();
+    RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
+    RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
+    RESPONSE_SIZES_here = Response_tlist_sizes.begin();
+    RESPONSE_SIZES_end = Response_tlist_sizes.end();
+    int n = 0;
+    while (RESPONSE_here != RESPONSE_end) {
+      n += *RESPONSE_SIZES_here;
+      if (n >= recnum) {
+	response = *RESPONSE_here;
+	CollectionName = *RESPONSE_COLNAMES_here;
+	recnum = *RESPONSE_SIZES_here - (n - recnum);
+	break;
+      }
+      // these should all have the same number of elements,
+      // so only need to check that one is within bounds.
+      // may want to combine these into a larger data structure later.
+      RESPONSE_here++;
+      RESPONSE_COLNAMES_here++;
+      RESPONSE_SIZES_here++;
+    }
+
+    // locate the desired record in the response
+    
+    MetadataInfo_tmap::iterator METAFIELD_here = response.docInfo[recnum-1].metadata.begin();
+    MetadataInfo_tmap::iterator METAFIELD_end = response.docInfo[recnum-1].metadata.end();
+    
+    while (METAFIELD_here!=METAFIELD_end) {
+      text_tarray::iterator METAVALUE_here = METAFIELD_here->second.values.begin();
+      text_tarray::iterator METAVALUE_end = METAFIELD_here->second.values.end();
+      while (METAVALUE_here!=METAVALUE_end) {
+	if (METAFIELD_here->first[0] >= 'A' &&
+	    METAFIELD_here->first[0] <= 'Z') {
+	  metatag *tmptag = new metatag();
+	  tmptag->name = METAFIELD_here->first.getcstr();
+	  tmptag->type = "";
+	  tmptag->scheme = "";
+	  tmptag->value = (*METAVALUE_here).getcstr();
+	  Metatag_list.push_back(tmptag);
+	}
+	METAVALUE_here++;
+      }
+      METAFIELD_here++;
+    }
+    return true; // succeeded
+  }
+}
+
+// *** implement this ***
+int ztest_fetch(void *handle, bend_fetch_rr *r)
+{
+  // *** called when client issues a "show" command, 2nd of 5
+    if (z3950_verbosity_>1) {
+      cerr << "Entering ztest_fetch" << endl;
+    }
+    char *cp;
+    r->errstring = 0;
+    r->last_in_set = 0;
+    r->basename = "DUMMY"; // this is set below
+    r->output_format = r->request_format;
+
+    // *** use this until found a good way of mapping Greenstone
+    // *** metadata fields to USMARC fields
+    if (r->request_format == VAL_SUTRS)
+    {
+      // copies record into r, errcode will be 13 if fails
+      text_t MetadataResult;
+      text_t CollectionName;
+      if (!get_sutrs_record(r->number, MetadataResult, CollectionName)) {
+	r->errcode = 13;
+	return 0;
+      } else {			
+	r->len = MetadataResult.size();
+	r->record = (char*) odr_malloc(r->stream, r->len+1);
+	char *tmptxt = MetadataResult.getcstr();
+	strcpy(r->record, tmptxt);
+	delete tmptxt;
+	r->basename = (char*) odr_malloc(r->stream, CollectionName.size()+1);
+	tmptxt = CollectionName.getcstr();
+	strcpy(r->basename, tmptxt);
+	delete tmptxt;
+      }
+    }
+    // *** do we want to use this format? ***
+    else if (r->request_format == VAL_GRS1)
+    {
+      // bail out, since we don't support grs (yet?)
+      r->errcode = 107; // "Query type not supported"
+      return 0;
+      
+    } 
+    // assume that here on in is some sort of MARC format
+    else {
+      marcrec *mrec = new marcrec;
+
+      mrec = (marcrec*) malloc(sizeof(*mrec));
+      
+      mrec->marcline = (char*) malloc(100000);
+      mrec->partitle = (char*) malloc(10000);
+      mrec->subtitle = (char*) malloc(10000);
+      mrec->year     = (char*) malloc(1000);
+      mrec->url      = (char*) malloc(1000);
+      mrec->fmat     = (char*) malloc(1000);
+      mrec->s008     = (char*) malloc(41);
+      
+      mrec->ncreators = 0;
+      mrec->ntitles   = 0;
+      *mrec->marcline = 0;
+      *mrec->subtitle = 0;
+      *mrec->partitle = 0;
+      *mrec->year     = 0;
+      *mrec->url      = 0;
+      *mrec->fmat     = 0;
+      strcpy(mrec->s008, "                                        ");
+
+      text_t CollectionName;
+      list<metatag*> Metatag_list;
+
+      if (!get_marc_record(r->number, Metatag_list, CollectionName)) {
+	r->errcode = 13;
+	return 0;
+      } else {
+	list<metatag*>::iterator METATAG_here = Metatag_list.begin();
+	list<metatag*>::iterator METATAG_end = Metatag_list.end();
+	while (METATAG_here != METATAG_end) {
+	  usMARC(*METATAG_here, mrec);
+	  METATAG_here++;
+	}
+
+	// set the date in the marc record to the current date
+	char today[32];
+	time_t d;
+	struct tm *time_struct;
+	//putenv("TZ=NFT-1DFT");
+	d = time(NULL);
+	time_struct = localtime(&d);
+	strftime(today, 16, "%y%m%d", time_struct);
+	put008(mrec->s008, today, F008_DATE_ENTERED);
+	put008(mrec->s008, "s", F008_TYPE_OF_DATE);
+
+	// to do: make this safer + more efficient
+	cp = new char[1000000];
+	char *cp2 = new char[1000000];
+	
+	switch(r->request_format) {
+	case VAL_DANMARC: {
+	  MARCtidy(mrec, cp, DANMARC);
+	  r->output_format = VAL_DANMARC;
+	  break; }
+	case VAL_FINMARC: {
+	  MARCtidy(mrec, cp, FINMARC);
+	  r->output_format = VAL_FINMARC;
+	  break; }
+	// YAZ doesn't know about ISMARC
+	/*
+	case VAL_ISMARC: {
+	  put008(mrec->s008, "k", F008_FORM_OF_PUBLICATION);
+	  MARCtidy(mrec, cp, ISMARC);
+	  r->output_format = VAL_ISMARC;
+	  break; }
+	*/
+	case VAL_NORMARC: {
+	  MARCtidy(mrec, cp, NORMARC);
+	  r->output_format = VAL_NORMARC;
+	  break; }
+	case VAL_SWEMARC: {
+	  MARCtidy(mrec, cp, SWEMARC);
+	  r->output_format = VAL_SWEMARC;
+	  break; }
+	default: {
+	  MARCtidy(mrec, cp, USMARC);
+	  r->output_format = VAL_USMARC;
+	  break; }
+	}
+	
+	sprintf(cp2, "%s", (char*) MARC2709(cp, 0, 6, 'n', 'm', ' '));
+	r->len = strlen(cp2);
+	r->record = (char*) odr_malloc(r->stream, r->len+1);
+	strcpy(r->record, cp2);     
+	r->basename = (char*) odr_malloc(r->stream, CollectionName.size()+1);
+	char *tmptxt;
+	tmptxt = CollectionName.getcstr();
+	strcpy(r->basename, tmptxt);
+	delete tmptxt;
+	delete cp2;      
+	cerr << "dumping record:`" << cp << "'" << endl;
+	delete cp;
+      }
+    }
+
+    r->errcode = 0;
+    return 0;
+}
+
+/*
+ * silly dummy-scan what reads words from a file.
+ */
+int ztest_scan(void *handle, bend_scan_rr *q)
+{
+  // *** called when client issues a "scan" command
+  if (z3950_verbosity_>1) {
+    cerr << "Entering ztest_scan" << endl;
+  }
+    
+  // bail out, since we don't support scan (yet?)
+  q->errcode = 107; // "Query type not supported"
+  return 0;
+
+    static FILE *f = 0;
+    static struct scan_entry list[200];
+    static char entries[200][80];
+    int hits[200];
+    char term[80], *p;
+    int i, pos;
+    int term_position_req = q->term_position;
+    int num_entries_req = q->num_entries;
+
+    q->errcode = 0;
+    q->errstring = 0;
+    q->entries = list;
+    q->status = BEND_SCAN_SUCCESS;
+    if (!f && !(f = fopen("dummy-words", "r")))
+    {
+	perror("dummy-words");
+	exit(1);
+    }
+    if (q->term->term->which != Z_Term_general)
+    {
+    	q->errcode = 229; /* unsupported term type */
+	return 0;
+    }
+    if (*q->step_size != 0)
+    {
+	q->errcode = 205; /*Only zero step size supported for Scan */
+	return 0;
+    }
+    if (q->term->term->u.general->len >= 80)
+    {
+    	q->errcode = 11; /* term too long */
+	return 0;
+    }
+    if (q->num_entries > 200)
+    {
+    	q->errcode = 31;
+	return 0;
+    }
+    memcpy(term, q->term->term->u.general->buf, q->term->term->u.general->len);
+    term[q->term->term->u.general->len] = '\0';
+    for (p = term; *p; p++)
+    	if (islower(*p))
+	    *p = toupper(*p);
+
+    fseek(f, 0, SEEK_SET);
+    q->num_entries = 0;
+
+    for (i = 0, pos = 0; fscanf(f, " %79[^:]:%d", entries[pos], &hits[pos]) == 2;
+	i++, pos < 199 ? pos++ : (pos = 0))
+    {
+    	if (!q->num_entries && strcmp(entries[pos], term) >= 0) /* s-point fnd */
+	{
+	    if ((q->term_position = term_position_req) > i + 1)
+	    {
+	    	q->term_position = i + 1;
+		q->status = BEND_SCAN_PARTIAL;
+	    }
+	    for (; q->num_entries < q->term_position; q->num_entries++)
+	    {
+	    	int po;
+
+		po = pos - q->term_position + q->num_entries+1; /* find pos */
+		if (po < 0)
+		    po += 200;
+
+		if (!strcmp (term, "SD") && q->num_entries == 2)
+		{
+		    list[q->num_entries].term = entries[pos];
+		    list[q->num_entries].occurrences = -1;
+		    list[q->num_entries].errcode = 233;
+		    list[q->num_entries].errstring = "SD for Scan Term";
+		}
+		else
+		{
+		    list[q->num_entries].term = entries[po];
+		    list[q->num_entries].occurrences = hits[po];
+		}
+	    }
+	}
+	else if (q->num_entries)
+	{
+	    list[q->num_entries].term = entries[pos];
+	    list[q->num_entries].occurrences = hits[pos];
+	    q->num_entries++;
+	}
+	if (q->num_entries >= num_entries_req)
+	    break;
+    }
+    if (feof(f))
+    	q->status = BEND_SCAN_PARTIAL;
+    return 0;
+}
+
+
+
+void bend_close(void *handle)
+{
+  if (z3950_verbosity_>1) {
+    cerr << "Entering bend_close" << endl;
+  }
+  delete Server;
+  delete Cservers;
+  delete Protocol;
+  if (z3950_verbosity_>1) {
+    cerr << "heap cleaned up, exiting bend_close" << endl;
+  }
+  return;
+}
+
+int main (int argc, char *argv[])
+{
+  
+  const int statserv_var =  statserv_main(argc, argv, bend_init, bend_close);
+  cerr << "statserv_main returns: " << statserv_var << endl;
+  return statserv_var;
+  
+  return 0;
+}
+
+
Index: /gsdl/trunk/src/recpt/z3950server.h
===================================================================
--- /gsdl/trunk/src/recpt/z3950server.h	(revision 15425)
+++ /gsdl/trunk/src/recpt/z3950server.h	(revision 15425)
@@ -0,0 +1,71 @@
+/**********************************************************************
+ *
+ * z3950server.h --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef Z3950SERVER_H
+#define Z3950ESRVER_H
+
+#include <string>
+#include <list>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+
+// Greenstone headers
+#include "fileutil.h"
+
+// the maximum number of hits allowed
+#define MAXHITS 10000
+
+// These globals are local to each thread: one Z39.50 connection = one thread.
+
+extern text_t gsdlhome; // this is specified externally when Greenstone is installed
+extern list<FilterResponse_t> Response_tlist; // list of response sets
+extern list<text_t> Response_tlist_colnames;  // collection names for the above
+extern list<int> Response_tlist_sizes;        // sizes (number of records) for the above
+extern z3950Server *Server;
+extern collectset *Cservers;
+extern nullproto *Protocol;
+extern map<text_t, gsdlCollection> Collection_map; // info and tools for collections
+extern map<text_t, text_t> Resultsets;             // mapping from ResultSetId to GSQuery 
+
+extern int z3950_verbosity_;
+
+bend_initresult *bend_init(bend_initrequest *q);
+void bend_close(void *handle);
+
+Z_GenericRecord *read_grs1(FILE *f, ODR o);
+
+int ztest_search (void *handle, bend_search_rr *rr);
+int ztest_sort (void *handle, bend_sort_rr *rr);
+int ztest_present (void *handle, bend_present_rr *rr);
+int ztest_esrequest (void *handle, bend_esrequest_rr *rr);
+int ztest_delete (void *handle, bend_delete_rr *rr);
+int ztest_fetch(void *handle, bend_fetch_rr *r);
+int ztest_scan(void *handle, bend_scan_rr *q);
+
+
+#endif
