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

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

---- Cut Here and unpack ----
#!/bin/sh
# This is part 04 of unidel-1.0
if touch 2>&1 | fgrep 'amc' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= unidel/Mesg.c ==============
echo "x - extracting unidel/Mesg.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/Mesg.c &&
X/*
X * NAME
X *     Mesg.c -- general message handling functions
X *
X * AUTHOR
X *     Ken MacLeod
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) Mesg.c  1.3 02 May 1992 09:12:35\n\t";
X#endif
X
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
Xchar *GetAddresses ();
Xstatic int ValidAddress ();
X
X#ifdef GETPATH
Xchar *pathfile = _pathsFileName;
X#endif
X
Xint
XValidAddresses (theAddresses)
Xchar *theAddresses;
X{
X  char *addresses, *address;
X  int status = 0;
X
X  addresses = NULL;
X  AllocString (&addresses, theAddresses);
X  if (GetAddresses (addresses) == NULL) {
X    free ((malloc_t)addresses);
X    return (0);
X  }
X  for (address = strtok (addresses, " ");
X       address != NULL;
X       address = strtok ((char *) NULL, " ")) {
X    status = ValidAddress (address);
X  }
X  free ((malloc_t)addresses);
X  return (status);
X}
X
X/*
X  ValidAddress
X
Xreturns 2 (impossible) for mixed ('@' and '!') addresses
X
Xreturns 1 (unlikely) if siteName in 'siteName!userName' or
X   'userName@siteName' is in _remoteUsersFile and userName
X   is not.
X
Xreturns 0 (likely) if any one of the following is true, 2 (impossible)
X   otherwise:
X
X   *  'address' is in 'aliases'
X
X   *  'address' is of the form 'userName' and userName is in 'passwd'
X
X   *  'address' is of the form 'userName@localSite' or 'localSite!userName'
X      and userName is in 'passwd'.  Both forms are converted to 'userName'
X
X   *  'address' is of the form 'userName@siteName' or 'siteName!userName' and
X     siteName or it's domain is in 'paths'.  'siteName!userName' is converted
X     to 'userName@siteName'
X
X   *  'address' is of the form 'siteA!siteB!siteC!userName' and siteA is
X      in 'L.sys' or 'Systems' (depending on UUCP version)
X
X*/
Xstatic int
XValidAddress (address)
Xchar *address;
X{
X  _FuncName ("ValidAddress");
X  char testLine[_bufSize], userName[_bufSize], siteName[_bufSize];
X  char siteRoot[_bufSize], siteDomain[_bufSize];
X  char *ptr, *ptr1;
X  FILE *lookupFile;
X  int hasSite;	/* _true if site is given and is not local site */
X  int hasPath;  /* _true if '!' form with more than one '!', first
X		   site in path can't be domain */
X  int i;
X
X  if ((strchr (address, '@') != NULL) && (strchr (address, '!') != NULL)) {
X    (void) printf ("Mixed addressing ('@' and '!') not allowed.\n");
X    /* XXX Well, we probably could try to resolve it, but why cater to bugs? */
X    return (2);	/* impossible */
X  }
X
X  hasSite = _false;
X  hasPath = _false;
X  userName[0] = siteName[0] = siteRoot[0] = siteDomain[0] = '\0';
X
X  /* Get all the relevant parts of an address */
X  (void)strcpy (testLine, address);
X  for (i = 0; testLine[i] != '\0'; i++)
X    if (isupper (testLine[i]))
X      testLine[i] = tolower (testLine[i]);
X  /* check for form 'siteName![...!]userName' */
X  if ((ptr = strchr (testLine, '!')) != NULL) {
X    *ptr++ = '\0';
X    /* Site name we're interested in is the first or only site */
X    (void)strcpy (siteName, testLine);
X    hasSite = _true;
X    /* the rest of the path plus/or name goes in userName */
X    (void)strcpy (userName, ptr);
X    /* if there's another '!' it's a path */
X    if (strchr (userName, '!') != NULL)
X      hasPath = _true;
X  } else if ((ptr = strchr (testLine, '@')) != NULL) {
X    *ptr++ = '\0';
X    /* Site name is after '@' */
X    (void)strcpy (siteName, ptr);
X    hasSite = _true;
X    /* User name is before '@' */
X    (void)strcpy (userName, testLine);
X  } else {
X    /* 'address' is user name only */
X    (void)strcpy (userName, testLine);
X  }
X
X  /* Split site root and site domain out */
X  if (hasSite) {
X    (void)strcpy (testLine, siteName);
X    if ((ptr = strchr (testLine, '.')) != NULL) {
X      *ptr++ = '\0';
X      (void)strcpy (siteRoot, testLine);
X      (void)strcpy (siteDomain, ptr);
X      if (strcmp (siteDomain, _siteDomain) == 0) {
X	ptr = strchr (siteName, '.');
X	*ptr = '\0';
X      }
X    } else {	/* a name without a domain is assumed to be in our domain */
X      (void)strcpy (siteRoot, testLine);
X      (void)strcpy (siteDomain, _siteDomain);
X    }
X  }
X
X  /* Check to see if 'site' is this site, clear it if so */
X  if (hasSite) {
X    if ((strcmp (siteRoot, _siteName) == 0)
X	&& (strcmp (siteDomain, _siteDomain) == 0)) {
X      siteRoot[0] = siteDomain[0] = siteName[0] = '\0';
X      hasSite = _false;
X    }
X  }
X
X  /* search for 'userName' in alias(8) file, only the first white-space
X     separated field of the alias file is checked */
X  lookupFile = fopen (_aliasFileName, "r");
X  if (lookupFile != NULL) {
X    while (fgets (testLine, _bufSize, lookupFile) != NULL) {
X      if (isspace (testLine[0]) || (testLine[0] == '#'))
X	continue;
X      if ((ptr = strpbrk (testLine, " \t@!:")) != NULL) {
X	if (*ptr == '!') {	/* skip past site if it's first */
X	  ptr1 = ptr ++;
X	  ptr = strpbrk (ptr1, " \t:");
X	  if (ptr == NULL)
X	    continue;
X	} else
X	  ptr1 = testLine;
X	*ptr = '\0';
X	if (strcmp (userName, ptr1) == 0) {
X	  (void)strcpy (address, userName);
X	  (void)fclose (lookupFile);
X	  return (0);	/* likely */
X	}
X      }
X    }
X    (void)fclose (lookupFile);
X  }
X
X  /* search for userName in passwd(4), only the first ':' separated field
X     of the passwd file is checked */
X  if (!hasSite) {
X    lookupFile = fopen (_passwdFileName, "r");
X    if (lookupFile == NULL) {
X      Log (funcName, __LINE__, LOG_ERROR, "Not able to open passwd file.");
X      return (2);	/* impossible */
X    }
X    while (fgets (testLine, _bufSize, lookupFile) != NULL) {
X      if ((ptr = strchr (testLine, ':')) != NULL) {
X	*ptr = '\0';
X	if (strcmp (userName, testLine) == 0) {
X	  (void)strcpy (address, userName);
X	  (void)fclose (lookupFile);
X	  return (0);	/* likely */
X	}
X      }
X    }
X    (void)fclose (lookupFile);
X    (void) printf ("'%s' is not a user on this system.\n", userName);
X    return (2); /* impossible */
X  }
X
X  /* check for siteName in 'L.sys' or 'Systems' file, only the first
X     white-space field is checked */
X  if (hasPath) {
X    lookupFile = fopen (_systemsFileName, "r");
X    if (lookupFile == NULL) {
X      Log (funcName, __LINE__, LOG_ERROR, "Not able to open Systems file.");
X      return (2);	/* impossible */
X    }
X    while (fgets (testLine, _bufSize, lookupFile) != NULL) {
X      if ((ptr = strpbrk (testLine, " \t")) != NULL) {
X	*ptr = '\0';
X	if (strcmp (siteName, testLine) == 0) {
X	  (void)fclose (lookupFile);
X	  return (0);	/* likely */
X	}
X      }
X    }
X    (void)fclose (lookupFile);
X    (void) printf ("'%s' is not a site connected to this system.\n", siteName);
X    /* XXX Attempt "well known site" search on path, display "user@site"
X       result */
X    return (2);	/* Impossible */
X  }
X
X#ifdef GETPATH
X  /* check for siteName in paths(8), only the first tab separated field is
X     checked */
X  if (siteName[0]) {
X    int cost;	/* dummy variable for 'getpath' */
X
X    ptr = siteName;
X    do {
X      if (!getpath (ptr, testLine, &cost))
X	return (0);	/* likely */
X    } while ((ptr = strchr (ptr + 1, '.')) != NULL);
X    (void) printf ("'%s' is not a site reachable from here.\n", siteName);
X    return (2);	/* impossible */
X  }
X#else
X  /* XXX Implement routines for using other mailers' address checking */
X  if (siteName[0]) {
X    /* Don't bother the user just to tell them we can't check */
X    return (0);
X  }
X#endif
X
X  /* We should have checked everything by now */
X  Log (funcName, __LINE__, LOG_ERROR,
X       "Aaack! We're not supposed to reach this looking for '%s'!", address);
X  return (2);	/* Ee gads */
X}
X
Xchar *
XGetAddresses (addresses)
Xchar *addresses;
X{
X  char *ptr, *ptr1;
X  int parenLevel = 0;
X
X  for (ptr1 = ptr = addresses; *ptr1 != '\0'; ptr1 ++) {
X    if (*ptr1 == '(') {
X      if (++parenLevel == 2) {
X	(void) printf ("Nested parenthesis, that's a no-no.\n");
X	return (NULL);
X      }
X      continue;
X    }
X    if (*ptr1 == ')') {
X      parenLevel --;
X      continue;
X    }
X    if (parenLevel != 0)
X      continue;
X    if (*ptr1 == ',') {
X      *ptr++ = ' ';
X      continue;
X    }
X    *ptr++ = *ptr1;
X  }
X  *ptr = '\0';
X  return (addresses);
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/Mesg.c &&
chmod 0444 unidel/Mesg.c ||
echo "restore of unidel/Mesg.c failed"
set `wc -c unidel/Mesg.c`;Wc_c=$1
if test "$Wc_c" != "8028"; then
	echo original size 8028, current size $Wc_c
fi
# ============= unidel/Message.h ==============
echo "x - extracting unidel/Message.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/Message.h &&
X/*
X * NAME
X *     Message.h -- Message handling definitions
X *
X * AUTHOR
X *     Ken MacLeod
X *
X * SCCS
X *     @(#) Message.h  1.2 11 Nov 1990 07:41:52 
X */
X
X#define _transferProtocol 0x00000001l
X#define _readNew 0x00000008l
X#define _readForward 0x00000010l
X#define _readAll 0x00000020l
X#define _readMoreDefault 0x00000040l
X#define _readMore 0x00000080l
X#define _readGlobal 0x00000100l
X#define _readFloor 0x00000200l
X#define _readHeaders 0x00000400l
X
X#define _hdrFrom_ 0
X#define _hdrFrom 1
X#define _hdrPath 2
X#define _hdrNewsgroups 3
X#define _hdrSubject 4
X#define _hdrMessageID 5
X#define _hdrReplyTo 6
X#define _hdrReferences 7
X#define _hdrDate 8
X#define _hdrExpires 9
X#define _hdrControl 10
X#define _hdrSender 11
X#define _hdrFollowupTo 12
X#define _hdrDistribution 13
X#define _hdrOrganization 14
X#define _hdrLines 15
X#define _hdrKeywords 16
X#define _hdrSummary 17
X#define _hdrApproved 18
X#define _hdrUploadFile 19
X#define _hdrTo 20
X#define _hdrPriority 21
X#define _hdrContentType 22
X#define _hdrCc 23
X#define _hdrBcc 24
X#define _hdrUser0 25
X#define _hdrUser1 26
X#define _hdrUser2 27
X#define _hdrUser3 28
X#define _hdrUser4 29
X#define _hdrUser5 30
X#define _hdrUser6 31
X#define _hdrUser7 32
X#define _hdrUser8 33
X#define _hdrUser9 34
X
X#define _hdrMax 35
X
Xextern char signature[];
X
Xextern char *editorName, *editorDescription, *editorFlags,
X  *editorCommand, *filePager;
X
Xtypedef struct {
X	long number;
X	unsigned int read:1;
X	unsigned int checked:1;
X} Article;
X
Xextern Article *articles;
Xextern int numArticles;
SHAR_EOF
$TOUCH -am 0502135492 unidel/Message.h &&
chmod 0444 unidel/Message.h ||
echo "restore of unidel/Message.h failed"
set `wc -c unidel/Message.h`;Wc_c=$1
if test "$Wc_c" != "1505"; then
	echo original size 1505, current size $Wc_c
fi
# ============= unidel/Read.c ==============
echo "x - extracting unidel/Read.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/Read.c &&
X/*
X * NAME
X *     Read.c -- General reading commands and functions
X *
X * AUTHOR
X *     Ken MacLeod
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) Read.c  1.4 02 May 1992 09:13:46\n\t";
X#endif
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <fgetmfs.h>
X#include <time.h>
X#include <string.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 char *hdr[];
Xextern int linesLeft;
Xstatic int PrintMessageByMessageID ();
X
X/* ARGSUSED */
Xint
XReadStatus (dummy)
Xlong dummy;
X{
X  time_t theTime;
X  long totalArticles, diff;
X  int totalRooms, totalFloors;
X  struct tm *tm;
X
X  (void) printf ("  This is %s, site name %s\n", _organization, _siteName);
X  (void) time (&theTime);
X  tm = localtime (&theTime);
X  (void) printf ("  %2d%s%2.2d %d:%2.2d %cm\n", tm -> tm_year,
X		 months[tm -> tm_mon], tm -> tm_mday, tm -> tm_hour % 12,
X		 tm -> tm_min, (tm -> tm_hour / 12) == 0 ? 'a' : 'p');
X  (void) printf ("  Version %s.\n", _version);
X  (void) printf ("  Logged in as %s (%s)\n", logname, longname);
X  if (floorMode)
X    (void) printf ("  Floor mode.\n");
X  (void) printf ("  Your terminal type is %s.\n", terminalType);
X  (void) printf ("  Your transfer protocol is %s.\n",
X		 transferProtocol == NULL ? "None" : transferProtocol);
X  (void) printf ("  Your editor is %s.\n",
X		 editorName == NULL ? "None" : editorName);
X  totalArticles = 0;
X  for (totalRooms = 0; rooms[totalRooms].name != NULL; totalRooms ++)
X    if ((diff = rooms[totalRooms].highest - rooms[totalRooms].lowest) != -1)
X      totalArticles += diff;
X  for (totalFloors = 0; floors[totalFloors].name != NULL; totalFloors ++);
X  (void) printf ("  %ld messages in %d rooms in %d floors.\n", totalArticles,
X		 totalRooms, totalFloors);
X  (void) printf ("  %dmeg message and file space.\n", _siteSize);
X
X  return 0;
X}
X
Xint
XReadMessageByNumber (firstDigit)
Xlong firstDigit;
X{
X  char articleString[_bufSize], fileName[_bufSize];
X  int article;
X
X  articleString[0] = '0' + (char) firstDigit;
X  GetString (&articleString[1], _normal);
X  article = atoi (articleString) - 1;
X  if (article < 0 || article > numArticles) {
X    (void) printf ("%d isn't a valid article number.\n", article + 1);
X    return 0;
X  }
X  (void) sprintf (fileName, "%s/%ld", RoomPath (rooms[currentRoom].name),
X		  articles[article].number);
X  linesLeft = lines;
X  (void) PrintMessage (_readMoreDefault, fileName, article, _false);
X  return 0;
X}
X
Xint
XReadMessageByMessageID ()
X{
X  char messageID[_bufSize], *ptr;
X
X  messageID[0] = '<';
X  GetString (&messageID[1], _normal);
X  ptr = strchr (messageID, '>');
X  if (ptr == NULL)
X    (void)strcat (messageID, ">");
X  if (messageID[0]) {
X    if (!PrintMessageByMessageID (messageID))
X      (void) printf ("Article %s not found.\n", messageID);
X  }
X  return 0;
X}
X
Xstatic int
XPrintMessageByMessageID (messageID)
X/* MessageID must include '<' and '>' */
Xchar *messageID;
X{
X  _FuncName ("PrintMessageByMessageID");
X  FILE *historyFile;
X  char historyFileName[_bufSize], historyLine[_bufSize * 4], *ptr1, *ptr2, fileName[_bufSize];
X  long articleNum, atol ();
X  int article, room;
X
X  (void) sprintf (historyFileName, "%s/history", _newsLibDir);
X  historyFile = fopen (historyFileName, "r");
X  if (historyFile == NULL) {
X    Log (funcName, __LINE__, LOG_WARNING, "Unable to open news history file.");
X    return (_false);
X  }
X  while (fgets (historyLine, _bufSize * 4, historyFile) != NULL) {
X    ptr1 = strchr (historyLine, '\t');	/* ptr1 --> tab before date */
X    if (ptr1 == NULL)
X      continue;	/* If no '\t' then must be a screwy line, try another */
X    *ptr1 = '\0';		/* terminate the messageID */
X    ptr1 = strchr (ptr1 + 1, '\t'); /* ptr1 --> tab before newsgroup/article */
X    /* We should have zipped past the date, if not, then another screwy line */
X    if (ptr1 == NULL)
X      continue;
X    if (ptr1[1] == '\n')
X      continue;	/* this article has expired, don't even try to test it */
X    ptr2 = ptr1 + 1;		/* ptr2 --> newsgroup/article */
X    ptr1 = strchr (ptr2, ' ');	/* ptr1 --> space before newsgroup/article */
X    if (ptr1 == NULL)
X      ptr1 = strchr (ptr2, '\n');	/* if not found, ptr1 --> new-line */
X    if (ptr1 == NULL)
X      continue;			/* if still not found, then it's screwy line */
X    *ptr1 = '\0';		/* terminate the first newsgroup/article */
X    if (strcmp (messageID, historyLine) == 0) {	/* Is this the article we're
X						   looking for? */
X      ptr1 = strrchr (ptr2, '/'); /* ptr1 --> '/' in newsgroup/article */
X      if (ptr1 == NULL)		/* if no '/' then screwy line */
X	return (_false);	/*   since we found the article, we'll exit */
X      articleNum = atol (ptr1 + 1);	/* get article number */
X      *ptr1 = '\0';			/* terminate newsgroup name */
X      room = FindRoom (_findExact, ptr2);
X      Goto (room);
X      for (article = 0;
X	   article < numArticles && articles[article].number != articleNum;
X	   article ++)
X	;
X      if (article < numArticles) {
X	(void) sprintf (fileName, "%s/%ld", RoomPath (rooms[currentRoom].name),
X			articles[article].number);
X	linesLeft = lines;
X	if (PrintMessage (_readMoreDefault, fileName, article, _false) == -1)
X	  return (_false);
X	else
X	  return (_true);
X      }
X      return (_false);
X    }
X  }
X  return (_false);
X}
X
Xint
XReadMessages (flags)
Xlong flags;
X{
X  _FuncName ("ReadMessages");
X  char fileName[_bufSize], dumpFileName[_bufSize];
X  int article, increment, start, end, back;
X
X  if (numArticles == 0)
X    return 0;
X
X  if (flags & _readForward) {
X    start = 0;
X    end = numArticles;
X    increment = 1;
X  } else {
X    start = numArticles - 1;
X    end = -1;
X    increment = -1;
X  }
X
X  if (flags & _transferProtocol) {
X    (void) sprintf (dumpFileName, "%s/tempFile", flTempDir);
X    dumpFile = fopen (dumpFileName, "w");
X    (void) printf ("Pre96paring download file...\n");
X  }
X
X  back = _false;		/* back == 2 to exit */
X  linesLeft = lines;
X  for (article = start; back != 2 && article != end; article += increment) {
X    if (!((flags & _readAll) || back
X	  || ((flags & _readNew) && !articles[article].read)
X	  || (!(flags & _readNew) && articles[article].read))) {
X      continue;
X    }
X    (void) sprintf (fileName, "%s/%ld", RoomPath (rooms[currentRoom].name),
X		    articles[article].number);
X    back = PrintMessage (flags, fileName, article, back);
X    if (back == _true) {
X      article -= increment * 2;
X    }
X    if (article < -1)
X      article = -1;
X    else if (article > numArticles)
X      article = numArticles;
X  }
X	
X  if (flags & _transferProtocol) {
X    (void)fclose (dumpFile);
X    dumpFile = stdout;
X    (void) printf ("Download file completed.\n");
X    ReadOneFile (dumpFileName);
X    if (unlink (dumpFileName) == -1) {
X      /* XXX errno? */
X      Log (funcName, __LINE__, LOG_ERROR,
X	   "Unlinking temporary download file '%s'.\n", dumpFileName);
X    }
X  }
X  return 0;
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/Read.c &&
chmod 0444 unidel/Read.c ||
echo "restore of unidel/Read.c failed"
set `wc -c unidel/Read.c`;Wc_c=$1
if test "$Wc_c" != "6873"; then
	echo original size 6873, current size $Wc_c
fi
# ============= unidel/ReadFile.c ==============
echo "x - extracting unidel/ReadFile.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/ReadFile.c &&
X/*
X * NAME
X *     ReadFile.c -- File reading (download) functions
X *
X * AUTHOR
X *     Ken MacLeod
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) ReadFile.c  1.5 02 May 1992 10:03:00\n\t";
X#endif
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <string.h>
X#include <time.h>
X#include <malloc.h>
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#include "File.h"
X#include "Log.h"
X
Xstatic char *fileFieldNames[] = {
X  "File: ",
X  "Desc: ",
X  "User: ",
X  "Date: ",
X  NULL,
X};
X
Xtypedef struct _fileList {
X  struct _fileList *next;
X  char *fileName;
X} FileList;
Xstatic FileList *ExpandFiles ();
X
Xstatic void ReadFile ();
X
X/* ARGSUSED */
Xint
XReadFileCommand (type)
Xlong type;
X{
X  char fileNames[_bufSize];
X  FileList *expandedList;
X
X  if (rooms[currentRoom].fileDir == NULL) {
X    (void) printf ("Files are only in rooms that end with \"]\".\n");
X    return 0;
X  }
X
X  (void) printf ("Enter filename(s):\n:");
X  GetString (&fileNames[0], _normal);
X  if (fileNames[0] == '\0') {
X    return 0;
X  }
X  if ((expandedList
X       = ExpandFiles (&fileNames[0],
X		      rooms[currentRoom].fileDir)) == (FileList *) NULL)
X    return 0;
X
X  ReadFile (expandedList);
X  while (expandedList != (FileList *) NULL) {
X    FileList *pp;
X
X    pp = expandedList;
X    free (pp -> fileName);
X    free (pp);
X    expandedList = pp -> next;
X  }
X
X  return 0;
X}
X
Xvoid
XReadOneFile (fileName)
Xchar *fileName;
X{
X  _FuncName ("ReadOneFile");
X  FileList *fileNames;
X
X  fileNames = (FileList *) malloc (sizeof (FileList));
X  if (fileNames == (FileList *) NULL) {
X    Log (funcName, __LINE__, LOG_ERROR, _outOfMemory);
X    exit (1);
X  }
X  fileNames->next = (FileList *) NULL;
X  fileNames->fileName = strdup (fileName);
X  if (fileNames->fileName == (char *) NULL) {
X    Log (funcName, __LINE__, LOG_ERROR, _outOfMemory);
X    exit (1);
X  }
X  ReadFile (fileNames);
X}
X
Xstatic void
XReadFile (fileNames)
XFileList *fileNames;
X{
X  char *commandString, *commandString1, destFileName[_bufSize],
X  readyQuestion[_bufSize], *oneFile;
X  int multipleFiles;
X
X  multipleFiles = fileNames->next != (FileList *) NULL;
X  if (local) {
X    (void) printf ("Download to: ");
X    GetString (destFileName, _normal);
X    if (destFileName[0] != '\0') {
X      if (multipleFiles)
X	(void) strcat (destFileName, "/");
X      while (fileNames != (FileList *) NULL) {
X	commandString
X	  = (char *)malloc ((size_t) (strlen (destFileName)
X				      + strlen (fileNames->fileName)) + 80);
X	(void) sprintf (commandString, "exec cp %s %s", fileNames->fileName,
X			destFileName);
X	(void)system (commandString);
X	free ((malloc_t)commandString);
X	fileNames = fileNames->next;
X      }
X    }
X  } else {
X    if (transferProtocol == NULL) {
X      (void) printf ("You have not selected a transfer protocol.\n");
X      return;
X    }
X    if (transferReadCommand == NULL) {
X      (void) printf ("%s transfer not implemented.\n", transferProtocol);
X      return;
X    }
X    /* 80 is a catchall for the 'exec' call below */
X    commandString
X      = (char *)malloc ((size_t) (strlen (transferReadCommand)
X				  + strlen (fileNames->fileName)) + 80);
X    commandString1
X      = (char *)malloc ((size_t) (strlen (transferReadCommand)
X				  + strlen (fileNames->fileName)) + 1);
X    (void) sprintf (readyQuestion, "Ready for %s download? ",
X		    transferProtocol);
X    if (transferBatch) {
X      if (AnswerYesNo (readyQuestion,
X		       _defaultAnswer | _defaultYes | _noEcho) == _true) {
X	/* XXX This isn't BATCH! */
X	(void) sprintf (commandString1, transferReadCommand,
X			fileNames->fileName);
X	/* XXX Not secure, but if I remember, rz/sz tests SHELL=r* and */
X	/* does not allow absolute file names? */
X	(void) sprintf (commandString, "cd %s ; exec %s",
X			rooms[currentRoom].fileDir
X			? rooms[currentRoom].fileDir : ".", commandString1);
X#ifdef notdef
X	(void) sprintf (commandString, "export SHELL PATH ; SHELL=/bin/rsh PATH=/usr/rbin cd %s ; exec %s",
X			rooms[currentRoom].fileDir, commandString1);
X#endif
X	(void) system (commandString);
X      }
X    } else {
X      oneFile = strtok (fileNames->fileName, " ");
X      while (oneFile != NULL) {
X	if (AnswerYesNo (readyQuestion,
X			 _defaultAnswer | _defaultYes | _noEcho) == _true) {
X	  (void) sprintf (commandString1, transferReadCommand, oneFile);
X	  /* XXX Not secure, but if I remember, rz/sz tests SHELL=r* and */
X	  /* does not allow absolute file names? */
X	  (void) sprintf (commandString, "cd %s ; exec %s",
X			  rooms[currentRoom].fileDir
X			  ? rooms[currentRoom].fileDir : ".", commandString1);
X#ifdef notdef
X	  (void) sprintf (commandString, "export SHELL PATH ; SHELL=/bin/rsh PATH=/usr/rbin cd %s ; exec %s",
X			  rooms[currentRoom].fileDir, commandString1);
X#endif
X	  (void) system (commandString);
X	} else
X	  break;
X	oneFile = strtok ((char *) NULL, " ");
X      }
X    }
X    free ((malloc_t)commandString);
X    free ((malloc_t)commandString1);
X  }
X}
X
Xint
XReadDirectory (extended)
Xlong extended;
X{
X  void ClearHeader (), FreeHeader ();
X  FILE *fileList;
X  struct stat statBuffer;
X  char *fileDesc[_maxFileFields];
X#ifdef useRegex
X  char *re, *regcmp (), *regex (), *dummy, *lcTemp;
X#endif
X  char fileListName[_bufSize];
X  char matchPattern[_bufSize], commandString[_bufSize];
X  char *ToLower ();
X  char uploadDate[14], *fileName, fileSize[14];
X  int found, aChar;
X  time_t messageTime, parsedate ();
X  struct tm *tm;
X
X  if (rooms[currentRoom].fileDir != NULL) {
X    if (extended) {
X      GetString (matchPattern, _normal);
X      (void) ToLower (matchPattern);
X#ifdef useRegex
X      if (matchPattern[0]) {
X	re = regcmp (matchPattern, NULL);
X      } else
X	re = NULL;
X#endif
X      (void) sprintf (fileListName, "%s/.fileList",
X		      rooms[currentRoom].fileDir);
X      if ((fileList = fopen (fileListName, "r")) != NULL) {
X	for (;;) {
X	  /* Read up to a non new-line */
X	  while ((aChar = getc (fileList)) == '\n')
X	    ;
X	  (void)ungetc (aChar, fileList);
X	  /* Termination condition */
X	  if (aChar == EOF)
X	    break;
X
X	  /* Read file entry */
X	  ClearHeader (fileDesc, fileFieldNames);
X	  /* XXX Status from ReadHeader */
X	  (void) ReadHeader (fileList, fileDesc, fileFieldNames);
X	  if (fileDesc[_fileName] == NULL) {
X	    FreeHeader (fileDesc, fileFieldNames);
X	    continue;
X	  }
X#ifdef useRegex
X	  /* If we have a search string, look for it */
X	  if (re == NULL)
X	    /* If we don't have a search string, print everything */
X	    found = _true;
X	  else {
X	    AllocString (&lcTemp, fileDesc[_fileName]);
X	    found = regex (re, ToLower (lcTemp), &dummy, &dummy, &dummy,
X			   &dummy, &dummy, &dummy, &dummy, &dummy, &dummy,
X			   &dummy) != NULL;
X	    free ((malloc_t)lcTemp);
X	    if (!found && fileDesc[_fileDesc]) {
X	      AllocString (&lcTemp, fileDesc[_fileDesc]);
X	      found = regex (re, ToLower (lcTemp), &dummy, &dummy, &dummy,
X			     &dummy, &dummy, &dummy, &dummy, &dummy, &dummy,
X			     &dummy) != NULL;
X	      free ((malloc_t)lcTemp);
X	    }
X	    if (!found && fileDesc[_fileUser]) {
X	      AllocString (&lcTemp, fileDesc[_fileUser]);
X	      found = regex (re, ToLower (lcTemp), &dummy, &dummy, &dummy,
X			     &dummy, &dummy, &dummy, &dummy, &dummy, &dummy,
X			     &dummy) != NULL;
X	      free ((malloc_t)lcTemp);
X	    }
X	  }
X#else
X	  found = _true;
X#endif
X	  if (found) {
X	    fileName =
X	      (char *)malloc ((size_t) (strlen (rooms[currentRoom].fileDir)
X					+ strlen (fileDesc[_fileName]) + 2));
X	    (void) sprintf (fileName, "%s/%s", rooms[currentRoom].fileDir,
X			    fileDesc[_fileName]);
X	    if (stat (fileName, &statBuffer) != -1)
X	      (void) sprintf (fileSize, "%ld", statBuffer.st_size);
X	    else
X	      (void) strcpy (fileSize, "offlin");
X	    if (fileDesc[_fileDate]) {
X	      messageTime = parsedate (fileDesc[_fileDate], NULL);
X	      tm = localtime (&messageTime);
X	      (void) sprintf (uploadDate, "(%d%s%2d)", tm -> tm_year,
X			      months[tm -> tm_mon], tm -> tm_mday);
X	    } else
X	      uploadDate[0] = '\0';
X	    (void) printf ("%-14s %6s | %s%s\n", fileDesc[_fileName],
X			   fileSize, fileDesc[_fileDesc]
X			   ? fileDesc[_fileDesc] : "", uploadDate);
X	    free ((malloc_t)fileName);
X	  }
X	  FreeHeader (fileDesc, fileFieldNames);
X	}
X      }
X#ifdef useRegex
X      if (re != NULL)
X	free ((malloc_t)re);
X#endif
X    } else {
X      GetString (matchPattern, _normal);
X      (void) sprintf (commandString, "cd %s ; exec ls -FRs %s",
X		      rooms[currentRoom].fileDir, matchPattern);
X      (void)system (commandString);
X    }
X  } else {
X    (void) printf ("\nFiles are only in rooms that end with \"]\".\n");
X  }
X
X  return 0;
X}
X
X/* ARGSUSED */
Xint
XReadArchiveHeader (dummy)
Xlong dummy;
X{
X  char fileName[_bufSize], filePath[_bufSize], commandString[_bufSize], *ptr;
X
X  if (rooms[currentRoom].fileDir == NULL) {
X    (void) printf ("\nFiles are only in rooms that end with \"]\".\n");
X    return 0;
X  }
X
X  (void) printf ("Enter Filename:\n: ");
X  GetString (fileName, _normal);
X  if (fileName[0] == '\0')
X    return 0;
X
X  if (fileName[0] == '/') {
X    (void) strcpy (filePath, fileName);
X  } else {
X    (void) sprintf (filePath, "%s/%s", rooms[currentRoom].fileDir, fileName);
X  }
X  ptr = strrchr (fileName, '.');
X  if ((ptr != NULL) && (strcmp (ptr, ".arc") == 0)) {
X    if (!access (filePath, 4)) {
X      (void) sprintf (commandString, "exec arc -il %s", filePath);
X      (void)system (commandString);
X    }
X  } else {
X    (void) printf ("File is not an archived file.\n");
X  }
X
X  return 0;
X}
X
Xstatic FileList *
XExpandFiles (fileNames, fileDir)
Xchar *fileNames, *fileDir;
X{
X  _FuncName ("ExpandFiles");
X  FileList *expandedFiles = (FileList *) NULL, *prevFile, *thisFile;
X  char *pp;
X  int fileDirNameLen;
X
X  fileDirNameLen = (fileDir != (char *) NULL) ? strlen (fileDir) : 0;
X  pp = strtok (fileNames, ", \t\n");
X  while (pp != (char *) NULL) {
X    thisFile = (FileList *) malloc (sizeof (FileList));
X    if (thisFile == (FileList *) NULL) {
X      Log (funcName, __LINE__, LOG_ERROR, _outOfMemory);
X      exit (1);
X    }
X    if (expandedFiles == (FileList *) NULL)
X      expandedFiles = thisFile;
X    else
X      /*LINTED prevFile used only after first iteration */
X      prevFile -> next = thisFile;
X    thisFile -> fileName = (char *) malloc (fileDirNameLen
X					    + strlen (pp) + 1);
X    if (thisFile -> fileName == (char *) NULL) {
X      Log (funcName, __LINE__, LOG_ERROR, _outOfMemory);
X      exit (1);
X    }
X    if (fileDir != (char *) NULL) {
X      (void) strcpy (thisFile -> fileName, fileDir);
X      (void) strcat (thisFile -> fileName, "/");
X      (void) strcat (thisFile -> fileName, pp);
X    } else {
X      (void) strcpy (thisFile -> fileName, pp);
X    }
X    thisFile -> next = (FileList *) NULL;
X    prevFile = thisFile;
X    pp = strtok ((char *) NULL, ", \t\n");
X  }
X  return (expandedFiles);
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/ReadFile.c &&
chmod 0444 unidel/ReadFile.c ||
echo "restore of unidel/ReadFile.c failed"
set `wc -c unidel/ReadFile.c`;Wc_c=$1
if test "$Wc_c" != "10722"; then
	echo original size 10722, current size $Wc_c
fi
echo "End of part 4, continue with part 5"
exit 0
