From the README
===============
This is a mail-server program, that is able to automatically send files
to persons who requested them via mail. Access to the mail-server may
be controlled by a permissions list, which contains a set of regular
expressions that are matched agains addresses.
We use this server for archiving news articles and source-code. The user
who wants something out of the archives, sends a message to the mail-server,
and promptly receives feed-back from the mail-server with the requested
articles and/or files.
---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is Mail-Server, a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 08/12/1991 14:27 UTC by j...@logixwi.UUCP
# Source directory /u/tools/etc/mail-server
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 886 -r--r--r-- mailserv.c
# 5177 -r--r--r-- parsemail.c
# 1993 -r--r--r-- mygets.c
# 2217 -r--r--r-- log.c
# 4463 -r--r--r-- send.c
# 1459 -r--r--r-- mail.c
# 1357 -r--r--r-- perm.c
# 6489 -r--r--r-- mserver.h
# 232 -r--r--r-- patchlevel.h
# 3175 -rw-r--r-- mail-server.1
# 2601 -rw-r--r-- INSTALL
# 740 -rw-r--r-- README
# 361 -rw-r--r-- Copyright
# 908 -rw-r--r-- Makefile
# 794 -rw-r--r-- MANIFEST
#
# ============= mailserv.c ==============
if test -f 'mailserv.c' -a X"$1" != X"-c"; then
echo 'x - skipping mailserv.c (File already exists)'
else
echo 'x - extracting mailserv.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mailserv.c' &&
/*
X * $Header: /u/tools/etc/mail-server/RCS/mailserv.c,v 1.1 1991/08/12 11:15:49 jpm Exp $
X *
X * $Log: mailserv.c,v $
X * Revision 1.1 1991/08/12 11:15:49 jpm
X * Initial revision
X *
X */
X
/*
X * Copyright 1991, Jan-Piet Mens
X * License to freely use and distribute this software is hereby granted
X * by the author, subject to the condition that this copyright notice
X * remains intact. The author retains the exclusive right to publish
X * derivative works based on this work, including, but not limited
X * to, revised versions of this work
X */
X
#ifndef lint
X static char rcs_id[] = "$Id: mailserv.c,v 1.1 1991/08/12 11:15:49 jpm Exp $";
#endif
X
#include "mserver.h"
X
BOOL verbose = FALSE;
X
main(argc, argv)
int argc;
char **argv;
{
X int c;
X
X while ((c = getopt(argc,argv,"v")) != EOF)
X {
X switch (c)
X {
X case 'v': verbose = TRUE;
X break;
X }
X }
X
X return (parsemail());
}
SHAR_EOF
chmod 0444 mailserv.c ||
echo 'restore of mailserv.c failed'
Wc_c="`wc -c < 'mailserv.c'`"
test 886 -eq "$Wc_c" ||
echo 'mailserv.c: original size 886, current size' "$Wc_c"
fi
# ============= parsemail.c ==============
if test -f 'parsemail.c' -a X"$1" != X"-c"; then
echo 'x - skipping parsemail.c (File already exists)'
else
echo 'x - extracting parsemail.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parsemail.c' &&
/*
X * $Header: /u/tools/etc/mail-server/RCS/parsemail.c,v 1.2 1991/08/12 14:09:23 jpm Exp $
X *
X * $Log: parsemail.c,v $
X * Revision 1.2 1991/08/12 14:09:23 jpm
X * Added permission checking with Regular Expressions.
X *
X * Revision 1.1 1991/08/12 11:15:49 jpm
X * Initial revision
X *
X */
X
/*
X * Copyright 1991, Jan-Piet Mens
X * License to freely use and distribute this software is hereby granted
X * by the author, subject to the condition that this copyright notice
X * remains intact. The author retains the exclusive right to publish
X * derivative works based on this work, including, but not limited
X * to, revised versions of this work
X */
X
#ifndef lint
X static char rcs_id[] = "$Id: parsemail.c,v 1.2 1991/08/12 14:09:23 jpm Exp $";
#endif
X
#include "mserver.h"
#include <ctype.h>
#include <sys/types.h>
#include <time.h>
X
char from[STRLEN];
char reply_to[STRLEN];
char subject[STRLEN];
char To[STRLEN];
X
static struct {
X char *header;
X int (*func)();
X char *var;
} hd[] = {
X "From:", mkaddress, from,
X "Reply-To:", mkaddress, reply_to,
X "Subject:", justcopy, subject,
X NULL, NULL };
X
X
char *filelist[MAX_FILES_TO_SEND];
char *subjects[MAX_FILES_TO_SEND];
long filecount = 0L; /* Keep count in filelist[] */
X
/*
X * Parsemail()
X * Read the mail that is coming in through stdin. Parse out the needed
X * mail headers, and parse the commands that the mailer wishes us to perform.
X */
X
int parsemail()
{
X char buf[BUFSIZ], *ptr;
X int i;
X
X while (mygets(buf,BUFSIZ,stdin) != (char *)0)
X {
X if (*buf == EOS)
X continue;
X /*
X * Check for which header was read. Either copy it if it is
X * something as unimportant as Subject:, or parse data out
X * of it as in From:
X */
X
X for (i = 0; hd[i].header != NULL; i++)
X {
X if (!strncmp(buf, hd[i].header, strlen(hd[i].header)))
X {
X (*hd[i].func)(hd[i].var, buf);
X break;
X }
X }
X
X if (EQUAL(buf, "help"))
X addfile(HELPFILE, HELPSUBJECT);
X if (EQUAL(buf, "index"))
X addfile(INDEXFILE, "Index");
X
X if (EQUAL(buf, "send"))
X {
X ptr = strpbrk(buf," \t") + 1;
X addfile(ptr, ptr);
X }
X if (EQUAL(buf, "end"))
X break;
X else if (EQUAL(buf, "quit"))
X break;
X }
X
X /*
X * End of message. Start work ;-)
X */
X
X for (i = 0; hd[i].header != NULL; i++)
X {
X if (strlen(hd[i].var))
X {
X if (verbose)
X printf("%-20s '%s'\n", hd[i].header, hd[i].var);
X }
X }
X
X if (verbose)
X {
X printf("---- Requests\n");
X for (i = 0; i < filecount; i++)
X printf("Send [%s] Subject: %s\n",
X filelist[i], subjects[i]);
X }
X
X /*
X * Whom should we send all this to ?
X * RFC822 prefers Reply-To: header.
X */
X
X if (strlen(from))
X strcpy(To, from);
X if (strlen(reply_to))
X strcpy(To, reply_to);
X
#ifdef PERMISSION
X if (permission(To) == FALSE)
X {
#ifndef NO_LOGGING
X log("No access for [%s].", To);
#endif
X mail(To,"Permission", "Sorry. You are not on the access list for the Mail-Server.\nPlease apply for free access at\n\t%s\n",ERRORS_TO);
X return (0);
X }
#endif
X
X for (i = 0; i < filecount; i++)
X {
X if (verbose)
X {
X printf("Sending [%s]\n", filelist[i]);
X }
X send(filelist[i], To);
X }
X
X /*
X * Must return zero for MMDF. Otherwise it will continue to
X * try and send the message ...
X */
X
X return (0);
}
X
/*
X * Add a file to the list of files to be transferred.
X */
X
int addfile(file, subj)
char *file, *subj;
{
X char *malloc();
X
X if (filecount >= MAX_FILES_TO_SEND)
X return;
X
X /*
X * Add filename...
X */
X
X if ((filelist[filecount] = malloc(strlen(file) + 5)) == (char *)0)
X return;
X strcpy(filelist[filecount], file);
X
X /*
X * Create subject...
X */
X
X if ((subjects[filecount] = malloc(strlen(subj) + 1)) == (char *)0)
X subjects[filecount] = (char *)0;
X else strcpy(subjects[filecount], subj);
X
X ++filecount;
}
X
int justcopy(to, from)
char *to, *from;
{
X strcpy(to, strpbrk(from, " \t") + 1);
}
X
/*
X * `from' contains an address header.
X * Either a From: or a Reply-To: header
X * Get the actual address out, and put it into `to'.
X */
X
int mkaddress(to, from)
char *to, *from;
{
X char buf[STRLEN];
X char *bp = buf;
X
X /*
X * Skip over keyword and colon
X */
X
X while (iskwchar(*from) && *from)
X ++from;
X ++from;
X
X /*
X * Skip over any remaining white space
X */
X
X while (iswhite(*from) && *from)
X ++from;
X
X /*
X * From: Jan-Piet Mens <j...@logixwi.uucp>
X * ^^^^^^^^^^^^^^^^
X * or
X * From: jpm@logixwi (Jan-Piet Mens)
X * ^^^^^^^^^^^
X */
X
X /*
X * If the rest of the buffer contains no '<', then we suppose the
X * address looks like "jpm@logixwi (Jan-Piet Mens).
X */
X
X if (strchr(from,'<') == (char *)0)
X {
X while ((*from != ' ') && (*from != '\t') && *from)
X *bp++ = *from++;
X }
X else
X {
X /*
X * It must be one of these.
X * From: Jan-Piet Mens <j...@logixwi.uucp>
X * ^^^^^^^^^^^^^^^^
X */
X
X while (*from != '<' && *from)
X ++from;
X ++from;
X while (*from != '>' && *from)
X *bp++ = *from++;
X }
X
X *bp = EOS;
X strcpy(to, buf);
}
X
char *getdate()
{
X static char date[20];
X time_t seconds;
X struct tm *tm, *localtime();
X
X time(&seconds);
X
X tm = localtime(&seconds);
X
X sprintf(date,"%02d.%02d.%02d %02d:%02d",
X tm->tm_mday,
X tm->tm_mon + 1,
X tm->tm_year,
X tm->tm_hour,
X tm->tm_min );
X
X return (date);
}
SHAR_EOF
chmod 0444 parsemail.c ||
echo 'restore of parsemail.c failed'
Wc_c="`wc -c < 'parsemail.c'`"
test 5177 -eq "$Wc_c" ||
echo 'parsemail.c: original size 5177, current size' "$Wc_c"
fi
# ============= mygets.c ==============
if test -f 'mygets.c' -a X"$1" != X"-c"; then
echo 'x - skipping mygets.c (File already exists)'
else
echo 'x - extracting mygets.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mygets.c' &&
/*
X * $Header: /u/tools/etc/mail-server/RCS/mygets.c,v 1.1 1991/08/12 11:15:49 jpm Exp $
X *
X * $Log: mygets.c,v $
X * Revision 1.1 1991/08/12 11:15:49 jpm
X * Initial revision
X *
X */
X
/*
X * Copyright 1991, Jan-Piet Mens
X * License to freely use and distribute this software is hereby granted
X * by the author, subject to the condition that this copyright notice
X * remains intact. The author retains the exclusive right to publish
X * derivative works based on this work, including, but not limited
X * to, revised versions of this work
X */
X
#ifndef lint
X static char rcs_id[] = "$Id: mygets.c,v 1.1 1991/08/12 11:15:49 jpm Exp $";
#endif
X
#include "mserver.h"
X
/*
X * Read a string into `s', maximum length is `n' from File `fp'.
X * If the line that is being read in, is part of an RFC822 mail header
X * handle split header lines.
X *
X * From: jpm@logixwi
X * (Jan-Piet Mens)
X *
X * becomes
X *
X * From: jpm@logixwi (Jan-Piet Mens)
X *
X * only, of course, if the first characters of the next line are white space.
X *
X * Mygets() returns NULL at EOF.
X */
X
char *mygets(s, n, fp)
char *s;
int n;
FILE *fp;
{
X int charcount = 0;
X char *bp = s;
X BOOL colon = FALSE; /* Have no colon yet */
X BOOL nowhite = TRUE; /* Have not yet read white sp */
X int c, c1;
X
X while ((c = fgetc(fp)) != EOF)
X {
X if (++charcount > n)
X {
X *bp = EOS;
X return (s);
X }
X if ((c == COLON) && (colon == FALSE) && (nowhite == TRUE))
X colon = TRUE;
X if (!iswhite(c)) nowhite = TRUE;
X else nowhite = FALSE;
X if (c == NL)
X {
X if (colon == TRUE)
X {
X if ((c1 = fgetc(fp)) == EOF)
X {
X *bp = EOS;
X return (s);
X }
X else
X {
X if (iswhite(c1))
X c = c1;
X else
X {
X ungetc(c1,fp);
X *bp = EOS;
X return (s);
X }
X }
X }
X else
X {
X *bp = EOS;
X return (s);
X }
X }
X *bp++ = c;
X }
X *bp = EOS;
X return ((char *)0);
}
X
#ifdef TESTING
main()
{
X char buf[BUFSIZ];
X
X while (mygets(buf, BUFSIZ, stdin) != (char *)0)
X puts(buf);
}
#endif /* TESTING */
SHAR_EOF
chmod 0444 mygets.c ||
echo 'restore of mygets.c failed'
Wc_c="`wc -c < 'mygets.c'`"
test 1993 -eq "$Wc_c" ||
echo 'mygets.c: original size 1993, current size' "$Wc_c"
fi
# ============= log.c ==============
if test -f 'log.c' -a X"$1" != X"-c"; then
echo 'x - skipping log.c (File already exists)'
else
echo 'x - extracting log.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'log.c' &&
/*
X * $Header: /u/tools/etc/mail-server/RCS/log.c,v 1.1 1991/08/12 11:15:49 jpm Exp $
X *
X * $Log: log.c,v $
X * Revision 1.1 1991/08/12 11:15:49 jpm
X * Initial revision
X *
X */
X
/*
X * Copyright 1991, Jan-Piet Mens
X * License to freely use and distribute this software is hereby granted
X * by the author, subject to the condition that this copyright notice
X * remains intact. The author retains the exclusive right to publish
X * derivative works based on this work, including, but not limited
X * to, revised versions of this work
X */
X
#ifndef lint
X static char rcs_id[] = "$Id: log.c,v 1.1 1991/08/12 11:15:49 jpm Exp $";
#endif
X
#include "mserver.h"
#include <fcntl.h>
#include <varargs.h>
X
#ifndef NO_LOGGING
X
/*VARARGS0*/
void log(va_alist)
va_dcl
{
X va_list args;
X char *fmt;
X char buf[BUFSIZ];
X
X va_start(args);
X fmt = va_arg(args, char *);
X vsprintf(buf,fmt,args);
X strcat(buf,"\n");
X
X write_log(buf);
}
X
void write_log(msg)
char *msg;
{
X extern char *calloc();
X static char *mem = (char *)0;
X char *bp;
X int fd;
X long n;
X
X /*
X * Try to open. If not possible, create the logfile, and
X * reopen it.
X */
X
X if ((fd = open(LOGFILENAME, O_RDWR)) == -1)
X {
X if ((fd = creat(LOGFILENAME, 0644)) == -1)
X printf("Cannot open or creat LOG");
X close(fd);
X if ((fd = open(LOGFILENAME, O_RDWR)) == -1)
X printf("Cannot reopen LOG");
X }
X
X n = lseek(fd, 0L, 2); /* Find log size */
X lseek(fd,0L,0); /* Rewind */
X
X if (n < 100)
X n = 1024L;
X
X if ((mem = calloc(n + 10, sizeof(char))) == (char *)0)
X printf("Not enough memory to read LOG");
X
X if ((n = read(fd, mem, n)) < 0) /* Read whole log */
X printf("Read error on LOG");
X
X if (n >= 0)
X mem[n] = EOS; /* Make string */
X
X bp = mem;
X
X if (n >= LOG_SIZE)
X {
X lseek(fd,0L,0); /* Rewind logfile */
X
X /*
X * Find the first nl-terminated string
X */
X
X while ((*bp != EOS) && bp)
X {
X --n;
X if (*bp != '\n')
X {
X ++bp;
X continue;
X }
X ++bp;
X if (n >= LOG_SIZE)
X continue;
X break;
X }
X close(fd);
X fd = open(LOGFILENAME, O_WRONLY|O_TRUNC);
X if (write(fd, bp, strlen(bp)) != strlen(bp))
X printf("write error on LOG");
X }
X
X write(fd, msg, strlen(msg)); /* Write new msg */
X
X free(mem);
X close(fd);
}
X
#endif /* NO_LOGGING */
SHAR_EOF
chmod 0444 log.c ||
echo 'restore of log.c failed'
Wc_c="`wc -c < 'log.c'`"
test 2217 -eq "$Wc_c" ||
echo 'log.c: original size 2217, current size' "$Wc_c"
fi
# ============= send.c ==============
if test -f 'send.c' -a X"$1" != X"-c"; then
echo 'x - skipping send.c (File already exists)'
else
echo 'x - extracting send.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'send.c' &&
/*
X * $Header: /u/tools/etc/mail-server/RCS/send.c,v 1.1 1991/08/12 11:15:49 jpm Exp $
X *
X * $Log: send.c,v $
X * Revision 1.1 1991/08/12 11:15:49 jpm
X * Initial revision
X *
X */
X
/*
X * Copyright 1991, Jan-Piet Mens
X * License to freely use and distribute this software is hereby granted
X * by the author, subject to the condition that this copyright notice
X * remains intact. The author retains the exclusive right to publish
X * derivative works based on this work, including, but not limited
X * to, revised versions of this work
X */
X
#ifndef lint
X static char rcs_id[] = "$Id: send.c,v 1.1 1991/08/12 11:15:49 jpm Exp $";
#endif
X
#include "mserver.h"
X
int send(fname, To)
char *fname;
char *To;
{
X FILE *fpi, *fpo;
X long msglen = 0;
X int partno, go_on;
X int maxparts;
X char command[BUFSIZ];
X char buf[BUFSIZ], sub[BUFSIZ];
X
X /*
X * Check for legal files
X */
X
X if (checkfilename(fname) == FALSE)
X {
X if (verbose)
X printf("Requested file `%s': Permission not Granted\n",
X fname);
X mail(To, fname, "You had requested file `%s'.\nYou have no permission to get that file.", fname);
X return (1);
X }
X
X /*
X * We have the address. We have the filename. She is allowed to get
X * the file. And now ?
X */
X
X if (access(fname, 04) != 0)
X {
#ifndef NO_LOGGING
X log("Cant open %s just before uuencodeing", fname);
#endif
X mail(To, fname, "Your requested file `%s', cannot be read\nPlease report this to the address in the X-Errors-To: header", fname);
X return (1);
X }
X
X /*
X * Send the HELPFILE in clear ascii text.
X * All else uuencoded.
X */
X
X if (!strcmp(fname, HELPFILE))
X sprintf(command, "cat %s", fname);
X else
X sprintf(command, "uuencode %s %s", fname, basename(fname));
X
X maxparts = countparts(command);
X
X if ((fpi = popen(command,"r")) == (FILE *)0)
X {
#ifndef NO_LOGGING
X log("Cannot open pipe from uuencode. [%s]", command);
#endif
X return (1);
X }
X
X partno = 1;
X
X TOP:
X
X go_on = FALSE;
X if ((fpo = popen(MAILERCMD,"w")) == (FILE *)0)
X {
#ifndef NO_LOGGING
X log("Cannot connect to [%s] for sending file %s",
X MAILERCMD, fname);
#endif
X return (1);
X }
X
X msglen = 0;
X if (!strcmp(fname, HELPFILE))
X strcpy(sub, HELPSUBJECT);
X else
X sprintf(sub, "Subject: %s Part %02d/%02d",
X fname, partno, maxparts);
X
X fprintf(fpo, "From: %s\n", FROMHEADER);
X fprintf(fpo, "To: %s\n", To);
X fprintf(fpo, "%s\n", sub);
X fprintf(fpo, "X-Errors-To: %s\n", ERRORS_TO);
X fprintf(fpo, "\n"); /* Add blank line */
X
X while (fgets(buf,BUFSIZ,fpi) != (char *)0)
X {
X msglen += strlen(buf);
X fputs(buf, fpo);
X if (msglen >= MESSAGE_SIZE)
X {
X msglen = 0;
X go_on = TRUE;
X ++partno;
X break;
X }
X }
X
X pclose(fpo);
X
X if (go_on == TRUE)
X goto TOP;
X
X pclose(fpi);
#ifndef NO_LOGGING
X log("Sent [%s] in %d Parts to %s. %s",
X fname, partno, To, getdate());
#endif
X return (0);
}
X
/*
X * Check if file name `fn' has a legal prefix.
X */
X
int checkfilename(fn)
char *fn;
{
X static char *dirlist[MAX_DIRS];
X static BOOL firstcall = TRUE;
X char filename[BUFSIZ];
X int i = 0, count = 0;
X char *dir, *dptr = DIRLIST, *malloc();
X
X if (firstcall == TRUE)
X {
X firstcall = FALSE;
X
X /*
X * Build list of directory prefixes.
X */
X
X while ((dir = strtok(dptr, ":")) != (char *)0)
X {
X dptr = (char *)0;
X dirlist[i] = malloc(strlen(dir) + 1);
X strcpy(dirlist[i], dir);
X if (verbose)
X printf("Dir: [%s]\n", dirlist[i]);
X ++i;
X }
X dirlist[i] = (char *)0;
X }
X
X strcpy(filename,fn);
X
X /*
X * This is awful. But what I want to do, is to chop the filename
X * off at the second slash. (If there is one). So,
X * `/pub/src/edit/whatever' will become `/pub'.
X */
X
X count = 0;
X for (i = 0; i < strlen(filename); i++)
X {
X if (filename[i] == '/')
X {
X if (count >= 1)
X {
X filename[i] = EOS;
X break;
X }
X ++count;
X }
X }
X
X /*
X * Check if prefix of `filename' is in `dirlist'.
X */
X
X for (i = 0; (i < MAX_DIRS) && dirlist[i] != (char *)0; i++)
X {
X if (!strcmp(filename, dirlist[i]))
X {
X if (verbose)
X printf("%s is in dirlist.\n", fn);
X return (TRUE);
X }
X }
X
X return (FALSE);
}
int countparts(command)
char *command;
{
X FILE *fp;
X int msglen = 0;
X char buf[BUFSIZ];
X int parts = 1;
X
X if ((fp = popen(command,"r")) == (FILE *)0)
X return (-1);
X
X while (fgets(buf,BUFSIZ,fp) != (char *)0)
X {
X msglen += strlen(buf);
X if (msglen >= MESSAGE_SIZE)
X {
X msglen = 0;
X ++parts;
X }
X }
X
X pclose(fp);
X
X return (parts);
}
X
char *basename(fn)
char *fn;
{
X static char *ptr;
X
X return (ptr = (ptr = strrchr(fn,'/')) ? ++ptr : fn);
}
SHAR_EOF
chmod 0444 send.c ||
echo 'restore of send.c failed'
Wc_c="`wc -c < 'send.c'`"
test 4463 -eq "$Wc_c" ||
echo 'send.c: original size 4463, current size' "$Wc_c"
fi
# ============= mail.c ==============
if test -f 'mail.c' -a X"$1" != X"-c"; then
echo 'x - skipping mail.c (File already exists)'
else
echo 'x - extracting mail.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mail.c' &&
/*
X * $Header: /u/tools/etc/mail-server/RCS/mail.c,v 1.2 1991/08/12 14:09:23 jpm Exp $
X *
X * $Log: mail.c,v $
X * Revision 1.2 1991/08/12 14:09:23 jpm
X * Added sys/types.h
X *
X * Revision 1.1 1991/08/12 11:15:49 jpm
X * Initial revision
X *
X */
X
/*
X * Copyright 1991, Jan-Piet Mens
X * License to freely use and distribute this software is hereby granted
X * by the author, subject to the condition that this copyright notice
X * remains intact. The author retains the exclusive right to publish
X * derivative works based on this work, including, but not limited
X * to, revised versions of this work
X */
X
#ifndef lint
X static char rcs_id[] = "$Id: mail.c,v 1.2 1991/08/12 14:09:23 jpm Exp $";
#endif
X
#include "mserver.h"
#include <varargs.h>
#include <sys/types.h>
#include <time.h>
X
X
/*VARARGS0*/
int mail(address,fn,va_alist)
char *address;
char *fn; /* Requested filename */
va_dcl
{
X va_list args;
X FILE *fp;
X time_t secs;
X char *fmt;
X char buf[BUFSIZ];
X
X va_start(args);
X fmt = va_arg(args, char *);
X vsprintf(buf,fmt,args);
X
X if ((fp = popen(MAILERCMD,"w")) == (FILE *)0)
X {
X perror(MAILERCMD);
X return (1);
X }
X
X time(&secs);
X fprintf(fp, "From: %s\n", FROMHEADER);
X fprintf(fp, "To: %s\n", address);
X fprintf(fp, "Subject: %s\n", fn);
X fprintf(fp, "X-Errors-To: %s\n", ERRORS_TO);
X fprintf(fp, "Date: %s", ctime(&secs));
X fprintf(fp, "\n"); /* Add blank line */
X fprintf(fp, "%s\n", buf); /* Add message */
X
X pclose(fp);
X return (0);
}
SHAR_EOF
chmod 0444 mail.c ||
echo 'restore of mail.c failed'
Wc_c="`wc -c < 'mail.c'`"
test 1459 -eq "$Wc_c" ||
echo 'mail.c: original size 1459, current size' "$Wc_c"
fi
# ============= perm.c ==============
if test -f 'perm.c' -a X"$1" != X"-c"; then
echo 'x - skipping perm.c (File already exists)'
else
echo 'x - extracting perm.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'perm.c' &&
/*
X * $Header: /u/tools/etc/mail-server/RCS/perm.c,v 1.1 1991/08/12 14:09:23 jpm Exp $
X *
X * $Log: perm.c,v $
X * Revision 1.1 1991/08/12 14:09:23 jpm
X * Initial revision
X *
X *
X */
X
/*
X * Copyright 1991, Jan-Piet Mens
X * License to freely use and distribute this software is hereby granted
X * by the author, subject to the condition that this copyright notice
X * remains intact. The author retains the exclusive right to publish
X * derivative works based on this work, including, but not limited
X * to, revised versions of this work
X */
X
#ifndef lint
X static char rcs_id[] = "$Id: perm.c,v 1.1 1991/08/12 14:09:23 jpm Exp $";
#endif
X
#include "mserver.h"
X
/*
X * Returns FALSE if permission denied
X */
X
int permission(addr)
char *addr; /* Address of requestor */
{
X FILE *fp;
X char line[BUFSIZ];
X
#ifndef PERMISSION
X return (TRUE);
#endif
X
X if ((fp = fopen(PERMLIST,"r")) == (FILE *)0)
X {
X if (verbose)
X perror(PERMLIST);
X return (FALSE);
X }
X
X while (fgets(line,BUFSIZ,fp) != (char *)0)
X {
X line[strlen(line) - 1] = EOS;
X if (reg(line,addr) == TRUE)
X {
X fclose(fp);
X return (TRUE);
X }
X }
X
X fclose(fp);
X return (FALSE);
}
X
int reg(expr, addr)
char *expr, *addr;
{
X extern char *regcmp(), *regex();
X char *cmp, *ptr;
X
X
X cmp = regcmp(expr, (char *)0);
X ptr = regex(cmp, addr);
X
X free(cmp);
X
X return ((ptr == (char *)0) ? FALSE : TRUE);
}
SHAR_EOF
chmod 0444 perm.c ||
echo 'restore of perm.c failed'
Wc_c="`wc -c < 'perm.c'`"
test 1357 -eq "$Wc_c" ||
echo 'perm.c: original size 1357, current size' "$Wc_c"
fi
# ============= mserver.h ==============
if test -f 'mserver.h' -a X"$1" != X"-c"; then
echo 'x - skipping mserver.h (File already exists)'
else
echo 'x - extracting mserver.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mserver.h' &&
#include <stdio.h>
X
/* ---------------------------------------------------------------------------+
X | MAX_FILES_TO_SEND So many files may be requested in any one |
X | message to the mail-server |
X +----------------------------------------------------------------------------*/
#define MAX_FILES_TO_SEND 10
X
/* ---------------------------------------------------------------------------+
X | STRING Define this if you want to include string.h |
X | else, strings.h will be included |
X +----------------------------------------------------------------------------*/
#define STRING /* */
X
X
/* ---------------------------------------------------------------------------+
X | HELPFILE Full pathname of the file (ascii text please) |
X | which will be sent on request of "help" |
X | This should contain info on how to reach you |
X | and how to get an index or whatever ... |
X | The dirname of HELPFILE must be in DIRLIST |
X | HELPSUBJECT Is a string that will be sent as Subject: |
X | header when HELPFILE is sent. |
X +----------------------------------------------------------------------------*/
#define HELPFILE "/pub/HELP"
#define HELPSUBJECT "Subject: HELP from mail-server@logixwi"
X
/* ---------------------------------------------------------------------------+
X | INDEXFILE Full pathname of file that contains index of |
X | The dirname of INDEXFILE must be in DIRLIST |
X | your archives. |
X +----------------------------------------------------------------------------*/
#define INDEXFILE "/pub/Index"
X
/*----------------------------------------------------------------------------+
X | NO_LOGGING if this symbol is defined, no logging of |
X | messages and errors will occur. In this case, |
X | the symbols LOGFILENAME and LOG_SIZE may be |
X | ignored |
X -----------------------------------------------------------------------------*/
#undef NO_LOGGING
X
/*----------------------------------------------------------------------------+
X | LOGFILENAME name of the logfile. |
X +----------------------------------------------------------------------------*/
#define LOGFILENAME "/v/spool/mail-server/Log"
X
/*----------------------------------------------------------------------------+
X | LOG_SIZE gives the size in bytes that the log file will have |
X | at most. The log file is circular. It will be kept |
X | at a size that should not surpass LOG_SIZE. |
X | plus-or-minus a few bytes ;-) |
X -----------------------------------------------------------------------------*/
#define LOG_SIZE (10*1024)
X
/* ---------------------------------------------------------------------------+
X | MAX_DIRS Maximum number of directories that contail filename |
X | prefixes. See DIRLIST |
X +----------------------------------------------------------------------------*/
#define MAX_DIRS 10
X
X
/* ---------------------------------------------------------------------------+
X | DIRLIST A colon-separated list of directory prefixes, that |
X | will be used to compare if a requested file is in one |
X | of these directories. If it is not, the requestor |
X | will get an error sent back. |
X +----------------------------------------------------------------------------*/
#define DIRLIST "/pub:/tmp"
X
/* ---------------------------------------------------------------------------+
X | MAILERCMD is the name of your mailer. It should be able to |
X | get a From:, To:, Subject: headers from stdin. |
X | If it can't, you'll have to hack up mail.c |
X | and send.c |
X +----------------------------------------------------------------------------*/
#define MAILERCMD "/usr/lib/sendmail -t"
X
/* ---------------------------------------------------------------------------+
X | FROMHEADER Content of the From: header |
X +----------------------------------------------------------------------------*/
#define FROMHEADER "MAIL-SERVER"
X
X
/* ---------------------------------------------------------------------------+
X | ERRORS_TO Content of the X-Errors-To: header. This should be |
X | the name of a Human! |
X +----------------------------------------------------------------------------*/
#define ERRORS_TO "postm...@logixwi.uucp"
X
/* ---------------------------------------------------------------------------+
X | MESSAGE_SIZE Length of one message in bytes. Note that some mailers|
X | can't handle mail larger than about 60K |
X +----------------------------------------------------------------------------*/
#define MESSAGE_SIZE (50*1024)
X
/* ---------------------------------------------------------------------------+
X | PERMISSION Define this if you want permission checking of users |
X | who are allowed/not allowed to request files. |
X +----------------------------------------------------------------------------*/
#define PERMISSION /* */
X
/* ---------------------------------------------------------------------------+
X | PERMLIST Filename of file that contains list of Reply-To: |
X | addresses of users who are allowed to request files |
X | If PERMISSION is defined, and PERMLIST cannot be |
X | opened, no one is allowed to request files |
X +----------------------------------------------------------------------------*/
#define PERMLIST "/v/spool/mail-server/request.allow"
X
/* End of configurable section */
X
#ifndef TRUE
# define TRUE (1)
# define FALSE (0)
#endif /* TRUE */
X
#define EOS '\0'
#define NL '\n'
#define COLON ':'
#define STRLEN 256 /* Length of strings */
X
typedef char BOOL;
X
extern BOOL verbose;
X
#define EQUAL(s, t) (!strncmp((s), (t), strlen((t))))
#define iskwchar(c) (isalnum(c) || (c) == '-' || (c) == '.')
#define iswhite(c) ( ((c) == ' ') || ((c) == '\t') )
X
#ifdef STRING
#include <string.h>
#else
# include <strings.h>
#endif
X
/* --------- Function declarations -----------------------------------------*/
#if defined(__STDC__) || defined(__cplusplus)
# define P_(s) s
#else
# define P_(s) ()
#endif
X
void log P_(());
void write_log P_((char *msg));
int main P_((int argc, char **argv));
char *basename P_((char *s));
char *mygets P_((char *s, int n, FILE *fp));
char *getdate P_((void));
int parsemail P_((void));
int addfile P_((char *file, char *subj));
int justcopy P_((char *to, char *from));
int mkaddress P_((char *to, char *from));
X
#undef P_
SHAR_EOF
chmod 0444 mserver.h ||
echo 'restore of mserver.h failed'
Wc_c="`wc -c < 'mserver.h'`"
test 6489 -eq "$Wc_c" ||
echo 'mserver.h: original size 6489, current size' "$Wc_c"
fi
# ============= patchlevel.h ==============
if test -f 'patchlevel.h' -a X"$1" != X"-c"; then
echo 'x - skipping patchlevel.h (File already exists)'
else
echo 'x - extracting patchlevel.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'patchlevel.h' &&
/*
X * $Log: patchlevel.h,v $
X * Revision 1.3 1991/08/12 14:11:02 jpm
X * Added Permission checking with Regular Expressions.
X *
X * Revision 1.2 1991/08/12 14:10:36 jpm
X * mail-server
X *
X */
X
#define VERSION "mail-server 1.01"
SHAR_EOF
chmod 0444 patchlevel.h ||
echo 'restore of patchlevel.h failed'
Wc_c="`wc -c < 'patchlevel.h'`"
test 232 -eq "$Wc_c" ||
echo 'patchlevel.h: original size 232, current size' "$Wc_c"
fi
# ============= mail-server.1 ==============
if test -f 'mail-server.1' -a X"$1" != X"-c"; then
echo 'x - skipping mail-server.1 (File already exists)'
else
echo 'x - extracting mail-server.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mail-server.1' &&
.TH MAIL-SERVER 1M "" "Local Software"
.SH NAME
mail-server - electronic mail server
.SH SYNOPSIS
.B mail-server
[
.B -v
]
.SH DESCRIPTION
A mail server is a program which receives requests for files via an electronic-
mail message, and queues these files, so as to be able to return them to the
requestor.
.PP
.B mail-server
requires an MTA (Mail Transport Agent) that is able to pass mail destined for
the mail-server to the
.B mail-server
program via standard input. This may be done via a
.B ".forward"
mechanism of
.I Sendmail,
or an alias of
.I MMDF.
.PP
This mail-server is able to control which users (addresses) are allowed access
to it. This is done by a
.I PERMLIST
file, which contains a set of regular expressions which must be positively
matched against the address of the requestor.
.SH OPTIONS
.B mail-server
recognizes the
.B -v
option as being a verbose mode. This is useful for debugging purposes only.
.SH COMMANDS
.B mail-server
recognizes the following commands:
.IP "\fBhelp\fR"
send help on the mail-server. This help information is the file specified in the HELPFILE variable.
.IP "\fBsend\fR \fIfilename\fR"
The file
.I filename
is returned to the requestor. The requestor is the address specified in a
.I "Reply-To:"
header, or if not available, in the
.I "From:"
header of the mail message.
All requested files are uuencoded before they go out.
.IP "\fBend\fR"
Finish parsing the message. This command tells the
.B mail-server
to ignore whatever follows. This may be used to ignore a possible signature.
.IP "\fBindex\fR"
Send the file INDEXFILE
.SH EXAMPLE
The following mail, is sent to the
.B mail-server
.PP
.nf
.in 1i
$ mail mail-server
Subject: \fIwhatever\fR
Lines: 1632
Subject: \fIwhatever\fR
Reply-To: \fIf...@address.of.fubar\fR
.sp
help
index
end
$
.fi
.in
.PP
The following two messages come back:
.PP
.nf
.in 1i
XFrom: MAIL-SERVER
To: j...@logixwi.UUCP
Subject: HELP from mail-server@logixwi
Lines: 1632
Subject: HELP from mail-server@logixwi
XX-Errors-To: postm...@logixwi.uucp
Date: Mon, 12 Aug 91 10:59:10 GMT
Sender: local@logixwi
Message-ID: <9108120359.aa15707@logixwi.UUCP>
X
This is the file /pub/HELP.
X
X ....
.sp 2
XFrom: MAIL-SERVER
To: j...@logixwi.UUCP
Subject: /pub/Index Part 01/01
Lines: 1632
Subject: /pub/Index Part 01/01
XX-Errors-To: postm...@logixwi.uucp
Date: Mon, 12 Aug 91 10:59:12 GMT
Sender: local@logixwi
Message-ID: <9108120359.aa15718@logixwi.UUCP>
Status: O
X
begin 644 Index
M+W!U8@HO<'5B+V1O<PHO<'5B+V1O8PHO<'5B+W-R8PHO<'5B+W-R8R]E9&ET
X ...
I93$W+W)O=&%T95]L;V<*+W!U8B]A;'0*+W!U8B]A;'0O<V]U<F-E<PIO
X
end
.SH FILES
.IP "data files"
All files in below any directory of the
.I DIRLIST
#define in "mserver.h"
.br
.IP "\fILOGFILENAME\fR"
contains a record of what file what sent in how many parts to what address,
when.
.IP "\fIPERMLIST\fR"
contains one regular expression per line. If any one of these expressions matches the address of the requestor, access to the
.B mail-server
is granted, else denied. In the latter case, the requestor gets a message
telling her to apply for access at the
.I ERRORS_TO
address.
.SH NOTES
Files sent back to the requestor are always
.I uuencoded.
.br
.SH SEE ALSO
mserver.h in the mail-server distribution directory
.br
MMDF, sendmail, aliases
.SH AUTHOR
Jan-Piet Mens - j...@logixwi.uucp
X
SHAR_EOF
chmod 0644 mail-server.1 ||
echo 'restore of mail-server.1 failed'
Wc_c="`wc -c < 'mail-server.1'`"
test 3175 -eq "$Wc_c" ||
echo 'mail-server.1: original size 3175, current size' "$Wc_c"
fi
# ============= INSTALL ==============
if test -f 'INSTALL' -a X"$1" != X"-c"; then
echo 'x - skipping INSTALL (File already exists)'
else
echo 'x - extracting INSTALL (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'INSTALL' &&
Installation Guide for Mail-Server
----------------------------------
X
1. Unpack the sources into a new directory. Change into that directory
X and edit mserver.h and Makefile. In mserver.h, make the necessary
X adjustments to the configurable variables; they are explained there.
X Check the Makefile for BINDIR, and adjust accordingly.
X
2. Do a `make'. This will create an executable `mail-server' in the
X current directory.
X
3. Test the mail-server, by giving it a "mail message".
X
X ./mailserver -v < xx
X
X where `xx' is a file that contains
X
X From: yourname
X Subject: bla bla
X
X help
X
X This should send you the HELP file by mail.
X
4. Check the LOG file. (LOGFILENAME). It should have been created, and
X should contain whatever you requested. Change the modes of the logfile
X and set the owner of the logfile, to the owner of the software.
X ( The process running the `mail-server' program, must be allowed to
X write into the logfile. In the MMDF case (below), the owner of
X my logfile is `local' ).
X
5. After you have successfully received mail from the mail-server, do
X a `make installdirs'. This will create the BINDIR and PREFIX directories
X if they don't exist yet.
X Then do a `make install'. This will put the mail-server program into
X your BINDIR.
X
6. Now comes the hard part ;-)
X You must create a forwarding interface between your mailer and the
X mail-server.
X
If you have MMDF
----------------
X
X Edit the file "/usr/mmdf/table/alias.list"
X This should contain an alias which looks like this:
X
X mail-server: "local|/BINDIR/mail-server"
X
X Where `local' is the owner of the mail-server software and the
X files, and BINDIR is the directory in which you have copied the
X executable `mail-server'.
X
X Then, as user "mmdf", do
X
X $ cd /usr/mmdf/table
X $ ./dbmbuild
X
X As soon as mail is sent to the address "mail-server" on your system,
X MMDF will forward that mail to the appropriate alias.
X
If you have Something else
--------------------------
X
X Create a ".forward" directory, or whatever else you need to get the
X `mail-server' program to read mail that is destined for it.
X
X The mail-server program expects no arguments, and the actual mail
X message in the standard input.
X
7. If you have compiled the mail-server with PERMISSIONS and PERMLIST
X defined, create the PERMLIST file with a regular expression to match
X your address (and the addresses of those people whom you wish to grant
X access to the mail-server)
X
X My address is: j...@logixwi.UUCP so, a few REs that would match my
X address are:
X
X jpm@.*.UUCP
X j..@l.*[Uu][Uu][Cc][Pp]
X .*@logix.*
X
X
X etc. etc...
SHAR_EOF
chmod 0644 INSTALL ||
echo 'restore of INSTALL failed'
Wc_c="`wc -c < 'INSTALL'`"
test 2601 -eq "$Wc_c" ||
echo 'INSTALL: original size 2601, current size' "$Wc_c"
fi
# ============= README ==============
if test -f 'README' -a X"$1" != X"-c"; then
echo 'x - skipping README (File already exists)'
else
echo 'x - extracting README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README' &&
Mail-Server
X
This is a mail-server program, that is able to automatically send files
to persons who requested them via mail. Access to the mail-server may
be controlled by a permissions list, which contains a set of regular
expressions that are matched agains addresses.
X
We use this server for archiving news articles and source-code. The user
who wants something out of the archives, sends a message to the mail-server,
and promptly receives feed-back from the mail-server with the requested
articles and/or files.
X
Prerequisites:
X A mailer that is able to send mail automatically to the standard-input
X of a program. (MMDF, sendmail, ...)
X
X
See the file INSTALL for installation instructions.
X
X
Author:
X Jan-Piet Mens
X j...@logixwi.uucp
SHAR_EOF
chmod 0644 README ||
echo 'restore of README failed'
Wc_c="`wc -c < 'README'`"
test 740 -eq "$Wc_c" ||
echo 'README: original size 740, current size' "$Wc_c"
fi
# ============= Copyright ==============
if test -f 'Copyright' -a X"$1" != X"-c"; then
echo 'x - skipping Copyright (File already exists)'
else
echo 'x - extracting Copyright (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Copyright' &&
/*
X * Copyright 1991, Jan-Piet Mens
X * License to freely use and distribute this software is hereby granted
X * by the author, subject to the condition that this copyright notice
X * remains intact. The author retains the exclusive right to publish
X * derivative works based on this work, including, but not limited
X * to, revised versions of this work
X */
SHAR_EOF
chmod 0644 Copyright ||
echo 'restore of Copyright failed'
Wc_c="`wc -c < 'Copyright'`"
test 361 -eq "$Wc_c" ||
echo 'Copyright: original size 361, current size' "$Wc_c"
fi
# ============= Makefile ==============
if test -f 'Makefile' -a X"$1" != X"-c"; then
echo 'x - skipping Makefile (File already exists)'
else
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
CFLAGS=-O -s
X
PREFIX= /v/spool/mail-server
BINDIR=$(PREFIX)/bin
X
# OWNER is the owner of the files in /pub, and the logfile. This should be
# taken into account when aliasing mail into the mail-server
OWNER= local
GROUP= local
X
PROG=mail-server
X
X
OBJ = mailserv.o parsemail.o mygets.o log.o send.o mail.o perm.o
SFILES= mailserv.c parsemail.c mygets.c log.c send.c mail.c perm.c
HFILES= mserver.h patchlevel.h
MANPAGE=mail-server.1
SHARFILES= INSTALL README Copyright Makefile MANIFEST
X
$(PROG): $(OBJ)
X $(CC) $(CFLAGS) -o $(PROG) $(OBJ)
X
install: $(PROG)
X cpset $(PROG) $(BINDIR) 111 $(OWNER) $(GROUP)
X
installdirs:
X -mkdir $(PREFIX)
X -mkdir $(BINDIR)
X
X
$(OBJ): $(HFILES)
X
clean:
X rm -f *.o a.out core Part0?
clobber: clean
X rm -f $(PROG)
X
dist: $(SFILES) $(HFILES) $(MANPAGE) $(SHARFILES)
X shar49 -n Mail-Server -a -s 'j...@logixwi.UUCP' -o Part -l 50 -c \
X $(SFILES) $(HFILES) $(MANPAGE) $(SHARFILES)
SHAR_EOF
chmod 0644 Makefile ||
echo 'restore of Makefile failed'
Wc_c="`wc -c < 'Makefile'`"
test 908 -eq "$Wc_c" ||
echo 'Makefile: original size 908, current size' "$Wc_c"
fi
# ============= MANIFEST ==============
if test -f 'MANIFEST' -a X"$1" != X"-c"; then
echo 'x - skipping MANIFEST (File already exists)'
else
echo 'x - extracting MANIFEST (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'MANIFEST' &&
X File Name Archive # Description
-----------------------------------------------------------
X Copyright 1 Bla Bla
X INSTALL 1 Installation Guide
X MANIFEST 1 This shipping list
X Makefile 1 Instructions
X README 1 Read me 1st
X log.c 1 Logfile routines
X mail-server.1 1 Manual page
X mail.c 1 Send msg to requestor
X mailserv.c 1 main()
X mserver.h 1 Configuration
X mygets.c 1 Read mail message
X parsemail.c 1 Parse mail message
X patchlevel.h 1 Current version
X perm.c 1 Permission checking with RE
X send.c 1 Send files to requestor
SHAR_EOF
chmod 0644 MANIFEST ||
echo 'restore of MANIFEST failed'
Wc_c="`wc -c < 'MANIFEST'`"
test 794 -eq "$Wc_c" ||
echo 'MANIFEST: original size 794, current size' "$Wc_c"
fi
exit 0
--
Jan-Piet Mens, Logix GmbH j...@logixwi.UUCP
Moritzstr. 50, D-6200 Wiesbaden ...!uunet!mcsun!unido!logixwi!jpm