satz@CSL-Vax.ARPA (Greg Satz) (12/07/84)
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@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!