Index: /gsdl/trunk/lib/Makefile.in
===================================================================
--- /gsdl/trunk/lib/Makefile.in	(revision 15417)
+++ /gsdl/trunk/lib/Makefile.in	(revision 15418)
@@ -91,19 +91,18 @@
   cfgread.h        cnfgable.h       cnfgator.h     display.h \
   fileutil.h       gsdlsitecfg.h    gsdltimes.h    gsdltools.h \
-  gsdlunicode.h    md5.h            phrases.h      text_t.h \
-  $(CORBAHEADERS)  gsdlconf.h
-
+  gsdlunicode.h    md5.h            OIDtools.h     phrases.h \
+  text_t.h         $(CORBAHEADERS)  gsdlconf.h
 
 SOURCES = \
   cfgread.cpp      cnfgable.cpp     cnfgator.cpp   display.cpp \
   fileutil.cpp     gsdlsitecfg.cpp  gsdltimes.cpp  gsdltools.cpp \
-  gsdlunicode.cpp  md5.cpp          phrases.cpp    text_t.cpp \
-  $(CORBASOURCES)
+  gsdlunicode.cpp  md5.cpp          OIDtools.cpp   phrases.cpp \
+  text_t.cpp       $(CORBASOURCES)
 
 OBJECTS = \
   cfgread.o        cnfgable.o       cnfgator.o     display.o \
   fileutil.o       gsdlsitecfg.o    gsdltimes.o    gsdltools.o \
