BBN-Vax-TCP/src/mtp/srvrmtp.c
#define DELIVERMAIL /* To use /etc/delivermail to send mail */
/*
* Eric Shienbrood (BBN) 3 Apr 81 - MTP server, based on BBN FTP server
*/
#include "stdio.h"
#include "signal.h"
#include "sys/types.h"
#include "sys/stat.h"
#define tel_iac 255
/************ F I L E S U S E D B Y M T P ***************/
/******/ /******/
#ifdef DELIVERMAIL
/******/ char *DELIVMAIL= "/etc/delivermail"; /******/
#else
/******/ char *SNDMSG = "sndmsg"; /******/
/******/ char *pwfile = "/etc/passwd"; /******/
/******/ char *afile = "/etc/net/aliases"; /******/
/******/ char *hmdbfile = "/etc/net/homedb"; /******/
#endif DELIVERMAIL
/******/ /******/
/************ F I L E S U S E D B Y M T P ***************/
char *BUGS = "bug-mtp at bbn-unix";
/*
* Structure for the components of the MAIL command's TO: argument.
* The argument is of the form [<path>]user@host
* where "path" is of the form "@host1,@host2,..."
*/
struct path {
char *p_first; /* first part of path (should be our name) */
char *p_hosts; /* path, after our name has been removed */
char *p_username; /* user name of destination mailbox */
char *p_hostname; /* host name of destination mailbox */
} rcvpath, sndpath;
char *progname, *us, *them;
char *sender; /* address of mail sender */
char *errmsg(), *sfind(), *sskip(), *scopy();
extern int errno; /* Has Unix error codes */
#include "errno.h"
#define ERRFD stderr /* this is presumably the log file */
int mail(), quit(), help(), mrsq(), mrcp(), accept();
/*
/****************************************************************
* *
* C O M M A N D D I S P A T C H T A B L E *
* *
****************************************************************/
struct comarr /* format of the command table */
{
char *cmdname; /* ascii name */
int (*cmdfunc)(); /* command procedure to call */
} commands[] = {
"mail", mail, "mrsq", mrsq,
"mrcp", mrcp, "help", help,
"noop", accept, "quit", quit,
"cont", accept, "abrt", accept,
NULL, NULL
};
/* communications buffers/counts/pointers */
int netcount = 0; /* number of valid characters in netbuf */
char netbuf[512]; /* the place that has the valid characters */
char *netptr = netbuf; /* next character to come out of netbuf */
#define BUFL 600 /* length of buf */
char buf[BUFL]; /* general usage */
char pwbuf[512]; /* password entry for current user */
char addressbuf[512]; /* holds <user>:<password> for logging purposes */
char tmpname[] = "/tmp/crmtpXXXXXX";
/* globals used by the mailing stuff */
#define MRSQ_D 0 /* default (no) scheme */
#define MRSQ_T 1 /* Text first scheme */
#define MRSQ_R 2 /* Recipient first scheme (not implemented yet) */
#define MBNAMSIZ 40
char mfname[MBNAMSIZ]; /* storage for mail file name */
int mrsqsw = MRSQ_D; /* semaphore for the mrsq/mrcp stuff */
/* character defines */
#define CR '\r' /* carriage return */
#define LF '\n' /* line feed */
#define CNULL '\0' /* null */
int just_con_data; /* used by getline procedure to limit function */
#ifdef DEBUG
int mypid;
#endif DEBUG
char *arg; /* zero if no argument - pts to comm param */
char *getline(), *strmove();
/*name:
main
function:
network server mtp program
Takes commands from the assumed network connection (file desc 0)
under the assumption that they follow the ARPA network mail
transfer protocol NIC doc ??? RFC 780 and appropriate modifications.
Command responses are returned via file desc 1.
algorithm:
process structure:
There is a small daemon waiting for connections to be
satisfied on socket 57 from any host. As connections
are completed by the ncpdaemon, the returned file descriptor
is setup as the standard input (file desc 0) and standard
output (file desc 1) and this program is executed to
deal with each specific connection. This allows multiple
server connections, and minimizes the system overhead
when connections are not in progress. File descriptors
zero and one are used to ease production debugging and
to allow the forking of other relavent Unix programs
with comparative ease.
main itself:
while commands can be gotten
find command procedure
call command procedure
get next command
command not found
parameters:
none
returns:
nothing
globals:
commands
calls:
getline
seq
netreply
( any of the procedures in the commands array )
called by:
small server daemon program
history:
initial coding 4/12/76 by S. F. Holmgren
long hosts jsq BBN 3-20-79
change error handling jsq BBN 20Aug79
turned into mtp Eric Shienbrood BBN 24Apr81
put in code to call delivermail, ifdef'd on
DELIVERMAIL - Eric Shienbrood BBN 12Aug81
*/
main(argc, argv)
char **argv;
{
register struct comarr *comp;
char *i;
long atime;
char *getuc(), *thisname();
#ifdef SIGINR
signal(SIGINR,1); /* ignore INS interrupts */
#endif SIGINR
progname = argv[0];
if (argc != 3){
fprintf(ERRFD, "%s: wrong number of arguments\n",
progname);
netreply("421 %s %s was incorrectly invoked by mtpsrv!\r\n",
getuc (thisname ()), progname);
exit(-1);
}
them = argv[1];
us = argv[2];
time(&atime);
fprintf(ERRFD, "%s %s %s", progname, them, ctime(&atime));
/* say we're listening */
#ifdef DEBUG
mypid = getpid();
#endif DEBUG
netreply("220 %s Experimental Server MTP\r\n", argv[2]);
nextcomm:
while (i = getline())
{
if (i == (char *)-1) /* handle error */
go_die(ERRFD, "%s: %s net input read error; %s\n",
progname, them, errmsg(0));
/* find and call command procedure */
comp = commands;
while( comp->cmdname != NULL) /* while there are names */
{
if (seq(buf, comp->cmdname)) /* a winner */
{
(*comp->cmdfunc)(); /* call comm proc */
goto nextcomm; /* back for more */
}
comp++; /* bump to next candidate */
}
netreply("500 I never heard of that command before\r\n" );
}
mail_reset(); /* flush any mrcp/mrsq stored text */
}
/*name:
getline
function:
get commands from the standard input terminated by <cr><lf>.
afix a pointer( arg ) to any arguments passed.
ignore carriage returns
map UPPER case to lower case.
manage the netptr and netcount variables
algorithm:
while we havent received a line feed and buffer not full
if netcount is zero or less
get more data from net
error: return 0
check for delimiter character
null terminate first string
set arg pointer to next character
check for carriage return
ignore it
if looking at command name
convert upper case to lower case
if command line (not mail)
null terminate last token
manage netptr
parameters:
none
returns:
0 for EOF
-1 when an error occurs on telnet connection
ptr to last character (null) in command line
globals:
just_con_data
netcount=
netptr =
buf=
calls:
read (sys)
called by:
main
history:
initial coding 4/12/76 by S. F. Holmgren
changed no more line condition from "read(..net..) < 0" to
"read(..net..) <= 0" 5Oct78 S.Y. Chiu
change error handling jsq BBN 20Aug79
*/
char *
getline()
{
register char *inp; /* input pointer in netbuf */
register char *outp; /* output pointer in buf */
register int c; /* temporary char */
int cmdflag; /* looking for telnet command */
extern char *progname;
inp = netptr;
outp = buf;
arg = 0;
cmdflag = 0;
do
{
if( --netcount <= 0 )
{
netcount = read (0, netbuf, 512);
if (netcount == 0) /* EOF */
return( 0 );
if (netcount < 0) /* error */
return((char *)-1);
inp = netbuf;
}
c = *inp++ & 0377;
#ifdef SIGINR
if (cmdflag) /* was last char IAC? */
{ cmdflag = 0; /* if so ignore this one too */
c = 0; /* make sure c != \n so loop won't */
continue; /* end */
}
if (c == tel_iac) /* is this a telnet IAC? */
{ cmdflag++; /* if so note that next char */
continue; /* to be ignored */
}
#endif SIGINR
if (c == '\r' || /* ignore CR */
c >= 0200) /* or any telnet codes that */
continue; /* try to sneak through */
if (just_con_data == 0 && arg == NULL)
{
/* if char is a delim afix token */
if (c == ' ' || c == ',')
{
c = CNULL; /* make null term'ed */
arg = outp + 1; /* set arg ptr */
}
else if (c >= 'A' && c <= 'Z')
/* do case mapping (UPPER -> lower) */
c += 'a' - 'A';
}
*outp++ = c;
} while( c != '\n' && outp < &buf[BUFL] );
if( just_con_data == 0 )
*--outp = 0; /* null term the last token */
/* scan off blanks in argument */
if( arg ){
while( *arg == ' ' )
arg++;
if( *arg == '\0' )
arg = 0; /* if all blanks, no argument */
}
#ifdef DEBUG
if (just_con_data == 0) {
fprintf (ERRFD, ":%d: %s", mypid, buf);
if (arg)
fprintf (ERRFD, " %s", arg);
fprintf (ERRFD, "\n");
}
#endif DEBUG
/* reset netptr for next trip in */
netptr = inp;
/* return success */
return( outp );
}
/*name:
mail
function:
handle the MAIL command over the command connection
General form:
MAIL from:<user@host> to:<@h1,@h2,@h3,user@host>
mail from div6net machines going to the arpanet (BBN ONLY)
through the forwarder uses the command
MAIL from:<user@div6host> to:<@FWDR,user@arpahost>
algorithm:
see if we have a known user
if mailbox file can't be gotten
return
tell him it is ok to go ahead with mail
while he doesnt type a period
read and write data
if path is nonempty, strip our name from the list.
send the mail to the destination
say completed
parameters:
username in arg
returns:
nothing
globals:
arg
username=
calls:
strmove
findmbox
loguser
getmbox
write (sys)
getline
chown (sys)
time (sys)
printf (sys)
called by:
main thru command array
history:
initial coding Mark Kampe UCLA-ATS
modified 4/13/76 by S. F. Holmgren for Illinois version
modified 6/30/76 by S. F. Holmgren to call getmbox
modified 10/18/76 by J. S. Kravitz to improve net mail header
modified by greep for Rand mail system
long host jsq BBN 3-20-79
error handling jsq BBN 20Aug79
modified 4/25/80 by dm(BBN) for mrsq/mrcp support
*/
mail()
{
register FILE * mboxfid; /* fid for temporary *mfname file */
register char *p; /* general use */
char *bufptr;
time_t tyme; /* for the time */
int werrflg; /* keep track of write errors */
int errflg; /* And other errors (dan) */
int keep; /* flag for rsq stuff */
FILE *getmbox();
extern char *errmsg();
keep = 0;
errflg = 0;
werrflg = 0;
mail_reset(); /* unlink any left over temporary files */
if (arg == 0) {
netreply("501 No arguments supplied\r\n");
return;
}
if (!veq_nocase (arg, "from:", 5)) {
netreply("501 No sender named\r\n");
return;
}
/* First, copy the argument into a non-volatile area */
scopy (arg, addressbuf, 0);
/* Scan FROM: and TO: parts of arg */
sender = sfind (addressbuf, ":") + 1;
p = sskip (sfind (sender, " "), " ");
if (dstparse (sender, &sndpath) != 0)
goto badsyn;
/*
* p now points to the beginning of
* the TO: argument, if any
*/
if (*p == CNULL) { /* make sure there is a user name */
keep++;
if (mrsqsw == MRSQ_D) { /* unless one is not necessary */
netreply("501 No recipient named.\r\n");
return;
}
} else {
/* parse destination arg */
if (!veq_nocase (p, "to:", 3)) {
netreply("501 No recipient named.\r\n");
return;
}
p = sfind (p, ":") + 1;
if (dstparse (p, &rcvpath) != 0)
goto badsyn;
/*
* If destination is on this machine,
* then user must be known.
*/
if (rcvpath.p_first == NULL && rcvpath.p_hosts == NULL) {
if (findmbox() == 0) {
netreply("553 User \"%s\" Unknown\r\n",
rcvpath.p_username);
return;
}
}
}
/* get to open mailbox file descriptor */
if ((mboxfid = getmbox()) == NULL)
return;
/* say its ok to continue */
netreply ("354 Enter Mail, end by a line with only '.'\r\n");
just_con_data = 1; /* tell getline only to drop cr */
#ifdef DEBUG
fprintf (ERRFD, ":%d: ... body of message ...\n", mypid);
#endif DEBUG
while (1) { /* forever */
if ((p = getline()) == 0) {
fprintf(mboxfid,"\n***Sender closed connection***\n");
errflg++;
break;
}
if (p == (char *)-1) {
fprintf(mboxfid, "\n***Error on net connection: %s***\n",
errmsg(0));
if (!errflg++)
log_error("(mail) errflg++");
break;
}
/* are we done? */
if (buf[0] == '.')
if (buf[1] == '\n')
break; /* yep */
else
bufptr = &buf[1]; /* skip leading . */
else
bufptr = &buf[0];
/* If write error occurs, stop writing but keep reading. */
if (!werrflg) {
if (fwrite( bufptr, 1, (p-bufptr),mboxfid ) < 0) {
werrflg++;
log_error("(mail) werrflg++");
}
}
}
just_con_data = 0; /* set getline to normal operation */
#ifdef DEBUG
fprintf (ERRFD, ":%d: Finished receiving text.\n", mypid);
#endif DEBUG
if (errflg) {
time (&tyme);
fprintf(mboxfid,"\n=== Network Mail from host %s on %20.20s ===\n",
them, ctime (&tyme) );
}
fclose (mboxfid);
if (werrflg) {
netreply("451-Mail trouble (write error to temporary file)\r\n");
netreply("451 (%s); try again later\r\n", errmsg(0));
mail_reset(); /* delete temporary file */
return;
}
if (mrsqsw == MRSQ_T && keep) {
netreply("250 Mail stored\r\n");
return;
}
if (sndmsg(mfname) == -1) /* call sndmsg to deliver mail */
netreply("451 Mail trouble (sndmsg balks), try later\r\n",
errmsg(0));
else
netreply("250 Mail Delivered \r\n");
mail_reset(); /* clean up (delete temporary file, *mfname) */
return;
badsyn:
netreply("501 Bad argument syntax\r\n");
return;
}
/*
* dstparse - parse the a path of the form
*
* <@h1,@h2,...,user@host>
*
* into its constituent parts.
* returns 0 for successful parse, -1 for failure
*/
dstparse (str, pp)
register char *str;
register struct path *pp;
{
if (str == NULL)
return (-1);
while (*str == ' ')
str++;
if (*str == CNULL || *str++ != '<' || *str == CNULL)
return (-1);
if (*str != '@') { /* simple address: user@host */
pp->p_hosts = NULL;
pp->p_first = NULL;
}
else { /* compound: @host1,@host2,...,user@host */
pp->p_first = str;
str = sfind (str, ",");
if (*str == CNULL)
return (-1);
*str++ = CNULL;
if (*str != '@')
pp->p_hosts = NULL;
else {
pp->p_hosts = str;
/*
* Find the first comma that is not
* followed by a @. That is the beginning
* of the user@host part.
*/
do {
str = sfind (str, ",");
if (*str++ == CNULL)
return (-1);
} while (*str == '@');
str[-1] = CNULL;
}
}
/* Now get the user@host part */
pp->p_username = str;
str = sfind (str, "@");
if (*str == CNULL)
return (-1);
*str++ = CNULL;
pp->p_hostname = str;
if (*str == '>')
return (-1);
for (; *str != '>'; str++)
if (*str == ',' || *str == CNULL)
return (-1);
*str = CNULL; /* Remove trailing '>' */
#ifdef PDEBUG
printf ("dstparse: p_first: %s\np_hosts: %s\np_username: %s\np_hostname: %s\n",
pp->p_first, pp->p_hosts, pp->p_username, pp->p_hostname);
#endif PDEBUG
return (0);
}
/*
name:
getuser
function:
getuser: find a match for the user in username
in /etc/passwd or /etc/net/aliases
parameters:
user name in username
name of file to look in
returns:
1 if user found
0 failure
pwbuf containing the line from the passwd or alias file which matched
history:
initial coding 4/12/76 by S. F. Holmgren
*/
#ifndef DELIVERMAIL
getuser(filename, must_exist)
char *filename;
int must_exist;
{
register char *p; /* general use */
char temp[sizeof(pwbuf)];
extern char *sfind();
FILE *iobuf;
/* Open the "password" file */
if ((iobuf = fopen(filename, "r")) == NULL) {
if (must_exist) {
netreply("421 can't open \"%s\" (%s); try again later\r\n",
filename, errmsg(0));
log_error("(getuser) can't open \"%s\"", filename);
exit(-1); /* fail exit */
}
else
return (0);
}
/* Look thru the entries in the password or alias file for a match. */
while (gets(iobuf, pwbuf)) /* Get entry from pwfile in pwbuf. */
{
scopy(pwbuf, temp, NULL); /* Copy into work area */
p = sfind(temp, ":");
*p = '\0'; /* Turn colon into null */
if (seq_nocase(rcvpath.p_username, temp)) { /* Found username in pwbuf */
fclose(iobuf); /* return success */
return(1);
}
}
fclose(iobuf); /* close password file */
return(0); /* Failure */
}
#endif DELIVERMAIL
/*
name:
getmbox
function:
return a file descriptor for a temporary mailbox
algorithm:
create unique file name
create file
if can't
signal error
return mailbox file descriptor
parameters:
none
returns:
file descriptor of open mailbox file
globals:
mfname
calls:
loguser
stat (sys)
creat(sys)
open (sys)
seek (sys)
called by:
mail
datamail
history:
initial coding 6/30/76 by S. F. Holmgren
rewritten by greep for Rand mail system
use fmodes for default creation mode jsq BBN 7-19-79
*/
FILE *
getmbox()
{
register FILE * mboxfid;
crname (mfname); /* create mailbox file name */
mboxfid = fopen(mfname,"w");
if (mboxfid == NULL)
{ netreply("450 Can't create \"%s\"; %s\r\n",mfname,errmsg(0));
log_error("(getmbox) can't create \"%s\"", mfname);
}
return (mboxfid);
}
/*name:
crname
function:
create a unique file name
algorithm:
use mktemp library routine
parameters:
address of string where result is to be put
returns:
nothing
globals:
none
calls:
mktemp (lib)
called by:
getmbox
history:
written by greep for Rand mail system
*/
crname(ptr)
register char *ptr;
{
register char *p;
register char *s = "/tmp/crmtpXXXXXX";
p = tmpname;
while (*p++ = *s++)
;
p = tmpname;
mktemp(p);
while (*ptr++ = *p++)
;
}
/*name:
mrsq, mrcp, mail_reset
algorithm:
obvious
function:
handle the MRSQ & MRCP protocols
history:
initial coding by dm(bbn) 25 april, 1980 to handle these protocols
*/
mrsq()
{
register int c;
mail_reset(); /* Always reset stored stuff */
if(arg == 0) {
mrsqsw = MRSQ_D; /* Back to default */
netreply("200 OK, using default scheme (none).\r\n");
}
else switch (c = arg[0]) {
case '?':
netreply("215 T Text-first, please.\r\n");
break;
case 't':
case 'T':
mrsqsw = MRSQ_T;
netreply("200 Win!\r\n");
break;
case '\0':
case ' ':
mrsqsw = MRSQ_D; /* Back to default */
netreply("200 OK, using default scheme (none).\r\n");
break;
default:
mrsqsw = MRSQ_D;
netreply("501 Scheme not implemented.\r\n");
break;
}
}
mrcp()
{
register char *p;
char rcpmbox[MBNAMSIZ];
if (mrsqsw == MRSQ_D) {
netreply("503 No scheme specified yet; use MRSQ.\r\n");
return;
}
if (*mfname == '\0') {
netreply("503 No stored text.\r\n");
return;
}
/* parse destination arg */
if (!veq_nocase (arg, "to:", 3)) {
netreply("501 No recipient named.\r\n");
return;
}
p = sfind (arg, ":") + 1;
if (dstparse (p, &rcvpath) != 0) {
netreply("501 Bad argument syntax.\r\n");
return;
}
/*
* If destination is on this machine,
* then user must be known.
*/
if (rcvpath.p_first == NULL &&
rcvpath.p_hosts == NULL && findmbox() == 0) {
netreply("553 User \"%s\" Unknown.\r\n", rcvpath.p_username);
return;
}
crname(rcpmbox);/* create a temporary name for sndmsg to mung */
if (link(mfname, rcpmbox) < 0) {
netreply("451 can't link \"%s\" to \"%s\"; %s\r\n",
mfname, rcpmbox, errmsg(0));
log_error("(mrcp) can't link \"%s\" to \"%s\"",
mfname, rcpmbox);
return;
}
if (sndmsg(rcpmbox) == -1) {
netreply("451 mail trouble, please try later.\r\n");
unlink(rcpmbox);
return;
}
else
netreply("250 Mail delivered.\r\n");
}
/* if "mrcp r" ever gets implemented, this will scrub out */
mail_reset()
{ /* the array of names, when finished, i guess */
/* if there is a temporary file left over from previous mrcp's */
if(*mfname)
unlink(mfname); /* remove it-- */
*mfname = '\0';
}
/*
name:
findmbox
function:
determine whether a mailbox exists
algorithm:
if destination host div6net and this is outgoing mail,
always indicate success, otherwise
look first in user-to-home data base,
if not found there, try password file
if getuser doesn't find name in password file
try in alias file
parameters:
none
returns:
1 if successful, 0 otherwise
history:
initial coding 12/15/76 by greep for Rand mail system
Modified by Eric Shienbrood(BBN): July 1981 to accept a
user name terminated by a * as the name of a file into
which mail should be deposited. The file must be publicly
writeable.
Modified by Eric Shienbrood(BBN): August 1981 to always return
success if DELIVERMAIL is #defined.
*/
findmbox()
{
#ifndef DELIVERMAIL
register char *sp;
char *uname;
int i;
char * lowercase();
struct stat statb;
sp = uname = rcvpath.p_username;
while (*sp++ != '\0')
;
if (sp > &uname[1] && sp[-2] == '*') { /* The "user" is a file */
sp[-2] = '\0';
/*
* To allow mail to be sent to a file,
* it must exist, it must be a regular
* file, and it must be publicly writeable.
*/
i = stat (uname, &statb);
sp[-2] = '*'; /* Put back the * for sndmsg */
if (i < 0)
return (0);
if ((statb.st_mode & S_IFMT) != S_IFREG)
return (0);
return (statb.st_mode & 02);
}
return (getuser(hmdbfile, 0) || getuser(pwfile, 1) || getuser(afile, 0));
#else
return (1);
#endif DELIVERMAIL
}
/*
name:
sndmsg
function:
call sndmsg to deliver mail
algorithm:
fork
execute sndmsg with special argument
parameters:
none
returns:
status of sndmsg, -1 if couldn't execute
globals:
username
mfname
calls:
fork (sys)
exec (sys)
called by:
mail
history:
initial coding 12/15/76 by greep for Rand mail system
long hosts, with kludge for short host sndmsg program jsq BBN 3-25-79
sndmsg kludge removed jsq BBN 4-25-79
dm(bbn) 4-25-80 take filename to send as an argument
*/
sndmsg(file)
char *file;
{
int n;
int status;
char address[40];
char returnto[40];
char *uname, *flag;
flag = "-netmsg";
while((n = fork()) == -1)
sleep(5);
if (n == 0) {
sprintf (returnto, "%s@%s", sndpath.p_username, sndpath.p_hostname);
if (rcvpath.p_first == NULL && rcvpath.p_hosts == NULL)
uname = rcvpath.p_username;
else if (rcvpath.p_hosts == NULL) {
sprintf(address, "%s@%s", rcvpath.p_username, rcvpath.p_hostname);
uname = address;
}
else
exit(-1); /* Can't handle this yet */
#ifdef DELIVERMAIL
/*
* Make the mail file be
* delivermail's standard input.
*/
close(0);
open(file, 0);
execl(DELIVMAIL, "delivermail", "-a", uname, 0);
log_error("(delivermail) can't execl \"%s\";", DELIVMAIL);
#else
execlp(SNDMSG, SNDMSG, flag, uname, file, returnto, 0);
log_error("(sndmsg) can't execl \"%s\";", SNDMSG);
#endif DELIVERMAIL
exit(-1);
}
wait(&status);
return (status>>8);
}
/*name:
quit
function:
handle the QUIT command
algorithm:
say goodbye
exit
parameters:
none
returns:
never
globals:
none
calls:
netreply
exit (sys)
called by:
main thru command array
history:
initial coding 4/13/76 by S. F. Holmgren
*/
quit()
{
mail_reset(); /* flush mail temporary files */
netreply("221 Toodles, call again\r\n" );
exit( 0 );
}
/*name:
accept
function:
to signal the current command has been logged and noted
algorithm:
say command has been logged and noted
parameters:
none
returns:
nothing
globals:
none
called by:
called by main thru command array
history:
initial coding 4/13/76 by S. F. Holmgren
*/
accept()
{
netreply( "200 OK\r\n");
}
/*name:
help
function:
give a list of valid commands
algorithm:
send list
parameters:
none
returns:
nothing
globals:
none
calls:
netreply
called by:
called by main thru the help command
history:
greep
altered by dm (12/3/79) to permit automatic addition of commands
(someone industrious should someday make help accept an argument,
like the protocol says it does...)
*/
help()
{
register i;
register struct comarr *p;
netreply("214-The following commands are accepted:\r\n" );
for(p = commands, i = 1; p->cmdname; p++, i++)
netreply("%s%s", p->cmdname, ((i%10)?" ":"\r\n") );
netreply("\r\n214 Please send complaints/bugs to %s\r\n", BUGS);
}
/*name:
netreply
function:
send appropriate ascii responses
algorithm:
get the length of the string
send it to the standard output file
parameters:
str to be sent to net
returns:
nothing
globals:
none
calls:
write (sys)
called by:
the world
history:
initial coding 4/13/76 by S. F. Holmgren
replaced by fdprintf facility to permit greater
versatility in replies (e.g.,
including errmsg, etc.) dm/bbn Apr 10, '80
*/
netreply(printargs)
char *printargs;
{
char replyline[256];
int len;
sprintf(replyline, "%r", &printargs);
if(write(1,replyline, len = slength(replyline)) < 0){
fprintf(ERRFD,"(netreply) error in writing [");
fprintf(ERRFD, "%r", &printargs);
fprintf(ERRFD,"]; %s\n", errmsg(0));
go_die(ERRFD, "\n");
}
#ifdef DEBUG
if (len >= 2 && replyline[len - 2] == '\r') {
replyline[len - 2] = '\n';
replyline[len - 1] = '\0';
}
fprintf (ERRFD, ":%d: %s", mypid, replyline);
#endif DEBUG
}
/* write error messages out to the log file */
log_error(printargs)
char *printargs;
{
fprintf(ERRFD, "%r", &printargs);
fprintf(ERRFD, "; %s\n", errmsg(0));
}
/* clean up mail stuff and call die */
go_die(n, args)
int n; char *args;
{
mail_reset();
die(n, &args);
}
/*name:
gets
function:
get characters from iobuffer until a newline is found
algorithm:
while get a character
if char is new line
stuff in a null
return success
return failure
parameters:
iobuffer - address of an iobuf see getc unix prog manual
buf - addres of character array to put data into
returns:
null terminated line
globals:
none
calls:
getc (sys)
called by:
getuser
history:
initial coding 4/12/76 by S. F. Holmgren
*/
#ifndef DELIVERMAIL
gets( iobuffer,destbuf )
FILE *iobuffer;
char *destbuf;
{
register int c;
register char *outp;
register FILE *iobuf;
iobuf = iobuffer;
outp = destbuf;
while( (c = getc( iobuf )) > 0 )
if( c == '\n' )
{
*outp = CNULL; /* null terminate */
return( 1 ); /* return success */
}
else
*outp++ = c; /* just bump to next spot */
/* return failure */
return( 0 );
}
#endif DELIVERMAIL
/*
* Uppercase a string in place. Return pointer to
* null at end.
*/
char *
getuc(s)
char *s;
{
register char *p,
c;
for (p = s; c = *p; p++)
{
if (c <= 'z' && c >= 'a')
*p -= ('a' - 'A');
}
return(s);
}