chiark / gitweb /
REORG Delete everything that's not innduct or build system or changed for innduct
[innduct.git] / innfeed / tape.c
diff --git a/innfeed/tape.c b/innfeed/tape.c
deleted file mode 100644 (file)
index a37f5c6..0000000
+++ /dev/null
@@ -1,1294 +0,0 @@
-/*  $Id: tape.c 6716 2004-05-16 20:26:56Z rra $
-**
-**  The implementation of the innfeed Tape class.
-**
-**  Written by James Brister <brister@vix.com>
-**
-**  The implementation of the Tape class. Tapes are read-only or write-only
-**  files that are accessed sequentially. Their basic unit of i/o is an
-**  Article. Tapes work out of a single directory and manage all file names
-**  themselves.
-**
-**  Tapes will checkpoint themselves periodically so that when innfeed exits
-**  or crashes things can restart close to where they were last. The period
-**  checkpointing is handled entirely by the Tape class, but the checkpoint
-**  period needs to be set by some external user before the first tape is
-**  created.
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <syslog.h>
-
-#if defined (HAVE_DIRENT_H)
-#include <dirent.h>
-typedef struct dirent DIRENTRY ;
-#else
-#include <sys/dir.h>
-typedef struct direct DIRENTRY ;
-#endif
-
-#ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# ifdef HAVE_SYS_TIME_H
-#  include <sys/time.h>
-# else
-#  include <time.h>
-# endif
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "article.h"
-#include "configfile.h"
-#include "endpoint.h"
-#include "tape.h"
-
-extern char *dflTapeDir;
-extern bool genHtml ;
-
-#if 0
-/* a structure for temporary storage of articles. */
-typedef struct q_e_s
-{
-    Article article ;
-    struct q_e_s *next ;
-} *QueueElem ;
-#endif
-
-/* The Tape class type. */
-struct tape_s
-{
-    /* the pathname of the file the administrator can drop in by hand. */
-    char *handFilename ;
-
-    /* the pathname of the file the Tape will read from */
-    char *inputFilename ;
-
-    /* the pathname of the file the Tape will write to. */
-    char *outputFilename ;
-
-    /* the pathname of the file used in locking */
-    char *lockFilename ;
-
-    /* the peer we're doing this for. */
-    char *peerName ;
-    
-    FILE *inFp ;                /* input FILE */
-    FILE *outFp ;               /* output FILE */
-
-    time_t lastRotated ;        /* time files last got switched */
-    bool checkNew ;             /* set bool when we need to check for
-                                   hand-crafted file. */
-    
-#if 0
-    /* the tape holds a small output queue in memory to avoid thrashing. */
-    QueueElem head ;            
-    QueueElem tail ;
-    unsigned int qLength ;             /* amount on the queue */
-#endif
-    
-    long outputSize ;           /* the current size of the output file. */
-    long lossage ;
-
-    /* the number of bytes we try to keep the output under. We actually
-       wait for the outputSize to get 10% greater than this amount before
-       shrinking the file down again. A value of zero means no limit. */
-    long outputLowLimit ;
-    long outputHighLimit ;
-    double backlogFactor ;
-    
-    bool scribbled ;            /* have we scribbled a checkpoint value in
-                                   the file. */
-    long tellpos ;              /* for input file checkpointing. */
-    bool changed ;              /* true if tape was read since last
-                                   checkpoint or start. */
-
-    /* true if articles that are output are NOT later input. */
-    bool noRotate ;     
-
-    /* true if no articles should ever be spooled */
-    bool noBacklog ;
-};
-
-
-static void checkpointTape (Tape tape) ;
-static void removeTapeGlobally (Tape tape) ;
-static void addTapeGlobally (Tape tape) ;
-static void prepareFiles (Tape tape) ;
-static void tapeCkNewFileCbk (TimeoutId id, void *d) ;
-static void tapeCheckpointCallback (TimeoutId id, void *d) ;
-#if 0
-static void flushTape (Tape tape) ;
-#endif
-static void tapesSetCheckNew (void) ;
-static void initTape (Tape nt) ;
-static void tapeCleanup (void) ;
-
-
-
-/* pathname of directory we store tape files in. */
-static char *tapeDirectory ;
-
-/* the callback ID of the checkpoint timer callback. */
-static TimeoutId checkPtId ;
-static TimeoutId ckNewFileId ;
-
-/* number of seconds between tape checkpoints. */
-static unsigned int tapeCkPtPeriod ;
-static unsigned int tapeCkNewFilePeriod ;
-
-static time_t rotatePeriod = TAPE_ROTATE_PERIOD ;
-
-/* global list of tapes so we can checkpoint them periodically */
-static Tape *activeTapes ;
-
-/* Size of the activeTapes array */
-static size_t activeTapeSize ;
-
-/* index of last element in activeTapes that's being used. */
-static size_t activeTapeIdx ;
-
-#if 0
-/* default limit of the size of output tapes. */
-static long defaultSizeLimit ;
-#endif
-
-unsigned int tapeHighwater ;
-
-bool debugShrinking = false ;
-
-extern bool talkToSelf ;        /* main.c */
-
-
-
-
-/* callback when config file is loaded */
-int tapeConfigLoadCbk (void *data)
-{
-  int rval = 1 ;
-  long iv ;
-  int bv ;
-  FILE *fp = (FILE *) data ;
-  char *dir, *p ;
-
-  if (getString (topScope,"backlog-directory",&p,NO_INHERIT))
-    {
-      dir = buildFilename(innconf->pathspool, p);
-      free(p);
-      if (tapeDirectory != NULL && strcmp (tapeDirectory,dir) != 0)
-        {
-          warn ("ME config: cannot change backlog-directory of a running"
-                " process") ;
-          free (dir) ;
-          dir = xstrdup (tapeDirectory) ;
-        }
-
-      if (!isDirectory (dir) && isDirectory (dflTapeDir))
-        {
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: definition of backlog-directory (%s) is a"
-                      " non-existant directory. Using %s",
-                      dir,dflTapeDir) ;
-          free (dir) ;
-          dir = xstrdup (dflTapeDir) ;
-        }
-      else if (!isDirectory (dir))
-        logAndExit (1,"ME config: no usable value for backlog-directory") ;
-    }
-  else if (!isDirectory (dflTapeDir))
-  {
-    logAndExit (1,"ME config: no usable value for backlog-directory") ;
-    return -1; /* not reached */
-  }
-  else
-    dir = xstrdup (dflTapeDir) ;
-  
-  if (tapeDirectory != NULL)
-    free (tapeDirectory) ;
-  tapeDirectory = dir ;
-
-
-  
-  if (getInteger (topScope,"backlog-highwater",&iv,NO_INHERIT))
-    {
-      if (iv < 0)
-        {
-          rval = 0 ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: value of %s (%ld) in %s cannot be less"
-                      " than 0. Using %ld","backlog-highwater",
-                      iv,"global scope",(long)TAPE_HIGHWATER);
-          iv = TAPE_HIGHWATER ;
-        }
-    }
-  else
-    iv = TAPE_HIGHWATER ;
-  tapeHighwater = (unsigned int) iv ;
-
-
-  
-  if (getInteger (topScope,"backlog-rotate-period",&iv,NO_INHERIT))
-    {
-      if (iv < 0)
-        {
-          rval = 0 ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: value of %s (%ld) in %s cannot be less"
-                      " than 0. Using %ld",
-                      "backlog-rotate-period",
-                      iv,"global scope",(long)TAPE_ROTATE_PERIOD);
-          iv = TAPE_ROTATE_PERIOD ;
-        }
-    }
-  else
-    iv = TAPE_ROTATE_PERIOD ;
-  rotatePeriod = (unsigned int) iv ;
-
-
-  if (getInteger (topScope,"backlog-ckpt-period",&iv,NO_INHERIT))
-    {
-      if (iv < 0)
-        {
-          rval = 0 ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: value of %s (%ld) in %s cannot be less"
-                      " than 0. Using %ld",
-                      "backlog-ckpt-period",iv,
-                      "global scope",(long)TAPE_CHECKPOINT_PERIOD);
-          iv = TAPE_CHECKPOINT_PERIOD ;
-        }
-    }
-  else
-    iv = TAPE_CHECKPOINT_PERIOD ;
-  tapeCkPtPeriod = (unsigned int) iv ;
-
-
-  if (getInteger (topScope,"backlog-newfile-period",&iv,NO_INHERIT))
-    {
-      if (iv < 0)
-        {
-          rval = 0 ;
-          logOrPrint (LOG_ERR,fp,
-                      "ME config: value of %s (%ld) in %s cannot be less"
-                      " than 0. Using %ld",
-                      "backlog-newfile-period",
-                      iv,"global scope",(long)TAPE_NEWFILE_PERIOD);
-          iv = TAPE_NEWFILE_PERIOD ;
-        }
-    }
-  else
-    iv = TAPE_NEWFILE_PERIOD ;
-  tapeCkNewFilePeriod = (unsigned int) iv ;
-
-
-  if (getBool (topScope,"debug-shrinking",&bv,NO_INHERIT))
-    debugShrinking = (bv ? true : false) ;
-  
-  return rval ;
-}
-
-
-/* Create a new Tape object. There are three potential files involved in
-   I/O. 'peerName' is what  the admin may have dropped in by
-   hand. 'peerName.input' is the file that was being used as input the last
-   time things were run. 'peerName.output' is the file that was being used
-   as output. The file 'peerName' is appended to 'peerName.input' (or
-   renamed if 'peerName.input' doesn't exist). Then 'peerName.output' is
-   appeneded (or renamed) to 'peerName.input' */
-
-static bool inited = false ;
-Tape newTape (const char *peerName, bool dontRotate)
-{
-  Tape nt = xmalloc (sizeof(struct tape_s)) ;
-  size_t pLen = strlen (peerName) ;
-  size_t dLen = strlen (tapeDirectory) ;
-
-  if (!inited)
-    {
-      inited = true ;
-      atexit (tapeCleanup) ;
-    }
-  
-  ASSERT (nt != NULL) ;
-
-  if (endsIn (peerName,INPUT_TAIL))
-    die ("Sorry, can't have a peer name ending in \"%s\"",INPUT_TAIL) ;
-
-  if (endsIn (peerName,OUTPUT_TAIL))
-    die ("Sorry, can't have a peer name ending in \"%s\"",OUTPUT_TAIL) ;
-
-  if (endsIn (peerName,LOCK_TAIL))
-    die ("Sorry, can't have a peer name ending in \"%s\"",LOCK_TAIL) ;
-
-  nt->peerName = xstrdup (peerName) ;
-  
-  nt->handFilename = xmalloc (pLen + dLen + 2) ;
-  sprintf (nt->handFilename,"%s/%s",tapeDirectory,peerName) ;
-
-  nt->lockFilename = xmalloc (pLen + dLen + strlen(LOCK_TAIL) + 2) ;
-  sprintf (nt->lockFilename,"%s/%s%s",tapeDirectory,peerName,LOCK_TAIL) ;
-
-  nt->inputFilename = xmalloc (pLen + dLen + strlen(INPUT_TAIL) + 2) ;
-  sprintf (nt->inputFilename,"%s/%s%s",tapeDirectory,peerName,INPUT_TAIL) ;
-
-  nt->outputFilename = xmalloc (pLen + dLen + strlen(OUTPUT_TAIL) + 2) ;
-  sprintf (nt->outputFilename,"%s/%s%s",tapeDirectory,peerName,OUTPUT_TAIL) ;
-
-  if ( !lockFile (nt->lockFilename) )
-    {
-      warn ("ME lock failed for host: %s", nt->lockFilename) ;
-      
-      free (nt->handFilename) ;
-      free (nt->lockFilename) ;
-      free (nt->inputFilename) ;
-      free (nt->outputFilename) ;
-      free (nt) ;
-
-      return NULL ;
-    }
-
-  nt->noRotate = false ;        /* for first time prepare */
-  initTape (nt) ;
-  nt->noRotate = dontRotate ;
-
-  addTapeGlobally (nt) ;
-
-  if (checkPtId == 0 && tapeCkPtPeriod > 0)     /* only done once. */
-    checkPtId = prepareSleep (tapeCheckpointCallback,tapeCkPtPeriod,NULL);
-
-  if (ckNewFileId == 0 && tapeCkNewFilePeriod > 0)
-    ckNewFileId = prepareSleep (tapeCkNewFileCbk,tapeCkNewFilePeriod,NULL) ;
-
-  return nt ;
-}
-
-static void initTape (Tape nt)
-{
-  value *peerVal = findPeer (nt->peerName) ;
-  scope *s = (peerVal == NULL ? NULL : peerVal->v.scope_val) ;
-
-  nt->inFp = NULL ;
-  nt->outFp = NULL ;
-
-  nt->lastRotated = 0 ;
-  nt->checkNew = false ;
-  
-#if 0
-  nt->head = NULL ;
-  nt->tail = NULL ;
-  nt->qLength = 0 ;
-#endif
-
-  nt->scribbled = false ;
-  nt->tellpos = 0 ;
-
-  nt->changed = false ;
-  
-  nt->outputSize = 0 ;
-  nt->lossage = 0 ;
-
-  nt->noBacklog = false ;
-  nt->backlogFactor = 0.0 ;
-  nt->outputLowLimit = 0 ;
-  nt->outputHighLimit = 0 ;
-
-  if (!talkToSelf)
-    {
-      int bval ;
-
-      if (getBool (s, "no-backlog", &bval, INHERIT))
-        nt->noBacklog = (bval ? true : false);
-      else
-        nt->noBacklog = TAPE_DISABLE;
-
-      if (getInteger (s,"backlog-limit",&nt->outputLowLimit,INHERIT))
-        {
-          if (!getReal (s,"backlog-factor",&nt->backlogFactor,INHERIT))
-            {
-              if (!getInteger (s,"backlog-limit-highwater",
-                               &nt->outputHighLimit,INHERIT))
-                {
-                  warn ("%s no backlog-factor or backlog-high-limit",
-                        nt->peerName) ;
-                  nt->outputLowLimit = 0 ;
-                  nt->outputHighLimit = 0 ;
-                  nt->backlogFactor = 0.0 ;
-                }
-            }
-          else
-            nt->outputHighLimit = (long)(nt->outputLowLimit * nt->backlogFactor);
-        }
-      else
-        warn ("ME config: no definition for required key backlog-limit") ;
-    }
-  
-  d_printf (1, "%s spooling: %s\n", nt->peerName, 
-          nt->noBacklog ? "disabled" : "enabled");
-
-  d_printf (1,"%s tape backlog limit: [%ld %ld]\n",nt->peerName,
-           nt->outputLowLimit,
-           nt->outputHighLimit) ;
-  
-  prepareFiles (nt) ;
-}
-
-
-void gFlushTapes (void)
-{
-  unsigned int i ;
-
-  notice ("ME flushing tapes") ;
-  for (i = 0 ; i < activeTapeIdx ; i++)
-    tapeFlush (activeTapes [i]) ;
-}
-
-
-
-/* close the input and output tapes and reinitialize everything in the
-  tape. */
-void tapeFlush (Tape tape)
-{
-  if (tape->inFp != NULL)
-    {
-      checkpointTape (tape) ;
-      fclose (tape->inFp) ;
-    }
-
-  if (tape->outFp != NULL)
-    fclose (tape->outFp) ;
-
-  initTape (tape) ;
-}
-
-
-
-void gPrintTapeInfo (FILE *fp, unsigned int indentAmt)
-{
-  char indent [INDENT_BUFFER_SIZE] ;
-  unsigned int i ;
-  
-  for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
-    indent [i] = ' ' ;
-  indent [i] = '\0' ;
-
-  fprintf (fp,"%sGlobal Tape List : (count %lu) {\n",
-           indent,(unsigned long) activeTapeIdx) ;
-
-  for (i = 0 ; i < activeTapeIdx ; i++)
-    printTapeInfo (activeTapes [i],fp,indentAmt + INDENT_INCR) ;
-  fprintf (fp,"%s}\n",indent) ;
-}
-
-
-void tapeLogGlobalStatus (FILE *fp)
-{
-  fprintf (fp,"%sBacklog file global values:%s\n",
-           genHtml ? "<B>" : "", genHtml ? "</B>" : "") ;
-  fprintf (fp,"        directory: %s\n",tapeDirectory) ;
-  fprintf (fp,"    rotate period: %-3ld seconds\n",(long) rotatePeriod) ;
-  fprintf (fp,"checkpoint period: %-3ld seconds\n",(long) tapeCkPtPeriod) ;
-  fprintf (fp,"   newfile period: %-3ld seconds\n",(long) tapeCkNewFilePeriod);
-  fprintf (fp,"\n") ;
-}
-
-
-void tapeLogStatus (Tape tape, FILE *fp)
-{
-  if (tape == NULL)
-    fprintf (fp,"(no tape)\n") ;
-  else if (tape->noBacklog)
-      fprintf (fp,"                 spooling: DISABLED\n");
-  else if (tape->outputLowLimit == 0)
-      fprintf (fp,"                 spooling: UNLIMITED\n");
-  else 
-    {
-      fprintf (fp,"                 backlog low limit: %ld\n",
-               tape->outputLowLimit) ;
-      fprintf (fp,"               backlog upper limit: %ld",
-               tape->outputHighLimit) ;
-      if (tape->backlogFactor > 0.0)
-        fprintf (fp," (factor %1.2f)",tape->backlogFactor) ;
-      fputc ('\n',fp) ;
-      fprintf (fp,"                 backlog shrinkage: ") ;
-      fprintf (fp,"%ld bytes (from current file)\n",tape->lossage) ;
-    }
-}
-
-void printTapeInfo (Tape tape, FILE *fp, unsigned int indentAmt)
-{
-  char indent [INDENT_BUFFER_SIZE] ;
-  unsigned int i ;
-#if 0
-  QueueElem qe ;
-#endif
-  
-  for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
-    indent [i] = ' ' ;
-  indent [i] = '\0' ;
-
-  fprintf (fp,"%sTape : %p {\n",indent,(void *) tape) ;
-
-  if (tape == NULL)
-    {
-      fprintf (fp,"%s}\n",indent) ;
-      return ;
-    }
-  
-  fprintf (fp,"%s    master-file : %s\n", indent, tape->handFilename) ;
-  fprintf (fp,"%s    input-file : %s\n", indent, tape->inputFilename) ;
-  fprintf (fp,"%s    output-file : %s\n",indent, tape->outputFilename) ;
-  fprintf (fp,"%s    lock-file : %s\n",indent, tape->lockFilename) ;
-  fprintf (fp,"%s    peerName : %s\n",indent,tape->peerName) ;
-  fprintf (fp,"%s    input-FILE : %p\n",indent, (void *) tape->inFp) ;
-  fprintf (fp,"%s    output-FILE : %p\n",indent, (void *) tape->outFp) ;
-  fprintf (fp,"%s    output-limit : %ld\n",indent, tape->outputLowLimit) ;
-
-#if 0
-  fprintf (fp,"%s    in-memory article queue (length  %d) {\n",indent,
-           tape->qLength) ;
-
-  for (qe = tape->head ; qe != NULL ; qe = qe->next)
-    {
-#if 0
-      printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
-#else
-      fprintf (fp,"%s    %p\n",indent,qe->article) ;
-#endif
-    }
-
-  fprintf (fp,"%s    }\n",indent) ;
-#endif
-
-  fprintf (fp,"%s    tell-position : %ld\n",indent,(long) tape->tellpos) ;
-  fprintf (fp,"%s    input-FILE-changed : %s\n",indent,
-           boolToString (tape->changed)) ;
-
-  fprintf (fp,"%s    no-rotate : %s\n",indent, boolToString (tape->noRotate));
-  
-  fprintf (fp,"%s}\n",indent) ;
-}
-
-
-
-
-/* delete the tape. Spools the in-memory articles to disk. */
-void delTape (Tape tape)
-{
-  struct stat st ;
-  
-  if (tape == NULL)
-    return ;
-
-#if 1
-  
-  if (tape->outFp != NULL && fclose (tape->outFp) != 0)
-    syswarn ("ME ioerr fclose %s", tape->outputFilename) ;
-
-  if (stat(tape->outputFilename, &st) == 0 && st.st_size == 0)
-    {
-      d_printf (1,"removing empty output tape: %s\n",tape->outputFilename) ;
-      unlink (tape->outputFilename) ;
-    }
-  
-  tape->outFp = NULL ;
-  tape->outputSize = 0 ;
-
-#else
-  
-  tapeClose (tape) ;
-
-#endif
-
-  if (tape->inFp != NULL)
-    {
-      checkpointTape (tape) ;
-      fclose (tape->inFp) ;
-    }
-
-  unlockFile (tape->lockFilename) ;
-
-  freeCharP (tape->handFilename) ;
-  freeCharP (tape->inputFilename) ;
-  freeCharP (tape->outputFilename) ;
-  freeCharP (tape->lockFilename) ;
-  freeCharP (tape->peerName) ;
-             
-  removeTapeGlobally (tape) ;
-  
-  free (tape) ;
-}
-
-
-void tapeTakeArticle (Tape tape, Article article)
-{
-#if 0
-  QueueElem elem ;
-#endif
-  int amt ;
-  const char *fname, *msgid ;
-
-  ASSERT (tape != NULL) ;
-
-  /* return immediately if spooling disabled - jgarzik */
-  if (tape->noBacklog)
-    {
-      delArticle (article) ;
-      return;
-    }
-
-  fname = artFileName (article) ;
-  msgid = artMsgId (article) ;
-  amt = fprintf (tape->outFp,"%s %s\n", fname, msgid) ;
-
-  /* I'd rather know where I am each time, and I don't trust all
-    fprintf's to give me character counts. */
-#if defined (TRUST_FPRINTF)
-
-  tape->outputSize += amt ;
-
-#else
-#if defined (NO_TRUST_STRLEN)
-
-  tape->outputSize = ftello (tape->outFp) ;
-
-#else
-
-  tape->outputSize += strlen(fname) + strlen(msgid) + 2 ; /* " " + "\n" */
-
-#endif
-#endif
-  
-  delArticle (article) ;
-
-  if (debugShrinking)
-    {
-      struct stat sb ;
-
-      fflush (tape->outFp) ;
-      
-      if (fstat (fileno (tape->outFp),&sb) != 0)
-        syswarn ("ME oserr fstat %s",tape->outputFilename) ;
-      else if (sb.st_size != tape->outputSize) 
-        syslog (LOG_ERR,"fstat and ftello do not agree: %ld %ld for %s\n",
-                (long)sb.st_size,tape->outputSize,tape->outputFilename) ;
-    }
-  
-  if (tape->outputHighLimit > 0 && tape->outputSize >= tape->outputHighLimit)
-    {
-      long oldSize = tape->outputSize ;
-      shrinkfile (tape->outFp,tape->outputLowLimit,tape->outputFilename,"a+");
-      tape->outputSize = ftello (tape->outFp) ;
-      tape->lossage += oldSize - tape->outputSize ;
-    }
-}
-
-
-/* Pick an article off a tape and return it. NULL is returned if there
-   are no more articles. */
-Article getArticle (Tape tape)
-{
-  char line [2048] ;            /* ick. 1024 for filename + 1024 for msgid */
-  char *p, *q ;
-  char *msgid, *filename ;
-  Article art = NULL ;
-  time_t now = theTime() ;
-
-  ASSERT (tape != NULL) ;
-
-  if (tape->inFp == NULL && (now - tape->lastRotated) > rotatePeriod)
-    prepareFiles (tape) ;       /* will flush queue too. */
-
-  while (tape->inFp != NULL && art == NULL)
-    {
-      tape->changed = true ;
-      
-      if (fgets (line,sizeof (line), tape->inFp) == NULL)
-        {
-          if (ferror (tape->inFp))
-            syswarn ("ME ioerr on tape file %s", tape->inputFilename) ;
-          else if ( !feof (tape->inFp) )
-            syswarn ("ME oserr fgets %s", tape->inputFilename) ;
-          
-          if (fclose (tape->inFp) != 0)
-            syswarn ("ME ioerr fclose %s", tape->inputFilename) ;
-
-          d_printf (1,"No more articles on tape %s\n",tape->inputFilename) ;
-
-          tape->inFp = NULL ;
-          tape->scribbled = false ;
-
-          unlink (tape->inputFilename) ;
-
-          if ((now - tape->lastRotated) > rotatePeriod)
-            prepareFiles (tape) ; /* rotate files to try next. */
-        }
-      else
-        {
-          msgid = filename = NULL ;
-          
-          for (p = line ; *p && CTYPE(isspace, *p) ; p++) /* eat whitespace */
-            /* nada */ ;
-
-          if (*p != '\0')
-            {
-              q = strchr (p,' ') ;
-
-              if (q != NULL)
-                {
-                  filename = p ;
-                  *q = '\0' ;
-      
-                  for (q++ ; *q && CTYPE(isspace, *q) ; q++)
-                    /* nada */ ;
-
-                  if (*q != '\0')
-                    {
-                      if (((p = strchr (q, ' ')) != NULL) ||
-                          ((p = strchr (q, '\n')) != NULL))
-                        *p = '\0' ;
-
-                      if (p != NULL)
-                        msgid = q ;
-                      else
-                        filename = NULL ; /* no trailing newline or blank */
-                    }
-                  else
-                    filename = NULL ; /* line had one field and some blanks */
-                }
-              else
-                filename = NULL ; /* line only had one field */
-            }
-
-          /* See if message ID looks valid. */
-          if (msgid) {
-            for (p = msgid; *p; p++)
-              ;
-            if (p > msgid) p--;
-            if (*msgid != '<' || *p != '>') {
-              warn ("ME tape invalid messageID in %s: %s",
-                    tape->inputFilename,msgid);
-              msgid = NULL;
-            }
-          }
-
-          if (filename != NULL && msgid != NULL)
-            art = newArticle (filename, msgid) ;
-
-          /* art may be NULL here if the file is no longer valid. */
-        }
-    }
-  
-#if 0
-  /* now we either have an article or there is no more on disk */
-  if (art == NULL)
-    {
-      if (tape->inFp != NULL && ((c = fgetc (tape->inFp)) != EOF))
-        ungetc (c,tape->inFp) ; /* shouldn't happen */
-      else if (tape->inFp != NULL)
-        {
-          /* last article read was the end of the tape. */
-          if (fclose (tape->inFp) != 0)
-            syswarn ("ME ioerr fclose %s", tape->inputFilename) ;
-          
-          tape->inFp = NULL ;
-          tape->scribbled = false ;
-          
-          /* toss out the old input file and prepare the new one */
-          unlink (tape->inputFilename) ;
-          
-          if (now - tape->lastRotated > rotatePeriod)
-            prepareFiles (tape) ;
-        }
-    }
-#endif
-  
-  if (art == NULL)
-    d_printf (2,"%s All out of articles in the backlog\n", tape->peerName) ;
-  else
-    d_printf (2,"%s Peeled article %s from backlog\n",tape->peerName,
-             artMsgId (art)) ;
-      
-  return art ;
-}
-
-
-/****************************************************/
-/**                  CLASS FUNCTIONS               **/
-/****************************************************/
-
-/* Cause all the Tapes to checkpoint themselves. */
-void checkPointTapes (void)
-{
-  unsigned int i ;
-
-  for (i = 0 ; i < activeTapeIdx ; i++)
-    checkpointTape (activeTapes [i]) ;
-}
-
-
-/* make all the tapes set their checkNew flag. */
-static void tapesSetCheckNew (void) 
-{
-  unsigned int i ;
-
-  for (i = 0 ; i < activeTapeIdx ; i++)
-    activeTapes[i]->checkNew = true ;
-}
-
-
-#if 0
-/* Set the pathname of the directory for storing tapes in. */
-void setTapeDirectory (const char *newDir)
-{
-  /* the activeTape variable gets set when the first Tape object
-     is created */
-  if (activeTapes != NULL)
-    {
-      syslog (LOG_CRIT,"Resetting backlog directory") ;
-      abort() ;
-    }
-  
-  if (tapeDirectory != NULL)
-    freeCharP (tapeDirectory) ;
-  
-  tapeDirectory = xstrdup (newDir) ;
-
-  addPointerFreedOnExit (tapeDirectory) ;
-}
-#endif
-
-/* Get the pathname of the directory tapes are stored in. */
-const char *getTapeDirectory (void)
-{
-  ASSERT (tapeDirectory != NULL) ;
-
-#if 0
-  if (tapeDirectory == NULL)
-    {
-      tapeDirectory = xstrdup (dflTapeDir) ;
-      addPointerFreedOnExit (tapeDirectory) ;
-    }
-#endif
-  
-  return tapeDirectory ;
-}
-
-
-#if 0
-void setOutputSizeLimit (long val)
-{
-  defaultSizeLimit = val ;
-}
-#endif
-
-
-
-
-
-
-/**********************************************************************/
-/*                          PRIVATE FUNCTIONS                         */
-/**********************************************************************/
-
-
-/* Add a new tape to the class-level list of active tapes.  */
-static void addTapeGlobally (Tape tape)
-{
-  ASSERT (tape != NULL) ;
-  
-  if (activeTapeSize == activeTapeIdx)
-    {
-      unsigned int i ;
-      
-      activeTapeSize += 10 ;
-      if (activeTapes != NULL)
-        activeTapes = xrealloc (activeTapes, sizeof(Tape) * activeTapeSize) ;
-      else
-        activeTapes = xmalloc (sizeof(Tape) * activeTapeSize) ;
-
-      for (i = activeTapeIdx ; i < activeTapeSize ; i++)
-        activeTapes [i] = NULL ;
-    }
-  activeTapes [activeTapeIdx++] = tape ;
-}
-
-
-/* Remove a tape for the class-level list of active tapes. */
-static void removeTapeGlobally (Tape tape)
-{
-  unsigned int i ;
-
-  if (tape == NULL)
-    return ;
-  
-  ASSERT (activeTapeIdx > 0) ;
-  
-  for (i = 0 ; i < activeTapeIdx ; i++)
-    if (activeTapes [i] == tape)
-      break ;
-
-  ASSERT (i < activeTapeIdx) ;
-
-  for ( ; i < (activeTapeIdx - 1) ; i++)
-    activeTapes [i] = activeTapes [i + 1] ;
-
-  activeTapes [--activeTapeIdx] = NULL ;
-
-  if (activeTapeIdx == 0)
-    {
-      free (activeTapes) ;
-      activeTapes = NULL ;
-    }
-}
-
-
-/* Have a tape checkpoint itself so that next process can pick up where
-   this one left off. */
-static void checkpointTape (Tape tape)
-{
-  if (tape->inFp == NULL)       /* no input file being read. */
-    return ;
-
-  if (!tape->changed)   /* haven't read since last checkpoint */
-    {
-      d_printf (1,"Not checkpointing unchanged tape: %s\n", tape->peerName) ;
-      return ;
-    }
-  
-  if ((tape->tellpos = ftello (tape->inFp)) < 0)
-    {
-      syswarn ("ME oserr ftello %s", tape->inputFilename) ;
-      return ;
-    }
-
-  /* strlen of "18446744073709551616\n" (2^64) */
-#define BITS64 21
-
-  /* make sure we're not right at the beginning of the file so we can write. */
-  if (tape->tellpos > BITS64)
-    {
-      rewind (tape->inFp) ;
-
-      /* scribble blanks over the first lines characters */
-      if (!tape->scribbled) 
-        {
-          int currloc = 0 ;
-          int c ;
-
-          while ((c = fgetc (tape->inFp)) != '\n' || currloc <= BITS64)
-            if (c == EOF)
-              return ;
-            else
-              currloc++ ;
-
-          rewind (tape->inFp) ;
-          
-          while (currloc-- > 0)
-            fputc (' ',tape->inFp) ;
-
-          rewind (tape->inFp) ;
-
-          fflush (tape->inFp) ;
-          tape->scribbled = true ;
-        }
-      
-      fprintf (tape->inFp,"%ld",tape->tellpos) ;
-
-      if (fseeko (tape->inFp,tape->tellpos,SEEK_SET) != 0)
-        syswarn ("ME oserr fseeko(%s,%ld,SEEK_SET)",tape->inputFilename,
-                 tape->tellpos) ;
-    }
-  
-  tape->changed = false ;
-}
-
-
-
-/* Prepare the tape file(s) for input and output */
-
-/* For a given Tape there are
- * three possible files: PEER.input PEER and
- * PEER.output. PEER.input and PEER.output are private to
- * innfeed. PEER is where a sysadmin can drop a file that (s)he
- * wants to inject into the process. If the first line of the input file
- * contains only an integer (possibly surrounded by spaces), then this is
- * taken to be the position to seek to before reading.
- *
- * prepareFiles will process them in a manner much like the following shell
- * commands:
- *
- * if [ ! -f PEER.input ]; then
- *     if [ -f PEER ]; then mv PEER PEER.input
- *     elif [ -f PEER.output ]; then mv PEER.output PEER; fi
- * fi
- *
- * At this point PEER.input is opened for reading if it exists.
- *
- * The checkpoint file is left as-is unless the PEER.input file
- * happens to be newer that the checkpoint file.
- */
-static void prepareFiles (Tape tape)
-{
-  bool inpExists ;
-  bool outExists ;
-  bool newExists ;
-
-#if 0
-  /* flush any in memory articles to disk */
-  if (tape->head != NULL && tape->outFp != NULL)
-    flushTape(tape) ;
-#endif
-
-  tape->tellpos = 0 ;
-
-  /*  First time through, or something external has set checkNew */
-  if (tape->lastRotated == 0 || tape->checkNew)
-    {
-      newExists = fileExistsP (tape->handFilename) ;
-      if (newExists)
-        notice ("%s new hand-prepared backlog file", tape->peerName) ;
-    }
-  else
-    newExists = false ;
-  
-  if (tape->lastRotated == 0)    /* first time here */
-    {
-      inpExists = fileExistsP (tape->inputFilename) ;
-      outExists = fileExistsP (tape->outputFilename) ;
-    }
-  else
-    {
-      inpExists = (tape->inFp != NULL) ? true : false ; /* can this ever be true?? */
-      outExists = (tape->outFp != NULL && tape->outputSize > 0) ? true : false ;
-    }
-  
-
-  /* move the hand-dropped file to the input file if needed. */
-  if (newExists && !inpExists)
-    {
-      if (rename (tape->handFilename,tape->inputFilename) != 0)
-        syswarn ("ME oserr rename %s, %s", tape->handFilename,
-                 tape->inputFilename);
-      else
-        {
-          notice ("%s grabbing external tape file", tape->peerName) ;
-          inpExists = true ;
-        }
-    }
-  
-  /* now move the output file to the input file, if needed and only if in
-     not in NOROTATE mode. */
-  if (outExists && !inpExists && !tape->noRotate)
-    {
-      if (tape->outFp != NULL)
-        {
-          fclose (tape->outFp) ;
-          tape->outFp = NULL ;
-        }
-      
-      if (rename (tape->outputFilename,tape->inputFilename) != 0)
-        syswarn ("ME oserr rename %s, %s", tape->outputFilename,
-                 tape->inputFilename) ;
-      else
-        inpExists = true ;
-
-      outExists = false ;
-    }
-
-  /* now open up the input file and seek to the proper position. */
-  if (inpExists)
-    {
-      int c ;
-      long flength ;
-      
-      if ((tape->inFp = fopen (tape->inputFilename,"r+")) == NULL)
-        syswarn ("ME fopen %s", tape->inputFilename) ;
-      else
-        {
-          char buffer [64] ;
-
-          if (fgets (buffer,sizeof (buffer) - 1, tape->inFp) == NULL)
-            {
-              if (feof (tape->inFp))
-                {
-                  d_printf (1,"Empty input file: %s\n",tape->inputFilename) ;
-                  unlink (tape->inputFilename) ;
-                }
-              else
-                syswarn ("ME oserr fgets %s", tape->inputFilename) ;
-              
-              fclose (tape->inFp) ;
-              tape->inFp = NULL ;
-              tape->scribbled = false ;
-            }
-          else
-            {
-              unsigned int len = strlen (buffer) ;
-              long newPos = 0 ;
-
-              if (len > 0 && buffer [len - 1] == '\n')
-                buffer [--len] = '\0' ;
-
-              if (len > 0 && strspn (buffer,"0123456789 \n") == len)
-                {
-                  if (sscanf (buffer,"%ld",&newPos) == 1)
-                    {
-                      tape->scribbled = true ;
-                      tape->tellpos = newPos ;
-                    }
-                }
-
-              if ((flength = fileLength (fileno (tape->inFp))) < tape->tellpos)
-                {
-                  warn ("ME tape short: %s %ld %ld", tape->inputFilename,
-                        flength, tape->tellpos) ;
-                  tape->tellpos = 0 ;
-                }
-              else if (tape->tellpos == 0)
-                rewind (tape->inFp) ;
-              else if (fseeko (tape->inFp,tape->tellpos - 1,SEEK_SET) != 0)
-                syswarn ("ME oserr fseeko(%s,%ld,SEEK_SET)",
-                         tape->inputFilename,tape->tellpos) ;
-              else if ((c = fgetc (tape->inFp)) != '\n')
-                {
-                  while (c != EOF && c != '\n')
-                    c = fgetc (tape->inFp) ;
-                  
-                  if (c == EOF)
-                    {
-                      fclose (tape->inFp) ;
-                      unlink (tape->inputFilename) ;
-                      tape->inFp = NULL ;
-                      tape->scribbled = false ;
-                      prepareFiles (tape) ;
-                    }
-                  else
-                    {
-                      long oldPos = tape->tellpos ;
-                      
-                      tape->changed = true ;
-                      checkpointTape (tape) ;
-
-                      warn ("ME internal checkpoint line boundary missed:"
-                            " %s %ld vs. %ld",tape->inputFilename,
-                              tape->tellpos, oldPos) ;
-                    }
-                }
-            }
-        }
-    }
-  
-  tape->lastRotated = theTime() ;
-  tape->checkNew = false ;
-
-  /* now open up the output file. */
-  if (tape->outFp == NULL)
-    {
-      if ((tape->outFp = fopen (tape->outputFilename,"a+")) == NULL)
-        {
-          syswarn ("ME tape open failed (a+) %s", tape->outputFilename) ;
-          return ;
-        }
-      fseeko (tape->outFp,0,SEEK_END) ;
-      tape->outputSize = ftello (tape->outFp) ;
-      tape->lossage = 0 ;
-    }
-}
-
-
-static void tapeCkNewFileCbk (TimeoutId id, void *d UNUSED)
-{
-  ASSERT (id == ckNewFileId) ;
-  ASSERT (tapeCkNewFilePeriod > 0) ;
-
-  tapesSetCheckNew () ;
-
-  ckNewFileId = prepareSleep (tapeCkNewFileCbk,tapeCkNewFilePeriod,NULL) ;
-}
-
-
-/* The timer callback function that will checkpoint all the active tapes. */
-static void tapeCheckpointCallback (TimeoutId id, void *d UNUSED)
-{
-  ASSERT (id == checkPtId) ;
-  ASSERT (tapeCkPtPeriod > 0) ;
-  
-  d_printf (1,"Checkpointing tapes\n") ;
-  
-  checkPointTapes () ;
-
-  checkPtId = prepareSleep (tapeCheckpointCallback,tapeCkPtPeriod,NULL) ;
-}
-
-
-
-#if 0
-static void flushTape (Tape tape)
-{
-  QueueElem elem ;
-
-  /* flush out queue to disk. */
-  elem = tape->head ;
-  while (elem != NULL)
-    {
-      tape->head = tape->head->next ;
-      fprintf (tape->outFp,"%s %s\n", artFileName (elem->article),
-               artMsgId (elem->article)) ;
-      
-      delArticle (elem->article) ;
-      
-      free (elem) ;
-      elem = tape->head ;
-    }
-  tape->tail = NULL ;
-  tape->qLength = 0;
-      
-
-  /* I'd rather know where I am each time, and I don't trust all
-     fprintf's to give me character counts. */
-  tape->outputSize = ftello (tape->outFp) ;
-  if (debugShrinking)
-    {
-      struct stat buf ;
-      static bool logged = false ;
-      
-      fflush (tape->outFp) ;
-      if (fstat (fileno (tape->outFp),&buf) != 0 && !logged)
-        {
-          syslog (LOG_ERR,FSTAT_FAILURE,tape->outputFilename) ;
-          logged = true ;
-        }
-      else if (buf.st_size != tape->outputSize)
-        {
-          warn ("ME fstat and ftello do not agree for %s",
-                tape->outputFilename) ;
-          logged = true ;
-        }
-    }
-  
-  if (tape->outputHighLimit > 0 && tape->outputSize > tape->outputHighLimit)
-    {
-      shrinkfile (tape->outFp,tape->outputLowLimit,tape->outputFilename,"a+");
-      tape->outputSize = ftello (tape->outFp) ;
-    }
-}
-#endif
-
-
-static void tapeCleanup (void)
-{
-  free (tapeDirectory) ;
-  tapeDirectory = NULL ;
-}