-  gsdlunicode.o    md5.o            phrases.o      text_t.o \
-  $(CORBAOBJECTS)
+  gsdlunicode.o    md5.o            OIDtools.o     phrases.o \
+  text_t.o         $(CORBAOBJECTS)
 
 
Index: /gsdl/trunk/lib/OIDtools.cpp
===================================================================
--- /gsdl/trunk/lib/OIDtools.cpp	(revision 15418)
+++ /gsdl/trunk/lib/OIDtools.cpp	(revision 15418)
@@ -0,0 +1,164 @@
+/**********************************************************************
+ *
+ * OIDtools.cpp -- 
+ * Copyright (C) 1999-2008  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 "OIDtools.h"
+
+
+// returns (in top) the top level of OID (i.e. everything
+// up until the first dot)
+void get_top (const text_t &OID, text_t &top)
+{
+  top.clear();
+  if (OID.empty()) return;
+
+  text_t::const_iterator begin = OID.begin();
+  text_t::const_iterator end = OID.end();
+
+  top.appendrange (begin, findchar(begin, end, '.'));
+}	
+
+
+// checks if OID is top level (i.e. contains no dots)
+bool is_top (const text_t &OID)
+{
+  if (OID.empty()) return true;
+
+  text_t::const_iterator here = OID.begin();
+  text_t::const_iterator end = OID.end();
+  here = findchar (here, end, '.');
+
+  if (here == end) return true;
+  return false;
+}
+
+
+// get_parents_array loads the parents array with all the parents of the
+// document or classification specified by OID (not including OID itself)
+void get_parents_array (const text_t &OID, text_tarray &parents)
+{
+  text_t::const_iterator here = OID.begin ();
+  text_t::const_iterator end = OID.end ();
+  text_t thisparent;
+
+  while (here != end) {
+    if (*here == '.') parents.push_back(thisparent);
+    thisparent.push_back(*here);
+    ++here;
+  }
+}
+
+
+// get_parent returns the parent of the document or classification
+// specified by OID
+text_t get_parent (const text_t& OID)
+{
+  if (OID.empty() || is_top (OID)) return g_EmptyText;
+
+  text_t::const_iterator begin = OID.begin();
+  text_t::const_iterator here = (OID.end() - 1);
+
+  while (here >= begin) {
+    if (*here == '.')
+      break;
+    if (here == begin)
+      break;
+    --here;
+  }
+
+  if (here != begin) {
+    text_t parentOID;
+    parentOID.appendrange(begin, here);
+    return parentOID;
+  }
+
+  return g_EmptyText;
+}
+
+
+// takes an OID like ".2 and replaces the " with parent
+void translate_parent (text_t &OID, const text_t &parent)
+{
+  text_t::const_iterator here = OID.begin();
+  text_t::const_iterator end = OID.end();
+  text_t temp;
+
+  while (here != end) {
+    if (*here == '"') temp += parent;
+    else temp.push_back (*here);
+    ++here;
+  }
+  OID = temp;
+}
+
+
+// shrink_parent does the opposite to translate_parent
+void shrink_parent (text_t &OID)
+{
+  text_tarray tmp;
+  splitchar (OID.begin(), OID.end(), '.', tmp);
+  OID = "\"." + tmp.back();
+}
+
+
+// checks if OID uses ".fc", ".lc", ".pr", "rt", ".ns",
+// or ".ps" syntax (first child, last child, parent, root,
+// next sibling, previous sibling)
+bool needs_translating (const text_t &OID)
+{
+  if (OID.size() < 4) return false;
+
+  text_t tail = substr (OID.end()-3, OID.end());
+  if (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
+      tail == ".rt" || tail == ".ns" || tail == ".ps") return true;
+
+  return false;
+}
+
+
+// strips the ".fc", ".lc", ".pr", ".ns",
+// or ".ps" suffix from the end of OID
+void strip_suffix (text_t &OID)
+{
+  text_t tail = substr (OID.end()-3, OID.end());
+  while (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
+	 tail == ".rt" || tail == ".ns" || tail == ".ps") {
+    OID.erase (OID.end()-3, OID.end());
+    tail = substr (OID.end()-3, OID.end());
+  }
+}
+
+
+// is_child_of returns true if OID2 is a child of OID1
+bool is_child_of(const text_t &OID1, const text_t &OID2)
+{
+  text_t parent = get_parent(OID2);
+
+  while (!parent.empty()) {
+    if (parent == OID1) return true;
+    parent = get_parent(parent);
+  }
+
+  return false;
+}
Index: /gsdl/trunk/lib/OIDtools.h
===================================================================
--- /gsdl/trunk/lib/OIDtools.h	(revision 15418)
+++ /gsdl/trunk/lib/OIDtools.h	(revision 15418)
@@ -0,0 +1,68 @@
+/**********************************************************************
+ *
+ * OIDtools.h -- 
+ * Copyright (C) 1999-2008  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 OIDTOOLS_H
+#define OIDTOOLS_H
+
+#include "text_t.h"
+
+
+void get_oid (const text_t &OID, text_t &to, size_t level);
+
+// returns (in top) the top level of OID (i.e. everything
+// up until the first dot)
+void get_top (const text_t &OID, text_t &top);
+
+// checks if OID is top level (i.e. contains no dots)
+bool is_top (const text_t &OID);
+
+// get_parents_array loads the parents array with all the parents of the
+// document or classification specified by OID (not including OID itself)
+void get_parents_array (const text_t &OID, text_tarray &parents);
+
+// get_parent returns the parent of the document or classification
+// specified by OID
+text_t get_parent (const text_t& OID);
+
+// takes an OID like ".2.3 and replaces the " with parent
+void translate_parent (text_t &OID, const text_t &parent);
+
+// shrink_parent does the opposite to translate_parent
+void shrink_parent (text_t &OID);
+
+// checks if OID uses ".fc", ".lc", ".pr", ".ns",
+// or ".ps" syntax (first child, last child, parent,
+// next sibling, previous sibling)
+bool needs_translating (const text_t &OID);
+
+// strips the ".fc", ".lc", ".pr", ".ns",
+// or ".ps" suffix from the end of OID
+void strip_suffix (text_t &OID);
+
+// is_child_of returns true if OID2 is a child of OID1
+bool is_child_of(const text_t &OID1, const text_t &OID2);
+
+
+#endif
Index: /gsdl/trunk/lib/win32.mak
===================================================================
--- /gsdl/trunk/lib/win32.mak	(revision 15417)
+++ /gsdl/trunk/lib/win32.mak	(revision 15418)
@@ -71,14 +71,21 @@
 	$(COMPILE) $< 
 
-HEADERS = cfgread.h fileutil.h gsdlunicode.h text_t.h display.h gsdlconf.h \
-	  gsdlsitecfg.h gsdltimes.h gsdltools.h cnfgable.h cnfgator.h phrases.h md5.h
+HEADERS = \
+  cfgread.h        cnfgable.h       cnfgator.h     display.h \
+  fileutil.h       gsdlsitecfg.h    gsdltimes.h    gsdltools.h \
+  gsdlunicode.h    md5.h            OIDtools.h     phrases.h \
+  text_t.h         gsdlconf.h
 
-SOURCES = cfgread.cpp fileutil.cpp gsdlunicode.cpp text_t.cpp display.cpp \
-	  gsdlsitecfg.cpp gsdltimes.cpp gsdltools.cpp cnfgable.cpp cnfgator.cpp phrases.cpp \
-	md5.cpp
+SOURCES = \
+  cfgread.cpp      cnfgable.cpp     cnfgator.cpp   display.cpp \
+  fileutil.cpp     gsdlsitecfg.cpp  gsdltimes.cpp  gsdltools.cpp \
+  gsdlunicode.cpp  md5.cpp          OIDtools.cpp   phrases.cpp \
+  text_t.cpp
 
-OBJECTS = cfgread.obj fileutil.obj gsdlunicode.obj text_t.obj display.obj \
-	  gsdlsitecfg.obj gsdltimes.obj gsdltools.obj cnfgable.obj cnfgator.obj phrases.obj \
-	md5.obj
+OBJECTS = \
+  cfgread.obj      cnfgable.obj     cnfgator.obj   display.obj \
+  fileutil.obj     gsdlsitecfg.obj  gsdltimes.obj  gsdltools.obj \
+  gsdlunicode.obj  md5.obj          OIDtools.obj   phrases.obj \
+  text_t.obj
 
 all: gsdllib.lib
Index: /gsdl/trunk/src/oaiservr/Makefile.in
===================================================================
--- /gsdl/trunk/src/oaiservr/Makefile.in	(revision 15417)
+++ /gsdl/trunk/src/oaiservr/Makefile.in	(revision 15418)
@@ -97,6 +97,5 @@
 SOURCES = $(COMMONSOURCES) $(OAISOURCES)
 
-RECPTOBJECTS = ../../src/recpt/OIDtools.o \
-	../../src/recpt/nullproto.o ../../src/recpt/recptproto.o \
+RECPTOBJECTS = ../../src/recpt/nullproto.o ../../src/recpt/recptproto.o \
 	../../src/recpt/htmlutils.o ../../src/recpt/infodbclass.o \
 	../../src/recpt/cgiargs.o ../../src/recpt/cgiutils.o
Index: /gsdl/trunk/src/oaiservr/win32.mak
===================================================================
--- /gsdl/trunk/src/oaiservr/win32.mak	(revision 15417)
+++ /gsdl/trunk/src/oaiservr/win32.mak	(revision 15418)
@@ -114,5 +114,5 @@
 SOURCES = $(COMMONSOURCES) $(OAISOURCES)
 
-RECPTOBJECTS = "$(recptDir)\OIDtools.obj" "$(recptDir)\nullproto.obj" "$(recptDir)\recptproto.obj" \
+RECPTOBJECTS = "$(recptDir)\nullproto.obj" "$(recptDir)\recptproto.obj" "$(recptDir)\recptprototools.obj" \
                "$(recptDir)\htmlutils.obj" "$(recptDir)\infodbclass.obj" "$(recptDir)\cgiargs.obj" \
                "$(recptDir)\cgiutils.obj"
Index: /gsdl/trunk/src/recpt/Makefile.in
===================================================================
--- /gsdl/trunk/src/recpt/Makefile.in	(revision 15417)
+++ /gsdl/trunk/src/recpt/Makefile.in	(revision 15418)
@@ -158,5 +158,5 @@
 
 COMMONHEADERS = receptionist.h cgiwrapper.h cgiargs.h action.h browserclass.h \
-                converter.h maincfg.h cgiutils.h OIDtools.h browsetoolsclass.h \
+                converter.h maincfg.h cgiutils.h recptprototools.h browsetoolsclass.h \
 		statusaction.h pageaction.h recptproto.h \
 		pingaction.h queryaction.h documentaction.h  \
@@ -180,5 +180,5 @@
 
 COMMONSOURCES = receptionist.cpp cgiwrapper.cpp cgiargs.cpp action.cpp browserclass.cpp \
-                converter.cpp maincfg.cpp cgiutils.cpp OIDtools.cpp browsetoolsclass.cpp \
+                converter.cpp maincfg.cpp cgiutils.cpp recptprototools.cpp browsetoolsclass.cpp \
 		statusaction.cpp pageaction.cpp \
 		recptproto.cpp pingaction.cpp queryaction.cpp documentaction.cpp \
@@ -213,5 +213,5 @@
 
 COMMONOBJECTS = receptionist.o cgiwrapper.o cgiargs.o action.o browserclass.o \
-                converter.o maincfg.o cgiutils.o OIDtools.o browsetoolsclass.o \
+                converter.o maincfg.o cgiutils.o recptprototools.o browsetoolsclass.o \
 		statusaction.o pageaction.o \
 		recptproto.o pingaction.o queryaction.o documentaction.o \
@@ -394,5 +394,5 @@
 test:
 
-Z3950_OBJS = recptproto.o infodbclass.o OIDtools.o \
+Z3950_OBJS = recptproto.o recptprototools.o infodbclass.o \
 	 $(COLSERVROBJECTS) \
     ../colservr/z3950parser.o ../colservr/z3950explain.o \
Index: dl/trunk/src/recpt/OIDtools.cpp
===================================================================
--- /gsdl/trunk/src/recpt/OIDtools.cpp	(revision 15417)
+++ 	(revision )
@@ -1,367 +1,0 @@
-/**********************************************************************
- *
- * OIDtools.cpp -- 
- * Copyright (C) 1999  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 "OIDtools.h"
-#include <assert.h>
-
-// returns (in top) the top level of OID (i.e. everything
-// up until the first dot)
-void get_top (const text_t &OID, text_t &top) {
-
-  top.clear();
-  if (OID.empty()) return;
-
-  text_t::const_iterator begin = OID.begin();
-  text_t::const_iterator end = OID.end();
-
-  top.appendrange (begin, findchar(begin, end, '.'));
-}	
-
-
-// checks if OID is top level (i.e. contains no dots)
-bool is_top (const text_t &OID) {
-
-  if (OID.empty()) return true;
-
-  text_t::const_iterator here = OID.begin();
-  text_t::const_iterator end = OID.end();
-  here = findchar (here, end, '.');
-
-  if (here == end) return true;
-  return false;
-}
-
-
-// get_parents_array loads the parents array with all the parents of the
-// document or classification specified by OID (not including OID itself)
-void get_parents_array (const text_t &OID, text_tarray &parents) {
-
-  text_t::const_iterator here = OID.begin ();
-  text_t::const_iterator end = OID.end ();
-  text_t thisparent;
-
-  while (here != end) {
-    if (*here == '.') parents.push_back(thisparent);
-    thisparent.push_back(*here);
-    ++here;
-  }
-}
-
-
-// get_info does a protocol call and returns (in response) the metadata 
-// associated with OID. Metadata should be loaded with whatever
-// metadata fields are to be requested.
-
-bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
-	       const text_tset &metadata, bool getParents,
-	       recptproto *collectproto, FilterResponse_t &response, 
-	       ostream &logout) {
-
-  response.clear();
-
-  comerror_t err = noError;
-  FilterRequest_t request;
-  request.clear();
-
-  request.filterName = "NullFilter";
-  request.filterLang = lang;
-  request.filterResultOptions = FRmetadata;
-  request.getParents = getParents;
-  request.fields = metadata;
-  request.docSet.push_back (OID);
-  assert (collectproto != NULL);
-
-  collectproto->filter (collection, request, response, err, logout);
-  if (err != noError) {
-    outconvertclass text_t2ascii;
-    logout << text_t2ascii
-	   << "Error: call to filter failed for " << OID
-	   << " in OIDtools::get_info (" 
-	   << get_comerror_string (err) << ")\n";
-    return false;
-  }
-  
-  return true;
-}
-
-// overloaded, to allow "custom" filter options.
-bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
-	       const text_tset &metadata, const OptionValue_tarray &options,
-	       bool getParents,
-	       recptproto *collectproto, FilterResponse_t &response, 
-	       ostream &logout) {
-
-  response.clear();
-
-  comerror_t err = noError;
-  FilterRequest_t request;
-
-  request.filterName = "NullFilter";
-  request.filterLang = lang;
-  request.filterResultOptions = FRmetadata;
-  request.getParents = getParents;
-  request.filterOptions = options;
-  request.fields = metadata;
-  request.docSet.push_back (OID);
-
-  assert (collectproto != NULL);
-  collectproto->filter (collection, request, response, err, logout);
-  if (err != noError) {
-    outconvertclass text_t2ascii;
-    logout << text_t2ascii
-	   << "Error: call to filter failed for " << OID
-	   << " in OIDtools::get_info (" 
-	   << get_comerror_string (err) << ")\n";
-    return false;
-  }
-  
-  return true;
-}
-
-bool get_info (const text_tarray &OIDs, const text_t &collection, const text_t &lang,
-	       const text_tset &metadata, bool getParents,
-	       recptproto *collectproto, FilterResponse_t &response, 
-	       ostream &logout) {
-
-  response.clear();
-  if (OIDs.empty()) return true;
-
-  comerror_t err = noError;
-  FilterRequest_t request;
-
-  request.filterName = "NullFilter";
-  request.filterLang = lang;
-  request.filterResultOptions = FRmetadata;
-  request.getParents = getParents;
-  request.fields = metadata;
-
-  request.docSet = OIDs;
-  
-  collectproto->filter (collection, request, response, err, logout);
-  if (err != noError) {
-    outconvertclass text_t2ascii;
-    logout << text_t2ascii
-	   << "Error: call to filter failed in OIDtools::get_info (" 
-	   << get_comerror_string (err) << ")\n";
-    return false;
-  }
-
-  return true;
-}
-
-
-
-// has_children returns true if OID has children
-bool has_children (const text_t &OID, const text_t &collection, const text_t &lang,
-		   recptproto *collectproto, ostream &logout) {
-
-  FilterResponse_t response;
-  text_tset metadata;
-  metadata.insert ("haschildren");
-
-  if (get_info (OID, collection, lang, metadata, false, collectproto,	response, logout)) {
-    if (response.docInfo[0].metadata["haschildren"].values[0] == "1")
-      return true;
-  }
-  return false;
-}
-
-
-// get_children does a protocol call and returns (in response) the OIDs and 
-// metadata of all the children of OID. The metadata set should be loaded
-// with whatever metadata fields are to be requested.
-
-bool get_children (const text_t &OID, const text_t &collection, const text_t &lang,
-		   const text_tset &metadata, bool getParents,
-		   recptproto *collectproto, FilterResponse_t &response, 
-		   ostream &logout) {
-  
-  response.clear();
-
-  comerror_t err = noError;
-  FilterRequest_t request;
-  OptionValue_t option;
-
-  option.name = "ParentNode";
-  option.value = OID;
-  request.filterOptions.push_back (option);
-  request.filterName = "BrowseFilter";
-  request.filterLang = lang;
-  request.filterResultOptions = FROID;
-
-  // Efficiency improvement: only get the filter to retrieve metadata if some has been requested
-  // Otherwise, the filter makes an unnecessary request to the GDBM database for each child node
-  // By Michael Dewsnip, DL Consulting Ltd
-  if (metadata.size() > 0)
-  {
-    request.filterResultOptions |= FRmetadata;
-  }
-
-  request.fields = metadata;
-  request.getParents = getParents;
-
-  collectproto->filter (collection, request, response, err, logout);
-
-  if (err != noError) {
-    outconvertclass text_t2ascii;
-    logout << text_t2ascii
-	   << "Error: call to filter failed for " << OID 
-	   << " in OIDtools::get_children (" 
-	   << get_comerror_string (err) << ")\n";
-    return false;
-  }
-  return true;
-}
-
-// get_parent returns the parent of the document or classification
-// specified by OID
-text_t get_parent (const text_t& OID)
-{
-  if (OID.empty() || is_top (OID)) return g_EmptyText;
-
-  text_t::const_iterator begin = OID.begin();
-  text_t::const_iterator here = (OID.end() - 1);
-
-  while (here >= begin) {
-    if (*here == '.')
-      break;
-    if (here == begin)
-      break;
-    --here;
-  }
-
-  if (here != begin) {
-    text_t parentOID;
-    parentOID.appendrange(begin, here);
-    return parentOID;
-  }
-
-  return g_EmptyText;
-}
-
-// takes an OID like ".2 and replaces the " with parent
-void translate_parent (text_t &OID, const text_t &parent) {
-
-  text_t::const_iterator here = OID.begin();
-  text_t::const_iterator end = OID.end();
-  text_t temp;
-
-  while (here != end) {
-    if (*here == '"') temp += parent;
-    else temp.push_back (*here);
-    ++here;
-  }
-  OID = temp;
-}
-
-// shrink_parent does the opposite to translate_parent
-void shrink_parent (text_t &OID) {
-  
-  text_tarray tmp;
-  splitchar (OID.begin(), OID.end(), '.', tmp);
-  OID = "\"." + tmp.back();
-}
-
-// checks if OID uses ".fc", ".lc", ".pr", "rt", ".ns",
-// or ".ps" syntax (first child, last child, parent, root,
-// next sibling, previous sibling)
-bool needs_translating (const text_t &OID) {
-
-  if (OID.size() < 4) return false;
-
-  text_t tail = substr (OID.end()-3, OID.end());
-  if (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
-      tail == ".rt" || tail == ".ns" || tail == ".ps") return true;
-
-  return false;
-}
-
-// strips the ".fc", ".lc", ".pr", ".ns",
-// or ".ps" suffix from the end of OID
-void strip_suffix (text_t &OID) {
-
-  text_t tail = substr (OID.end()-3, OID.end());
-  while (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
-	 tail == ".rt" || tail == ".ns" || tail == ".ps") {
-    OID.erase (OID.end()-3, OID.end());
-    tail = substr (OID.end()-3, OID.end());
-  }
-}
-
-static void recurse_contents (ResultDocInfo_t section, const bool &is_classify, 
-			      const text_t &collection, const text_t &lang,
-			      const text_tset &metadata, 
-			      recptproto *collectproto, FilterResponse_t &response, 
-			      ostream &logout) {
-
-  int haschildren = section.metadata["haschildren"].values[0].getint();
-  const text_t &doctype = section.metadata["doctype"].values[0];
-
-  if ((haschildren == 1) && ((!is_classify) || (doctype == "classify"))) {
-    FilterResponse_t tmp;
-    bool getParents = false;
-    get_children (section.OID, collection, lang, metadata, getParents, collectproto, tmp, logout);
-    ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin();
-    ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end();
-    while (thisdoc != lastdoc) {
-      response.docInfo.push_back (*thisdoc);
-      recurse_contents (*thisdoc, is_classify, collection, lang, metadata, 
-			collectproto, response, logout);
-      ++thisdoc;
-    }
-  }
-}
-
-// get_contents returns OIDs and metadata of all contents 
-// below (and including) OID.
-void get_contents (const text_t &topOID, const bool &is_classify, 
-		   text_tset &metadata, const text_t &collection, const text_t &lang,
-		   recptproto *collectproto, FilterResponse_t &response, 
-		   ostream &logout) {
-
-  if (topOID.empty()) return;
-  response.clear();
-
-  metadata.insert ("haschildren");
-  metadata.insert ("doctype");
-
-  // get topOIDs info
-  if (get_info (topOID, collection, lang, metadata, false, collectproto, response, logout)) {
-    recurse_contents (response.docInfo[0], is_classify, collection, lang,
-		      metadata, collectproto, response, logout);
-  }
-}
-
-// is_child_of returns true if OID2 is a child of OID1
-bool is_child_of(const text_t &OID1, const text_t &OID2) {
-
-  text_t parent = get_parent(OID2);
-
-  while (!parent.empty()) {
-    if (parent == OID1) return true;
-    parent = get_parent(parent);
-  }
-  return false;
-}
Index: dl/trunk/src/recpt/OIDtools.h
===================================================================
--- /gsdl/trunk/src/recpt/OIDtools.h	(revision 15417)
+++ 	(revision )
@@ -1,105 +1,0 @@
-/**********************************************************************
- *
- * OIDtools.h -- 
- * Copyright (C) 1999  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 OIDTOOLS_H
-#define OIDTOOLS_H
-
-#include "text_t.h"
-#include "recptproto.h"
-
-void get_oid (const text_t &OID, text_t &to, size_t level);
-
-// returns (in top) the top level of OID (i.e. everything
-// up until the first dot)
-void get_top (const text_t &OID, text_t &top);
-
-// checks if OID is top level (i.e. contains no dots)
-bool is_top (const text_t &OID);
-
-// get_parents_array loads the parents array with all the parents of the
-// document or classification specified by OID (not including OID itself)
-void get_parents_array (const text_t &OID, text_tarray &parents);
-
-// get_info does a protocol call and returns (in response) the info 
-// associated with OID. Metadata should be loaded with whatever
-// metadata fields are to be requested
-bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
-	       const text_tset &metadata, bool getParents,
-	       recptproto *collectproto, FilterResponse_t &response, 
-	       ostream &logout);
-bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
-	       const text_tset &metadata, const OptionValue_tarray &options,
-	       bool getParents,
-	       recptproto *collectproto, FilterResponse_t &response, 
-	       ostream &logout);
-bool get_info (const text_tarray &OIDs, const text_t &collection, const text_t &lang,
-	       const text_tset &metadata, bool getParents,
-	       recptproto *collectproto, FilterResponse_t &response, 
-	       ostream &logout);
-
-// has_children returns true if OID has children
-bool has_children (const text_t &OID, const text_t &collection, const text_t &lang, 
-		   recptproto *collectproto, ostream &logout);
-
-// get_children does a protocol call and returns (in response) the OIDs and 
-// metadata of all the children of OID. The metadata set should be loaded
-// with whatever metadata fields are to be requested.
-bool get_children (const text_t &OID, const text_t &collection, const text_t &lang, 
-		   const text_tset &metadata, bool getParents,
-		   recptproto *collectproto, FilterResponse_t &response, 
-		   ostream &logout);
-
-// get_parent returns the parent of the document or classification
-// specified by OID
-text_t get_parent (const text_t& OID);
-
-// takes an OID like ".2.3 and replaces the " with parent
-void translate_parent (text_t &OID, const text_t &parent);
-
-// shrink_parent does the opposite to translate_parent
-void shrink_parent (text_t &OID);
-
-// checks if OID uses ".fc", ".lc", ".pr", ".ns",
-// or ".ps" syntax (first child, last child, parent,
-// next sibling, previous sibling)
-bool needs_translating (const text_t &OID);
-
-// strips the ".fc", ".lc", ".pr", ".ns",
-// or ".ps" suffix from the end of OID
-void strip_suffix (text_t &OID);
-
-// get_contents returns OIDs and metadata of all contents 
-// below (and including) OID.
-void get_contents (const text_t &topOID, const bool &is_classify, 
-		   text_tset &metadata, const text_t &collection, const text_t &lang, 
-		   recptproto *collectproto, FilterResponse_t &response, 
-		   ostream &logout);
-
-// is_child_of returns true if OID2 is a child of OID1
-bool is_child_of(const text_t &OID1, const text_t &OID2);
-
-
-#endif
Index: /gsdl/trunk/src/recpt/browseaction.cpp
===================================================================
--- /gsdl/trunk/src/recpt/browseaction.cpp	(revision 15417)
+++ /gsdl/trunk/src/recpt/browseaction.cpp	(revision 15418)
@@ -30,5 +30,5 @@
 #include "querytools.h"
 #include "browseactiontools.h"
-#include "OIDtools.h"
+#include "recptprototools.h"
 
 browseaction::browseaction(){
Index: /gsdl/trunk/src/recpt/browsetoolsclass.cpp
===================================================================
--- /gsdl/trunk/src/recpt/browsetoolsclass.cpp	(revision 15417)
+++ /gsdl/trunk/src/recpt/browsetoolsclass.cpp	(revision 15418)
@@ -28,4 +28,5 @@
 
 #include "browsetoolsclass.h"
+#include "recptprototools.h"
 #include "OIDtools.h"
 #include "gsdlunicode.h"
Index: /gsdl/trunk/src/recpt/documentaction.cpp
===================================================================
--- /gsdl/trunk/src/recpt/documentaction.cpp	(revision 15417)
+++ /gsdl/trunk/src/recpt/documentaction.cpp	(revision 15418)
@@ -27,4 +27,5 @@
 
 #include "documentaction.h"
+#include "recptprototools.h"
 #include "OIDtools.h"
 #include "querytools.h"
Index: /gsdl/trunk/src/recpt/extlinkaction.cpp
===================================================================
--- /gsdl/trunk/src/recpt/extlinkaction.cpp	(revision 15417)
+++ /gsdl/trunk/src/recpt/extlinkaction.cpp	(revision 15418)
@@ -29,5 +29,5 @@
 #include <string.h>
 #include "extlinkaction.h"
-#include "OIDtools.h"
+#include "recptprototools.h"
 #include "cgiutils.h"
 
Index: /gsdl/trunk/src/recpt/formattools.cpp
===================================================================
--- /gsdl/trunk/src/recpt/formattools.cpp	(revision 15417)
+++ /gsdl/trunk/src/recpt/formattools.cpp	(revision 15418)
@@ -26,4 +26,5 @@
 #include "formattools.h"
 #include "cgiutils.h"
+#include "recptprototools.h"
 #include "OIDtools.h"
 #include "summarise.h"
Index: /gsdl/trunk/src/recpt/historydb.cpp
===================================================================
--- /gsdl/trunk/src/recpt/historydb.cpp	(revision 15417)
+++ /gsdl/trunk/src/recpt/historydb.cpp	(revision 15418)
@@ -28,5 +28,5 @@
 #include "cgiutils.h"
 #include "recptproto.h"
-#include "OIDtools.h"
+#include "recptprototools.h"
 
 #define MAX_RECORDS 20
Index: /gsdl/trunk/src/recpt/hlistbrowserclass.cpp
===================================================================
--- /gsdl/trunk/src/recpt/hlistbrowserclass.cpp	(revision 15417)
+++ /gsdl/trunk/src/recpt/hlistbrowserclass.cpp	(revision 15418)
@@ -26,5 +26,5 @@
 #include "hlistbrowserclass.h"
 #include <assert.h>
-#include "OIDtools.h"
+#include "recptprototools.h"
 
 hlistbrowserclass::hlistbrowserclass () {
Index: /gsdl/trunk/src/recpt/pageaction.cpp
===================================================================
--- /gsdl/trunk/src/recpt/pageaction.cpp	(revision 15417)
+++ /gsdl/trunk/src/recpt/pageaction.cpp	(revision 15418)
@@ -33,7 +33,7 @@
 
 
-#include "OIDtools.h"
 #include "pageaction.h"
 #include "receptionist.h"
+#include "recptprototools.h"
 #include "fileutil.h"
 #include "gsdltools.h"
Index: /gsdl/trunk/src/recpt/pagedbrowserclass.cpp
===================================================================
--- /gsdl/trunk/src/recpt/pagedbrowserclass.cpp	(revision 15417)
+++ /gsdl/trunk/src/recpt/pagedbrowserclass.cpp	(revision 15418)
@@ -29,4 +29,5 @@
 #include "pagedbrowserclass.h"
 #include <assert.h>
+#include "recptprototools.h"
 #include "OIDtools.h"
 #include "gsdltools.h"
Index: /gsdl/trunk/src/recpt/receptionist.cpp
===================================================================
--- /gsdl/trunk/src/recpt/receptionist.cpp	(revision 15417)
+++ /gsdl/trunk/src/recpt/receptionist.cpp	(revision 15418)
@@ -29,4 +29,5 @@
 
 #include "receptionist.h"
+#include "recptprototools.h"
 #include "fileutil.h"
 #include "cgiutils.h"
Index: /gsdl/trunk/src/recpt/recptprototools.cpp
===================================================================
--- /gsdl/trunk/src/recpt/recptprototools.cpp	(revision 15418)
+++ /gsdl/trunk/src/recpt/recptprototools.cpp	(revision 15418)
@@ -0,0 +1,250 @@
+/**********************************************************************
+ *
+ * recptprototools.cpp -- 
+ * Copyright (C) 1999-2008  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 "recptprototools.h"
+#include <assert.h>
+
+
+// get_info does a protocol call and returns (in response) the metadata 
+// associated with OID. Metadata should be loaded with whatever
+// metadata fields are to be requested.
+
+bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout)
+{
+  response.clear();
+
+  comerror_t err = noError;
+  FilterRequest_t request;
+  request.clear();
+
+  request.filterName = "NullFilter";
+  request.filterLang = lang;
+  request.filterResultOptions = FRmetadata;
+  request.getParents = getParents;
+  request.fields = metadata;
+  request.docSet.push_back (OID);
+  assert (collectproto != NULL);
+
+  collectproto->filter (collection, request, response, err, logout);
+  if (err != noError)
+  {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed for " << OID
+	   << " in OIDtools::get_info (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+  
+  return true;
+}
+
+
+// overloaded, to allow "custom" filter options.
+bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, const OptionValue_tarray &options,
+	       bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout)
+{
+  response.clear();
+
+  comerror_t err = noError;
+  FilterRequest_t request;
+
+  request.filterName = "NullFilter";
+  request.filterLang = lang;
+  request.filterResultOptions = FRmetadata;
+  request.getParents = getParents;
+  request.filterOptions = options;
+  request.fields = metadata;
+  request.docSet.push_back (OID);
+
+  assert (collectproto != NULL);
+  collectproto->filter (collection, request, response, err, logout);
+  if (err != noError)
+  {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed for " << OID
+	   << " in OIDtools::get_info (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+  
+  return true;
+}
+
+
+bool get_info (const text_tarray &OIDs, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout)
+{
+  response.clear();
+  if (OIDs.empty()) return true;
+
+  comerror_t err = noError;
+  FilterRequest_t request;
+
+  request.filterName = "NullFilter";
+  request.filterLang = lang;
+  request.filterResultOptions = FRmetadata;
+  request.getParents = getParents;
+  request.fields = metadata;
+
+  request.docSet = OIDs;
+  
+  collectproto->filter (collection, request, response, err, logout);
+  if (err != noError)
+  {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed in OIDtools::get_info (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+
+  return true;
+}
+
+
+// has_children returns true if OID has children
+bool has_children (const text_t &OID, const text_t &collection, const text_t &lang,
+		   recptproto *collectproto, ostream &logout) {
+
+  FilterResponse_t response;
+  text_tset metadata;
+  metadata.insert ("haschildren");
+
+  if (get_info (OID, collection, lang, metadata, false, collectproto,	response, logout))
+  {
+    if (response.docInfo[0].metadata["haschildren"].values[0] == "1")
+    {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+// get_children does a protocol call and returns (in response) the OIDs and 
+// metadata of all the children of OID. The metadata set should be loaded
+// with whatever metadata fields are to be requested.
+
+bool get_children (const text_t &OID, const text_t &collection, const text_t &lang,
+		   const text_tset &metadata, bool getParents,
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout)
+{
+  response.clear();
+
+  comerror_t err = noError;
+  FilterRequest_t request;
+  OptionValue_t option;
+
+  option.name = "ParentNode";
+  option.value = OID;
+  request.filterOptions.push_back (option);
+  request.filterName = "BrowseFilter";
+  request.filterLang = lang;
+  request.filterResultOptions = FROID;
+
+  // Efficiency improvement: only get the filter to retrieve metadata if some has been requested
+  // Otherwise, the filter makes an unnecessary request to the GDBM database for each child node
+  // By Michael Dewsnip, DL Consulting Ltd
+  if (metadata.size() > 0)
+  {
+    request.filterResultOptions |= FRmetadata;
+  }
+
+  request.fields = metadata;
+  request.getParents = getParents;
+
+  collectproto->filter (collection, request, response, err, logout);
+
+  if (err != noError)
+  {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed for " << OID 
+	   << " in OIDtools::get_children (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+
+  return true;
+}
+
+
+static void recurse_contents (ResultDocInfo_t section, const bool &is_classify, 
+			      const text_t &collection, const text_t &lang,
+			      const text_tset &metadata, 
+			      recptproto *collectproto, FilterResponse_t &response, 
+			      ostream &logout)
+{
+  int haschildren = section.metadata["haschildren"].values[0].getint();
+  const text_t &doctype = section.metadata["doctype"].values[0];
+
+  if ((haschildren == 1) && ((!is_classify) || (doctype == "classify")))
+  {
+    FilterResponse_t tmp;
+    bool getParents = false;
+    get_children (section.OID, collection, lang, metadata, getParents, collectproto, tmp, logout);
+    ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin();
+    ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end();
+    while (thisdoc != lastdoc)
+    {
+      response.docInfo.push_back (*thisdoc);
+      recurse_contents (*thisdoc, is_classify, collection, lang, metadata, collectproto, response, logout);
+      ++thisdoc;
+    }
+  }
+}
+
+
+// get_contents returns OIDs and metadata of all contents 
+// below (and including) OID.
+void get_contents (const text_t &topOID, const bool &is_classify, 
+		   text_tset &metadata, const text_t &collection, const text_t &lang,
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout)
+{
+  if (topOID.empty()) return;
+  response.clear();
+
+  metadata.insert ("haschildren");
+  metadata.insert ("doctype");
+
+  // get topOIDs info
+  if (get_info (topOID, collection, lang, metadata, false, collectproto, response, logout))
+  {
+    recurse_contents (response.docInfo[0], is_classify, collection, lang, metadata, collectproto, response, logout);
+  }
+}
Index: /gsdl/trunk/src/recpt/recptprototools.h
===================================================================
--- /gsdl/trunk/src/recpt/recptprototools.h	(revision 15418)
+++ /gsdl/trunk/src/recpt/recptprototools.h	(revision 15418)
@@ -0,0 +1,71 @@
+/**********************************************************************
+ *
+ * recptprototools.h -- 
+ * Copyright (C) 1999-2008  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 RECPTPROTOTOOLS_H
+#define RECPTPROTOTOOLS_H
+
+
+#include "text_t.h"
+#include "recptproto.h"
+
+
+// get_info does a protocol call and returns (in response) the info 
+// associated with OID. Metadata should be loaded with whatever
+// metadata fields are to be requested
+bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout);
+bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, const OptionValue_tarray &options,
+	       bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout);
+bool get_info (const text_tarray &OIDs, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout);
+
+// has_children returns true if OID has children
+bool has_children (const text_t &OID, const text_t &collection, const text_t &lang, 
+		   recptproto *collectproto, ostream &logout);
+
+// get_children does a protocol call and returns (in response) the OIDs and 
+// metadata of all the children of OID. The metadata set should be loaded
+// with whatever metadata fields are to be requested.
+bool get_children (const text_t &OID, const text_t &collection, const text_t &lang, 
+		   const text_tset &metadata, bool getParents,
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout);
+
+// get_contents returns OIDs and metadata of all contents 
+// below (and including) OID.
+void get_contents (const text_t &topOID, const bool &is_classify, 
+		   text_tset &metadata, const text_t &collection, const text_t &lang, 
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout);
+
+
+#endif
