SMTP SEND command for Sendmail
sources-request at panda.UUCP
sources-request at panda.UUCP
Fri May 23 07:55:33 AEST 1986
Mod.sources: Volume 5, Issue 13
Submitted by: Greg Satz <talcott!mojave.stanford.edu:satz>
Since I saw a request for this on Unix-Wizards and someone asked me for
it, I thought I would send it here for others who may be interested.
The following shell archive contains context diffs that support the
SMTP send command. These diffs were extracted from the 4.3beta
sendmail and extraneous patches removed, so don't believe the line
numbers at all.
The only change to the configuration files is in localm.m4 where a TTY
mailer needs to be defined. I included an example as localm.m4.
Also included is the program we use to send messages, to. It is a
simple program that was originally written by Stuart Cracraft. I
hacked it up to use Sendmail/SMTP. It isn't much but it will deliver
tty messages.
This code has been in use here at Stanford for over a year. It is
known to work with the TOPS-20 implementation for sending and receiving
messages.
If anyone makes any changes to these things, I would appreciate it if
you could send them back to me. I have always wanted to add a reply
command and "what are the last N messages" command, but have never
found the time. Manual pages are needed too.
Enjoy!
Greg Satz satz at mojave.stanford.edu
Shasta!satz
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting sendmail.diffs'
sed 's/^X//' <<'//go.sysin dd *' >sendmail.diffs
*** /tmp/,RCSt1001511 Thu May 1 09:59:09 1986
--- collect.c Wed Mar 5 10:45:21 1986
***************
*** 197,203 ****
*/
if (hvalue("to") == NULL && hvalue("cc") == NULL &&
! hvalue("bcc") == NULL && hvalue("apparently-to") == NULL)
{
register ADDRESS *q;
--- 197,204 ----
*/
if (hvalue("to") == NULL && hvalue("cc") == NULL &&
! hvalue("bcc") == NULL && hvalue("apparently-to") == NULL &&
! !bitset(EF_TTYSEND, CurEnv->e_flags))
{
register ADDRESS *q;
*** /tmp/,RCSt1001521 Thu May 1 09:59:18 1986
--- deliver.c Wed Mar 5 22:52:23 1986
***************
*** 1286,1292 ****
{
extern bool shouldqueue();
! if (shouldqueue(e->e_msgpriority))
mode = SM_QUEUE;
else
mode = SendMode;
--- 1288,1296 ----
{
extern bool shouldqueue();
! if (bitset(EF_TTYSEND, e->e_flags))
! mode = SM_QUICKD;
! else if (shouldqueue(e->e_msgpriority))
mode = SM_QUEUE;
else
mode = SendMode;
*** /tmp/,RCSt1001526 Thu May 1 09:59:31 1986
--- main.c Fri Mar 21 13:44:49 1986
***************
*** 451,457 ****
expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
MyHostName = jbuf;
! /* the indices of local and program mailers */
st = stab("local", ST_MAILER, ST_FIND);
if (st == NULL)
syserr("No local mailer defined");
--- 485,491 ----
expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
MyHostName = jbuf;
! /* the indices of local and program and tty mailers */
st = stab("local", ST_MAILER, ST_FIND);
if (st == NULL)
syserr("No local mailer defined");
***************
*** 462,467 ****
--- 496,506 ----
syserr("No prog mailer defined");
else
ProgMailer = st->s_mailer;
+ st = stab("tty", ST_MAILER, ST_FIND);
+ if (st == NULL)
+ syserr("No tty mailer defined");
+ else
+ TTYMailer = st->s_mailer;
/* operate in queue directory */
if (chdir(QueueDir) < 0)
*** /tmp/,RCSt1001545 Thu May 1 09:59:49 1986
--- recipient.c Wed Mar 5 14:48:16 1986
***************
*** 192,199 ****
stripquotes(buf, TRUE);
/* do sickly crude mapping for program mailing, etc. */
! if (m == LocalMailer && buf[0] == '|')
! {
a->q_mailer = m = ProgMailer;
a->q_user++;
if (a->q_alias == NULL && !tTd(0, 1) && !QueueRun && !ForceMail)
--- 193,200 ----
stripquotes(buf, TRUE);
/* do sickly crude mapping for program mailing, etc. */
! if (m == LocalMailer)
! if (buf[0] == '|') {
a->q_mailer = m = ProgMailer;
a->q_user++;
if (a->q_alias == NULL && !tTd(0, 1) && !QueueRun && !ForceMail)
***************
*** 201,207 ****
usrerr("Cannot mail directly to programs");
a->q_flags |= QDONTSEND;
}
! }
/*
** Look up this person in the recipient list.
--- 202,211 ----
usrerr("Cannot mail directly to programs");
a->q_flags |= QDONTSEND;
}
! } else
! if (bitset(EF_TTYSEND, CurEnv->e_flags))
! a->q_mailer = m = TTYMailer;
!
/*
** Look up this person in the recipient list.
***************
*** 265,291 ****
** the user (which is probably correct anyway).
*/
! if (!bitset(QDONTSEND, a->q_flags) && m == LocalMailer)
{
struct stat stb;
extern bool writable();
--- 269,309 ----
** the user (which is probably correct anyway).
*/
! if (!bitset(QDONTSEND, a->q_flags) && (m == LocalMailer ||
! m == TTYMailer))
{
struct stat stb;
extern bool writable();
*** /tmp/,RCSt1001550 Thu May 1 09:59:53 1986
--- sendmail.h Wed Mar 5 14:51:58 1986
***************
*** 153,158 ****
--- 153,159 ----
EXTERN MAILER *LocalMailer; /* ptr to local mailer */
EXTERN MAILER *ProgMailer; /* ptr to program mailer */
+ EXTERN MAILER *TTYMailer; /* ptr to tty mailer */
/*
** Header structure.
** This structure is used internally to store header items.
***************
*** 243,248 ****
--- 244,250 ----
#define EF_KEEPQUEUE 000100 /* keep queue files always */
#define EF_RESPONSE 000200 /* this is an error or return receipt */
#define EF_RESENT 000400 /* this message is being forwarded */
+ #define EF_TTYSEND 001000 /* this message go to tty mailer */
EXTERN ENVELOPE *CurEnv; /* envelope currently being processed */
/*
*** /tmp/,RCSt1001555 Thu May 1 09:59:58 1986
--- srvrsmtp.c Wed Mar 12 22:49:18 1986
***************
*** 60,69 ****
--- 60,71 ----
# define CMDDBGKILL 13 /* kill -- kill sendmail */
# define CMDDBGWIZ 14 /* wiz -- become a wizard */
# define CMDONEX 15 /* onex -- sending one transaction only */
+ # define CMDSEND 17 /* send -- designate sender of a send */
static struct cmd CmdTab[] =
{
"mail", CMDMAIL,
+ "send", CMDSEND,
"rcpt", CMDRCPT,
"data", CMDDATA,
"rset", CMDRSET,
***************
*** 209,219 ****
--- 211,226 ----
+ case CMDSEND:
case CMDMAIL: /* mail -- designate sender */
SmtpPhase = "MAIL";
***************
*** 245,250 ****
--- 252,259 ----
if (p == NULL)
break;
setsender(p);
+ if (c->cmdcode == CMDSEND)
+ CurEnv->e_flags |= EF_TTYSEND;
if (Errors == 0)
{
message("250", "Sender ok");
***************
*** 640,645 ****
--- 650,656 ----
char *label;
{
int childpid;
+ char *s;
if (!OneXact)
{
***************
*** 669,675 ****
--- 680,689 ----
/* child */
InChild = TRUE;
QuickAbort = FALSE;
+ s = macvalue('s', CurEnv);
clearenvelope(CurEnv, FALSE);
+ if (s)
+ define('s', s, CurEnv);
}
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 sendmail.diffs
/bin/echo -n ' '; /bin/ls -ld sendmail.diffs
fi
/bin/echo 'Extracting localm.m4'
sed 's/^X//' <<'//go.sysin dd *' >localm.m4
Mlocal, P=/bin/mail, F=rlsDFMmn, S=10, R=20, A=mail -d $u
Mprog, P=/bin/sh, F=lsDFMe, S=10, R=20, A=sh -c $u
Mtty, P=/usr/stanford/bin/to, F=rlsn, S=10, R=20, A=to $u, M=5000
S10
R@ $n errors to mailer-daemon
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 localm.m4
/bin/echo -n ' '; /bin/ls -ld localm.m4
fi
/bin/echo 'Extracting to.c'
sed 's/^X//' <<'//go.sysin dd *' >to.c
X/*
* Send terminal messages locally and over the Internet
*/
#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <utmp.h>
#include <pwd.h>
#include <sysexits.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define MSG_SIZE 5000
struct sockaddr_in hisctladdr;
struct utmp utmp, *utmpp;
struct stat statb;
char msg[MSG_SIZE], buffer[BUFSIZ];
char tpath[] = "/dev/";
char term[sizeof(tpath)+sizeof(utmp.ut_line)];
int netfd, msglen;
char *from, /* Remote user at host */
*mytimestr, /* time string */
*myname, /* Local username */
*mytty, /* Local TTY */
myhost[100]; /* Local host name */
int alarmed;
int sendmail;
time_t mytime;
char *getlogin(), *index(), *ctime(), *malloc(), *ttyname();
int nothing();
time_t time();
main (argc, argv)
int argc;
char **argv;
{
register char *p, *q;
int ufd;
char person[80];
struct hostent *hp;
argc--, argv++;
while (argc > 0 && **argv == '-')
switch (*++*argv) {
case 'r':
argc--, argv++;
if (argc > 0)
from = *argv;
else
goto usage;
argc--, argv++;
break;
case 'd':
sendmail++;
case NULL:
argc--, argv++;
break; /* we can ignore this */
default:
goto usage;
}
if (argc < 1) {
usage:
fprintf (stderr, "usage: to address[,...,address] [message]\n");
exit (EX_USAGE);
}
signal(SIGALRM, nothing);
if (stat("/etc/utmp", &statb) < 0) {
perror("to: /etc/utmp");
exit(EX_OSFILE);
}
utmpp = (struct utmp *) malloc((unsigned)statb.st_size);
if ((ufd = open("/etc/utmp", 0)) < 0) {
perror("to: /etc/utmp");
exit(EX_OSFILE);
}
read(ufd, (char *)utmpp, (unsigned) statb.st_size);
close(ufd);
if ((myname = getlogin()) == NULL)
myname = "UNKNOWN";
if ((mytty = ttyname(0)) != NULL)
mytty += 5;
mytime = time((time_t *) 0);
mytimestr = ctime(&mytime);
gethostname(myhost, sizeof myhost);
if ((hp = gethostbyname(myhost)) != NULL)
strcpy(myhost, hp->h_name);
if (argc == 1) {
fputs ("Msg:\n", stdout);
p = msg;
while (p < &msg[MSG_SIZE] && gets(p) != NULL) {
p += strlen(p);
*p++ = '\r'; *p++ = '\n';
}
msglen = p - msg;
p = *argv;
} else {
p = *argv;
q = msg;
while (--argc && q < &msg[MSG_SIZE]) {
strcpy(q, *++argv);
q += strlen(*argv);
*q++ = ' ';
}
*q++ = '\r';
*q++ = '\n';
msglen = q - msg;
}
for (; *p;) {
for(q = person; *p && *p != ',';)
*q++ = *p++;
*q = '\0';
if ((q = index(person, '@')) != NULL) {
*q++ = '\0';
netsend(person, q);
} else
if (!locsend(person)) { /* user not logged in */
if (!sendmail)
fprintf(stderr, "to: %s: not logged in\n", person);
exit(EX_UNAVAILABLE);
}
}
exit(EX_OK);
}
X/*
* Send a message to a remote user
*/
netsend (person, host)
char *person, *host;
{
register int n;
char newhost[100];
struct servent *sp;
struct hostent *hp;
#ifdef DEBUG
printf("net user = %s@%s\n",person, host);
#endif
hp = gethostbyname(host);
if (hp == NULL) {
fprintf(stderr, "to: %s: no such host\n", host);
exit(EX_NOHOST);
}
strcpy(newhost, hp->h_name);
sp = getservbyname("smtp", "tcp");
if (sp == NULL) {
fprintf(stderr, "to: smtp/tcp: service not found\n");
exit(EX_UNAVAILABLE);
}
if ((netfd = socket(hp->h_addrtype, SOCK_STREAM, 0, 0)) < 0) {
perror("to: socket");
exit(EX_UNAVAILABLE);
}
if (bind(netfd, &hisctladdr, sizeof hisctladdr, 0) < 0) {
perror("to: bind");
exit(EX_UNAVAILABLE);
}
bcopy(hp->h_addr, (caddr_t)&hisctladdr.sin_addr, hp->h_length);
hisctladdr.sin_family = hp->h_addrtype;
hisctladdr.sin_port = sp->s_port;
if (connect(netfd, &hisctladdr, sizeof hisctladdr, 0) < 0) {
perror("to: connect");
exit (EX_UNAVAILABLE);
}
n = getrply ();
if (n != 220) /* Got the site */
goto error;
sprintf (buffer, "HELO %s\r\n",myhost);
#ifdef DEBUG
printf("buffer = %s\n",buffer);
#endif
write(netfd, buffer, strlen (buffer));
n = getrply ();
if (n != 250)
goto error;
sprintf (buffer, "SEND FROM:<%s@%s>\r\n", myname, myhost);
#ifdef DEBUG
printf("buffer = %s\n",buffer);
#endif
write (netfd, buffer, strlen (buffer));
n = getrply ();
if (n != 250)
goto error;
sprintf (buffer, "RCPT TO:<%s@%s>\r\n", person, newhost);
#ifdef DEBUG
printf("buffer = %s\n",buffer);
#endif
write (netfd, buffer, strlen (buffer));
n = getrply ();
if (n != 250)
goto error;
#ifdef DEBUG
printf("buffer = DATA\n");
#endif
write (netfd, "DATA\r\n", 6);
n = getrply ();
if (n != 354)
goto error;
write (netfd, msg, msglen);
#ifdef DEBUG
printf(".\n");
#endif
write (netfd, ".\r\n", 3);
n = getrply ();
if (n != 250)
goto error;
#ifdef DEBUG
printf("buffer = QUIT\n");
#endif
write (netfd, "QUIT\r\n",6);
n = getrply ();
if (n != 221 && n != 220)
goto error;
done:
disconnect ();
return;
error:
fprintf(stderr, "to: network error: %s\n", buffer);
goto done;
}
X/*
* Send a message to a local user
*/
locsend(person)
char *person;
{
char tbuf[MSG_SIZE+BUFSIZ];
int count, found;
FILE *tf;
register struct utmp *up;
count = statb.st_size / sizeof(struct utmp);
found = 0;
for (up = utmpp; up < &utmpp[count]; up++) {
if (up->ut_name[0] == '\0' || strncmp(person, up->ut_name,
sizeof(utmp.ut_name)))
continue;
strcpy(term, tpath);
strncat(term, up->ut_line, sizeof(utmp.ut_line));
alarmed = 0;
alarm(3);
if ((tf = fopen(term, "w")) != NULL) {
alarm(0);
setbuf(tf, tbuf);
fprintf(tf, "\r\n\007%s,", from ? from : myname);
if (mytty)
fprintf(tf, " %s,", mytty);
fprintf(tf, " %.7s%.4s%.9s\r\n%s",
&mytimestr[4],
&mytimestr[20],
&mytimestr[10],
msg);
alarm(5);
fflush(tf);
fclose(tf);
alarm(0);
if (!alarmed)
found++;
}
}
return(found);
}
X/*
* Disconnect from SMTP server
*/
disconnect ()
{
write(netfd, "QUIT\r\n", 6);
close(netfd);
}
X/*
* Read reply code from SMTP server
*/
getrply ()
{
char temp[BUFSIZ];
register int i, n;
while((i = read(netfd, temp, sizeof temp)) == 0)
;
temp[i] = NULL;
#ifdef DEBUG
printf("temp=\"%s\"\n",temp);
#endif
for (i = 0, n = 0; temp[i] != NULL; i++)
if (temp[i] != '\n' && temp[i] != '\r') {
buffer[n++] = temp[i];
}
buffer[n] = NULL;
n = 0;
for (i = 0; i < strlen (buffer); i++) {
if (isdigit (buffer[i]))
n = (n * 10) + (buffer[i] - '0');
else
break;
}
#ifdef DEBUG
printf("n=%d temp=\"%s\"\n",n, temp);
#endif
return (n);
}
nothing()
{
alarmed++;
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 to.c
/bin/echo -n ' '; /bin/ls -ld to.c
fi
More information about the Mod.sources
mailing list