/*************************************************
*        A program to read a smail spool file    *
*************************************************/


/*
Author:   Philip Hazel (ph10@cus.cam.ac.uk)
Version:  0.00
Date:     18 Jan 1995
*/

/* Smail messages are kept as a single file on the smail spool.
For this reason they have to be readable only by root, in order
that the contents of messages remain private. However, a program
that wants to display statistics of the queued messages needs to
be able to see the envelope and the header data, which is less
private.

This program reads the envelope and header lines from a smail
spool file and writes them to its current output. It checks that
the name of the file is in the correct format, and that the contents
of the file look like a spool file. The mail smail spool directory 
name is built into this program. It will look in the subdirectories
"input" and "error" for the given file name.

This program has to be setuid root in order to work. It should
probably also not be executable by ordinary mortals. Although
less private than the contents, the envelopes and headers of messages
might be felt to be somewhat private. */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>     /* SunOS needs this */


#define SPOOLDIR "/var/spool/smail"


static FILE *spool_file = NULL;


/*************************************************
*                 Error handler                  *
*************************************************/

static void error(s)
char *s;
{
printf("readspool: %s\n", s);
if (spool_file != NULL) fclose(spool_file);
exit(99);
}



/*************************************************
*           Entry point and main program         *
*************************************************/

int main(argc, argv)
int argc;
char **argv;
{
int i;
int state = 0;
char *name;
char buffer[256];

/* Check for the existence of one argument */

if (argc != 2) error("exactly one argument required");

/* Check the format of the name. */

name = argv[1];
if (strlen(name) != 14) error("name has wrong length");
for (i = 0; i < 14; i++)
  {
  if (i == 6)
    {
    if (name[i] != '-') error("name has wrong format"); 
    }  
  else
    {
    if (!isalnum(name[i])) error("name has wrong format"); 
    }  
  } 

/* Try to open file in the input directory */

strcpy(buffer, SPOOLDIR);
strcat(buffer, "/input/");
strcat(buffer, name);
spool_file = fopen(buffer, "r");

/* If failed, and not permission denied, try to look
in the error directory. */

if (spool_file == NULL)
  {
  if (errno == 13) error("permission denied");
  strcpy(buffer, SPOOLDIR);
  strcat(buffer, "/error/");
  strcat(buffer, name);
  spool_file = fopen(buffer, "r");
  if (spool_file == NULL) 
    {
    if (errno == 13) error("permission denied"); 
      else error("file not found"); 
    } 
  } 

/* Got the file open; read envelope and header, checking for
content as best we can. */

while (fgets(buffer, 256, spool_file) != NULL)
  {
  char *p = buffer+1; 
  switch(state)
    {
    /* 1st line - expect !name */ 
     
    case 0:  
    if (buffer[0] != '!') error("malformed spool file (1)"); 
    while (!isspace(*p)) p++;
    while (*p == ' ') p++;
    if (*p != '\n') error("malformed spool file (2)");
    fputs(buffer, stdout); 
    state = 1;  
    break;
     
    /* 2nd line - expect !uid gid */
     
    case 1:  
    if (buffer[0] != '!') error("malformed spool file (3)"); 
    while (isdigit(*p)) p++;
    if (*p++ != ' ') error("malformed spool file (4)");
    while (isdigit(*p)) p++;
    if (*p != '\n') error("malformed spool file (5)");
    fputs(buffer, stdout); 
    state = 2; 
    break;
    
    /* expecting flag line or first destination - there
    may be no destinations if the -t flag is used */
    
    case 2:          
    fputs(buffer, stdout);
    if (buffer[0] == '\n') { state = 4; break; }
    if (buffer[0] != '!') error("malformed spool file (6)"); 
    if (buffer[1] == '-')
      {
      if (strcmp(buffer, "!-f\n") == 0 ||
          strcmp(buffer, "!-F\n") == 0 || 
            (strncmp(buffer, "!-oM", 4) == 0 &&
             buffer[5] == '\n' &&
             strchr("saruvP", buffer[4]) != NULL))
        {
        if (fgets(buffer, 256, spool_file) == NULL) 
          error("malformed spool file (7)");
        fputs(buffer, stdout);
        }
      }
    else state = 3; 
    break;
    
    /* expecting subsequent destinations */
     
    case 3:  
    fputs(buffer, stdout);
    if (buffer[0] == '\n') state = 4;
    else if (buffer[0] != '!' || buffer[1] == '-') 
      error("malformed spool file (9)"); 
    break;
    
    /* expecting header line */
     
    case 4:  
    fputs(buffer, stdout);
    if (buffer[0] == '\n') goto ENDLOOP; 
    break;     
    }  
  } 
   
ENDLOOP:
fclose(spool_file);
fclose(stdout);
return 0;
}


/* End of readspool.c */
