Newsgroups: alt.sources
From: ken@bitsko.slc.ut.us (Ken MacLeod)
Subject: Unidel 1.0, a Citadel-style news/mail reader and BBS, part 02 of 09
Message-ID: <1992May3.012934.18650@bitsko.slc.ut.us>
Date: Sun, 3 May 1992 01:29:34 GMT

Submitted-by: ken@bitsko.slc.ut.us
Archive-name: unidel-1.0/part02

---- Cut Here and unpack ----
#!/bin/sh
# This is part 02 of unidel-1.0
if touch 2>&1 | fgrep 'amc' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= unidel/EnterMesg.c ==============
echo "x - extracting unidel/EnterMesg.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/EnterMesg.c &&
X/*
X * NAME
X *     EnterMesg.c -- Message entering
X *
X * AUTHOR
X *     Ken MacLeod
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) EnterMesg.c  1.7 02 May 1992 09:03:29\n\t";
X#endif
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <string.h>
X#include <fgetmfs.h>
X#include <time.h>
X#include <malloc.h>
X#include "protos.h"
X#include "defs.h"
X#include "Unidel.h"
X#include "Room.h"
X#include "Message.h"
X#include "User.h"
X#include "File.h"
X
Xvoid StrCat ();
Xstatic void CopyMessage ();
Xstatic int GetHeaders ();
X
Xchar *GetAddresses ();
X
Xstatic int EditSend (), EditPrint (), EditAbort (), EditContinue (),
X  EditHold (), EditHelp ();
Xstatic int EdHeadHelp (), EdHeadTo (), EdHeadExpires (),
X  EdHeadUserHeader (), EdHeadNewsgroups (), EdHeadOther ();
Xstatic int ValidNewsgroups (), EdHeadDistribution ();
X
Xstatic Menu editMenu[] = {
X  "?", "Help", NULL, NULL, NULL, 0l, EditHelp,
X  "S", "Send", NULL, NULL, NULL, 0l, EditSend,
X  "P", "Print", NULL, NULL, NULL, 0l, EditPrint,
X  "A", "Abort", NULL, NULL, NULL, 0l, EditAbort,
X  "C", "Continue", NULL, NULL, NULL, 0l, EditContinue,
X  "H", "Hold Message", NULL, NULL, NULL, 0l, EditHold,
X
X  /* Edit Headers */
X  "E?", "Edit ", "\b, Help", NULL, NULL, 0l, EdHeadHelp,
X  "EB", NULL, "=Bcc", NULL, NULL, (long) _hdrBcc, EdHeadTo,
X  "EC", NULL, "=Cc", NULL, NULL, (long) _hdrCc, EdHeadTo,
X  "ED", NULL, "=Distribution", NULL, NULL, (long) _hdrDistribution, EdHeadDistribution,
X  "EE", NULL, "=Expires", NULL, NULL, (long) _hdrExpires, EdHeadExpires,
X  "EF", NULL, "=Followup-To", NULL, NULL, (long) _hdrFollowupTo, EdHeadNewsgroups,
X  "EK", NULL, "=Keywords", NULL, NULL, (long) _hdrKeywords, EdHeadOther,
X  "EM", NULL, "=Summary", NULL, NULL, (long) _hdrSummary, EdHeadOther,
X  "EN", NULL, "=Newsgroups", NULL, NULL, (long) _hdrNewsgroups, EdHeadNewsgroups,
X  "EO", NULL, "=Organization", NULL, NULL, (long) _hdrOrganization, EdHeadOther,
X  "EP", NULL, "=Priority", NULL, NULL, (long) _hdrPriority, EdHeadOther,
X  "ER", NULL, "=Reply-To", NULL, NULL, (long) _hdrReplyTo, EdHeadTo,
X  "ES", NULL, "=Subject", NULL, NULL, (long) _hdrSubject, EdHeadOther,
X  "ET", NULL, "=To", NULL, NULL, (long) _hdrTo, EdHeadTo,
X  "E0", NULL, "=", NULL, NULL, (long) _hdrUser0, EdHeadUserHeader,
X  "E1", NULL, "=", NULL, NULL, (long) _hdrUser1, EdHeadUserHeader,
X  "E2", NULL, "=", NULL, NULL, (long) _hdrUser2, EdHeadUserHeader,
X  "E3", NULL, "=", NULL, NULL, (long) _hdrUser3, EdHeadUserHeader,
X  "E4", NULL, "=", NULL, NULL, (long) _hdrUser4, EdHeadUserHeader,
X  "E5", NULL, "=", NULL, NULL, (long) _hdrUser5, EdHeadUserHeader,
X  "E6", NULL, "=", NULL, NULL, (long) _hdrUser6, EdHeadUserHeader,
X  "E7", NULL, "=", NULL, NULL, (long) _hdrUser7, EdHeadUserHeader,
X  "E8", NULL, "=", NULL, NULL, (long) _hdrUser8, EdHeadUserHeader,
X  "E9", NULL, "=", NULL, NULL, (long) _hdrUser9, EdHeadUserHeader,
X
X  /* End of list */
X  "", NULL, NULL, NULL, NULL, 0l, NULL,
X};
X
Xstatic int followup, reply, mailFlag, editing, edit;
Xstatic char *tempFileName;
Xstatic char *newHdr[_hdrMax];
Xextern char *hdr[], *hdrFieldNames[];
X
Xint
XEnterMessageCommand (flags)
Xlong flags;
X{
X  (void) EnterMessage (flags, "", _false);
X  return 0;
X}
X
X/* ARGSUSED */
Xint
XEnterMessage (type, articleFileName, replyByMail)
Xlong type;
Xchar *articleFileName;
Xint replyByMail;	/* _true if doing a 'reply' by mail */
X{
X  void ClearHeader (), FreeHeader ();
X  int answer, i;
X
X  if (rooms[currentRoom].readOnly || floors[currentFloor].readOnly) {
X    (void) printf ("No messages can be entered in this room.\n");
X    return (_false);
X  }
X
X  followup = (articleFileName[0] != '\0');
X  reply = replyByMail;
X  mailFlag = (replyByMail || (rooms[currentRoom].type == _mailType));
X
X  ClearHeader (newHdr, hdrFieldNames);
X  /* Clear the extra fields not defined with hdrFieldNames */
X  for (i = _hdrUser0; i <= _hdrUser9; i ++)
X    newHdr[i] = NULL;
X  if (!GetHeaders ())
X    return (_true);
X
X  tempFileName = tmpnam ((char *) NULL);
X
X  if (followup
X      && (answer = AnswerYesNo ("Do you want to include a copy of the message (Y/[N])? ", _defaultAnswer)) == _true) {
X    CopyMessage (articleFileName, tempFileName);
X  }
X  if (answer == -1)
X    return (_true);
X
X  editing = _true;
X  edit = _true;
X  do {
X    if (edit)
X      (void) Edit (tempFileName);
X    (void) printf ("Edit: ");
X    edit = _false;
X    (void) DoMenu (0l, editMenu);
X  } while (editing);
X
X  FreeHeader (newHdr, hdrFieldNames);
X  /* Free the extra fields not defined with hdrFieldNames */
X  for (i = _hdrUser0; i <= _hdrUser9; i ++)
X    if (newHdr[i])
X      free ((malloc_t)newHdr[i]);
X  return (_false);
X}
X
Xstatic void
XCopyMessage (source, dest)
Xchar *source, *dest;
X{
X  FILE *sourceFile, *destFile;
X  char *headerLine;
X  int aChar, lastChar;
X
X  (void) printf ("OK, but edit it to remove unnecessary verbiage, signatures, etc.\n");
X
X  if ((sourceFile = fopen (source, "r")) == NULL) {
X    /* XXX log */
X    (void) printf ("Aack!  Couldn't open the original file!  Scream at sysop\n");
X    return;
X  }
X  if ((destFile = fopen (dest, "w")) == NULL) {
X    (void) fclose (sourceFile);
X    (void) printf ("Aack!  Couldn't open the new file!  Scream at sysop\n");
X    return;
X  }
X
X  /* Zip past header of article */
X  while ((headerLine = fgetms (sourceFile)) != NULL) {
X    aChar = headerLine[0];
X    free ((malloc_t)headerLine);
X    if (aChar == '\n')
X      break;
X  }
X
X  if (hdr[_hdrMessageID]) {
X    (void) fprintf (destFile, "In article %s", hdr[_hdrMessageID]);
X    if (mailFlag || hdr[_hdrFrom])
X      (void) fprintf (destFile, ", ");
X  }
X  if (mailFlag)
X    (void) fprintf (destFile, "you write");
X  else if (hdr[_hdrFrom])
X    (void) fprintf (destFile, "%s writes", hdr[_hdrFrom]);
X  if (hdr[_hdrMessageID] || hdr[_hdrFrom])
X    (void) fprintf (destFile, ":\n");
X  lastChar = '\n';
X  while ((aChar = getc (sourceFile)) != EOF) {
X    if (lastChar == '\n')
X      (void) putc ('>', destFile);
X    (void) putc (aChar, destFile);
X    lastChar = aChar;
X  }
X  if (lastChar != '\n')
X    (void) putc ('\n', destFile);
X
X  (void) fclose (sourceFile);
X  (void) fclose (destFile);
X}
X
X/* ARGSUSED */
Xstatic int
XEditSend (flag)
Xlong flag;
X{
X  FILE *messageFile, *outPipe;
X  char commandString[_bufSize], signatureFileName[_bufSize];
X  int aChar, lastChar, i;
X
X  /* XXX Can/should we Cc or Bcc an article using mail? */
X  messageFile = fopen (tempFileName, "r");
X  if (messageFile != NULL) {
X    if (newHdr[_hdrTo]) {
X      (void) sprintf (commandString, "%s %s %s %s %s", _mailDelivery,
X		      GetAddresses (newHdr[_hdrTo]),
X		      newHdr[_hdrCc] ? GetAddresses (newHdr[_hdrCc]) : "",
X		      newHdr[_hdrBcc] ? GetAddresses (newHdr[_hdrBcc]) : "",
X		      logname);
X      outPipe = popen (commandString, "w");
X      if (newHdr[_hdrBcc]) {	/* It _is_ a blind cc! */
X	free ((malloc_t)newHdr[_hdrBcc]);
X	newHdr[_hdrBcc] = NULL;
X      }
X    } else if (!mailFlag && newHdr[_hdrNewsgroups]) {
X      outPipe = popen (_newsDelivery, "w");
X    } else {
X      (void) printf ("Either a \"To:\" for mail or a \"Newsgroups:\" for messages must be set.\n");
X      (void) printf ("Use \"E(dit) T(o)\" or \"E(dit) N(ewgroups)\" to fix this.\n");
X      return (_false);
X    }
X  }
X  if (outPipe == NULL || messageFile == NULL) {
X    (void) sprintf (commandString, "mv %s %s/held.message\n", tempFileName,
X		    homeDir);
X    if (system (commandString) == 0)
X      (void) printf ("Unable to save message, message held.\n");
X    else
X      (void) printf ("Unable to save message, unable to hold message; do you have a paddle?\n");
X    if (messageFile != NULL) {
X      (void) fclose (messageFile);
X      if (outPipe != NULL)
X	(void) pclose (outPipe);
X    }
X    return (_false);
X  }
X
X  /* XXX Not any more. */
X  /* Both mail and news add From, Date, and Message-ID */
X  /* Write the extra headers not defined with hdrFieldNames,
X     these headers before the defined headers is kinda icky but
X     WriteHeader terminates the header */
X  for (i = _hdrUser0; i <= _hdrUser9; i ++)
X    if (newHdr[i])
X      (void)fprintf (outPipe, "%s\n", newHdr[i]);
X  WriteHeader (outPipe, newHdr, hdrFieldNames);
X
X  while ((aChar = getc (messageFile)) != EOF) {
X    (void) putc (aChar, outPipe);
X    lastChar = aChar;
X  }
X  if (lastChar != '\n')
X    (void) putc ('\n', outPipe);
X
X  (void) fclose (messageFile);
X  (void) sprintf (signatureFileName, "%s/.signature", homeDir);
X  if (mailFlag && (messageFile = fopen (signatureFileName, "r")) != NULL) {
X    /* Normally, this would be "\n-- \n", but we've guaranteed new-line
X       at end of file */
X    (void) fprintf (outPipe, "-- \n");
X    while ((aChar = getc (messageFile)) != EOF) {
X      (void) putc (aChar, outPipe);
X      lastChar = aChar;
X    }
X    if (lastChar != '\n')
X      (void) putc ('\n', outPipe);
X    (void) fclose (messageFile);
X  }
X
X  (void) pclose (outPipe);
X  (void) unlink (tempFileName);
X
X  editing = _false;
X  return (_true);
X}
X
X/* ARGSUSED */
Xstatic int
XEditAbort (flag)
Xlong flag;
X{
X  if (AnswerYesNo ("Are you sure (Y/N)? ", 0) == _true) {
X    editing = _false;
X    (void) unlink (tempFileName);
X  }
X  return 0;
X}
X
Xstatic int
XGetHeaders ()
X{
X  char tempBuf[_bufSize*4];
X  char *copyOfFrom, *author, *fullname, *sitename;
X  int answer;
X
X  if (mailFlag) {
X    if (reply) {
X      copyOfFrom = NULL;
X      if (hdr[_hdrReplyTo]) {
X	AllocString (&copyOfFrom, hdr[_hdrReplyTo]);
X	BreakFrom (copyOfFrom, &author, &fullname, &sitename);
X      } else if (hdr[_hdrFrom]) {
X	AllocString (&copyOfFrom, hdr[_hdrFrom]);
X	BreakFrom (copyOfFrom, &author, &fullname, &sitename);
X      } else
X	author = fullname = sitename = NULL;
X      if (author == NULL || sitename == NULL) {
X	if (copyOfFrom)
X	  free ((malloc_t)copyOfFrom);
X	(void) printf ("There is no return or reply-to address.\n");
X	return (_false);
X      }
X      (void) sprintf (tempBuf, "%s@%s", author, sitename);
X      if (copyOfFrom)
X	free ((malloc_t)copyOfFrom);
X      AllocString (&newHdr[_hdrTo], tempBuf);
X    }
X    (void) printf ("To");
X    if (!EdHeadTo ((long) _hdrTo))
X      return (_false);
X  } else if (!followup
X	     && (answer = AnswerYesNo ("Is this a follow-up to another message (Y/[N])? ", _defaultAnswer)) == _true) {
X    (void) printf ("  You should go to the message you wish to follow-up to and\n");
X    (void) printf ("use F(ollow-up).  Using R(everse read) is one way to go back\n");
X    (void) printf ("through messages.\n");
X    return (_false);
X  }
X  if (answer == -1)
X    return (_false);
X
X  /* Create From */
X  newHdr[_hdrFrom]
X    = (char *)malloc ((size_t) (strlen (logname) + strlen (longname)
X				+ strlen (_siteName) + 5));
X  (void) sprintf (newHdr[_hdrFrom], "%s@%s (%s)", logname, _siteName,longname);
X
X  /* Get subject */
X  if (followup && hdr[_hdrSubject]) {
X    if (!(strncmp (hdr[_hdrSubject], "Re:", 3) == 0
X	  || strncmp (hdr[_hdrSubject], "RE:", 3) == 0
X	  || strncmp (hdr[_hdrSubject], "re:", 3) == 0)) {
X      StrCat (tempBuf, "Re: ");
X    } else
X      StrCat (tempBuf, "");
X    StrCat ((char *) NULL, hdr[_hdrSubject]);
X    AllocString (&newHdr[_hdrSubject], tempBuf);
X  }
X  (void) printf ("Subject");
X  if (!EdHeadOther ((long) _hdrSubject))
X    return (_false);
X
X  if (followup) {
X    if (hdr[_hdrSummary])
X      AllocString (&newHdr[_hdrSummary], hdr[_hdrSummary]);
X    (void) printf ("Summary");
X    if (!EdHeadOther ((long) _hdrSummary))
X      return (_false);
X  }
X
X  if (followup && hdr[_hdrKeywords])
X    AllocString (&newHdr[_hdrKeywords], hdr[_hdrKeywords]);
X
X  /* Get key words */
X#ifndef askForKeywords		/* Otherwise we only ask for keywords if they're already there */
X  if (newHdr[_hdrKeywords]) {
X#endif
X    (void) printf ("Keywords");
X    if (!EdHeadOther ((long) _hdrKeywords))
X      return (_false);
X#ifndef askForKeywords
X  }
X#endif
X
X  if (!mailFlag && (strchr (rooms[currentRoom].name, '.') != NULL
X		    || (followup && (hdr[_hdrDistribution] != NULL)))) {
X    if (hdr[_hdrDistribution] != NULL)
X      AllocString (&newHdr[_hdrDistribution], hdr[_hdrDistribution]);
X    (void) printf ("Distribution");
X    if (!EdHeadDistribution ((long) _hdrDistribution))
X      return (_false);
X  }
X
X  if (!mailFlag && followup
X      && (hdr[_hdrFollowupTo]
X	  || (hdr[_hdrNewsgroups]
X	      && (strchr (hdr[_hdrNewsgroups], ',') != NULL)))) {
X    if (hdr[_hdrFollowupTo]) {
X      (void) printf ("Followups have been redirected to\n");
X      AllocString (&newHdr[_hdrNewsgroups], hdr[_hdrFollowupTo]);
X    } else
X      AllocString (&newHdr[_hdrNewsgroups], hdr[_hdrNewsgroups]);
X    (void) printf ("Newsgroups");
X    if (!EdHeadNewsgroups ((long) _hdrNewsgroups))
X      return (_false);
X  } else if (!mailFlag)
X    AllocString (&newHdr[_hdrNewsgroups], rooms[currentRoom].name);
X
X  /* Create or prepend references */
X  if (followup && (hdr[_hdrMessageID] || hdr[_hdrReferences])) {
X    newHdr[_hdrReferences]
X      = (char *)malloc ((size_t) ((hdr[_hdrMessageID]
X				   ? strlen (hdr[_hdrMessageID]) : 0)
X				  + (hdr[_hdrReferences]
X				     ? strlen (hdr[_hdrReferences]) : 0)) +14);
X    StrCat (newHdr[_hdrReferences], "");
X    if (hdr[_hdrMessageID])
X      StrCat ((char *)NULL, hdr[_hdrMessageID]);
X    if (hdr[_hdrReferences]) {
X      if (hdr[_hdrMessageID])
X	StrCat ((char *)NULL, " ");
X      StrCat ((char *)NULL, hdr[_hdrReferences]);
X    }
X  }
X
X  AllocString (&newHdr[_hdrOrganization], _organization);
X
X  return (_true);
X}
X
X/* ARGSUSED */
Xstatic int
XEditPrint (flag)
Xlong flag;
X{
X  char commandString[_bufSize];
X
X  PrintShortHeader (newHdr, -1);
X  (void) sprintf (commandString, "%s %s", filePager,
X		  tempFileName);
X  (void) printf ("\n");
X  (void) UserCommand (commandString);
X  (void) printf ("\n");
X  return (_false);
X}
X
X/* ARGSUSED */
Xstatic int
XEditContinue (flag)
Xlong flag;
X{
X  edit = _true;
X  return (_false);
X}
X
X/* ARGSUSED */
Xstatic int
XEditHold (flag)
Xlong flag;
X{
X  char commandString[_bufSize];
X
X  (void) sprintf (commandString, "mv %s %s/held.message\n", tempFileName,
X		  homeDir);
X  if (system (commandString) == 0)
X    (void) printf ("Message held.\n");
X  else
X    (void) printf ("Error trying to hold message; do you have a paddle?\n");
X  editing = _false;
X  return (_false);
X}
X
X/* ARGSUSED */
Xstatic int
XEditHelp (flag)
Xlong flag;
X{
X  Help ("edit");
X  return (_false);
X}
X
X/* ARGSUSED */
Xstatic int
XEdHeadHelp (dummy)
Xlong dummy;
X{
X  static char helpful[] = { _hdrSubject, _hdrCc, _hdrBcc, _hdrKeywords,
X			      _hdrSummary, _hdrDistribution, _hdrPriority,
X			      _hdrExpires, '\0' };
X  int i;
X
X  for (i = 0; i < _hdrMax; i ++) {
X    if (newHdr[i] != NULL || ((i != '\0') && (strchr (helpful, i) != NULL)))
X      if ((i >= _hdrUser0) && (i <= _hdrUser9))
X	(void) printf ("%d) %s\n", i - _hdrUser0, newHdr[i]);
X      else
X	(void) printf ("%s%s\n", hdrFieldNames[i], newHdr[i] ? newHdr[i] : "");
X  }
X  (void) printf ("\nType E(dit) and the first letter of header to change.\n");
X  return (_false);
X}
X
Xstatic int
XEdHeadTo (field)
Xlong field;
X{
X  char workingAddresses[_bufSize];
X  int status, answer;
X
X  if (newHdr[field])
X    (void) strcpy (workingAddresses, newHdr[field]);
X  else
X    workingAddresses[0] = '\0';
X
X  if ((field == _hdrTo) && !mailFlag) {
X    (void) printf ("\n  Using \"To:\" will cause your message to be mailed.\nTo");
X  }
X
X  do {
X    if (GetStringWDefault ("", workingAddresses, (field == _hdrTo)
X			   ? _adminName : NULL, _normal) == _keyAbort) {
X      (void) printf ("%s unchanged.\n", hdrFieldNames[field]);
X      return (_false);
X    }
X    if (workingAddresses[0] == '\0')
X      break;
X    status = ValidAddresses (workingAddresses);
X    if (status == 1) {
X      if ((answer = AnswerYesNo ("Do you want to send anyway (Y/[N])? ",
X				 _defaultAnswer)) == _true)
X	status = 0;
X    }
X    if (answer == -1)
X      return (_false);
X  } while (status != 0);
X
X  if (workingAddresses[0] != '\0')
X    AllocString (&newHdr[field], workingAddresses);
X  else if (newHdr[field])
X    free ((malloc_t)newHdr[field]), newHdr[field] = NULL;
X
X  return (_true);
X}
X
Xstatic int
XEdHeadOther (field)
Xlong field;
X{
X  int status;
X  char workingString[_bufSize];
X
X  if (newHdr[field])
X    (void) strcpy (workingString, newHdr[field]);
X  else
X    workingString[0] = '\0';
X
X  do {
X    if ((status = GetStringWDefault ("", workingString, (char *) NULL, _normal)) == _keyAbort)
X      break;
X    status = 0;
X    if ((int) field == _hdrSubject && workingString[0] == '\0'
X	&& (rooms[currentRoom].displaySubject
X	    || floors[rooms[currentRoom].floor].displaySubject)) {
X      (void) printf ("Message \"Subjects\" are required in this room.\n");
X      status = 1;
X    }
X  } while (status != 0);
X  if (status == _keyAbort) {
X    (void) printf ("%s unchanged.\n", hdrFieldNames[field]);
X    return (_false);
X  }
X  if (workingString[0] != '\0')
X    AllocString (&newHdr[field], workingString);
X  else if ((int) field == _hdrSubject)
X    AllocString (&newHdr[field], "(None)");
X  else if (newHdr[field] != NULL)
X    free ((malloc_t)newHdr[field]), newHdr[field] = NULL;
X
X  return (_true);
X}
X
Xstatic int
XEdHeadNewsgroups (field)
Xlong field;
X{
X  char workingString[_bufSize];
X
X  if (newHdr[field])
X    (void) strcpy (workingString, newHdr[field]);
X  else
X    workingString[0] = '\0';
X
X  for(;;) {
X    if (GetStringWDefault ("", workingString, (char *) NULL, _normal) == _keyAbort) {
X      (void) printf ("%s unchanged.\n", hdrFieldNames[field]);
X      return (_false);
X    }
X    if (workingString[0] == '\0'
X	|| (field == _hdrFollowupTo && strcmp (workingString, "poster") == 0)
X	|| ValidNewsgroups (workingString))
X      break;
X    else
X      (void) printf ("%s\b\b", hdrFieldNames[field]);
X  }
X  if (workingString[0] != '\0')
X    AllocString (&newHdr[field], workingString);
X  else if (newHdr[field])
X    free ((malloc_t)newHdr[field]), newHdr[field] = NULL;
X
X  return (_true);
X}
X
Xstatic int
XEdHeadDistribution (field)
Xlong field;
X{
X  char workingString[_bufSize];
X
X  if (newHdr[field])
X    (void) strcpy (workingString, newHdr[field]);
X  else
X    workingString[0] = '\0';
X  for(;;) {
X    if (GetStringWDefault ("", workingString,
X			   (char *) NULL, _normal) == _keyAbort) {
X      (void) printf ("%s unchanged.\n", hdrFieldNames[field]);
X      return (_false);
X    }
X    /* XXX Put the dists in def or load them from Init */
X    if (workingString[0] == '\0'
X	|| IsIn (workingString, "~world~na~usa~utah~cit~"))
X      break;
X    else
X      (void) printf ("'%s' is not a valid distribution.\n%s\b\b",
X		     workingString, hdrFieldNames[field]);
X  }
X
X  if (strcmp ("world", workingString) != 0 || workingString[0] != '\0')
X    AllocString (&newHdr[field], workingString);
X  else if (newHdr[field])
X    free ((malloc_t)newHdr[field]), newHdr[field] = NULL;
X
X  return (_true);
X}
X
Xstatic int
XEdHeadExpires (field)
Xlong field;
X{
X  time_t theExpiry, parsedate ();
X  struct tm *tm;
X  char timeZone[4], *ptr, workingExpire[_bufSize];
X
X  if (newHdr[field])
X    (void) strcpy (workingExpire, newHdr[field]);
X  else
X    workingExpire[0] = '\0';
X
X  for (;; (void) printf ("%s\b\b", hdrFieldNames[field])) {
X    if (GetStringWDefault ("", workingExpire,
X			   (char *) NULL, _normal) == _keyAbort) {
X      (void) printf ("%s unchanged.\n", hdrFieldNames[field]);
X      return (_false);
X    }
X    if (workingExpire == '\0') {
X      if (newHdr[field])
X	free ((malloc_t)newHdr[field]), newHdr[field] = NULL;
X      return (_true);
X    }
X    if ((theExpiry = parsedate (workingExpire, NULL)) < 8 * 60 * 60 * 24 * 7) {
X      (void) printf ("I don't understand that date.\n");
X      continue;
X    }
X    if (theExpiry > (time ((long *) 0) + 8 * 60 * 60 * 24 * 7)) {
X      /* WEEKS */
X      (void) printf ("Too far in the future.\n");
X      continue;
X    }
X    if (theExpiry < (time ((long *) 0) - 1 * 60 * 60 * 24)) { /* DAYS */
X      (void) printf ("Expiry date already past.\n");
X      continue;
X    }
X
X    /* If all checks pass, we're done */
X    break;
X  }
X
X  /* Put expiry in local-time internet format */
X  (void) strcpy (timeZone, "GMT");
X  if ((ptr = getenv ("TZ")) != NULL)
X    (void) strncpy (timeZone, ptr, 3);
X
X  tm = localtime (&theExpiry);
X  (void) printf ("Expires: %s, %2d %s %2d %2d:%2.2d:%2.2d %s\n",
X		 days[tm -> tm_wday], tm -> tm_mday, months[tm -> tm_mon],
X		 tm -> tm_year, tm -> tm_hour, tm -> tm_min, tm -> tm_sec,
X		 timeZone);
X  tm = gmtime (&theExpiry);
X  (void) sprintf (workingExpire, "%s, %2d %s %2d %2d:%2.2d:%2.2d GMT",
X		  days[tm -> tm_wday], tm -> tm_mday, months[tm -> tm_mon],
X		  tm -> tm_year,tm -> tm_hour, tm -> tm_min, tm -> tm_sec);
X
X  AllocString (&newHdr[field], workingExpire);
X
X  return (_true);
X}
X
Xstatic int
XEdHeadUserHeader (field)
Xlong field;
X{
X  char workingString[_bufSize];
X
X  if (newHdr[field])
X    (void) strcpy (workingString, newHdr[field]);
X  else
X    workingString[0] = '\0';
X	
X  if (GetStringWDefault ("", workingString,
X			 (char *) NULL, _normal) == _keyAbort)
X    return (_false);
X
X  if (workingString[0] != '\0') {
X    /* XXX check header name syntax */
X    AllocString (&newHdr[field], workingString);
X  } else if (newHdr[field])
X    free ((malloc_t)newHdr[field]), newHdr[field] = NULL;
X  return (_false);
X}
X
Xstatic int
XValidNewsgroups (newsgroups)
Xchar *newsgroups;
X{
X  char copyOfNewsgroups[_bufSize], *ptr;
X  int badRoom;
X
X  (void) strcpy (copyOfNewsgroups, newsgroups);
X  badRoom = _false;
X  for (ptr = strtok (copyOfNewsgroups, ", ");
X       ptr != NULL;
X       ptr = strtok ((char *) NULL, ", ")) {
X    if (FindRoom (_findExact, ptr) == -1) {
X      (void) printf ("'%s' is not a valid room name.\n", ptr);
X      badRoom |= _true;
X    }
X  }
X  return (!badRoom);
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/EnterMesg.c &&
chmod 0444 unidel/EnterMesg.c ||
echo "restore of unidel/EnterMesg.c failed"
set `wc -c unidel/EnterMesg.c`;Wc_c=$1
if test "$Wc_c" != "21299"; then
	echo original size 21299, current size $Wc_c
fi
# ============= unidel/File.h ==============
echo "x - extracting unidel/File.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/File.h &&
X/*
X * NAME
X *     File.h -- definitions for filing variables and routines
X *
X * AUTHOR
X *     Ken MacLeod
X *
X * SCCS
X *     @(#) File.h  1.1 07 Nov 1990 09:55:12 
X */
X
Xextern char *transferProtocol, *transferDescription, *transferFlags, *transferReadCommand,
X	*transferEnterCommand;
Xextern int transferBatch;	/* true if transfer protocol is a batch protocol */
X
Xextern char *flTempDir;
X
X#define _fileName 0
X#define _fileDesc 1
X#define _fileUser 2
X#define _fileDate 3
X
X#define _maxFileFields 4
SHAR_EOF
$TOUCH -am 0502135492 unidel/File.h &&
chmod 0444 unidel/File.h ||
echo "restore of unidel/File.h failed"
set `wc -c unidel/File.h`;Wc_c=$1
if test "$Wc_c" != "493"; then
	echo original size 493, current size $Wc_c
fi
# ============= unidel/Floor.c ==============
echo "x - extracting unidel/Floor.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/Floor.c &&
X/*
X * NAME
X *     Floor.c -- Floor functions
X *
X * AUTHOR
X *     Ken MacLeod
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) Floor.c  1.2 02 May 1992 09:06:32\n\t";
X#endif
X
X#include <stdio.h>
X#include <ctype.h>
X#include "protos.h"
X#include "defs.h"
X#include "Unidel.h"
X#include "Room.h"
X#include "User.h"
X
Xstatic int FindFloor ();
X
Xextern char *user[];
X
Xint
XGotoFloorCommand (type)
Xlong type;
X{
X  char floorName[_bufSize];
X  int room, floor;
X
X  switch ((int) type) {
X  case 0:		/* Goto Floor */
X    GetString (floorName, _normal);
X    if (floorName[0]) {
X      room = FindFloor (floorName);
X      if (room != -1) {
X	MarkRead ();
X	Goto (room);
X      }
X    }
X    break;
X  case 1:		/* Skip Floor */
X  case 2:		/* Next Floor */
X    floor = currentFloor;
X    do {
X      floor ++;
X      if (floors[floor].name == NULL)
X	floor = 0;
X      /* This actually looks up the first non-forgotten room in that floor */
X      room = FindFloor (floors[floor].name);
X    } while (floors[floor].forgotten ||
X	     ((room == -1) && (floor != currentFloor)));
X    if (room != -1) {
X      MarkRead ();
X      Goto (room);
X    }
X    break;
X  case 3:		/* Previous Floor */
X    floor = currentFloor;
X    do {
X      if (floor == 0)
X	for (floor = 0; floors[floor].name != NULL; floor ++);
X      floor --;
X      /* This actually looks up the first non-forgotten room in that floor */
X      room = FindFloor (floors[floor].name);
X    } while (floors[floor].forgotten ||
X	     ((room == -1) && (floor != currentFloor)));
X    if (room != -1) {
X      MarkRead ();
X      Goto (room);
X    }
X    break;
X  }
X
X  return 0;
X}
X
Xstatic int
XFindFloor (floorName)
X/* Returns the first known room on this floor or -1 */
Xchar *floorName;
X{
X  char floorNameCopy[_bufSize];
X  int floor, room, i;
X
X  for (i = 0; floorName[i] != '\0'; i ++)
X    floorNameCopy[i] = isupper (floorName[i])
X      ? tolower (floorName[i]) : floorName[i];
X  floorNameCopy[i] = '\0';
X
X  for (floor = 0;
X       (floors[floor].name != NULL)
X       && !IsIn (floorNameCopy, floors[floor].name)
X       && !IsIn (floorNameCopy, floors[floor].description); floor ++)
X    ;
X  if (floors[floor].name == NULL)		/* No floor by that name */
X    return (-1);
X
X  for (room = 0;
X       (rooms[room].name != NULL)
X       && !(!rooms[room].forgotten && (rooms[room].floor == floor));
X       room ++);
X  if (rooms[room].name == NULL)		/* No known rooms on that floor */
X    return (-1);
X  return (room);
X}
X
X/* ARGSUSED */
Xint
XForgetFloor (dummy)
Xlong dummy;
X{
X  if (currentFloor != 0) {
X    floors[currentFloor].forgotten = _true;
X    (void) GotoFloorCommand (2l);	/* Next Floor */
X  }
X
X  return 0;
X}
X
X/* ARGSUSED */
Xint
XKnownFloors (dummy)
Xlong dummy;
X{
X  int floor;
X
X  for (floor = 0; floors[floor].name != NULL; floor ++) {
X    if (!floors[floor].forgotten) {
X      (void) printf ("[%s", floors[floor].name);
X      if (floors[floor].description != NULL)
X	(void) printf (":\t%s", floors[floor].description);
X      (void) printf ("]\n");
X    }
X  }
X
X  return 0;
X}
X
X/* ARGSUSED */
Xint
XToggleFloorMode (dummy)
Xlong dummy;
X{
X  if (floorMode) {
X    floorMode = _false;
X    AllocString (&user[_userFloorMode], "No");
X    (void) printf ("Normal mode.\n");
X  } else {
X    floorMode = _true;
X    AllocString (&user[_userFloorMode], "Yes");
X    (void) printf ("Floor mode.\n");
X  }
X
X  return 0;
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/Floor.c &&
chmod 0444 unidel/Floor.c ||
echo "restore of unidel/Floor.c failed"
set `wc -c unidel/Floor.c`;Wc_c=$1
if test "$Wc_c" != "3297"; then
	echo original size 3297, current size $Wc_c
fi
# ============= unidel/FromNews.c ==============
echo "x - extracting unidel/FromNews.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/FromNews.c &&
X/*
X * This software is Copyright (c) 1986 by Rick Adams.
X *
X * Permission is hereby granted to copy, reproduce, redistribute or
X * otherwise use this software as long as: there is no monetary
X * profit gained specifically from the use or reproduction or this
X * software, it is not sold, rented, traded or otherwise marketed, and
X * this copyright notice is included prominently in any copy
X * made.
X *
X * The author make no claims as to the fitness or correctness of
X * this software for any use whatsoever, and it is provided as is. 
X * Any use of this software is at the user's own risk.
X *
X * [These routines are all pulled from UseNet News source files, but
X *  all fall under the copyright above.  KWM 03/02/88]
X *
X * nstrip -- strips spaces from end of a string.
X *
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) FromNews.c  1.1 07 Nov 1990 09:55:14\n\t";
X#endif
X
X#define FALSE 0
X#define TRUE 1
X
X/*
X * Strip trailing newlines, blanks, and tabs from 's'.
X * Return TRUE if newline was found, else FALSE.
X */
Xnstrip(s)
Xregister char *s;
X{
X	register char *p;
X	register int rc;
X
X	rc = FALSE;
X	p = s;
X	while (*p)
X		if (*p++ == '\n')
X			rc = TRUE;
X	while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t'));
X	*++p = '\0';
X	return rc;
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/FromNews.c &&
chmod 0444 unidel/FromNews.c ||
echo "restore of unidel/FromNews.c failed"
set `wc -c unidel/FromNews.c`;Wc_c=$1
if test "$Wc_c" != "1240"; then
	echo original size 1240, current size $Wc_c
fi
# ============= unidel/General.c ==============
echo "x - extracting unidel/General.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/General.c &&
X/*
X * NAME
X *     General.c -- general functions
X *
X * AUTHOR
X *     Ken MacLeod
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) General.c  1.6 02 May 1992 09:07:34\n\t";
X#endif
X
X#include <termio.h>
X#include <stdio.h>
X#include <fgetmfs.h>
X#include <string.h>
X#include <malloc.h>
X#include <ctype.h>
X#include "protos.h"
X#include "Log.h"
X#include "defs.h"
X#include "Unidel.h"
X#include "Room.h"
X#include "User.h"
X#include "Message.h"
X#include "File.h"
X
Xextern int linesLeft;
X
Xvoid
XScanNewArticles ()
X{
X  char *ptr;
X  int i;
X
X  for (i = 0; rooms[i].name != NULL; i ++) {
X    if (!rooms[i].forgotten) {
X      rooms[i].newArticles = 0;
X      if (rooms[i].highest != 0) {
X	if (strchr (rooms[i].articlesRead, ',') == NULL) {
X	  if ((ptr = strchr (rooms[i].articlesRead, '-')) == NULL) {
X	    rooms[i].newArticles = 1;
X	  } else {
X	    rooms[i].newArticles = atoi (ptr + 1) < rooms[i].highest;
X	  }
X	} else {
X	  rooms[i].newArticles = 1;
X	}
X      }
X    }
X  }
X}
X
Xint
XHelpCommand (topic)
Xlong topic;
X{
X  Help (selectorStrings[topic]);
X  return 0;
X}
X
Xvoid
XHelp (topic)
Xchar *topic;
X{
X#ifdef XXXPageHelp
X  char commandString[_bufSize];
X#endif
X  char tempString[_bufSize], fileName[_bufSize];
X
X  if (topic == NULL) {
X    GetString (tempString, _lowerCase);
X    /* XXX tempString gets put into a command, make sure it's _just_ a */
X    /* file name */
X  } else
X    (void)strcpy (tempString, topic);
X  (void) sprintf (fileName, "%s/%s.doc", _docDir, tempString);
X  if (tempString[0]) {
X    linesLeft = lines;
X    if (PrintMessage (_readMoreDefault, fileName, -2, 0) == -1)
X      (void) printf ("No such topic, %s.\n", tempString);
X#ifdef XXXPageHelp
X    (void) printf ("\n");
X    (void) sprintf (commandString, "%s -v \"^#\" %s | %s"
X		    _egrep, fileName, filePager);
X    (void) UserCommand (commandString);
X#endif
X    (void) printf ("\n");
X  }
X}
X
Xint
XUserCommand (command)
Xchar *command;
X{
X  char commandString[_bufSize];
X  extern int secure;
X  int status;
X  
X  if (secure)
X    (void) sprintf (commandString, "export SHELL PATH ; SHELL=/bin/rsh PATH=/usr/rbin cd %s ; %s",
X		    flTempDir, command);
X  else
X    (void) sprintf (commandString, "%s", command);
X  SetupTerminal (_false);
X  status = system (commandString);
X  SetupTerminal (_true);
X
X  return (status);
X}
X
Xvoid
XSetupTerminal (userMode)
Xint userMode;		/* TRUE means set to run in user mode, FALSE means
X			   restore */
X{
X#ifdef noway
X  static struct termio originalMode;
X  struct termio currentMode;
X#endif
X
X  if (userMode) {
X    setbuf (stdout, (char *) NULL);
X    (void)system ("stty -icrnl -icanon -echo -isig eof \\^a eol \\^@");
X#ifdef noway
X    ioctl (0, TCGETA, &originalMode);
X    originalMode . c_lflag &= ~(XCASE);
X    originalMode . c_lflag |= (ECHOE);
X    originalMode . c_cc [VERASE] = 0x08;
X    originalMode . c_cc [VKILL] = 0x15;
X    originalMode . c_cc [VSWTCH] = 0x03;
X    currentMode = originalMode;
X    currentMode.c_iflag &= ~(ICRNL);
X    currentMode.c_lflag &= ~(ICANON | ECHO | ISIG);
X    currentMode.c_cc[VEOF] = 1;
X    currentMode.c_cc[VEOL] = 0;
X    ioctl (0, TCSETA, &currentMode);
X#endif
X  } else {
X    (void)system ("stty icrnl icanon echo isig eof \\^d eol \\^`");
X#ifdef noway
X    ioctl (0, TCSETA, &originalMode);
X#endif
X  }
X}
X
X/* ARGSUSED */
Xint
XDisabled (dummy)
Xlong dummy;
X{
X  (void) printf ("This function is under construction, please excuse the dust.\n");
X  return 0;
X}
X
Xint
XTerminate (quitAlso)
Xlong quitAlso;
X{
X  if (quitAlso) {
X    finished = _true;
X  } else {
X    (void) printf ("Do you really want to quit (Y/[N])? ");
X    if (GetChar (_upperCase) == 'Y')
X      finished = _true;
X  }
X  if (finished == _true)
X    MarkRead ();
X
X  return 0;
X}
X
Xint
XSystemCommand (selector)
Xlong selector;
X{
X  SetupTerminal (_false);
X  (void)system (selectorStrings[selector]);
X  SetupTerminal (_true);
X  return 0;
X}
X
X/* ARGSUSED */
Xint
XChat (dummy)
Xlong dummy;
X{
X  char userName[_bufSize], chatCommand[_bufSize];
X
X  (void) printf ("\n");
X  SetupTerminal (_false);
X  (void)system (_listUsersCommand);
X  SetupTerminal (_true);
X  (void) printf ("\nEnter NAME of the person you would like to chat with.\n: ");
X  GetString (userName, _lowerCase);
X  if (userName[0] != '\0') {
X    (void) sprintf (chatCommand, "%s %s", _chatCommand, userName);
X    SetupTerminal (_false);
X    (void)system (chatCommand);
X    SetupTerminal (_true);
X    (void) printf ("\nYou are now back in room:\n");
X  }
X
X  return 0;
X}
X
Xvoid
XSetupTransferProtocol (protocol)
Xchar *protocol;
X{
X  _FuncName ("SetupTransferProtocol");
X  FILE *protocolFile;
X  char protocolFileName[_bufSize], *fields[5];
X  static char *protocolLine;
X  int nf;
X
X  if (protocol == NULL || protocol[0] == '\0')
X    return;
X  (void) sprintf (protocolFileName, "%s/Transfers", _libDir);
X  if ((protocolFile = fopen (protocolFileName, "r")) != NULL) {
X    while ((protocolLine = fgetms (protocolFile)) != NULL) {
X      if (protocolLine[0] == '\0' || protocolLine[0] == '#'
X	  || isspace(protocolLine[0])) {
X	free ((malloc_t)protocolLine);
X	continue;
X      }
X      (void)nstrip (protocolLine);
X      nf = split (protocolLine, fields, 5, ":");
X      if (nf >= 5 && strcmp (fields[0], protocol) == 0) {
X	(void)fclose (protocolFile);
X	transferProtocol = fields[0];
X	transferDescription = fields[1];
X	transferFlags = fields[2];
X	transferEnterCommand = fields[3];
X	transferReadCommand = fields[4];
X	transferBatch = IsIn ("batch", transferFlags);
X	(void)fclose (protocolFile);
X	return;
X      }
X      free ((malloc_t)protocolLine);
X    }
X    (void)fclose (protocolFile);
X  } else {
X    Log (funcName, __LINE__, LOG_ERROR, "Could not open Transfers file '%s'.",
X		    protocolFileName);
X  }
X  Log (funcName, __LINE__, LOG_ERROR, "Could not find protocol '%s'.",
X       protocol);
X  transferProtocol = NULL;
X}
X
Xvoid
XSetupEditor (editor)
Xchar *editor;
X{
X  _FuncName ("SetupEditor");
X  FILE *editorFile;
X  char editorFileName[_bufSize], *fields[4];
X  static char *editorLine;
X  int nf;
X
X  if (editor == NULL || editor[0] == '\0')
X    return;
X  (void) sprintf (editorFileName, "%s/Editors", _libDir);
X  if ((editorFile = fopen (editorFileName, "r")) != NULL) {
X    while ((editorLine = fgetms (editorFile)) != NULL) {
X      if (editorLine[0] == '\0' || editorLine[0] == '#'
X	  || isspace(editorLine[0])) {
X	free ((malloc_t)editorLine);
X	continue;
X      }
X      (void)nstrip (editorLine);
X      nf = split (editorLine, fields, 4, ":");
X      if (nf >= 4 && strcmp (fields[0], editor) == 0) {
X	(void)fclose (editorFile);
X	editorName = fields[0];
X	editorDescription = fields[1];
X	editorFlags = fields[2];
X	editorCommand = fields[3];
X	(void)fclose (editorFile);
X	return;
X      }
X      free ((malloc_t)editorLine);
X    }
X    (void)fclose (editorFile);
X  } else {
X    Log (funcName, __LINE__, LOG_ERROR, "Could not open Editors file '%s'.",
X	 editorFileName);
X  }
X  Log (funcName, __LINE__, LOG_ERROR, "Could not find editor '%s'.", editor);
X  editorName = NULL;
X}
X
Xint
XEdit (fileName)
Xchar * fileName;
X{
X  char commandString[_bufSize];
X  int status;
X
X  if (editorName == NULL || editorCommand == NULL) {
X    (void) printf ("You have not selected an editor.\n");
X    return (_false);
X  }
X
X  (void) sprintf (commandString, editorCommand, fileName);
X  status = UserCommand (commandString);
X
X  return (!status);	/* Reverse the sense of shell exits */
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/General.c &&
chmod 0444 unidel/General.c ||
echo "restore of unidel/General.c failed"
set `wc -c unidel/General.c`;Wc_c=$1
if test "$Wc_c" != "7236"; then
	echo original size 7236, current size $Wc_c
fi
# ============= unidel/Headers.c ==============
echo "x - extracting unidel/Headers.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/Headers.c &&
X/*
X * NAME
X *     Header.c -- Header handling functions
X *
X * AUTHOR
X *     Ken MacLeod
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) Headers.c  1.3 02 May 1992 09:08:21\n\t";
X#endif
X
X#include <fgetmfs.h>
X#include <stdio.h>
X#include <malloc.h>
X
Xstatic int StrLNCmp ();
Xextern int nstrip ();
Xextern size_t strlen ();
X
Xvoid
XClearHeader (hdr, hdrFieldNames)
Xchar **hdr, **hdrFieldNames;
X{
X  while (*hdrFieldNames++)
X    *hdr++ = NULL;
X}
X
Xvoid
XFreeHeader (hdr, hdrFieldNames)
Xchar **hdr, **hdrFieldNames;
X{
X  while (*hdrFieldNames++) {
X    if (*hdr)
X      free ((malloc_t)*hdr);
X    hdr ++;
X  }
X}
X
Xint
XReadHeader (file, hdr, hdrFieldNames)
Xchar **hdr, **hdrFieldNames;
XFILE *file;
X{
X  char *headerLine;
X  int i;
X
X  while ((headerLine = cfgetms (file)) != NULL) {
X    if (headerLine[0] == '\n') {
X      free ((malloc_t)headerLine);
X      break;
X    }
X    (void) nstrip (headerLine);
X    if (headerLine[0] == '>') {	/* Quicky, get rid of '>From ' lines in mail */
X      free ((malloc_t)headerLine);
X      continue;
X    }
X    for (i = 0;
X	 hdrFieldNames[i] != NULL
X	 && StrLNCmp (headerLine, hdrFieldNames[i],
X		      strlen (hdrFieldNames[i])) != 0; i ++);
X    if (hdrFieldNames[i] != NULL) {
X      register char *ptr, *ptr1;
X
X      hdr[i] = headerLine;
X      ptr = &headerLine[0];
X      ptr1 = &headerLine[strlen(hdrFieldNames[i])];
X      while (*ptr++ = *ptr1++)
X	;
X    } else
X      free ((malloc_t)headerLine);
X  }
X  return (feof (file));	/* Error: out of memory, iff not end of file */
X}
X
Xvoid
XWriteHeader (file, hdr, hdrFieldNames)
XFILE *file;
Xchar **hdr, **hdrFieldNames;
X{
X  while (*hdrFieldNames) {
X    if (*hdr)
X      (void) fprintf (file, "%s%s\n", *hdrFieldNames, *hdr);
X    hdr ++;
X    hdrFieldNames ++;
X  }
X  (void) putc ('\n', file);
X}
X
X/* Assumes ASCII strings and only characters from "A-Za-z0-9" and "-" */
Xstatic int
XStrLNCmp (s1, s2, nn)
Xregister char *s1, *s2;
Xunsigned int nn;
X{
X  register int dd;
X
X  while (*s1 && *s2 && nn && ((dd = (*s1-*s2)) == 0 || dd == -32 || dd == 32))
X    s1++, s2++, nn--;
X
X  return (nn);
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/Headers.c &&
chmod 0444 unidel/Headers.c ||
echo "restore of unidel/Headers.c failed"
set `wc -c unidel/Headers.c`;Wc_c=$1
if test "$Wc_c" != "2035"; then
	echo original size 2035, current size $Wc_c
fi
# ============= unidel/INSTALL ==============
echo "x - extracting unidel/INSTALL (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/INSTALL &&
X#
X#  INSTALL -- Instructions for installation of Unidel
X#
X#  SCCS
X#      @(#) INSTALL  1.1 02 May 1992 11:06:03 
X#
X  Here is the source for the Unidel News/Mail reader.  To get it
Xcompiled, copy Make.dist to Makefile and defs.dist to defs.h.  Edit
Xthese two new files to reflect your system.  You may want to modify
Xand use localize.sh to save time on future updates.  If I've done as
Xwell as I like to think, it should make and run without error.
X
X  Stop here.  Play with it.  All the rest of this can be done later.
X
X  FILES
X  -----
X  The following files in LIBDIR will also need to be edited at some
Xtime to reflect your system.
X
X  'Editors'   contains the available editors, if the users are 'local'
X              and already have user accounts, the environment variable
X              "EDITOR" will be used to pick the editor _from_this_file_.
X
X  'Floors'    contains descriptions of floors.  If absent, all rooms
X              appear on one floor, "lobby.".
X
X  'Transfers' is used to define upload/download programs.  If absent
X              then no protocol transfers can be used.  Local 'cp' will
X              still be used for 'local' users.
X
X  'FileDirs'  describes directories and permissions for rooms that
X              have files in them.
X
X  In your news directory, Unidel will use 'active' to get the latest
Xarticle numbers to find rooms with new messages, and 'newsgroups' to
Xget the descriptive names of rooms.  If the description in
X'newsgroups' is less than 30 characters then it's displayed as the
Xroom name.
X
X  LOCAL USERS
X  -----------
X  A 'local' user is one that logs in normally, and then uses unidel to
Xread news and mail, they upload and download files and messages by
Xusing 'cp'.  In defs.h are two variables, _local and _isLocal, that
Xdefine how to find out if a user is on a local terminal or dialed-in
Xand needs a file transfer protocol.  Set _local to a file that lists
Xall the terminals and dial-up lines (/etc/inittab for sysV, or you can
Xcreate your own) and set _isLocal to a string to look for in that file
Xto see if the tty line is local.  Example
X
X  #define _local "myTTYFile"
X  #define _isLocal "local"
X
X  myTTYFile:
X     tty01	local
X     tty02      local
X     tty03	dial-in
X     tty04	dial-in
X
X  MAIL
X  ----
X  Unidel wants each user's mail database to look like a second news
Xdatabase.  That means there's an '$HOME/mail/active' file, directories
Xfor each mail room under $HOME/mail, and each mail message in an
Xindividually numbered file.
X
X  I've managed this several ways with varying degrees of features:
X
X    Simplest and Easiest:
X       Use 'place' that comes with Unidel.
X
X       If your mail system uses a .forward file, create $HOME/mail and
X       put this in your .forward file:
X
X           "|/usr/local/lib/unidel/place mail"
X
X       Or, if your mail system can put |pipes in /usr/mail/USERNAME,
X       create $HOME/mail and put this in /usr/mail/USERNAME:
X
X           Forward to |/usr/local/lib/unidel/place mail
X
X       'place' will take care of the active file and subdirectories
X       under $HOME/mail.  There will only be one mail room, 'mail'.
X
X    If your mail system can't pipe:
X      Get SMail.
X
X    Multiple Mail Rooms, easy way:
X      Instead of calling 'place' directly, as above, call a shell
X      script that you write that 'cat's stdin to a file, 'grep's it
X      for particular strings ('root', 'sysop', 'help', mail-list
X      addresses, etc.), chooses which room to put it in, then calls
X      'place ROOMNAME' where ROOMNAME is the room you've decided on.
X      Remember to delete the file you 'cat'ed.
X
X    Multiple Mail Rooms, better way:
X      Use Chip Salzenberg's 'deliver' program, then use 'place'.
X
X    Neato Whiz Bang, All the Bells and Whistles:
X      Modify CNews's bin/config file to point NEWSCTL to
X      $HOME/mail.ctl and NEWSARTS to $HOME/mail.  Change
X      ReadActiveFile in Init.c to get 'active' from
X      $HOME/mail.ctl/active instead of $HOME/mail/active.
X      Use 'deliver' or your own shell script to add appropriate
X      "Newsgroups:" header lines and remove "From_" and ">From" lines
X      before calling CNews's 'relaynews' to do actual placement.
X
X      With CNews you can archive, expire, forward to other systems
X      you read mail on, etc.
SHAR_EOF
$TOUCH -am 0502135492 unidel/INSTALL &&
chmod 0444 unidel/INSTALL ||
echo "restore of unidel/INSTALL failed"
set `wc -c unidel/INSTALL`;Wc_c=$1
if test "$Wc_c" != "4249"; then
	echo original size 4249, current size $Wc_c
fi
echo "End of part 2, continue with part 3"
exit 0
