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

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

---- Cut Here and unpack ----
#!/bin/sh
# This is part 03 of unidel-1.0
if touch 2>&1 | fgrep 'amc' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= unidel/Init.c ==============
echo "x - extracting unidel/Init.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/Init.c &&
X/*
X * NAME
X *     Init.c -- Load and initialization functions
X *
X * AUTHOR
X *     Ken MacLeod
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) Init.c  1.14 02 May 1992 10:51:01\n\t";
X#endif
X
X#include <sys/types.h>
X#include <fgetmfs.h>
X#include <stdio.h>
X#include <string.h>
X#include <malloc.h>
X#include <ctype.h>
X#include <search.h>
X#include <getenvs.h>
X#include <pwd.h>
X#include "protos.h"
X#include "Log.h"
X#include "defs.h"
X#include "Unidel.h"
X#include "Message.h"
X#include "User.h"
X#include "Room.h"
X#include "File.h"
X
Xstatic void ReadUserControlFile(), ReadNewsFile(), ReadFileDirectoryFile (),
X  ReadNewsgroupsFile (), ReadFloorsFile(), Initialize (), ReadActiveFile (),
X  ReadUserFile (), UserLoop (), WriteNewsFile (), WriteUserFile (),
X  UnInitialize ();
X
XENTRY *hsearch ();
X
Xextern Envs envs[];		/* Environment table */
X
Xstatic char *userFieldNames[] = {
X  "Mail-Directory: ",
X  "Terminal: ",
X  "Editor: ",
X  "More: ",
X  "FloorMode: ",
X  "ExpertMode: ",
X  "Columns: ",
X  "Lines: ",
X  "Transfer: ",
X  "KnownFloors: ",
X  "Pager: ",
X  NULL,
X};
Xchar *user[sizeof (userFieldNames)/sizeof (char *)-1];
X
Xstatic char *controlFieldNames[] = {
X  "Invited: ",
X  NULL,
X};
Xstatic char *control[sizeof (userFieldNames)/sizeof (char *)-1];
X
X/* the options line from .newsrc, will be saved and re-written out
X   if needed */
Xstatic char *options = NULL;
X
Xint secure;	/* true if we started as r* */
Xextern char version[];
X
Xmain (argc, argv)
X
Xint argc;
Xchar *argv[];
X
X{
X  extern char *logFileName;
X
X  if (InitLog (argv[0]) == -1) {
X    (void) fprintf (stderr, "Unable to initialize logging.\n");
X    exit (1);
X  }
X  debugMask = ~0l;
X  whereMask = ~0l;
X  logFileName = "/usr/local/lib/unidel/lib/log";
X
X  (void)hcreate (_maxRooms);
X  free (malloc (32000));	/* Keep from calling brk so many times */
X  setbuf (stdout, (char *) NULL);
X  Initialize (argc, argv);
X  (void) printf ("Running: %s\n", version);
X  (void) printf (".");
X  ReadFloorsFile ();		/* '_libDir/Floors', floor descriptions */
X  (void) printf (".");
X  ReadNewsFile ();		/* '$HOME/.newsrc' Articles that user has
X				   already read, fills 'room' array in
X				   user's preferred order */
X  (void) printf (".");
X  ReadActiveFile ();		/* '_newsLibDir/active' Articles that are
X				   available, adds any rooms not in
X				   '.newsrc' */
X  (void) printf (".");
X  ReadUserFile ();		/* '$HOME/.unidelrc' */
X  (void) printf (".");
X  ReadUserControlFile ();		/* '_libDir/Admin/$LOGNAME' */
X  (void) printf (".");
X  ReadFileDirectoryFile ();	/* '_libDir/FileDirs' */
X  (void) printf (".");
X  ReadNewsgroupsFile ();		/* '_newsLibDir/newsgroups' */
X  (void) printf (".");
X
X  ScanNewArticles ();		/* Find out which newsgroups have new
X				   articles */
X  (void) printf ("\n");
X
X  SetupTerminal (_true);
X  UserLoop ();
X  SetupTerminal (_false);
X
X  WriteNewsFile ();
X  WriteUserFile ();
X  UnInitialize ();
X
X  return (0);
X}
X
X/*ARGSUSED*/
Xstatic void
XInitialize (argc, argv)
Xint argc;
Xchar *argv[];
X{
X  _FuncName ("Initialize");
X  struct passwd *pwdEnt;
X  char commandString[_bufSize], *lineBuf, *ptr, *realLine,
X  *ttyname ();
X  FILE			*ttyFile;
X
X  /* modes */
X  local = _false;
X  dumpFile = stdout;
X  secure = (programName [0] == 'r')
X    || ((programName[0] == '-') && (programName[1] == 'r'));
X
X  if ((realLine = ttyname (fileno (stdin))) != NULL) {
X    if ((ptr = strrchr (realLine, '/')) != NULL)
X      realLine = ptr + 1;
X    if ((ttyFile = fopen (_local, "r")) != NULL) {
X      while ((lineBuf = fgetms (ttyFile)) != NULL) {
X	if (IsIn (realLine, lineBuf) && IsIn (_isLocal, lineBuf)) {
X	  local = _true;
X	  free ((malloc_t)lineBuf);
X	  break;
X	}
X	free ((malloc_t)lineBuf);
X      }
X      (void)fclose (ttyFile);
X    }
X  }
X
X  if (getenvs (envs) == -1) {
X    Log (funcName, __LINE__, LOG_ERROR, _outOfMemory);
X    exit (1);
X  }
X
X  if ((pwdEnt = getpwnam (logname)) == (struct passwd *) NULL) {
X    longname = (char *) NULL;
X  } else {
X    AllocString (&longname, pwdEnt -> pw_comment);
X  }
X	
X  guest = (strcmp (logname, _guestName) == 0) ? _true : _false;
X
X  if ((rooms = (Room *) malloc ((size_t) _maxRooms * sizeof (Room))) == NULL) {
X    Log (funcName, __LINE__, LOG_ERROR, _outOfMemory);
X    exit (1);
X  }
X
X  (void) memset ((char *) rooms, 0, _maxRooms * sizeof (Room));
X
X  floors = (Floor *) malloc ((size_t) _maxFloors * sizeof (Floor));
X  if (floors == NULL) {
X    Log (funcName, __LINE__, LOG_ERROR, _outOfMemory);
X    exit (1);
X  }
X
X  (void) memset ((char *) floors, 0, _maxFloors * sizeof (Floor));
X
X  (void) sprintf (commandString, "%s/unidelin", _libDir);
X  if (!access (commandString, 0))
X    (void)system (commandString);
X  (void) sprintf (commandString, "%s/.unidelin", homeDir);
X  if (!access (commandString, 0))
X    (void)system (commandString);
X
X  flTempDir = tmpnam ((char *) NULL);
X  flTempDir = KeepString (flTempDir, strlen (flTempDir));
X  if (mkdir (flTempDir, 0755) == -1) {
X    Log (funcName, __LINE__, LOG_ERROR, "Cannot mkdir '%s'.", flTempDir);
X    exit (1);
X  }
X}
X
X/* Read in user's '.unidelrc' file */
Xstatic void
XReadUserFile ()
X{
X  _FuncName ("ReadUserFile");
X  void ClearHeader ();
X  FILE *userFile;
X  char userFileName[_bufSize], *knownFloor, *ptr;
X  int floor;
X
X  (void) sprintf (userFileName, "%s/.unidelrc", homeDir);
X  if (access (userFileName, 0)) {	/* Is there a unidelrc file? */
X    if (close (creat (userFileName, 0666))) {	/* No, try to create it */
X      Log (funcName, __LINE__, LOG_WARNING, "Cannot create '%s'.",
X	   userFileName);
X    }
X  }
X  userFile = fopen (userFileName, "r");
X  if (userFile == NULL) {
X    Log (funcName, __LINE__, LOG_ERROR, "Unable to open '%s'.", userFileName);
X    exit (1);
X  }
X  ClearHeader (user, userFieldNames);
X  /* XXX Check status from ReadHeader */
X  (void) ReadHeader (userFile, user, userFieldNames);
X  (void)fclose (userFile);
X
X  if (user[_userTerm] && (putenvs (envs, "TERM", user[_userTerm]) == -1)) {
X    Log (funcName, __LINE__, LOG_ERROR, _outOfMemory);
X    exit (1);
X  }
X
X  more = moreDefault = 1;
X  if (user[_userMore] && isdigit (user[_userMore][0]))
X    more = moreDefault = atoi (user[_userMore]);
X  if (more < 0 || more > 2)
X    more = 1;
X
X  if (user[_userFloorMode])
X    floorMode = (strcmp (user[_userFloorMode], "Yes") == 0) ? _true : _false;
X  else
X    floorMode = _true;
X  if (user[_userExpertMode])
X    expertMode = (strcmp (user[_userExpertMode], "Yes") == 0) ? _true : _false;
X  else
X    expertMode = _false;
X
X  columns = 80;
X  if (user[_userTermWidth])
X    columns = atoi (user[_userTermWidth]);
X  lines = 24;
X  if (user[_userTermHeight])
X    lines = atoi (user[_userTermHeight]);
X
X  transferProtocol = NULL;
X  SetupTransferProtocol (user[_userProtocol]);
X  if (editorCommand != NULL) {
X    editorName = NULL;
X    /* XXX KeepString? */
X    AllocString (&editorName, editorCommand);
X    (void) strtok (editorName, " \t");
X    if ((ptr = strrchr (editorName, '/')) != NULL)
X      editorName = ptr;
X    SetupEditor (editorName);
X  } else
X    SetupEditor (user[_userEditor]);
X  /* XXX	SetupPager (&user[_userPager]); */
X
X  /* knownFloors are floors that we know about, i.e. not forgotten */
X  if (user[_userFloors]) {
X    int forgotten;
X
X    for (knownFloor = strtok (user[_userFloors], ", ");
X	 knownFloor != NULL;
X	 knownFloor = strtok ((char *)NULL, ", ")) {
X      if (*knownFloor == '!') {
X	forgotten = _true;
X	knownFloor ++;
X      } else {
X	forgotten = _false;
X      }
X      for (floor = 0;
X	   (floors[floor].name != NULL)
X	   && (strcmp (floors[floor].name, knownFloor) != 0);
X	   floor ++);
X      if (floors[floor].name != NULL)
X	floors[floor].forgotten = forgotten;
X    }
X    free ((malloc_t)user[_userFloors]), user[_userFloors] = NULL;
X  }
X}
X
Xstatic void
XReadUserControlFile ()
X{
X  void ClearHeader ();
X  ENTRY theEntry, *entry;
X  FILE *controlFile;
X  char controlFileName[_bufSize], *knownFloor;
X  int floor;
X
X  (void) sprintf (controlFileName, "%s/Admin/%s", _libDir, logname);
X  controlFile = fopen (controlFileName, "r");
X  if (controlFile == NULL)
X    return;			/* No problem if no file for this user */
X  ClearHeader (control, controlFieldNames);
X  /* XXX Check status from ReadHeader */
X  (void) ReadHeader (controlFile, control, controlFieldNames);
X  (void)fclose (controlFile);
X
X  /* Invited are rooms and floors that we have been invited into */
X  if (control[_controlInvited]) {
X    knownFloor = strtok (control[_controlInvited], ", ");
X    while (knownFloor != NULL) {
X      for (floor = 0;
X	   (floors[floor].name != NULL)
X	   && strcmp (floors[floor].name, knownFloor) != 0;
X	   floor ++);
X      if (floors[floor].name != NULL)
X	floors[floor].invited = _true;
X      else {	/* try rooms */
X	theEntry.key = knownFloor;
X	theEntry.data = NULL;
X	if ((entry = hsearch (theEntry, FIND)) != NULL)
X	  ((Room *) entry -> data) -> invited = _true;
X      }
X      knownFloor = strtok ((char *) NULL, ", ");
X    }
X    free ((malloc_t)control[_controlInvited]);
X    control[_controlInvited] = NULL;
X  }
X}
X
Xstatic void
XReadNewsFile ()
X/* Read in user's '.newsrc' file */
X
X{
X  _FuncName ("ReadNewsFile");
X  ENTRY theEntry;
X  FILE *newsrcFile;
X  char newsrcFileName[_bufSize], *newsrcLine, *roomName, *articlesRead, *ptr;
X  int line, i;
X
X  (void) sprintf (newsrcFileName, "%s/.newsrc", homeDir);
X  if ((newsrcFile = fopen (newsrcFileName, "r")) == NULL)
X    return;
X
X  line = -1;
X  options = NULL;
X  while ((newsrcLine = cfgetms (newsrcFile)) != NULL) {
X    if (line == -1 && strncmp (newsrcLine, "options", 7) == 0) {
X      options = newsrcLine;	/* We'll leave the malloced string in
X				   the options variable */
X      continue;
X    }
X
X    if (++line >= _maxRooms) {
X      Log (funcName, __LINE__, LOG_ERROR, "Too many .newsrc lines.");
X      exit (1);			/* XXX is this necessary? */
X    }
X
X    /* Note: We're using pointers here instead of strtok/split for speed */
X    /* Get room name, name length in i */
X    roomName = ptr = newsrcLine;
X    while (*ptr && *ptr != ' ' && *ptr != '!' && *ptr != ':')
X      ptr++;
X    i = ptr - roomName; /* String length */
X    /* Test forgotten/not-forgotten flag */
X    if (*ptr == '!')
X      rooms[line].forgotten = 1;
X    else
X      rooms[line].forgotten = 0;
X    *ptr++ = '\0';
X    while (*ptr && (*ptr == ' ' || *ptr == '\t')) /* skip spaces */
X      ptr++;
X    /* Get articles read */
X    articlesRead = ptr;
X    while (*ptr && *ptr != '\n')
X      ptr ++;
X    *ptr = '\0';
X
X    rooms[line].name = KeepString (roomName, i);
X    AllocString (&rooms[line].articlesRead, articlesRead);
X    rooms[line].originalArticlesRead = KeepString (articlesRead, i);
X    for (i = 0;
X	 floors[i].name != NULL
X	 && strncmp (floors[i].name, rooms[line].name,
X		     floors[i].nameLength - 1) != 0;
X	 i ++);
X    if (floors[i].name == NULL)
X      i = 0;
X    rooms[line].floor = (short) i;
X
X    theEntry.key = rooms[line].name;
X    theEntry.data = (char *) &rooms[line];
X    (void) hsearch (theEntry, ENTER);
X    free ((malloc_t)newsrcLine);
X  }
X  (void)fclose (newsrcFile);
X}
X
Xstatic void
XReadActiveFile ()
X{
X  _FuncName ("ReadActiveFile");
X  FILE *activeFile;
X  ENTRY theEntry, *entry;
X  Room *theRoom;
X  char *activeFileNames[2], types[2], *ptr;
X  char activeLine[_bufSize], *roomStatus, *roomName, *highestString,
X  *lowestString;
X  int n, i, j, room, highest, lowest, newRoom;
X  short floor;
X
X  /* parse Active files for newsgroups and highest/lowest values */
X  /* XXX where we get active files should be more generic,
X     from Config and .unidelrc maybe? */
X  /* XXX Because news/active is parsed before mail/active
X     newsgroups are, mail shows up last in the G)oto/N)ew sequence */
X  activeFileNames[0] = (char *)malloc ((size_t) strlen (_newsLibDir) + 8);
X  (void) sprintf (activeFileNames[0], "%s/active", _newsLibDir);
X  types[0] = _newsType;
X  activeFileNames[1] = (char *)malloc ((size_t) strlen (homeDir) + 14);
X  (void) sprintf (activeFileNames[1], "%s/mail/active", homeDir);
X  types[1] = _mailType;
X  for (j = 0; j < 2; j ++) {
X    activeFile = fopen (activeFileNames[j], "r");
X    if (activeFile == (FILE *)NULL)
X      continue;
X
X    while (fgets (activeLine, _bufSize, activeFile) != (char *)NULL) {
X      roomName = ptr = activeLine;
X      while (*ptr && *ptr != ' ')
X	ptr ++;
X      *ptr++ = '\0';
X      highestString = ptr;
X      while (*ptr && *ptr != ' ')
X	ptr ++;
X      *ptr++ = '\0';
X      highest = atoi (highestString);
X      lowestString = ptr;
X      while (*ptr && *ptr != ' ')
X	ptr++;
X      *ptr++ = '\0';
X      lowest = atoi (lowestString);
X      roomStatus = ptr;
X      while (*ptr && *ptr != ' ' && *ptr != '\n' && *ptr != '\t')
X	ptr++;
X      *ptr = '\0';
X
X      newRoom = _false;
X      theEntry.key = roomName;
X      theEntry.data = NULL;
X      entry = hsearch (theEntry, FIND);
X      if (entry == NULL) {
X	for (room = 0; rooms[room].name != NULL; room ++);
X	if (room >= _maxRooms) {
X	  Log (funcName, __LINE__, LOG_ERROR, 
X	       "Too many .newsrc lines.");
X	  exit (1);
X	}
X				
X	n = strlen (roomName);
X	rooms[room].name = KeepString (roomName, n);
X	/*AllocString (&rooms[room].articlesRead, "");*/
X	rooms[room].originalArticlesRead = KeepString ("", 0);
X	newRoom = _true;
X	theEntry.key = rooms[room].name;
X	theEntry.data = (char *) &rooms[room];
X	(void) hsearch (theEntry, ENTER);
X	theRoom = &rooms[room];
X      } else
X	theRoom = (Room *) entry -> data;
X      theRoom -> lowest = lowest;
X      theRoom -> highest = highest;
X      theRoom -> type = types[j];
X      for (floor = 0; floors[floor].name != NULL
X	   && strncmp (floors[floor].name, theRoom -> name,
X		       floors[floor].nameLength - 1) != 0;
X	   floor ++)
X	;
X
X      if (floors[floor].name == NULL)
X	floor = 0;
X      theRoom -> floor = floor;
X      for (i = 0; roomStatus[i] != '\0'; i ++) {
X	if (islower (roomStatus[i]))
X	  roomStatus[i] = toupper (roomStatus[i]);
X
X	switch (roomStatus[i]) {
X	case 'A':	/* Anonymous */
X	  theRoom -> anonymous = _true;
X	  break;
X	case 'D':	/* Display article number */
X	  theRoom -> displayNumber = _true;
X	  break;
X	case 'I':	/* Invite only */
X	  theRoom -> inviteOnly = _true;
X	  /* FALLTHRU */
X	case 'P':	/* Private */
X	  theRoom -> private = _true;
X	  /* FALLTHRU */
X	case 'F':	/* Forgotten */
X	  if (newRoom)
X	    theRoom -> forgotten = _true;
X	  break;
X	case 'L':	/* local distribution only */
X	  theRoom -> localOnly = _true;
X	  break;
X	case 'M':	/* moderated */
X	  theRoom -> moderated = _true;
X	  break;
X	case 'R':	/* Read only */
X	  theRoom -> readOnly = _true;
X	  break;
X	case 'S':	/* Display Subject */
X	  theRoom -> displaySubject = _true;
X	  break;
X	}
X      }
X    }
X    (void)fclose (activeFile);
X  }
X}
X
Xstatic void
XReadFileDirectoryFile ()
X
X{
X  ENTRY theEntry, *entry;
X  FILE *directoryFile;
X  char directoryFileName[_bufSize], *lineBuf, *fields[3];
X  int nf;
X
X  /* parse FileDir file directories matched to rooms */
X  (void) sprintf (directoryFileName, "%s/FileDirs", _libDir);
X  directoryFile = fopen (directoryFileName, "r");
X  if (directoryFile == NULL)
X    return;
X
X  while ((lineBuf = fgetms (directoryFile)) != NULL) {
X    if (lineBuf[0] == '#' || isspace (lineBuf[0])) {
X      free ((malloc_t)lineBuf);
X      continue;
X    }
X    (void)nstrip (lineBuf);
X    /* fields: name flags directory */
X    nf = split (lineBuf, fields, 3, " \t");
X    if (nf == 3) {
X      theEntry.key = fields[0];
X      theEntry.data = NULL;
X      entry = hsearch (theEntry, FIND);
X      if (entry != NULL)
X	((Room *) entry -> data) -> fileDir = KeepString (fields[2],
X							  strlen (fields[2]));
X    }
X    free ((malloc_t)lineBuf);
X  }
X  (void)fclose (directoryFile);
X}
X
Xstatic void
XReadNewsgroupsFile ()
X/* parse newsgroups file for newsgroup descriptions */
X{
X  ENTRY theEntry, *entry;
X  FILE *newsgroupsFile;
X  char newsgroupsFileName[_bufSize], *description, *newsgroupName;
X  register char *ptr;
X  char newsgroupLine[_bufSize];
X
X  (void) sprintf (newsgroupsFileName, "%s/newsgroups", _newsLibDir);
X  newsgroupsFile = fopen (newsgroupsFileName, "r");
X  if (newsgroupsFile == NULL)
X    return;
X
X  while (fgets (newsgroupLine, _bufSize, newsgroupsFile) != NULL) {
X    newsgroupName = ptr = newsgroupLine;
X    while (*ptr && *ptr != ' ' && *ptr != '\t')
X      ptr ++;
X    *ptr++ = '\0';
X    while (*ptr && (*ptr == ' ' || *ptr == '\t'))
X      ptr ++;
X    description = ptr;
X    while (*ptr && *ptr != '\n')
X      ptr ++;
X    *ptr = '\0';
X
X    theEntry.key = newsgroupName;
X    theEntry.data = NULL;
X    if ((entry = hsearch (theEntry, FIND)) != NULL)
X      ((Room *) entry -> data) -> description
X	= KeepString (description, strlen (description));
X  }
X  (void)fclose (newsgroupsFile);
X}
X
Xstatic void
XReadFloorsFile ()
X/* parse Floors file for floor descriptions */
X{
X  _FuncName ("ReadFloorsFile");
X  FILE *floorsFile;
X  char floorsFileName[_bufSize], floorName[_bufSize], description[_bufSize],
X  floorStatus[_bufSize], floorsLine[_bufSize];
X  int i, floor;
X
X  (void) sprintf (floorsFileName, "%s/Floors", _libDir);
X  floorsFile = fopen (floorsFileName, "r");
X  if (floorsFile == NULL) {
X    floors[0].name = KeepString ("lobby.", 6);
X    floors[0].nameLength = strlen (floors[0].name);
X    floors[0].description = KeepString ("The Floor with No Door", 22);
X    floors[0].allowNewRooms = _true;
X    return;
X  }
X  floor = 0;
X  while (fgets (floorsLine, _bufSize, floorsFile) != NULL) {
X    if (isspace (floorsLine[0]) || floorsLine[0] == '#')
X      continue;
X    (void)sscanf (floorsLine, "%s %s %[^\n]", floorName, floorStatus,
X		  description);
X    floors[floor].name = KeepString (floorName, strlen (floorName));
X    floors[floor].nameLength = strlen (floors[floor].name);
X    floors[floor].description = KeepString (description, strlen (description));
X    for (i = 0; floorStatus[i] != '\0'; i ++) {
X      if (islower (floorStatus[i]))
X	floorStatus[i] = toupper (floorStatus[i]);
X      switch (floorStatus[i]) {
X      case 'A':	/* Anonymous */
X	floors[floor].anonymous = _true;
X	break;
X      case 'D':	/* Display article number */
X	floors[floor].displayNumber = _true;
X	break;
X      case 'I':	/* Invite only */
X	floors[floor].inviteOnly = _true;
X	/* FALLTHRU */
X      case 'P':	/* Private */
X	floors[floor].private = _true;
X	/* FALLTHRU */
X      case 'F':	/* Forgotten */
X	floors[floor].forgotten = _true;
X	break;
X      case 'L':	/* local distribution only */
X	floors[floor].localOnly = _true;
X	break;
X      case 'N':	/* Allow New Rooms */
X	floors[floor].allowNewRooms = _true;
X	break;
X      case 'M':	/* moderated */
X	floors[floor].moderated = _true;
X	break;
X      case 'R':	/* Read only */
X	floors[floor].readOnly = _true;
X	break;
X      case 'S':	/* Display Subject */
X	floors[floor].displaySubject = _true;
X	break;
X      }
X    }
X    floor ++;
X    if (floor >= _maxFloors) {
X      Log (funcName, __LINE__, LOG_ERROR, "Too many Floors.");
X      exit (1);
X    }
X
X  }
X  (void)fclose (floorsFile);
X}
X
Xstatic void
XWriteNewsFile ()
X/* Write out '.newsrc' file */
X{
X  _FuncName ("WriteNewsFile");
X  FILE *newsrcFile;
X  char newsrcFileName[_bufSize];
X  int line;
X
X  (void) sprintf (newsrcFileName, "%s/.newsrc", homeDir);
X  newsrcFile = fopen (newsrcFileName, "w");
X  if (newsrcFile == NULL) {
X    Log (funcName, __LINE__, LOG_ERROR, "Unable to open '%s' to update.",
X	 newsrcFileName);
X    exit (1);
X  }
X
X  if (options != NULL)
X    (void) fprintf (newsrcFile, "%s", options);
X
X  for (line = 0; rooms[line].name != NULL; line++) {
X    if (rooms[line].type != _deadType)
X      (void) fprintf (newsrcFile, "%s%c %s\n", rooms[line].name,
X		      rooms[line].forgotten ? '!' : ':',
X		      rooms[line].articlesRead);
X  }
X  (void)fclose (newsrcFile);
X}
X
Xstatic void
XWriteUserFile ()
X/* Write out '.unidelrc' file */
X{
X  _FuncName ("WriteUserFile");
X  FILE *userFile;
X  void WriteHeader();
X  char userFileName[_bufSize];
X  int floor;
X
X  (void) sprintf (userFileName, "%s/.unidelrc", homeDir);
X  userFile = fopen (userFileName, "w");
X  if (userFile == NULL) {
X    Log (funcName, __LINE__, LOG_ERROR, "Unable to open '%s'.", userFileName);
X    exit (1);
X  }
X
X  for (floor = 1; floors[floor].name != NULL; floor ++) {
X    if (floor == 1)
X      (void) fprintf (userFile, "KnownFloors: ");
X    else
X      (void) fprintf (userFile, ",");
X    if (floors[floor].forgotten)
X      (void) fprintf (userFile, "!%s", floors[floor].name);
X    else
X      (void) fprintf (userFile, "%s", floors[floor].name);
X  }
X  if (floor != 1)
X    (void) fprintf (userFile, "\n");
X  if (user[_userFloors])
X    free ((malloc_t)user[_userFloors]), user[_userFloors] = NULL;
X  WriteHeader (userFile, user, userFieldNames);
X  (void)fclose (userFile);
X}
X
Xstatic void
XUserLoop ()
X{
X  time_t time ();
X  static time_t startTime = (time_t) 0;
X
X  if (startTime == (time_t) 0)
X    startTime = time ((time_t *) 0);
X  PrintRoomsWithUnreadMessages ();
X  Goto (0);
X  finished = _false;
X  while (!finished) {
X    if (jokes)
X      (void) printf ("You have been on for %ld min.  You have the rest of your life remaining.\n", (startTime-time((time_t *)0))/60);
X    if (!expertMode)
X      (void) printf ("[?]=menu, [H]elp%s\n", guest ? ", [L]ogin" : "");
X    (void) printf ("%s ", RoomNameString (currentRoom));
X    (void) DoMenu (0l, mainMenu);
X  }
X}
X
Xstatic void
XUnInitialize ()
X{
X  char commandString[_bufSize];
X
X  (void) sprintf (commandString, "%s/unidelout", _libDir);
X  if (!access (commandString, 0))
X    (void)system (commandString);
X  (void) sprintf (commandString, "%s/.unidelout", homeDir);
X  if (!access (commandString, 0))
X    (void)system (commandString);
X  (void) sprintf (commandString, "rm -r %s", flTempDir);
X  (void)system (commandString);
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/Init.c &&
chmod 0444 unidel/Init.c ||
echo "restore of unidel/Init.c failed"
set `wc -c unidel/Init.c`;Wc_c=$1
if test "$Wc_c" != "21321"; then
	echo original size 21321, current size $Wc_c
fi
# ============= unidel/Input.c ==============
echo "x - extracting unidel/Input.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/Input.c &&
X/*
X * NAME
X *     Input -- user input functions
X *
X * AUTHOR
X *     Ken MacLeod
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) Input.c  1.3 02 May 1992 09:10:12\n\t";
X#endif
X
X#include <stdio.h>
X#include <ctype.h>
X#include <Unidel.h>
X#include "protos.h"
X
Xstatic int SpecialChar ();
Xextern size_t strlen ();
Xextern char *strcpy ();
X
Xint
XAnswerYesNo (string, flags)
Xchar *string;
Xint flags;
X{
X  int aChar, done, answer;
X
X  aChar = '\0';
X  done = _false;
X  while (!done) {
X    (void) printf ("%s", string);
X    aChar = GetChar (flags | _noEcho);
X    if ((flags & _defaultAnswer) && aChar == ' ' || aChar == '\n') {
X      aChar = (flags & _defaultYes) ? 'Y' : 'N';
X    }
X    switch (aChar) {
X    case 'y':
X    case 'Y':
X      if (!(flags & _noEcho))
X	(void) printf ("Yes\n");
X      answer = _true;
X      done = _true;
X      break;
X    case 'n':
X    case 'N':
X      if (!(flags & _noEcho))
X	(void) printf ("No\n");
X      answer = _false;
X      done = _true;
X      break;
X    case _keyAbort:
X      answer = -1;
X      done = _true;
X      break;
X    default:
X      if (isprint (aChar))
X	(void)putchar (aChar);
X      (void) printf (" ?\n");
X      break;
X    }
X  }
X  return (answer);
X}
X
Xint
XGetChar (inputMode)
Xint inputMode;
X{
X  int aChar;
X
X  aChar = getchar ();
X  aChar = SpecialChar (aChar);
X  if (inputMode & _upperCase) {
X    if (isalpha (aChar) && islower (aChar)) {
X      aChar = toupper (aChar);
X    }
X  }
X  if (inputMode & _lowerCase) {
X    if (isalpha (aChar) && isupper (aChar)) {
X      aChar = tolower (aChar);
X    }
X  }
X  if (!(inputMode & _noEcho) && (aChar < 0x100)) {
X    (void)putchar (aChar);
X  }
X  return (aChar);
X}
X
Xint
XSpecialChar (theChar)
Xint theChar;
X{
X  switch (theChar) {
X  case 0x0d:	/* ^M */
X    theChar = '\n';
X    break;
X  case 0x08:	/* ^H */
X    theChar = _keyLeft;
X    break;
X  case 0x0c:	/* ^L */
X    theChar = _keyRight;
X    break;
X  case 0x0b:	/* ^K */
X    theChar = _keyUp;
X    break;
X  case 0x0a:	/* ^J */
X    theChar = _keyDown;
X    break;
X  case 0x7f:	/* <DEL> */
X    theChar = _keyLeft;
X    break;
X  case '\033':
X  case '\003':
X    theChar = _keyAbort;
X    break;
X  }
X  return (theChar);
X}
X
Xvoid
XGetString (theString, inputMode)
Xchar *theString;
Xint inputMode;
X{
X  int i, aChar;
X
X  i = 0;
X  while ((aChar = GetChar (inputMode)) != '\n') {
X    if (isprint (aChar))
X      theString[i++] = (char) aChar;
X    else switch (aChar) {
X    case _keyLeft:
X    case '\10':
X    case '\177':
X      if (i > 0) {
X	i--;
X	(void) printf ("\10 \10");
X      }
X      break;
X    }
X  }
X  theString[i] = '\0';
X}
X
XGetStringWDefault (prompt, theString, noBrainer, inputMode)
X
Xchar *prompt, *theString, *noBrainer;
Xint inputMode;
X
X{
X  int i, aChar;
X
X  if (noBrainer && noBrainer[0] != '\0' && theString[0] == '\0')
X    (void) printf ("%s [%s]: ", prompt, noBrainer);
X  else
X    (void) printf ("%s: %s", prompt, theString);
X  i = strlen (theString);
X  while ((aChar = GetChar (inputMode)) != '\n') {
X    if (isprint (aChar))
X      theString[i++] = (char) aChar;
X    else switch (aChar) {
X    case _keyLeft:
X    case '\10':
X    case '\177':
X      if (i > 0) {
X	i--;
X	(void) printf ("\10 \10");
X      }
X      break;
X    case _keyAbort:
X      (void) printf ("\nAborted.\n");
X      return _keyAbort;
X    }
X  }
X  theString[i] = '\0';
X  if (i == 0 && noBrainer && noBrainer[0] != '\0')
X    (void) strcpy (theString, noBrainer);
X  return (aChar);
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/Input.c &&
chmod 0444 unidel/Input.c ||
echo "restore of unidel/Input.c failed"
set `wc -c unidel/Input.c`;Wc_c=$1
if test "$Wc_c" != "3344"; then
	echo original size 3344, current size $Wc_c
fi
# ============= unidel/Log.c ==============
echo "x - extracting unidel/Log.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/Log.c &&
X/*
X * 
X * NAME
X *     log -- log an error or debug message to a file.
X *
X * SYNOPSIS
X *     log (char *funcName, int lineNo, int level, char *format, args ...)
X *
X * DESCRIPTION
X *     (See log(3))
X * 
X * AUTHOR
X *     Ken MacLeod
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) Log.c  1.1 02 May 1992 10:59:48\n\t";
X#endif
X
X#include <sys/types.h>
X#include <unistd.h>
X#include <stdio.h>
X#include <varargs.h>
X#include <string.h>
X#include <malloc.h>
X#if !defined(BSD) && !defined(SYSV4) && 0
Xtypedef void *malloc_t;
X#endif
X#include <time.h>
X#include <Log.h>
X
X#ifndef lint
Xstatic char _sccsID[]="@(#)Log.c	1.1 02 May 1992";
X#endif
X
X#ifdef LEVELED_ERRORS
Xstatic char *errorNames[] = {
X  "ERROR: ",		/* -3 */
X  "ERROR: ",			/* -2 */
X  "Warning: ",		/* -1 */
X  "",
X  "Level 1: ",
X  "Level 2: ",
X  "Level 3: ",
X  "Level 4: ",
X  "Level 5: ",
X  "Level 6: ",
X  "Level 7: ",
X  "Level 8: ",
X  "Level 9: "
X};
Xint debug = 0;
X#else
Xlong debugMask = LOG_ERROR | LOG_WARNING | LOG_MESSAGE;
Xlong whereMask = ~0l;
X#endif
X
Xchar *programName;
Xchar *invoker;
Xchar *logFileName;
Xvoid exit ();
Xlong time ();
X
Xint
XInitLog (programName)
X     char *programName;
X{
X  char *userName, *systemName, *getenv ();
X#ifdef HAVE_gethostname
X  size_t systemNameSize = 40;	/* A seemingly oversized place to start */
X#endif
X  
X  programName = programName;
X  userName = getenv ("LOGNAME");
X  if (userName == (char *) NULL)
X    userName = "unknown";
X#ifdef HAVE_gethostname
X  systemName = (char *) malloc (systemNameSize);
X  if (systemName == (char *) NULL)
X    return (-1);
X  /* We loop here to make sure that we get all of systemName, because
X     we can only find out how long it is by trial and error */
X  while (1) {
X    (void) gethostname (systemName, systemNameSize);
X    for (ii = 0; ii < systemNameSize && systemName[ii] != '\0'; ii ++)
X      ;
X    if (ii != systemNameSize)
X      break;			/* we know we got it when we see nul */
X    systemNameSize += 40;	/* A seemingly reasonable increment */
X    systemName = (char *) realloc ((malloc_t) systemName,
X				   systemNameSize);
X    if (systemName == (char *) NULL)
X      return (-1);
X  }
X#else
X  systemName = "unknown";
X#endif
X  invoker = (char *) malloc (((size_t) strlen (userName)) + strlen (systemName) + 3);
X  if (invoker == (char *) NULL)
X    return (-1);
X  (void) strcpy (invoker, userName);
X  (void) strcat (invoker, "@");
X  (void) strcat (invoker, systemName);
X  (void) strcat (invoker, " ");
X#ifdef HAVE_gethostname
X  free ((malloc_t) systemName);
X#endif
X  logFileName = (char *) NULL;
X
X  return (0);
X}
X
X/*VARARGS0*/
Xvoid
XLog (va_alist)
X/* log (char *funcName, int lineNo, int level, char *format [, arg ] ...) */
X
Xva_dcl
X
X{
X  char *funcName;
X  int lineNo;
X  char *format;
X  va_list args;
X#ifdef LEVELED_ERRORS
X  int level;
X#else
X  long mask;
X#endif
X  FILE *logFile;
X  long theTime;
X  struct tm *localTime;
X  char errorString[1024];
X  char outString[1024];
X  char routineString[1024];
X
X  va_start (args);
X  /*LINTED va_arg */
X  funcName = (char *) va_arg (args, char *);
X  /*LINTED va_arg */
X  lineNo = (int) va_arg (args, int);
X#ifdef LEVELED_ERRORS
X  /*LINTED va_arg */
X  level = (int) va_arg (args, int);
X#else /* !LEVELED_ERRORS */
X  /*LINTED va_arg */
X  mask = (long) va_arg (args, long);
X#endif /* LEVELED_ERRORS */
X#ifdef LEVELED_ERRORS
X  if (level <= debug) {
X#else
X  if ((mask & debugMask) != 0) {
X#endif
X    /*LINTED va_arg */
X    format = (char *) va_arg (args, char *);
X    (void) time (&theTime);
X    localTime = localtime (&theTime);
X#ifdef LEVELED_ERRORS
X    if (debug > 0)
X#else
X    if ((mask & whereMask) != 0)
X#endif
X      (void) sprintf (routineString, ":%s:%d", funcName, lineNo);
X    else
X      routineString[0] = '\0';
X    (void) vsprintf (errorString, format, args);
X    (void) sprintf (outString, "%s(%d/%d-%d:%2.2d:%2.2d) (%s:%ld%s) %s%s\n",
X		    invoker, localTime -> tm_mon + 1, localTime -> tm_mday,
X		    localTime -> tm_hour, localTime -> tm_min,
X		    localTime -> tm_sec, programName, getpid (), routineString,
X#ifdef LEVELED_ERRORS
X		    errorNames[level + 3],
X#else
X		    "",
X#endif
X		    errorString);
X    if (logFileName == (char *) NULL || logFileName[0] == '-')
X      logFile = stderr;
X    else
X      logFile = fopen (logFileName, "a");
X    (void) fprintf (logFile, "%s", outString);
X    if (logFile != stderr)
X      (void) fclose (logFile);
X  }
X  va_end (args);
X#ifdef LEVELED_ERRORS
X  if (level == LOG_FATAL_ERROR)
X    exit (1);
X#endif
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/Log.c &&
chmod 0444 unidel/Log.c ||
echo "restore of unidel/Log.c failed"
set `wc -c unidel/Log.c`;Wc_c=$1
if test "$Wc_c" != "4405"; then
	echo original size 4405, current size $Wc_c
fi
# ============= unidel/Log.h ==============
echo "x - extracting unidel/Log.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/Log.h &&
X/*
X * NAME
X *     log.h -- Header for log(3)
X *
X * AUTHOR
X *     Ken MacLeod
X *
X * SCCS
X *     @(#) Log.h  1.1 02 May 1992 10:59:52 
X */
X
X#ifdef LEVELED_ERRORS
X#define LOG_FATAL_ERROR -3
X#define LOG_ERROR -2
X#define LOG_WARNING -1
X#define LOG_MESSAGE 0
X#define LOG_DEBUG1 1
X#define LOG_DEBUG2 2
X#define LOG_DEBUG3 3
X#define LOG_DEBUG4 4
X#define LOG_DEBUG5 5
X#define LOG_DEBUG6 6
X#define LOG_DEBUG7 7
X#define LOG_DEBUG8 8
X#define LOG_DEBUG9 9
X#ifndef LOG_PROG_TRACE
X#define LOG_PROG_TRACE 1		/* level of program tracing info */
X#endif
X
X#ifndef LOG_FUNC_TRACE
X#define LOG_FUNC_TRACE 5		/* level of function tracing info */
X#endif
X
X#else
X#define LOG_ERROR (0x00000001l)
X#define LOG_WARNING (0x00000002l)
X#define LOG_MESSAGE (0x00000004l)
X#define LOG_PROG_TRACE (0x00000008l)
X#define LOG_FUNC_TRACE (0x00000010l)
X#endif
X
X#ifdef LEVELED_ERRORS
Xextern int debug;		/* program debugging level */
X#else
Xextern long debugMask;		/* mask of debugging info to display */
Xextern long whereMask;		/* mask of what errors will display
X				   function/line info */
X#endif
Xextern char *logFileName;	/* name of file to log to */
Xextern char *programName;	/* name of program */
Xextern char *invoker;		/* system!name of user */
X
X#define _FuncName(NAME) static char funcName[]=NAME
Xint InitLog (/* char *programName */);
Xvoid Log (/* char *funcName, int *lineNo, int level,
X	       char *format, ... */ );
SHAR_EOF
$TOUCH -am 0502135492 unidel/Log.h &&
chmod 0444 unidel/Log.h ||
echo "restore of unidel/Log.h failed"
set `wc -c unidel/Log.h`;Wc_c=$1
if test "$Wc_c" != "1383"; then
	echo original size 1383, current size $Wc_c
fi
# ============= unidel/newvers.sh ==============
echo "x - extracting unidel/newvers.sh (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/newvers.sh &&
X#!/bin/sh -
X#
X# Copyright (c) 1983 The Regents of the University of California.
X# All rights reserved.
X#
X# Redistribution and use in source and binary forms are permitted
X# provided that the above copyright notice and this paragraph are
X# duplicated in all such forms and that any documentation,
X# advertising materials, and other materials related to such
X# distribution and use acknowledge that the software was developed
X# by the University of California, Berkeley.  The name of the
X# University may not be used to endorse or promote products derived
X# from this software without specific prior written permission.
X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X#
X#	@(#)newvers.sh	5.4 (Berkeley) 12/7/88
X#
X#  UNIDEL SCCS
X#      @(#) newvers.sh  1.2 02 May 1992 19:15:38 
X#
Xif [ ! -r version ]; then echo 0 > version; fi
Xtouch version
Xawk '
X{
X  version = $1 + 1;
X}
XEND {
X  printf ("char version[] = \"Unidel 1.0.%d (of '"`date '+%y%b%d %H:%m'`"')\";\n", version) > "vers.c";
X  printf "%d\n", version > "version";
X}' < version
SHAR_EOF
$TOUCH -am 0502191592 unidel/newvers.sh &&
chmod 0444 unidel/newvers.sh ||
echo "restore of unidel/newvers.sh failed"
set `wc -c unidel/newvers.sh`;Wc_c=$1
if test "$Wc_c" != "1181"; then
	echo original size 1181, current size $Wc_c
fi
# ============= unidel/MenuDef.c ==============
echo "x - extracting unidel/MenuDef.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > unidel/MenuDef.c &&
X/*
X * NAME
X *     MenuDef.c -- Top level menu
X *
X * AUTHOR
X *     Ken MacLeod
X */
X
X#ifndef lint
Xstatic char sccsId [] = "@(#) MenuDef.c  1.4 02 May 1992 09:11:54\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 "Message.h"
X#include "Log.h"
X
Xextern int strncmp ();
X
Xint Chat ();
Xint ReadMessages (), EnterMessageCommand (), GotoCommand (), KnownRooms (),
X  Disabled (), HelpCommand ();
Xint EnterFileCommand (), ReadDirectory (), ReadStatus (), ReadFileCommand (),
X  FindRoomCommand (), Terminate ();
Xint EnterRoom (), EnterSignature (), EnterFullName (), ToggleExpertMode (),
X  EnterPauseMode (), EnterTerminalType ();
Xint EnterTransferProtocol (), EnterEditor ();
Xint PrintForgottenRooms (), ReadMessageByNumber (), ReadMessageByMessageID (),
X  SystemCommand ();
Xint ReadArchiveHeader ();
Xint  GotoFloorCommand (), KnownFloors (), ForgetFloor (), ToggleFloorMode ();
Xstatic int ReadSubMenu ();
X
X/*-
X * NAME
X *   Menu -- table for specifying commands and their procedures
X * 
X * SYNOPSIS
X *   command, text1, text2, text3, text4, parameter, procedure
X *
X * DESCRIPTION
X *   The first field is the sequence of four or less characters needed
X * to execute the command.  The next four fields are the words that
X * are displayed for each character, respectively.  An "=" prefix
X * means do not new-line after printing the word.  The sixth field, a
X * long int, is passed to the procedure, the seventh field, as it's
X * only parameter.
X *
X *   Since the table is searched from the beginning until the first
X * match is found, only the first match needs to have a matching word
X * in a position, the rest would not have been reached by then, for
X * example:
X * 
X *	".E?", ".", "Enter ", "\b, Help", NULL, 2l, HelpCommand,
X *	".ER", NULL, NULL, "oom", NULL, 0l, EnterRoom,
X *
X * the "." and "Enter" are not duplicated on the ".ER" line.  The
X * procedure is executed only when a complete match is found.
X *
X *   For submenus, found elsewhere, the parameter in the sixth field
X * is 'or'ed into the submenu's parameter field.
X */
X
XMenu mainMenu[] = {
X  /* Reading Commands */
X  "N", "New", NULL, NULL, NULL, _readMoreDefault | _readNew | _readForward, ReadMessages,
X  "O", "Old Reverse", NULL, NULL, NULL, _readMoreDefault, ReadMessages,
X  "F", "Forward", NULL, NULL, NULL, _readMoreDefault | _readAll | _readForward, ReadMessages,
X  "R", "Reverse", NULL, NULL, NULL, _readMoreDefault | _readAll, ReadMessages,
X  "E", "Enter Message", NULL, NULL, NULL, 0l, EnterMessageCommand,
X  "0", "=0", NULL, NULL, NULL, 0l, ReadMessageByNumber,
X  "1", "=1", NULL, NULL, NULL, 1l, ReadMessageByNumber,
X  "2", "=2", NULL, NULL, NULL, 2l, ReadMessageByNumber,
X  "3", "=3", NULL, NULL, NULL, 3l, ReadMessageByNumber,
X  "4", "=4", NULL, NULL, NULL, 4l, ReadMessageByNumber,
X  "5", "=5", NULL, NULL, NULL, 5l, ReadMessageByNumber,
X  "6", "=6", NULL, NULL, NULL, 6l, ReadMessageByNumber,
X  "7", "=7", NULL, NULL, NULL, 7l, ReadMessageByNumber,
X  "8", "=8", NULL, NULL, NULL, 8l, ReadMessageByNumber,
X  "9", "=9", NULL, NULL, NULL, 9l, ReadMessageByNumber,
X  "<", "=0", NULL, NULL, NULL, 0l, ReadMessageByMessageID,
X  "=", "New Headers", NULL, NULL, NULL, _readHeaders | _readMoreDefault | _readNew | _readForward, ReadMessages,
X
X  /* Room Commands */
X  "G", "=Goto ", NULL, NULL, NULL, 0l, GotoCommand,
X  "S", "Skip", NULL, NULL, NULL, 1l, GotoCommand,
X  "B", "Backup", NULL, NULL, NULL, 2l, GotoCommand,
X/*	"U", "Ungoto", NULL, NULL, NULL, 2l, GotoCommand,*/
X  "Z", "Forget Room", NULL, NULL, NULL, 3l, GotoCommand,
X  "K", "Known Rooms", NULL, NULL, NULL, 0l, KnownRooms,
X
X  /* File Commands */
X  "U", "Upload file", NULL, NULL, NULL, 0l, EnterFileCommand,
X  "D", "Download file", NULL, NULL, NULL, 0l, ReadFileCommand,
X  "L", "=List files ", NULL, NULL, NULL, (long) _true, ReadDirectory,
X
X  /* Miscellaneous */
X  "C", "Chat", NULL, NULL, NULL, 0l, Chat,
X  "H", "Help", NULL, NULL, NULL, 7l, HelpCommand,
X  "?", "Help", NULL, NULL, NULL, 1l, HelpCommand,
X  "T", "Terminate", NULL, NULL, NULL, (long) _false, Terminate,
X  "Y", "Your Info", NULL, NULL, NULL, 0l, ReadStatus,
X
X  /*
X   * Extended Commands
X   */
X
X  /* Enter Commands */
X  ".E?", ".", "Enter ", "\b, Help", NULL, 2l, HelpCommand,
X  ".ER", NULL, NULL, "oom", NULL, 0l, EnterRoom,
X
X  ".EM", NULL, NULL, "Message", NULL, 0l, EnterMessageCommand,
X  ".EF", NULL, NULL, "File", NULL, 0l, EnterFileCommand,
X  ".EPM", NULL, NULL, "Protocol", "Messsage", _transferProtocol, EnterMessageCommand,
X
X  /* Configuration Commands */
X  ".EC?", NULL, NULL, "Configuration ", "\b, Help", 8l, HelpCommand,
X  ".ECD", NULL, NULL, NULL, "Editor", 0l, EnterEditor,
X  ".ECE", NULL, NULL, NULL, "=", 0l, ToggleExpertMode,
X  ".ECF", NULL, NULL, NULL, "=", 0l, ToggleFloorMode,
X  ".ECM", NULL, NULL, NULL, "Pause Messages", 0l, EnterPauseMode,
X  ".ECN", NULL, NULL, NULL, "Full Name", 0l, EnterFullName,
X  ".ECP", NULL, NULL, NULL, "Password", 3l, SystemCommand,
X  ".ECS", NULL, NULL, NULL, "Signature", 0l, EnterSignature,
X  ".ECT", NULL, NULL, NULL, "Terminal Type", 0l, EnterTerminalType,
X  ".ECX", NULL, NULL, NULL, "Transfer Protocol", 0l, EnterTransferProtocol,
X
X  /* Read Commands */
X  ".R?", NULL, "Read ", "\b, Help", NULL, 4l, HelpCommand,
X  ".RD", NULL, NULL, "=Directory ", NULL, (long) _false, ReadDirectory,
X  ".RE", NULL, NULL, "=Extended Directory ", NULL, (long) _true, ReadDirectory,
X  ".RS", NULL, NULL, "Status", NULL, 0l, ReadStatus,
X  ".R0", NULL, NULL, "=0", NULL, 0l, ReadMessageByNumber,
X  ".R1", NULL, NULL, "=1", NULL, 1l, ReadMessageByNumber,
X  ".R2", NULL, NULL, "=2", NULL, 2l, ReadMessageByNumber,
X  ".R3", NULL, NULL, "=3", NULL, 3l, ReadMessageByNumber,
X  ".R4", NULL, NULL, "=4", NULL, 4l, ReadMessageByNumber,
X  ".R5", NULL, NULL, "=5", NULL, 5l, ReadMessageByNumber,
X  ".R6", NULL, NULL, "=6", NULL, 6l, ReadMessageByNumber,
X  ".R7", NULL, NULL, "=7", NULL, 7l, ReadMessageByNumber,
X  ".R8", NULL, NULL, "=8", NULL, 8l, ReadMessageByNumber,
X  ".R9", NULL, NULL, "=9", NULL, 9l, ReadMessageByNumber,
X  ".R<", NULL, NULL, "=<", NULL, 0l, ReadMessageByMessageID,
X
X  ".RH", NULL, NULL, "Archive Header", NULL, 0l, ReadArchiveHeader,
X  ".RA", NULL, NULL, "All", NULL, _readMoreDefault | _readAll | _readForward, ReadMessages,
X  ".RG", NULL, NULL, "Global New", NULL, _readMoreDefault | _readGlobal | _readAll | _readForward, ReadMessages,
X  ".RN", NULL, NULL, "New", NULL, _readMoreDefault | _readNew | _readForward, ReadMessages,
X  ".RO", NULL, NULL, "Old Reverse", NULL, _readMoreDefault, ReadMessages,
X  ".RR", NULL, NULL, "Reverse", NULL, _readMoreDefault | _readAll, ReadMessages,
X  ".RF", NULL, NULL, "File", NULL, _transferProtocol, ReadFileCommand,
X  ".RM", NULL, NULL, "=More ", NULL, _readMore, ReadSubMenu,
X  ".RT", NULL, NULL, "=Text ", NULL, _readMoreDefault, ReadSubMenu,
X  ".RP", NULL, NULL, "=Protocol ", NULL, _transferProtocol, ReadSubMenu,
X  ".R=", NULL, NULL, "=Headers ", NULL, _readHeaders, ReadSubMenu,
X
X  /* Miscellaneous extended commands */
X  ".?", NULL, "Help", NULL, NULL, 5l, HelpCommand,
X  ".H", NULL, "=Help ", NULL, NULL, 0l, HelpCommand,
X  ".K", NULL, "=Known ", NULL, NULL, _findPartial, FindRoomCommand,
X  ".S", NULL, "=Skip", NULL, NULL, 4l, GotoCommand,
X  ".TQ", NULL, "Terminate ", "Quit-Also", NULL, (long) _true, Terminate,
X  ".U", NULL, "=Ungoto ", NULL, NULL, 5l, GotoCommand,
X  ".G", NULL, "=Goto ", NULL, NULL, 6l, GotoCommand,
X  ".Z", NULL, "List Forgotten Rooms", NULL, NULL, 0l, PrintForgottenRooms,
X
X  /* Floor Commands */
X  ";?", "", "Floor Commands Summary", NULL, NULL, 6l, HelpCommand,
X  ";G", NULL, "=Goto Floor ", NULL, NULL, 0l, GotoFloorCommand,
X  ";C", NULL, "=", NULL, NULL, 0l, ToggleFloorMode,
X  ";K", NULL, "Known Floors", NULL, NULL, 0l, KnownFloors,
X  ";S", NULL, "Skip Floor", NULL, NULL, 1l, GotoFloorCommand,
X  ";Z", NULL, "Forget Floor", NULL, NULL, 0l, ForgetFloor,
X  ";>", NULL, "Next Floor", NULL, NULL, 2l, GotoFloorCommand,
X  ";<", NULL, "Previous Floor", NULL, NULL, 3l, GotoFloorCommand,
X  ">", "Next Floor", NULL, NULL, NULL, 2l, GotoFloorCommand,
X  "<", "Previous Floor", NULL, NULL, NULL, 3l, GotoFloorCommand,
X  ";N", NULL, "New messages on this floor", NULL, NULL, _readFloor | _readNew | _readForward, ReadMessages,
X
X  /* End of list */
X  "", NULL, NULL, NULL, NULL, 0l, NULL,
X};
X
Xstatic Menu readTypesSubMenu[] = {
X  "A", "All", NULL, NULL, NULL, _readAll | _readForward, ReadMessages,
X  "G", "Global New", NULL, NULL, NULL, _readGlobal | _readAll | _readForward, ReadMessages,
X  "N", "New", NULL, NULL, NULL, _readNew | _readForward, ReadMessages,
X  "O", "Old Reverse", NULL, NULL, NULL, 0l, ReadMessages,
X  "R", "Reverse", NULL, NULL, NULL, _readAll, ReadMessages,
X  "F", "File", NULL, NULL, NULL, 0l, ReadFileCommand,
X
X  /* End of list */
X  "", NULL, NULL, NULL, NULL, 0l, NULL,
X};
X
Xchar *selectorStrings[] = {
X  NULL,				/* 0 */
X  "mainmenu",
X  "enter",
X  "/bin/passwd",
X  "read",
X  "summary",			/* 5 */
X  "floorsum",
X  "help",
X  "config",
X};
X
Xstatic int
XReadSubMenu (type)
Xlong type;
X{
X  return (DoMenu (type, readTypesSubMenu));
X}
X
Xint
XDoMenu (type, menu)
Xlong type;
XMenu *menu;
X{
X  char *funcName = "DoMenu";
X  char command[4];
X  int aChar, i, noCR, done, status;
X  unsigned int charIndex;
X
X  charIndex = 0;
X  done = _false;
X  while (!done) {
X    aChar = GetChar (_upperCase | _noEcho);
X    command[charIndex] = (char) aChar;
X    /* search for first matching command */
X    for (i = 0;
X	 menu[i].command[0] != '\0'
X	 && strncmp (menu[i].command, command, charIndex + 1);
X	 i ++);
X    if (menu[i].command[0] == '\0') { /* Not found */
X      if (isprint (aChar))
X	(void) printf ("%c ?\n", aChar); /*   error */
X      else if (iscntrl (aChar))
X	(void) printf ("^%c ?\n", (aChar == 0x7f) ? '?' : aChar | 0x60);
X      else
X	(void) printf ("?? ?\n");
X      done = _true;
X    } else {			/* Found */
X      if (menu[i].printString[charIndex][0] == '=') {
X	/*   should we CR after printing? */
X	noCR = _true;
X	/* print string sans '=' */
X	(void) printf ("%s", &menu[i].printString[charIndex][1]);
X      } else {
X	noCR = _false;
X	/* print text of string */
X	(void) printf ("%s", menu[i].printString[charIndex]);
X      }
X      if ((charIndex == 3) || (menu[i].command[charIndex + 1] == '\0')) {
X	/* is the command complete? */
X	if (!noCR)
X	  (void) printf ("\n");	/* Yes, print that CR */
X	Log (funcName, __LINE__, LOG_COMMANDS, "'%-4.*s'", charIndex + 1,
X	     command);
X	/* Call the command */
X	status = (* menu[i].function) (type | menu[i].selector);
X	done = _true;
X      } else {
X	/* No, try some more */
X	charIndex ++;
X      }
X    }
X  }
X  return (status);
X}
SHAR_EOF
$TOUCH -am 0502135492 unidel/MenuDef.c &&
chmod 0444 unidel/MenuDef.c ||
echo "restore of unidel/MenuDef.c failed"
set `wc -c unidel/MenuDef.c`;Wc_c=$1
if test "$Wc_c" != "10549"; then
	echo original size 10549, current size $Wc_c
fi
echo "End of part 3, continue with part 4"
exit 0
