home *** CD-ROM | disk | FTP | other *** search
- Subject: SMTP SEND command for Sendmail
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- 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@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@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
-
-