sendmail support for the SMTP send command
Greg Satz
satz at CSL-Vax.ARPA
Sat Dec 8 04:21:22 AEST 1984
The following shell archive will extract the necessary diffs and
programs to support sending messages between hosts via the SMTP send
command. You need to add the following line to your sendmail.cf file:
Mlocal, P=/bin/mail, F=rlsDFmn, S=10, R=20, A=mail -d $u
Mprog, P=/bin/sh, F=lsDFMeuP, S=10, R=20, A=sh -c $u
+ Mtty, P=/usr/local/bin/to, F=rlsn, S=10, R=20, A=to $u, M=5000
It has been working here at Stanford for about a month. Enjoy!
------------------------------------------------------------------------
#! /bin/sh
: This is a shar archive. Extract with sh, not csh.
echo x - to.c
cat > to.c << '19127!Funky!Stuff!'
/*
* 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[32]; /* Local host name */
int alarmed;
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];
argc--, argv++;
while (argc > 0 && **argv == '-')
switch (*++*argv) {
case 'r':
argc--, argv++;
if (argc > 0)
from = *argv;
else
goto usage;
argc--, argv++;
break;
case NULL:
case 'd':
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 (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 */
exit(EX_NOUSER);
}
exit(EX_OK);
}
/*
* Send a message to a remote user
*/
netsend (person, host)
char *person, *host;
{
register int n;
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);
}
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, host);
#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;
}
/*
* 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);
}
/*
* Disconnect from SMTP server
*/
disconnect ()
{
write(netfd, "QUIT\r\n", 6);
close(netfd);
}
/*
* 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++;
}
19127!Funky!Stuff!
echo x - sendmail.diffs
cat > sendmail.diffs << '19127!Funky!Stuff!'
*** sendmail.h_ Fri Jul 6 18:14:12 1984
--- sendmail.h Sun Nov 4 23:53:14 1984
***************
*** 129,134
EXTERN MAILER *LocalMailer; /* ptr to local mailer */
EXTERN MAILER *ProgMailer; /* ptr to program mailer */
/*
** Header structure.
** This structure is used internally to store header items.
--- 129,135 -----
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.
***************
*** 217,222
#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 */
EXTERN ENVELOPE *CurEnv; /* envelope currently being processed */
/*
--- 218,224 -----
#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 */
/*
*** collect.c_ Fri Jul 6 18:14:45 1984
--- collect.c Tue Nov 6 12:40:07 1984
***************
*** 181,187
*/
if (hvalue("to") == NULL && hvalue("cc") == NULL &&
! hvalue("bcc") == NULL && hvalue("apparently-to") == NULL)
{
register ADDRESS *q;
--- 181,188 -----
*/
if (hvalue("to") == NULL && hvalue("cc") == NULL &&
! hvalue("bcc") == NULL && hvalue("apparently-to") == NULL &&
! !bitset(EF_TTYSEND, CurEnv->e_flags))
{
register ADDRESS *q;
*** deliver.c_ Sat Jul 28 17:20:41 1984
--- deliver.c Sun Nov 4 23:53:34 1984
***************
*** 1204,1209
{
extern int QueueLA;
if (getla() > QueueLA)
mode = SM_QUEUE;
else
--- 1204,1212 -----
{
extern int QueueLA;
+ if (bitset(EF_TTYSEND, e->e_flags))
+ mode = SM_QUICKD;
+ else
if (getla() > QueueLA)
mode = SM_QUEUE;
else
*** main.c_ Fri Jul 6 18:14:01 1984
--- main.c Sun Nov 4 23:52:58 1984
***************
*** 375,381
expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
HostName = jbuf;
! /* the indices of local and program mailers */
st = stab("local", ST_MAILER, ST_FIND);
if (st == NULL)
syserr("No local mailer defined");
--- 375,381 -----
expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
HostName = 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");
***************
*** 386,391
syserr("No prog mailer defined");
else
ProgMailer = st->s_mailer;
/* operate in queue directory */
if (chdir(QueueDir) < 0)
--- 386,396 -----
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)
*** recipient.c_ Sun Nov 4 21:01:25 1984
--- recipient.c Tue Nov 6 13:53:33 1984
***************
*** 180,187
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)
--- 180,187 -----
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)
***************
*** 189,195
usrerr("Cannot mail directly to programs");
a->q_flags |= QDONTSEND;
}
! }
/*
** Look up this person in the recipient list.
--- 189,198 -----
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.
***************
*** 252,258
** the user (which is probably correct anyway).
*/
! if (!bitset(QDONTSEND, a->q_flags) && m == LocalMailer)
{
struct stat stb;
extern bool writable();
--- 255,262 -----
** the user (which is probably correct anyway).
*/
! if (!bitset(QDONTSEND, a->q_flags) && (m == LocalMailer ||
! m == TTYMailer))
{
struct stat stb;
extern bool writable();
*** srvrsmtp.c_ Fri Jul 6 18:45:22 1984
--- srvrsmtp.c Mon Nov 5 00:05:06 1984
***************
*** 48,53
# define CMDDBGWIZ 14 /* wiz -- become a wizard */
# define CMDONEX 15 /* onex -- sending one transaction only */
# define CMDDBGSHELL 16 /* shell -- give us a shell */
static struct cmd CmdTab[] =
{
--- 48,54 -----
# define CMDDBGWIZ 14 /* wiz -- become a wizard */
# define CMDONEX 15 /* onex -- sending one transaction only */
# define CMDDBGSHELL 16 /* shell -- give us a shell */
+ # define CMDSEND 17 /* send -- designate sender of a send */
static struct cmd CmdTab[] =
{
***************
*** 52,57
static struct cmd CmdTab[] =
{
"mail", CMDMAIL,
"rcpt", CMDRCPT,
"data", CMDDATA,
"rset", CMDRSET,
--- 53,59 -----
static struct cmd CmdTab[] =
{
"mail", CMDMAIL,
+ "send", CMDSEND,
"rcpt", CMDRCPT,
"data", CMDDATA,
"rset", CMDRSET,
***************
*** 184,189
HostName, p);
break;
case CMDMAIL: /* mail -- designate sender */
/* force a sending host even if no HELO given */
if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
--- 186,192 -----
HostName, p);
break;
+ case CMDSEND:
case CMDMAIL: /* mail -- designate sender */
/* force a sending host even if no HELO given */
if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
***************
*** 211,216
if (p == NULL)
break;
setsender(p);
if (Errors == 0)
{
message("250", "Sender ok");
--- 214,221 -----
if (p == NULL)
break;
setsender(p);
+ if (c->cmdcode == CMDSEND)
+ CurEnv->e_flags |= EF_TTYSEND;
if (Errors == 0)
{
message("250", "Sender ok");
19127!Funky!Stuff!
More information about the Comp.sources.unix
mailing list