/********************************************************************
 * $Author: lindner $
 * $Revision: 1.1 $
 * $Date: 1992/12/10 23:13:27 $
 * $Source: /home/mudhoney/GopherSrc/release1.11/gopherd/RCS/serverutil.c,v $
 * $Status: $
 *
 * Paul Lindner, University of Minnesota CIS.
 *
 * Copyright 1991, 1992 by the Regents of the University of Minnesota
 * see the file "Copyright" in the distribution for conditions of use.
 *********************************************************************
 * MODULE: serverutil.c
 * utilities for the server.
 *********************************************************************
 * Revision History:
 * $Log: serverutil.c,v $
 * Revision 1.1  1992/12/10  23:13:27  lindner
 * gopher 1.1 release
 *
 *
 *********************************************************************/



#include "gopherd.h"

/* 
 * This routine cleans up an open file descriptor and sends out a bogus
 * filename with the error message
 */

void
Abortoutput(sockfd, errmsg)
  int sockfd;
  char *errmsg;
{
     char outputline[256];
     
     sprintf(outputline, "0Server error: %s\t\terror.host\t1\r\n.\r\n", errmsg);
     LOGGopher(sockfd, errmsg);

     if (writestring(sockfd, outputline)<0) {
	  LOGGopher(sockfd, "Client went away!");
	  exit(-1);
     }
     close(sockfd);

     return;
}



/*
 * is_mail_from_line - Is this a legal unix mail "From " line?
 *
 * Given a line of input will check to see if it matches the standard
 * unix mail "from " header format. Returns 0 if it does and <0 if not.
 *
 * 2 - Very strict, also checks that each field contains a legal value.
 *
 * Assumptions: Not having the definitive unix mailbox reference I have
 * assumed that unix mailbox headers follow this format:
 *
 * From <person> <date> <garbage>
 *
 * Where <person> is the address of the sender, being an ordinary
 * string with no white space imbedded in it, and <date> is the date of
 * posting, in ctime(3C) format.
 *
 * This would, on the face of it, seem valid. I (Bernd) have yet to find a
 * unix mailbox header which doesn't follow this format.
 *
 * From: Bernd Wechner (bernd@bhpcpd.kembla.oz.au)
 * Obfuscated by: KFS (as usual)
 */

#define MAX_FIELDS 10

static char legal_day[]         = "SunMonTueWedThuFriSat";
static char legal_month[]       = "JanFebMarAprMayJunJulAugSepOctNovDec";
static int  legal_numbers[]     = { 1, 31, 0, 23, 0, 59, 0, 60, 1969, 2199 };

int is_mail_from_line(line)
char *line;     /* Line of text to be checked */
{
    char *fields[MAX_FIELDS];
    char *sender_tail;
    register char *lp, **fp;
    register int n, i;

    if (strncmp(line, "From ", 5)) return -100;

    lp = line + 5;
    /* sender day mon dd hh:mm:ss year */
    for (n = 0, fp = fields; n < MAX_FIELDS; n++) {
        while (*lp && *lp != '\n' && isascii(*lp) && isspace(*lp)) lp++;
        if (*lp == '\0' || *lp == '\n') break;
        *fp++ = lp;
        while (*lp && isascii(*lp) && !isspace(*lp))
            if (*lp++ == ':' && (n == 4 || n == 5)) break;
        if (n == 0) sender_tail = lp;
   }

    if (n < 8) return -200-n;

    fp = fields;

    if (n > 8 && !isdigit(fp[7][0])) fp[7] = fp[8]; /* ... TZ year */
    if (n > 9 && !isdigit(fp[7][0])) fp[7] = fp[9]; /* ... TZ DST year */

    fp++;
    for (i = 0; i < 21; i += 3)
        if (strncmp(*fp, &legal_day[i], 3) == 0) break;
    if (i == 21) return -1;

    fp++;
    for (i = 0; i < 36; i += 3)
        if (strncmp(*fp, &legal_month[i], 3) == 0) break;
    if (i == 36) return -2;

    for (i = 0; i < 10; i += 2) {
        lp = *++fp;
        if (!isdigit(*lp)) return -20-i;
        n = atoi(lp);
        if (n < legal_numbers[i] || legal_numbers[i+1] < n) return -10-i;
   }
    return 0;
}



/* 
 * Return the basename of a filename string, i.e. everything
 * after the last "/" character. 
 */

char *mtm_basename(string)
	char *string;
{
  static   char *buff;
  buff = string + strlen(string); /* start at last char */
  while (*buff != '/' && buff > string)
	  buff--;
  return( (char *) (*buff == '/'? ++buff : buff));
}

FILE*
Gpopen(sockfd, cmd, rw)
  int sockfd;
  char *cmd;
  char *rw;
{
     int inquote = 0;
     int insquote = 0;
     int i;

     /** Strip out the naughty bits..  **/
     for (i=0; cmd[i] != '\0'; i++) {
	  switch (cmd[i]) {
	  case '"':
	       if (!insquote)
		    inquote = 1-inquote;
	       break;
	       
	  case '\'':
	       if (!inquote)
		    insquote = 1-insquote;
	       break;

	  case '*':
	  case '&':
	  case '|':
	  case ';':
	  case '=':
	  case '?':
	  case '<':
	  case '>':
	  case '(':
	  case ')':
	  case '{':
	  case '}':
	  case '[':
	  case ']':
	  case '^':
	       /*** Stuff that's okay if quoted.. ***/

	       if (!inquote && !insquote) {
		    char tmpstr[512];
		    sprintf(tmpstr, "Possible Security Violation", cmd);
		    LOGGopher(sockfd, tmpstr);
		    return(NULL);
	       }
	       
	       break;

	  case '!':
	  case '\\':
	  case '`':
	  case '\n':
	  case '$':
	       /*** Stuff that shouldn't be in there at all! **/
	  {
	       char tmpstr[512];
	       sprintf(tmpstr, "Possible Security Violation", cmd);
	       LOGGopher(sockfd, tmpstr);
	       return(NULL);
	  }

	       break;
	  }
     }

     return(popen(cmd, rw));
}
