home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume5 / smtp_send < prev    next >
Text File  |  1986-11-30  |  15KB  |  619 lines

  1. Subject: SMTP SEND command for Sendmail
  2. Newsgroups: mod.sources
  3. Approved: jpn@panda.UUCP
  4.  
  5. Mod.sources:  Volume 5, Issue 13
  6. Submitted by: Greg Satz <talcott!mojave.stanford.edu:satz>
  7.  
  8.  
  9. Since I saw a request for this on Unix-Wizards and someone asked me for
  10. it, I thought I would send it here for others who may be interested.
  11.  
  12. The following shell archive contains context diffs that support the
  13. SMTP send command.  These diffs were extracted from the 4.3beta
  14. sendmail and extraneous patches removed, so don't believe the line
  15. numbers at all.
  16.  
  17. The only change to the configuration files is in localm.m4 where a TTY
  18. mailer needs to be defined. I included an example as localm.m4.
  19.  
  20. Also included is the program we use to send messages, to.  It is a
  21. simple program that was originally written by Stuart Cracraft.  I
  22. hacked it up to use Sendmail/SMTP.  It isn't much but it will deliver
  23. tty messages.
  24.  
  25. This code has been in use here at Stanford for over a year.  It is
  26. known to work with the TOPS-20 implementation for sending and receiving
  27. messages.
  28.  
  29. If anyone makes any changes to these things, I would appreciate it if
  30. you could send them back to me.  I have always wanted to add a reply
  31. command and "what are the last N messages" command, but have never
  32. found the time.  Manual pages are needed too.
  33.  
  34. Enjoy!
  35.  
  36. Greg Satz    satz@mojave.stanford.edu
  37.         Shasta!satz
  38.  
  39. : Run this shell script with "sh" not "csh"
  40. PATH=:/bin:/usr/bin:/usr/ucb
  41. export PATH
  42. all=FALSE
  43. if [ $1x = -ax ]; then
  44.     all=TRUE
  45. fi
  46. /bin/echo 'Extracting sendmail.diffs'
  47. sed 's/^X//' <<'//go.sysin dd *' >sendmail.diffs
  48. *** /tmp/,RCSt1001511    Thu May  1 09:59:09 1986
  49. --- collect.c    Wed Mar  5 10:45:21 1986
  50. ***************
  51. *** 197,203 ****
  52.       */
  53.   
  54.       if (hvalue("to") == NULL && hvalue("cc") == NULL &&
  55. !         hvalue("bcc") == NULL && hvalue("apparently-to") == NULL)
  56.       {
  57.           register ADDRESS *q;
  58.   
  59. --- 197,204 ----
  60.       */
  61.   
  62.       if (hvalue("to") == NULL && hvalue("cc") == NULL &&
  63. !         hvalue("bcc") == NULL && hvalue("apparently-to") == NULL &&
  64. !         !bitset(EF_TTYSEND, CurEnv->e_flags))
  65.       {
  66.           register ADDRESS *q;
  67.   
  68.  
  69. *** /tmp/,RCSt1001521    Thu May  1 09:59:18 1986
  70. --- deliver.c    Wed Mar  5 22:52:23 1986
  71. ***************
  72. *** 1286,1292 ****
  73.       {
  74.           extern bool shouldqueue();
  75.   
  76. !         if (shouldqueue(e->e_msgpriority))
  77.               mode = SM_QUEUE;
  78.           else
  79.               mode = SendMode;
  80. --- 1288,1296 ----
  81.       {
  82.           extern bool shouldqueue();
  83.   
  84. !         if (bitset(EF_TTYSEND, e->e_flags))
  85. !             mode = SM_QUICKD;
  86. !         else if (shouldqueue(e->e_msgpriority))
  87.               mode = SM_QUEUE;
  88.           else
  89.               mode = SendMode;
  90.  
  91. *** /tmp/,RCSt1001526    Thu May  1 09:59:31 1986
  92. --- main.c    Fri Mar 21 13:44:49 1986
  93. ***************
  94. *** 451,457 ****
  95.       expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
  96.       MyHostName = jbuf;
  97.   
  98. !     /* the indices of local and program mailers */
  99.       st = stab("local", ST_MAILER, ST_FIND);
  100.       if (st == NULL)
  101.           syserr("No local mailer defined");
  102. --- 485,491 ----
  103.       expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
  104.       MyHostName = jbuf;
  105.   
  106. !     /* the indices of local and program and tty mailers */
  107.       st = stab("local", ST_MAILER, ST_FIND);
  108.       if (st == NULL)
  109.           syserr("No local mailer defined");
  110. ***************
  111. *** 462,467 ****
  112. --- 496,506 ----
  113.           syserr("No prog mailer defined");
  114.       else
  115.           ProgMailer = st->s_mailer;
  116. +     st = stab("tty", ST_MAILER, ST_FIND);
  117. +     if (st == NULL)
  118. +         syserr("No tty mailer defined");
  119. +     else
  120. +         TTYMailer = st->s_mailer;
  121.   
  122.       /* operate in queue directory */
  123.       if (chdir(QueueDir) < 0)
  124.  
  125. *** /tmp/,RCSt1001545    Thu May  1 09:59:49 1986
  126. --- recipient.c    Wed Mar  5 14:48:16 1986
  127. ***************
  128. *** 192,199 ****
  129.       stripquotes(buf, TRUE);
  130.   
  131.       /* do sickly crude mapping for program mailing, etc. */
  132. !     if (m == LocalMailer && buf[0] == '|')
  133. !     {
  134.           a->q_mailer = m = ProgMailer;
  135.           a->q_user++;
  136.           if (a->q_alias == NULL && !tTd(0, 1) && !QueueRun && !ForceMail)
  137. --- 193,200 ----
  138.       stripquotes(buf, TRUE);
  139.   
  140.       /* do sickly crude mapping for program mailing, etc. */
  141. !     if (m == LocalMailer)
  142. !         if (buf[0] == '|') {
  143.           a->q_mailer = m = ProgMailer;
  144.           a->q_user++;
  145.           if (a->q_alias == NULL && !tTd(0, 1) && !QueueRun && !ForceMail)
  146. ***************
  147. *** 201,207 ****
  148.               usrerr("Cannot mail directly to programs");
  149.               a->q_flags |= QDONTSEND;
  150.           }
  151. !     }
  152.   
  153.       /*
  154.       **  Look up this person in the recipient list.
  155. --- 202,211 ----
  156.               usrerr("Cannot mail directly to programs");
  157.               a->q_flags |= QDONTSEND;
  158.           }
  159. !     } else
  160. !         if (bitset(EF_TTYSEND, CurEnv->e_flags))
  161. !             a->q_mailer = m = TTYMailer;
  162. !     
  163.   
  164.       /*
  165.       **  Look up this person in the recipient list.
  166. ***************
  167. *** 265,291 ****
  168.       **  the user (which is probably correct anyway).
  169.       */
  170.   
  171. !     if (!bitset(QDONTSEND, a->q_flags) && m == LocalMailer)
  172.       {
  173.           struct stat stb;
  174.           extern bool writable();
  175.  
  176. --- 269,309 ----
  177.       **  the user (which is probably correct anyway).
  178.       */
  179.   
  180. !     if (!bitset(QDONTSEND, a->q_flags) && (m == LocalMailer ||
  181. !                            m == TTYMailer))
  182.       {
  183.           struct stat stb;
  184.           extern bool writable();
  185.   
  186. *** /tmp/,RCSt1001550    Thu May  1 09:59:53 1986
  187. --- sendmail.h    Wed Mar  5 14:51:58 1986
  188. ***************
  189. *** 153,158 ****
  190. --- 153,159 ----
  191.   
  192.   EXTERN MAILER    *LocalMailer;        /* ptr to local mailer */
  193.   EXTERN MAILER    *ProgMailer;        /* ptr to program mailer */
  194. + EXTERN MAILER    *TTYMailer;        /* ptr to tty mailer */
  195.    /*
  196.   **  Header structure.
  197.   **    This structure is used internally to store header items.
  198. ***************
  199. *** 243,248 ****
  200. --- 244,250 ----
  201.   #define EF_KEEPQUEUE    000100        /* keep queue files always */
  202.   #define EF_RESPONSE    000200        /* this is an error or return receipt */
  203.   #define EF_RESENT    000400        /* this message is being forwarded */
  204. + #define    EF_TTYSEND    001000        /* this message go to tty mailer */
  205.   
  206.   EXTERN ENVELOPE    *CurEnv;    /* envelope currently being processed */
  207.    /*
  208.  
  209. *** /tmp/,RCSt1001555    Thu May  1 09:59:58 1986
  210. --- srvrsmtp.c    Wed Mar 12 22:49:18 1986
  211. ***************
  212. *** 60,69 ****
  213. --- 60,71 ----
  214.   # define CMDDBGKILL    13    /* kill -- kill sendmail */
  215.   # define CMDDBGWIZ    14    /* wiz -- become a wizard */
  216.   # define CMDONEX    15    /* onex -- sending one transaction only */
  217. + # define CMDSEND    17    /* send -- designate sender of a send */
  218.   
  219.   static struct cmd    CmdTab[] =
  220.   {
  221.       "mail",        CMDMAIL,
  222. +     "send",        CMDSEND,
  223.       "rcpt",        CMDRCPT,
  224.       "data",        CMDDATA,
  225.       "rset",        CMDRSET,
  226. ***************
  227. *** 209,219 ****
  228. --- 211,226 ----
  229.   
  230. +           case CMDSEND:
  231.             case CMDMAIL:        /* mail -- designate sender */
  232.               SmtpPhase = "MAIL";
  233.   
  234. ***************
  235. *** 245,250 ****
  236. --- 252,259 ----
  237.               if (p == NULL)
  238.                   break;
  239.               setsender(p);
  240. +             if (c->cmdcode == CMDSEND)
  241. +                 CurEnv->e_flags |= EF_TTYSEND;
  242.               if (Errors == 0)
  243.               {
  244.                   message("250", "Sender ok");
  245. ***************
  246. *** 640,645 ****
  247. --- 650,656 ----
  248.       char *label;
  249.   {
  250.       int childpid;
  251. +     char *s;
  252.   
  253.       if (!OneXact)
  254.       {
  255. ***************
  256. *** 669,675 ****
  257. --- 680,689 ----
  258.               /* child */
  259.               InChild = TRUE;
  260.               QuickAbort = FALSE;
  261. +             s = macvalue('s', CurEnv);
  262.               clearenvelope(CurEnv, FALSE);
  263. +             if (s)
  264. +                 define('s', s, CurEnv);
  265.           }
  266.       }
  267.   
  268. //go.sysin dd *
  269. made=TRUE
  270. if [ $made = TRUE ]; then
  271.     /bin/chmod 644 sendmail.diffs
  272.     /bin/echo -n '    '; /bin/ls -ld sendmail.diffs
  273. fi
  274. /bin/echo 'Extracting localm.m4'
  275. sed 's/^X//' <<'//go.sysin dd *' >localm.m4
  276.  
  277. Mlocal,    P=/bin/mail, F=rlsDFMmn, S=10, R=20, A=mail -d $u
  278. Mprog,    P=/bin/sh,   F=lsDFMe,   S=10, R=20, A=sh -c $u
  279. Mtty,    P=/usr/stanford/bin/to, F=rlsn, S=10, R=20, A=to $u, M=5000
  280.  
  281. S10
  282. R@            $n            errors to mailer-daemon
  283. //go.sysin dd *
  284. made=TRUE
  285. if [ $made = TRUE ]; then
  286.     /bin/chmod 644 localm.m4
  287.     /bin/echo -n '    '; /bin/ls -ld localm.m4
  288. fi
  289. /bin/echo 'Extracting to.c'
  290. sed 's/^X//' <<'//go.sysin dd *' >to.c
  291. X/*
  292.  * Send terminal messages locally and over the Internet
  293.  */
  294.  
  295. #include <sys/types.h>
  296. #include <stdio.h>
  297. #include <ctype.h>
  298. #include <signal.h>
  299. #include <utmp.h>
  300. #include <pwd.h>
  301. #include <sysexits.h>
  302. #include <sys/stat.h>
  303. #include <sys/socket.h>
  304. #include <netinet/in.h>
  305. #include <netdb.h>
  306.  
  307. #define    MSG_SIZE 5000
  308.  
  309. struct    sockaddr_in  hisctladdr;
  310. struct    utmp utmp, *utmpp;
  311. struct    stat statb;
  312. char    msg[MSG_SIZE], buffer[BUFSIZ];
  313. char    tpath[] = "/dev/";
  314. char    term[sizeof(tpath)+sizeof(utmp.ut_line)];
  315. int    netfd, msglen;
  316.  
  317. char    *from,              /* Remote user@host */
  318.     *mytimestr,          /* time string */
  319.     *myname,          /* Local username */
  320.     *mytty,              /* Local TTY */
  321.     myhost[100];          /* Local host name */
  322.  
  323. int    alarmed;
  324. int    sendmail;
  325. time_t    mytime;
  326.  
  327. char    *getlogin(), *index(), *ctime(), *malloc(), *ttyname();
  328. int    nothing();
  329. time_t    time();
  330.  
  331. main (argc, argv)
  332. int argc;
  333. char **argv;
  334. {
  335.     register char *p, *q;
  336.     int ufd;
  337.     char person[80];
  338.     struct hostent *hp;
  339.  
  340.     argc--, argv++;
  341.     while (argc > 0 && **argv == '-')
  342.     switch (*++*argv) {
  343.  
  344.     case 'r':
  345.         argc--, argv++;
  346.         if (argc > 0)
  347.             from = *argv;
  348.         else
  349.             goto usage;
  350.         argc--, argv++;
  351.         break;
  352.  
  353.     case 'd':
  354.         sendmail++;
  355.     case NULL:
  356.         argc--, argv++;
  357.         break;            /* we can ignore this */
  358.  
  359.     default:
  360.         goto usage;
  361.     }
  362.  
  363.     if (argc < 1) {
  364. usage:
  365.     fprintf (stderr, "usage: to address[,...,address] [message]\n");
  366.     exit (EX_USAGE);
  367.     }
  368.     signal(SIGALRM, nothing);
  369.     if (stat("/etc/utmp", &statb) < 0) {
  370.     perror("to: /etc/utmp");
  371.     exit(EX_OSFILE);
  372.     }
  373.     utmpp = (struct utmp *) malloc((unsigned)statb.st_size);
  374.     if ((ufd = open("/etc/utmp", 0)) < 0) {
  375.     perror("to: /etc/utmp");
  376.     exit(EX_OSFILE);
  377.     }
  378.     read(ufd, (char *)utmpp, (unsigned) statb.st_size);
  379.     close(ufd);
  380.     if ((myname = getlogin()) == NULL)
  381.     myname =  "UNKNOWN";
  382.     if ((mytty = ttyname(0)) != NULL)
  383.     mytty += 5;
  384.     mytime = time((time_t *) 0);
  385.     mytimestr = ctime(&mytime);
  386.     gethostname(myhost, sizeof myhost);
  387.     if ((hp = gethostbyname(myhost)) != NULL)
  388.     strcpy(myhost, hp->h_name);
  389.     if (argc == 1) {
  390.     fputs ("Msg:\n", stdout);
  391.     p = msg;
  392.     while (p < &msg[MSG_SIZE] && gets(p) != NULL) {
  393.         p += strlen(p);
  394.         *p++ = '\r'; *p++ = '\n';
  395.     }
  396.     msglen = p - msg;
  397.     p = *argv;
  398.     } else {
  399.     p = *argv;
  400.     q = msg;
  401.     while (--argc && q < &msg[MSG_SIZE]) {
  402.         strcpy(q, *++argv);
  403.         q += strlen(*argv);
  404.         *q++ = ' ';
  405.     }
  406.     *q++ = '\r';
  407.     *q++ = '\n';
  408.     msglen = q - msg;
  409.     }
  410.     for (; *p;) {
  411.     for(q = person; *p && *p != ',';)
  412.         *q++ = *p++;
  413.     *q = '\0';
  414.     if ((q = index(person, '@')) != NULL) {
  415.         *q++ = '\0';
  416.         netsend(person, q);
  417.     } else
  418.         if (!locsend(person)) {    /* user not logged in */
  419.         if (!sendmail)
  420.             fprintf(stderr, "to: %s: not logged in\n", person);
  421.         exit(EX_UNAVAILABLE);
  422.         }
  423.     }
  424.     exit(EX_OK);
  425. }
  426.  
  427. X/*
  428.  * Send a message to a remote user
  429.  */
  430. netsend (person, host)
  431. char *person, *host;
  432. {
  433.     register int n;
  434.     char newhost[100];
  435.     struct servent *sp;
  436.     struct hostent *hp;
  437.  
  438. #ifdef DEBUG
  439.     printf("net user = %s@%s\n",person, host);
  440. #endif
  441.     hp = gethostbyname(host);
  442.     if (hp == NULL) {
  443.     fprintf(stderr, "to: %s: no such host\n", host);
  444.     exit(EX_NOHOST);
  445.     }
  446.     strcpy(newhost, hp->h_name);
  447.     sp = getservbyname("smtp", "tcp");
  448.     if (sp == NULL) {
  449.     fprintf(stderr, "to: smtp/tcp: service not found\n");
  450.     exit(EX_UNAVAILABLE);
  451.     }
  452.     if ((netfd = socket(hp->h_addrtype, SOCK_STREAM, 0, 0)) < 0) {
  453.     perror("to: socket");
  454.     exit(EX_UNAVAILABLE);
  455.     }
  456.     if (bind(netfd, &hisctladdr, sizeof hisctladdr, 0) < 0) {
  457.     perror("to: bind");
  458.     exit(EX_UNAVAILABLE);
  459.     }
  460.     bcopy(hp->h_addr, (caddr_t)&hisctladdr.sin_addr, hp->h_length);
  461.     hisctladdr.sin_family = hp->h_addrtype;
  462.     hisctladdr.sin_port = sp->s_port;
  463.     if (connect(netfd, &hisctladdr, sizeof hisctladdr, 0) < 0) {
  464.         perror("to: connect");
  465.     exit (EX_UNAVAILABLE);
  466.     }
  467.     n = getrply ();
  468.     if (n != 220)        /* Got the site */
  469.     goto error;
  470.     sprintf (buffer, "HELO %s\r\n",myhost);
  471. #ifdef DEBUG
  472.     printf("buffer = %s\n",buffer);
  473. #endif
  474.     write(netfd, buffer, strlen (buffer));
  475.     n = getrply ();
  476.     if (n != 250)
  477.     goto error;
  478.     sprintf (buffer, "SEND FROM:<%s@%s>\r\n", myname, myhost);
  479. #ifdef DEBUG
  480.     printf("buffer = %s\n",buffer);
  481. #endif
  482.     write (netfd, buffer, strlen (buffer));
  483.     n = getrply ();
  484.     if (n != 250)
  485.     goto error;
  486.     sprintf (buffer, "RCPT TO:<%s@%s>\r\n", person, newhost);
  487. #ifdef DEBUG
  488.     printf("buffer = %s\n",buffer);
  489. #endif
  490.     write (netfd, buffer, strlen (buffer));
  491.     n = getrply ();
  492.     if (n != 250)
  493.     goto error;
  494. #ifdef DEBUG
  495.     printf("buffer = DATA\n");
  496. #endif
  497.     write (netfd, "DATA\r\n", 6);
  498.     n = getrply ();
  499.     if (n != 354)
  500.     goto error;
  501.     write (netfd, msg, msglen);
  502. #ifdef DEBUG
  503.     printf(".\n");
  504. #endif
  505.     write (netfd, ".\r\n", 3);
  506.     n = getrply ();
  507.     if (n != 250)
  508.     goto error;
  509. #ifdef DEBUG
  510.     printf("buffer = QUIT\n");
  511. #endif
  512.     write (netfd, "QUIT\r\n",6);
  513.     n = getrply ();
  514.     if (n != 221 && n != 220)
  515.     goto error;
  516. done:
  517.     disconnect ();
  518.     return;
  519. error:
  520.     fprintf(stderr, "to: network error: %s\n", buffer);
  521.     goto done;
  522. }
  523.  
  524. X/*
  525.  * Send a message to a local user
  526.  */
  527. locsend(person)
  528. char   *person;
  529. {
  530.     char tbuf[MSG_SIZE+BUFSIZ];
  531.     int count, found;
  532.     FILE *tf;
  533.     register struct utmp *up;
  534.  
  535.     count = statb.st_size / sizeof(struct utmp);
  536.     found = 0;
  537.     for (up = utmpp; up < &utmpp[count]; up++) {
  538.     if (up->ut_name[0] == '\0' || strncmp(person, up->ut_name,
  539.                             sizeof(utmp.ut_name)))
  540.         continue;
  541.     strcpy(term, tpath);
  542.     strncat(term, up->ut_line, sizeof(utmp.ut_line));
  543.     alarmed = 0;
  544.     alarm(3);
  545.     if ((tf = fopen(term, "w")) != NULL) {
  546.         alarm(0);
  547.         setbuf(tf, tbuf);
  548.         fprintf(tf, "\r\n\007%s,", from ? from : myname);
  549.         if (mytty)
  550.         fprintf(tf, " %s,", mytty);
  551.         fprintf(tf, " %.7s%.4s%.9s\r\n%s",
  552.         &mytimestr[4],
  553.         &mytimestr[20],
  554.         &mytimestr[10],
  555.         msg);
  556.         alarm(5);
  557.         fflush(tf);
  558.         fclose(tf);
  559.         alarm(0);
  560.         if (!alarmed)
  561.         found++;
  562.     }
  563.     }
  564.     return(found);
  565. }
  566.  
  567. X/*
  568.  * Disconnect from SMTP server
  569.  */
  570. disconnect ()
  571. {
  572.     write(netfd, "QUIT\r\n", 6);
  573.     close(netfd);
  574. }
  575.  
  576. X/*
  577.  * Read reply code from SMTP server
  578.  */
  579. getrply ()
  580. {
  581.     char temp[BUFSIZ];
  582.     register int i, n;
  583.  
  584.     while((i = read(netfd, temp, sizeof temp)) == 0)
  585.     ;
  586.     temp[i] = NULL;
  587. #ifdef DEBUG
  588.     printf("temp=\"%s\"\n",temp);
  589. #endif
  590.     for (i = 0, n = 0; temp[i] != NULL; i++)
  591.     if (temp[i] != '\n' && temp[i] != '\r')    {
  592.         buffer[n++] = temp[i];
  593.     }
  594.     buffer[n] = NULL;
  595.     n = 0;
  596.     for (i = 0; i < strlen (buffer); i++) {
  597.     if (isdigit (buffer[i]))
  598.         n = (n * 10) + (buffer[i] - '0');
  599.     else
  600.         break;
  601.     }
  602. #ifdef DEBUG
  603.     printf("n=%d temp=\"%s\"\n",n, temp);
  604. #endif
  605.     return (n);
  606. }
  607.  
  608. nothing()
  609. {
  610.     alarmed++;
  611. }
  612. //go.sysin dd *
  613. made=TRUE
  614. if [ $made = TRUE ]; then
  615.     /bin/chmod 644 to.c
  616.     /bin/echo -n '    '; /bin/ls -ld to.c
  617. fi
  618.  
  619.