home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / goodies / tap.txt (.txt) < prev    next >
Microsoft Windows Help File Content  |  1995-05-03  |  20KB  |  710 lines

  1. : This is a shar archive.  Extract with sh, not csh.
  2. echo x - Makefile
  3. cat > Makefile << '!Funky!Stuff!'
  4. CC= cc
  5. CCFLAGS= -g
  6.                         
  7. all: testmain pagemail
  8. pagemail:    tap.h tap.o io.o misc.o lock.o pagemail.o
  9.     $(CC) $(CCFLAGS) -o pagemail tap.o io.o misc.o lock.o pagemail.o
  10. testmain:    tap.h tap.o io.o misc.o lock.o testmain.o
  11.     $(CC) $(CCFLAGS) -o testmain tap.o io.o misc.o lock.o testmain.o
  12. # Dependencies
  13. tap.o:    tap.c tap.h
  14. io.o:    io.c tap.h
  15. misc.o:    misc.c tap.h
  16. lock.o:    lock.c tap.h
  17. !Funky!Stuff!
  18. echo x - tap.h
  19. cat > tap.h << '!Funky!Stuff!'
  20.  * defines and globals for the tap subroutines
  21. #define DEBUG 1
  22. #define LOCKDIR "/var/spool/locks"
  23. #define    PAGER    "/etc/pagedata"
  24. #define    MAXPAGE    2048    /* maximum message length */
  25. #include <stdio.h>
  26. #include <fcntl.h>
  27. #include <string.h>
  28. #include <strings.h>
  29. #include <ctype.h>
  30. #include <errno.h>
  31. #include <sysexits.h>
  32. #include <sys/termios.h>
  33. #include <sys/types.h>
  34. #include <sys/time.h>        /* required for <sys/resource.h> */
  35. #include <sys/resource.h>    /* required for getpriority() */
  36. /* ASCII constants */
  37. #define    STX    0x02
  38. #define    ETX    0x03
  39. #define    EOT    0x04
  40. #define    ACK    0x06
  41. #define    LF    0x0A
  42. #define    CR    0x0D
  43. #define    NAK    0x15
  44. #define    ESC    0x1B
  45. #define    RS    0x1E
  46. /* this trick makes easy work of global variables */
  47. #ifndef GLOBAL
  48. #define GLOBAL
  49. #endif
  50. GLOBAL int modem;        /* the modem device */
  51. GLOBAL char mdmdev[32];        /* the modem device name */
  52. GLOBAL char lockname[256];    /* the rooted modem lock file name */
  53. GLOBAL char mdmbuf[4096];    /* what the modem saw */
  54. GLOBAL char *mdm;
  55. !Funky!Stuff!
  56. echo x - io.c
  57. cat > io.c << '!Funky!Stuff!'
  58. #define    GLOBAL    extern
  59. #include "tap.h"
  60.  * read a character from the modem.  If there is an I/O error,
  61.  * return -1.  If it times out, return 0.  Else return the char
  62.  * timeout is in seconds; 0 = poll
  63.  getmdmchar(timeout)
  64.  int timeout;
  65.     char c[2];
  66.     fd_set readfd;
  67.     struct timeval tm;
  68.     int rslt;
  69.     if (DEBUG)
  70.         printf("getmdmchar(%d) ", timeout);
  71.         fflush(stdout);
  72. recall:
  73.     FD_ZERO(&readfd);
  74.     FD_SET(modem, &readfd);
  75.     tm.tv_usec = 0;
  76.     tm.tv_sec = timeout;
  77.     rslt = select(20, &readfd, NULL, NULL, &tm);
  78.     if (rslt < 0)
  79.         if (errno == EINTR)
  80.             goto recall;
  81.         return(-1);
  82.     if (rslt == 0)    /* timed out */
  83.         if (DEBUG)
  84.             puts("read timed out");
  85.         return(0);
  86.     if (!FD_ISSET(modem, &readfd))
  87.         return(-1);
  88.     if (DEBUG)
  89.         printf("got ");
  90.     /* so get the char already */
  91.     if (read(modem, c, 1) != 1)
  92.         perror("modem read");
  93.         return(-1);
  94.     c[0] &= 0x7f;    /* toss input parity if any */
  95.     if ((mdm - mdmbuf) < sizeof(mdmbuf))
  96.         *mdm++ = c[0];
  97.         *mdm = 0;
  98.     if (DEBUG)
  99.         safechar(c[0]);
  100.         puts("");
  101.         fflush(stdout);
  102.     return(c[0]);
  103.  * send a string to the modem, one char at a time, and wait for each
  104.  * character to be echoed by the modem before you send the next one
  105.  * prevents outspeeding modem
  106.  * returns 0 if string is sent ok, +1 if it times out before the char
  107.  * echoes, -1 if there is an I/O problem
  108. echosend(str)
  109. char *str;
  110.     char c;
  111.     if (DEBUG)
  112.         printf("echosend: ");
  113.     /* what we saw */
  114.     mdm = mdmbuf;
  115.     *mdm = 0;
  116.     while (*str)
  117.         /* squirt out ONE character */
  118.         if (DEBUG)
  119.             safechar(*str);
  120.         if (write(modem, str, 1) != 1)
  121.             perror("echosend write");
  122.             return(-1);
  123.         /* get its echo if it's printable*/
  124.         while(isprint(*str))
  125.             c = getmdmchar(1);
  126.             if (c == 0)
  127.                 return(1);
  128.             if (c == *str)
  129.                 break;
  130.             /* spin until we get the echo */
  131.         /* got it, send the next one */
  132.         str++;
  133.     if (DEBUG)
  134.         puts("end echosend");
  135.     return(0);
  136. /* open the modem */
  137. opendev()
  138.     struct termios  ti;
  139.     int err;
  140.     modem = open(mdmdev, (O_RDWR|O_EXCL), 0);
  141.     if (modem < 0)
  142.         perror(mdmdev);
  143.         return(errno);
  144.     if (DEBUG)
  145.         printf("%s is open on fd %d\n", mdmdev, modem);
  146.     /* get current port settings */
  147.     err = ioctl(modem, TCGETS, &ti);
  148.     if (err < 0)
  149.         perror(mdmdev);
  150.         return(errno);
  151.      * set tty params to 300bps, even parity, 7/E/1
  152.      * this is for SunOS 4.1.3.  God help you on other systems.
  153.     ti.c_iflag |= IGNBRK;   /* ignore breaks */
  154.     ti.c_iflag &= ~INPCK;   /* ignore parity errors */
  155.     ti.c_iflag |= ISTRIP;   /* strip 8th bit */
  156.     ti.c_iflag &= ~INLCR;   /* don't cr->nl */
  157.     ti.c_iflag &= ~ICRNL;   /* don't cr->nl */
  158.     ti.c_iflag &= ~IGNCR;   /* don't ignore cr */
  159.     ti.c_oflag &= ~OPOST;   /* don't process output */
  160.     ti.c_cflag &= ~CBAUD;
  161.     ti.c_cflag |= B300;    /* baud=300 */
  162.     ti.c_cflag &= ~CSIZE;   /* 7-bit bytes */
  163.     ti.c_cflag |= CS7;
  164.     ti.c_cflag &= ~CSTOPB;  /* one stop bit */
  165.     ti.c_cflag |= PARENB;      /* parity */
  166.     ti.c_cflag &= ~PARODD;  /* even parity */
  167.     ti.c_cflag |= HUPCL;    /* hang up on last close */
  168.     ti.c_cc[VMIN] = 1;    /* read() can return 1 byte */
  169.     ti.c_cc[VTIME] = 0;     /* no time out */
  170.     ti.c_lflag &= ~ISIG;    /* disable signals */
  171.     ti.c_lflag &= ~ICANON;  /* disable signals */
  172.     ti.c_lflag &= ~ECHO;    /* don't echo */
  173.     errno = 0;
  174.     err = ioctl(modem, TCSETS, &ti);
  175.     if (err < 0)
  176.         perror(mdmdev);
  177.         return(errno);
  178.     return 0;
  179. /* hang up the modem */
  180. void 
  181. hangup()
  182.     sleep(3);
  183.     write(modem, "+++", 3);
  184.     sleep(3);
  185.     write(modem, "ATH\r", 4);
  186.     sleep(1);
  187.     write(modem, "ATZ\r", 4);
  188.  * swallows all characters from the modem until none for n seconds
  189. swallow(n)
  190. int n;
  191.     while (getmdmchar(n) > 0)
  192. !Funky!Stuff!
  193. echo x - lock.c
  194. cat > lock.c << '!Funky!Stuff!'
  195. #define GLOBAL    extern
  196. #include "tap.h"
  197.  * unlock the modem's tty port
  198. unlockdev()
  199.     unlink(lockname);
  200.  * lock the modem's tty port
  201. lockdev()
  202.     int lock, pid;
  203.     int fails = 5;
  204.     sprintf(lockname, "%s/LCK..%s", LOCKDIR, (rindex(mdmdev, '/')+1));
  205.     if (DEBUG)
  206.         printf("lock file = %s\n", lockname);
  207. tryagain:
  208.     /* try to lock the modem a few times */
  209.     lock = open(lockname, (O_CREAT|O_RDWR|O_EXCL), 0666);
  210.     if (lock < 0)
  211.         if (errno != EEXIST)    /* lock file problem */
  212.             perror("can't create modem lock file ");
  213.             return(EX_OSFILE);
  214.         /* see if it's a dead lock */
  215.         pid = 0;
  216.         lock = open(lockname, (O_CREAT|O_RDWR), 0666);
  217.         if (lock >= 0)
  218.             (void)read(lock, &pid, sizeof(int));
  219.             if (DEBUG)
  220.                 printf("locked; pid %d\n", pid);
  221.             /* is he still there? */
  222.             errno = 0;
  223.             (void)kill(pid, 0);
  224.             if (errno != ESRCH)    /* live pid */
  225.                 {
  226.                 close(lock);
  227.                 if (fails--)    /* try a few times */
  228.                     {
  229.                     sleep(30);
  230.                     goto tryagain;
  231.                     }
  232.                 /* couldn't get modem, tempfail, try later */
  233.                 printf("modem line %s not available\n", mdmdev);
  234.                 return(EX_TEMPFAIL);
  235.                 }
  236.             if (DEBUG)
  237.                 puts("lock is stale");
  238.     /* we lock it for us! */
  239.     pid = getpid();
  240.     lseek(lock, 0L, 0);
  241.     write(lock, &pid, sizeof(int));
  242.     close(lock);
  243.     if (DEBUG)
  244.         printf("we locked line to pid %d\n", pid);
  245.     return(0);
  246. !Funky!Stuff!
  247. echo x - misc.c
  248. cat > misc.c << '!Funky!Stuff!'
  249. #define    GLOBAL    extern
  250. #include "tap.h"
  251.  * crunch extra blanks out of a line of text
  252. deblank(str)
  253. char *str;
  254.     char *p;
  255.     /* tabs become spaces */
  256.     while ((p = index(str, '\t')))
  257.         *p = ' ';
  258.     /* leading spaces */
  259.     p = str;
  260.     while (*p && *p == ' ')
  261.         p++;
  262.     if (p != str)
  263.         strcpy(str, p);
  264.     /* trailing spaces */
  265.     p = str + (strlen(p) - 1);
  266.     while(p > str && *p == ' ')
  267.         *p-- = 0;
  268.     /* imbedded multiple strings */
  269.     p = str;
  270.     while ((p = index(p, ' ')))
  271.         if (*(p+1) == ' ')
  272.             strcpy(p, p+1);
  273.         else
  274.             p++;
  275. /* print a character interpreting unprintable charactors */
  276. void 
  277. safechar(c)
  278. char c;
  279.     if (isprint(c))
  280.         (void)printf("`%c' ", c);
  281.     else
  282.         switch(c)
  283.         case LF:
  284.             (void)printf("`\\n' ");
  285.             break;
  286.         case CR:
  287.             (void)printf("`\\r' ");
  288.             break;
  289.         case '\t':
  290.             (void)printf("`^I' ");
  291.             break;
  292.         default:
  293.             (void)printf("0x%02x ", c);
  294.             break;
  295. /* print a string interpreting unprintable charactors */
  296. void 
  297. safeprint(str)
  298. char *str;
  299.     if (str == NULL)
  300.         return;
  301.     while (*str)
  302.         safechar(*str++);
  303.     fflush(stdout);
  304. /* calculate checksum of a packet */
  305. char *checksum(str)
  306. char *str;
  307.     static char csum[10];
  308.     int sum = 0;
  309.     for (; *str; str++)
  310.         sum += *str;
  311.     csum[2] = '0' + (sum & 0x0f);
  312.     sum = sum >> 4;
  313.     csum[1] = '0' + (sum & 0x0f);
  314.     sum = sum >> 4;
  315.     csum[0] = '0' + (sum & 0x0f);
  316.     csum[3] = 0;
  317.     if (DEBUG)
  318.         printf("checksum=%s\n", csum);
  319.     return(csum);
  320.  * expect a string from the modem - we assume it'll end in CR/LF
  321.  * and do the appropriate thing
  322.  * input: an array of pointers to strings that are matched.  
  323.  * returns -1 if I/O error, 0 if timeout, n+1 if matched, -2 if no match
  324.  * (timeout means we didn't get CR or LF before time expired)
  325.  * ignores blank lines from the modem
  326. expect(str, timeout)
  327. char **str;
  328. int timeout;
  329.     int i, rslt;
  330.     char *p;
  331. again:
  332.     mdm = mdmbuf;
  333.     *mdm = 0;
  334.     for(;;)
  335.         rslt = getmdmchar(timeout);
  336.         if (rslt <= 0)
  337.             if (DEBUG)
  338.                 printf("expect returns %d\n", rslt);
  339.             return(rslt);
  340.         if (rslt == '\r' || rslt == '\n')
  341.             break;
  342.     /* ignore blank lines from the modem */
  343.     if (strlen(mdmbuf) == 1 && (mdmbuf[0] == '\n' || mdmbuf[0] == '\r'))
  344.         goto again;
  345.      * mdmbuf contains the null-terminated string of what we rec'd.
  346.      * just search through all the strings until we find a match
  347.     if (DEBUG)
  348.         printf("modem returned ");
  349.         safeprint(mdmbuf);
  350.         puts("");
  351.     for (i=0; str[i]; i++)
  352.         if (DEBUG)
  353.             printf("find [%d]", i+1);
  354.             safeprint(str[i]);
  355.             puts("");
  356.         if (strstr(mdmbuf, str[i]))
  357.             if (DEBUG)
  358.                 printf("expect returns %d\n", i+1);
  359.             return(i+1);
  360.     if (DEBUG)
  361.         puts("expect: no match (-2)");
  362.     return(-2);
  363. !Funky!Stuff!
  364. echo x - pagemail.c
  365. cat > pagemail.c << '!Funky!Stuff!'
  366.  * sendmail backend program for sending e-mail to pagers
  367.  *    Brian Kantor, UCSD, May 1994
  368.  * username is the only argument
  369.  * expects to find the username, device, phone#, and pin in '/etc/pager'
  370. #include "tap.h"
  371. FILE *pager;
  372. int main(argc, argv)
  373. int argc;
  374. char *argv[];
  375.     int rslt, found;
  376.     char buf[BUFSIZ];
  377.     char usr[64];
  378.     char dev[64];
  379.     char tel[64];
  380.     char pin[64];
  381.     /* check arguments */
  382.     if (argc != 2)
  383.         fprintf(stderr, "Usage: %s username\n", argv[0]);
  384.         exit(EX_USAGE);
  385.      * open the pager database file
  386.     pager = fopen(PAGER, "r");
  387.     if (pager == NULL)
  388.         perror(PAGER);
  389.         exit(EX_UNAVAILABLE);
  390.      * search the pager database file for the user
  391.     found = 0;
  392.     while (fgets(buf, sizeof(buf), pager))
  393.         if (buf[0] == '#')        /* skip comments */
  394.             continue;
  395.         rslt = sscanf(buf, "%s %s %s %s", usr, dev, tel, pin);
  396.         if (rslt != 4)            /* bad entry */
  397.             fprintf(stderr, "error in %s entry\n", PAGER);
  398.             exit(EX_OSFILE);
  399.         if (strcasecmp(usr, argv[1]) == 0)    /* found him! */
  400.             found++;
  401.             break;
  402.     if (!found)
  403.         fprintf(stderr, "Paging user '%s' not on file\n", argv[1]);
  404.         exit(EX_NOUSER);
  405.     rslt = tap(dev, tel, pin);
  406.     exit(rslt);
  407. !Funky!Stuff!
  408. echo x - tap.c
  409. cat > tap.c << '!Funky!Stuff!'
  410.  * given a modem device name, a telephone number, a pager pin,
  411.  * and an RFC-822-compliant message to be read from infile,
  412.  * locks and opens the modem device, dials the number, and 
  413.  * sends the first 2k or so of the mail to the pager.
  414.  * Brian Kantor, UCSD, May 1994
  415.  * some of the ideas taken from 'tpage', but almost all of the code
  416.  * is mine.
  417.  * 'dev' must be of the form "/dev/cua0", and expects a Hayes-type modem
  418.  * the terminal I/O is set up for SunOS 4.1.3.  If you have something
  419.  * else, you're probably going to have to hack it.
  420. #define GLOBAL extern
  421. #include "tap.h"
  422.  * modem dialing result strings
  423. static char *dialing[] = {    /* 'expect' returns */
  424.     "CONNECT",        /* 1 */
  425.     "BUSY",            /* 2 */
  426.     "NO DIAL TONE",        /* 3 */
  427.     "VOICE",        /* 4 */
  428.     "NO CARRIER",        /* 5 */
  429.     NULL };
  430.  * protocol responses
  431. static char *proto[] = {    /* 'expect' returns */
  432.     "ID=",            /* 1 */
  433.     "\033\004",        /* 2, ESC EOT */
  434.     "\033[p",        /* 3, ESC [p (go ahead) */
  435.     "\006",            /* 4, ACK */
  436.     "\025",            /* 5, NAK */
  437.     "\036",            /* 6, RS */
  438.     "\004",            /* 7, EOT */
  439.     NULL };
  440. tap(dev, telno, pin)
  441. char *dev, *telno, *pin;
  442.     char pagebuf[MAXPAGE];
  443.     char buf[BUFSIZ];
  444.     char mesg[256];
  445.     char from[256];
  446.     char subj[256];
  447.     char word[256];
  448.     int failcnt, len;
  449.     int err;
  450.     char c;
  451.     char *m, *p;
  452.      * Read through the mail message to grab the From: address
  453.      * and the subject line
  454.     strcpy(from, "unknown");
  455.     strcpy(subj, "");
  456.     /* we're in the mail message header now */
  457.     while (fgets(buf, sizeof(buf), stdin))
  458.         p = index(buf, '\n');    if (p) *p = 0;    /* elide EOL */
  459.         if (strlen(buf) < 1)    /* empty line is end of header */
  460.             break;
  461.         deblank(buf);
  462.         if (strncasecmp(buf, "From: ", 6) == 0)
  463.             sprintf(from, "Fm: %s", buf+6);
  464.         if (strncasecmp(buf, "Subject: ", 9) == 0)
  465.             sprintf(subj, "[Sb: %s]", buf+9);
  466.     deblank(from);
  467.     strcpy(pagebuf, from);
  468.     strcat(pagebuf, " ");
  469.     deblank(subj);
  470.     if (strlen(subj))
  471.         strcat(pagebuf, subj);
  472.         strcat(pagebuf, " ");
  473.     /* we're in the mail message body now */
  474.     while (fgets(buf, sizeof(buf), stdin))
  475.         p = index(buf, '\n'); if (p) *p = 0;    /* elide EOL */
  476.         deblank(buf);
  477.         strcat(pagebuf, buf);
  478.         strcat(pagebuf, " ");
  479.         if (strlen(pagebuf) > MAXPAGE)
  480.             break;
  481.     if (DEBUG)
  482.         puts(pagebuf);
  483.      * all done with the incoming message
  484.      * we now have the message in 'pagebuf', proceed to page
  485.     /* can we have the modem? */
  486.     err = lockdev();
  487.     if (err != 0)
  488.         return(err);
  489.     /* we've got it reserved, open it */
  490.     err = opendev();
  491.     if (err != 0)
  492.         unlockdev();
  493.         return(err);
  494.     /* just in case it's off-hook for some reason */
  495.     hangup();
  496.     mdm = mdmbuf;
  497.     *mdm = 0;
  498.     /* flush any garbage in the rx queue */
  499.     swallow(1);
  500.     (void)echosend("\r\r");    /* terminate any partial command */
  501.     swallow(1);
  502.     /* Ok, at this point, the modem should be ready and waiting */
  503.     err = 5;    /* try 5 times to speed sense the modem */
  504.     while (err && echosend("A") == 1)
  505.         err--;
  506.     if (err == 0)    /* it didn't wake up */
  507.         unlockdev();
  508.         return(EX_TEMPFAIL);
  509.     swallow(1);
  510.     /* send the dialstring */
  511.     sprintf(buf, "ATDT %s \r", telno);
  512.     if (echosend(buf))    /* couldn't dial the modem */
  513.         unlockdev();
  514.         return(EX_TEMPFAIL);
  515.     err = expect(dialing, 60);
  516.     if (err != 1)
  517.         fprintf(stderr, "calling error #%d\n", err);
  518.         hangup();
  519.         unlockdev();
  520.         return(EX_IOERR);
  521.     /* ----------------------------------------------------
  522.      * connected, start the TAP protocol dance.
  523.      * ---------------------------------------------------- */
  524.     if (DEBUG)
  525.         printf("Waiting for ID=\n");
  526.     failcnt = 0;
  527.     for (;;)
  528.         if (failcnt > 3)
  529.             hangup();
  530.             unlockdev();
  531.             fprintf(stderr, "unable to sync with central\n");
  532.             return(EX_TEMPFAIL);
  533.         err = expect(proto, 2);
  534.         if (err == 0)    /* timeout, send a CR and wait again */
  535.             write(modem, "\r", 1);
  536.             continue;
  537.         if (err == 1)    /* got ID= */
  538.             break;
  539.         /* something else went wrong */
  540.         hangup();
  541.         unlockdev();
  542.         return(EX_TEMPFAIL);
  543.     if (DEBUG)
  544.         printf("Logging in\n");
  545.     failcnt = 0;
  546. login:
  547.     /* switch to "automatic protocol" */
  548.     printf("Sending ESC, termtype, and password\n");
  549.     write(modem, "\033", 1);
  550.     /* send our terminal type */
  551.     write(modem, "PG1", 3);
  552.     /* alphanumeric password */
  553.     write(modem, "000000\r", 7);
  554.     /* see what response we get to our login attempt */
  555.     err = expect(proto, 60);
  556.     if (err == 0)    /* timeout */
  557.         hangup();
  558.         unlockdev();
  559.         fprintf(stderr, "no response from central\n");
  560.         return(EX_TEMPFAIL);
  561.     /* if our login failed, we might have got ID= or NAK again */
  562.     if (err == 1 || err == 5)
  563.         failcnt++;
  564.         if (failcnt > 3)
  565.             hangup();
  566.             unlockdev();
  567.             fprintf(stderr, "unable to log in to central\n");
  568.             return(EX_TEMPFAIL);
  569.         goto login;
  570.     if (err == 2)    /* ESC EOT = disconnect now */
  571.         hangup();
  572.         unlockdev();
  573.         fprintf(stderr, "central demanded disconnect\n");
  574.         return(EX_TEMPFAIL);
  575.     if (err != 4)    /* ACK = proceed */
  576.         hangup();
  577.         unlockdev();
  578.         fprintf(stderr, "unknown response from central: %s\n", mdmbuf);
  579.         return(EX_TEMPFAIL);
  580.      * Hah!  We're in!
  581.      * wait for them to stop spewing and give us the go-ahead
  582. processing:
  583.     err = expect(proto, 30);
  584.     if (err == 0)    /* timeout */
  585.         hangup();
  586.         unlockdev();
  587.         fprintf(stderr, "no response from central\n");
  588.         return(EX_TEMPFAIL);
  589.     /* absorb any irrelevant spew */
  590.     if (err == -2)    /* nothing we care about */
  591.         goto processing;
  592.     if (err != 3)    /* not a go-ahead */
  593.         hangup();
  594.         unlockdev();
  595.         fprintf(stderr, "unknown response from central: %s\n", mdmbuf);
  596.         return(EX_TEMPFAIL);
  597.      * loop through here until you've sent it all
  598.      * you have to break the message into pieces about 230 chars
  599.     m = pagebuf;
  600.     p = word;
  601.     *p = 0;
  602.      * copy the message into 220 character pieces,
  603.      * one word at a time, breaking at whitespace
  604.     while (*m)
  605.         while (*m)
  606.             if (!isspace(*m))
  607.                 {
  608.                 *p++ = *m++;
  609.                 *p = 0;
  610.                 continue;
  611.                 }
  612.             m++;
  613.             if (DEBUG)
  614.                 printf("word '%s'\n", word);
  615.             /* long enough? */
  616.             if ((strlen(mesg) + strlen(word)) > 220)
  617.                 break;
  618.             strcat(mesg, word);
  619.             p = word;
  620.             *p = 0;
  621.             strcat(mesg, " ");
  622.         if (DEBUG)
  623.             printf("mesg '%s'\n", mesg);
  624.         failcnt = 0;
  625. blockagain:
  626.         sprintf(buf, "%c%s\r%s\r%c", STX, pin, mesg, ETX);
  627.         strcat(buf, checksum(buf));
  628.         strcat(buf, "\r");
  629.         if (DEBUG)
  630.             printf("send packet (length %d): ", strlen(buf));
  631.             safeprint(buf);
  632.             puts("");
  633.         write(modem, buf, strlen(buf));
  634.         err = expect(proto, 30);
  635.         if (err == 0)    /* timeout */
  636.             hangup();
  637.             unlockdev();
  638.             fprintf(stderr, "no response from central\n");
  639.             return(EX_TEMPFAIL);
  640.         if (err == 5)    /* NAK, send block again */
  641.             failcnt++;
  642.             if (failcnt > 3)
  643.                 {
  644.                 hangup();
  645.                 unlockdev();
  646.                 fprintf(stderr, "excessive retransmits\n");
  647.                 return(EX_TEMPFAIL);
  648.                 }
  649.             goto blockagain;
  650.         if (err != 4)    /* not an ACK */
  651.             hangup();
  652.             unlockdev();
  653.             fprintf(stderr, "error from central: %s\n", mdmbuf);
  654.             return(EX_TEMPFAIL);
  655.     /* all done with message, tell them so. */
  656.     if (DEBUG)
  657.         printf("send EOT at end of message\n");
  658.     write(modem, "\004\r", 2);
  659.     /* wait for them to finish spewing */
  660.     err = expect(proto, 30);
  661.     if (err == 0 || err == 2 || err == 7)    /* timeout, disc, EOT */
  662.         hangup();
  663.         unlockdev();
  664.         puts(mdmbuf);    /* in case rcpt-to */
  665.         return(EX_OK);    /* message got through, so it's ok */
  666.     /* hmm.  If we got here, we got some late error.  Fail! */
  667.     hangup();
  668.     unlockdev();
  669.     fprintf(stderr, "late error from central: %s\n", mdmbuf);
  670.     return(EX_UNAVAILABLE);
  671. !Funky!Stuff!
  672. echo x - testmain.c
  673. cat > testmain.c << '!Funky!Stuff!'
  674. #define GLOBAL 
  675. #include "tap.h"
  676. int main(argc, argv)
  677. int argc;
  678. char *argv[];
  679.     int rslt;
  680.     /* check arguments */
  681.     if (argc != 3)
  682.         fprintf(stderr, "Usage: %s device telno pin\n", argv[0]);
  683.         exit(EX_USAGE);
  684.     rslt = tap(argv[1], argv[2], argv[3]);
  685.     fprintf(stderr, "\ntap(%s, %s, %s) returned %d\n",
  686.         argv[1], argv[2], argv[3], rslt);
  687.     exit(rslt);
  688. !Funky!Stuff!
  689. echo x - test.sh
  690. cat > test.sh << '!Funky!Stuff!'
  691. testmain /dev/cua0 82328425 19620 < testmsg
  692. !Funky!Stuff!
  693. echo x - testmsg
  694. cat > testmsg << '!Funky!Stuff!'
  695. From: pagertest@my.local.host
  696. Subject: test message
  697. I have seen potatoes you people wouldn't believe.
  698. Attack tractors on fire off the shoulder of Clare.
  699. I watched spuds glitter in the dark near the farmhouse gate.
  700. All those moments will be lost in time, like tears in the rain.
  701. Time to eat.      - jslttery@GS150.SP.CS.CMU.EDU
  702.     catnip is a kitty cat drug
  703.     one puff two puffs -- high in a dream
  704.     funny kitty's got very sleepy eyes
  705.     i wonder what he's dreaming of
  706.     catnip dream catnip dream catnip dream
  707.     meow meow meow
  708.         - shonen knife 
  709. !Funky!Stuff!
  710.