home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / SUN / PPP / SUNOS_OL / KF_PPP.TAR / chat.c next >
Encoding:
C/C++ Source or Header  |  1991-01-03  |  9.5 KB  |  551 lines

  1. /*
  2.  *    Chat -- a program for automatic session establishment (i.e. dial
  3.  *        the phone and log in).
  4.  *
  5.  *    This software is in the public domain.
  6.  *
  7.  *    Please send all bug reports, requests for information, etc. to:
  8.  *
  9.  *        Karl Fox <karl@MorningStar.Com>
  10.  *        Morning Star Technologies, Inc.
  11.  *        1760 Zollinger Road
  12.  *        Columbus, OH  43221
  13.  *        (614)451-1883
  14.  */
  15.  
  16. static char sccs_id[] = "@(#)chat.c    1.1";
  17.  
  18. # include    <stdio.h>
  19. # include    <termio.h>
  20. # include    <fcntl.h>
  21. # include    <signal.h>
  22. # include    <errno.h>
  23. # include    <sys/types.h>
  24. # include    <sys/stat.h>
  25. # include    <ctype.h>
  26.  
  27. # define    STR_LEN        1024
  28.  
  29. # define    OPTION(c,v)    (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
  30.                 (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
  31.                 &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
  32. # define    OPTARG(c,v)    (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
  33.                 (_O=4,(char*)0):(char*)0)
  34. # define    OPTONLYARG(c,v)    (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
  35. # define    ARG(c,v)    (c?(--c,*v++):(char*)0)
  36.  
  37. static int _O = 0;        /* Internal state */
  38. char *program_name;
  39.  
  40. extern char *strcpy(), *strcat(), *malloc();
  41. extern int strlen();
  42. # define    copyof(s)    ((s) ? strcpy(malloc(strlen(s) + 1), s) : (s))
  43.  
  44. # ifndef LOCK_DIR
  45. #  ifdef HDB
  46. #   define    LOCK_DIR    "/usr/spool/locks"
  47. #  else /* HDB */
  48. #   define    LOCK_DIR    "/usr/spool/uucp"
  49. #  endif /* HDB */
  50. # endif /* LOCK_DIR */
  51.  
  52. int verbose = 0;
  53. int quiet = 0;
  54. char *lock_file = (char *)0;
  55. int timeout = 30;
  56.  
  57. /*
  58.  *    chat [ -v ] [ -l lock-file ] [...[[expect[-say[-expect...]] say \
  59.  *            expect[-say[-expect]] ...]]]
  60.  *
  61.  *    Perform a UUCP-dialer-like chat script on stdin and stdout.
  62.  */
  63. main(argc, argv)
  64. int argc;
  65. char **argv;
  66.     {
  67.     int option, n;
  68.     char *arg;
  69.  
  70.     program_name = *argv;
  71.  
  72.     while (option = OPTION(argc, argv))
  73.     switch (option)
  74.         {
  75.         case 'v':
  76.         ++verbose;
  77.         break;
  78.  
  79.         case 'l':
  80.         if (arg = OPTARG(argc, argv))
  81.             lock_file = copyof(arg);
  82.         else
  83.             usage();
  84.  
  85.         break;
  86.  
  87.         case 't':
  88.         if (arg = OPTARG(argc, argv))
  89.             timeout = atoi(arg);
  90.         else
  91.             usage();
  92.  
  93.         break;
  94.  
  95.         default:
  96.         usage();
  97.         }
  98.  
  99.     init();
  100.     
  101.     while (arg = ARG(argc, argv))
  102.     {
  103.     expect(arg);
  104.  
  105.     if (arg = ARG(argc, argv))
  106.         send(arg);
  107.     }
  108.  
  109.     exit(0);
  110.     }
  111.  
  112. /*
  113.  *    We got an error parsing the command line.
  114.  */
  115. usage()
  116.     {
  117.     fprintf(stderr, "Usage: %s [ -v ] [ -l lock-file ] [-t timeout ]\n", program_name);
  118.     exit(1);
  119.     }
  120.  
  121. /*
  122.  *    Print a warning message.
  123.  */
  124. /*VARARGS1*/
  125. warning(format, arg1, arg2, arg3, arg4)
  126. char *format;
  127. int arg1, arg2, arg3, arg4;
  128.     {
  129.     fprintf(stderr, "%s: Warning: ", program_name);
  130.     fprintf(stderr, format, arg1, arg2, arg3, arg4);
  131.     fprintf(stderr, "\n");
  132.     }
  133.  
  134. /*
  135.  *    Print an error message and terminate.
  136.  */
  137. /*VARARGS1*/
  138. fatal(format, arg1, arg2, arg3, arg4)
  139. char *format;
  140. int arg1, arg2, arg3, arg4;
  141.     {
  142.     fprintf(stderr, "%s: ", program_name);
  143.     fprintf(stderr, format, arg1, arg2, arg3, arg4);
  144.     fprintf(stderr, "\n");
  145.     unlock();
  146.     exit(1);
  147.     }
  148.  
  149. /*
  150.  *    Print an error message along with the system error message and
  151.  *    terminate.
  152.  */
  153. /*VARARGS1*/
  154. sysfatal(format, arg1, arg2, arg3, arg4)
  155. char *format;
  156. int arg1, arg2, arg3, arg4;
  157.     {
  158.     char message[STR_LEN];
  159.  
  160.     sprintf(message, "%s: ", program_name);
  161.     sprintf(message + strlen(message), format, arg1, arg2, arg3, arg4);
  162.     perror(message);
  163.     unlock();
  164.     exit(1);
  165.     }
  166.  
  167. int alarmed = 0;
  168.  
  169. sigalrm()
  170.     {
  171.     int flags;
  172.  
  173.     alarm(1); alarmed = 1;        /* Reset alarm to avoid race window */
  174.     signal(SIGALRM, sigalrm);        /* that can cause hanging in read() */
  175.  
  176.     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
  177.     sysfatal("Can't get file mode flags on stdin");
  178.     else
  179.     if (fcntl(0, F_SETFL, flags | FNDELAY) == -1)
  180.         sysfatal("Can't set file mode flags on stdin");
  181.  
  182.     if (verbose)
  183.     {
  184.     fprintf(stderr, "alarm\n");
  185.     fflush(stderr);
  186.     }
  187.     }
  188.  
  189. unalarm()
  190.     {
  191.     int flags;
  192.  
  193.     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
  194.     sysfatal("Can't get file mode flags on stdin");
  195.     else
  196.     if (fcntl(0, F_SETFL, flags & ~FNDELAY) == -1)
  197.         sysfatal("Can't set file mode flags on stdin");
  198.     }
  199.  
  200. init()
  201.     {
  202.     if (lock_file)
  203.     lock();
  204.  
  205.     set_tty_parameters();
  206.     signal(SIGALRM, sigalrm);
  207.     alarm(0); alarmed = 0;
  208.     }
  209.  
  210. set_tty_parameters()
  211.     {
  212.     struct termio t;
  213.  
  214.     if (ioctl(0, TCGETA, &t) < 0)
  215.     sysfatal("Can't get terminal parameters");
  216.  
  217.     t.c_iflag = IXOFF | IXON | ISTRIP | IGNPAR | IGNBRK;
  218.     t.c_cflag = CLOCAL | CREAD | CS8 | (t.c_cflag & CBAUD) | HUPCL;
  219.     t.c_lflag = 0;
  220.     t.c_cc[VERASE] = 0;
  221.     t.c_cc[VKILL] = 0;
  222.     t.c_cc[VMIN] = 1;
  223.     t.c_cc[VTIME] = 0;
  224.  
  225.     if (ioctl(0, TCSETA, &t) < 0)
  226.     sysfatal("Can't set terminal parameters");
  227.     }
  228.  
  229. /*
  230.  *    Create a lock file for the named lock device
  231.  */
  232. lock()
  233.     {
  234.     char hdb_lock_buffer[12];
  235.     int fd, pid;
  236.  
  237.     lock_file = strcat(strcat(strcpy(malloc(strlen(LOCK_DIR)
  238.                        + 1 + strlen(lock_file) + 1),
  239.                 LOCK_DIR), "/"), lock_file);
  240.  
  241.     if ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0)
  242.     sysfatal("Can't get lock file '%s'", lock_file);
  243.  
  244. # ifdef HDB
  245.     sprintf(hdb_lock_buffer, "%10d\n", getpid());
  246.     write(fd, hdb_lock_buffer, 11);
  247. # else /* HDB */
  248.     pid = getpid();
  249.     write(fd, &pid, sizeof pid);
  250. # endif /* HDB */
  251.  
  252.     close(fd);
  253.     }
  254.  
  255. /*
  256.  *    Remove our lockfile
  257.  */
  258. unlock()
  259.     {
  260.     if (lock_file)
  261.     {
  262.     unlink(lock_file);
  263.     lock_file = (char *)0;
  264.     }
  265.     }
  266.  
  267. /*
  268.  *    'Clean up' this string.
  269.  */
  270. char *clean(s, add_newline)
  271. register char *s;
  272. int add_newline;
  273.     {
  274.     char temp[STR_LEN];
  275.     register char *s1;
  276.  
  277.     for (s1 = temp; *s; ++s)
  278.      switch (*s)
  279.          {
  280.          case '\\':
  281.          switch (*++s)
  282.              {
  283.              case 'q':    quiet = ! quiet; break;
  284.              case 'r':    *s1++ = '\r'; break;
  285.              case 'n':    *s1++ = '\n'; break;
  286.              case 's':    *s1++ = ' '; break;
  287.              case 'c':    add_newline = 0; break;
  288.              default:    *s1++ = *s;
  289.              }
  290.  
  291.          break;
  292.  
  293.          case '^':
  294.          *s1++ = (int)(*++s) & 0x1F;
  295.          break;
  296.  
  297.          default:
  298.          *s1++ = *s;
  299.          }
  300.     
  301.     if (add_newline)
  302.     *s1++ = '\n';
  303.  
  304.     *s1 = '\0';
  305.     return (copyof(temp));
  306.     }
  307.  
  308. /*
  309.  *
  310.  */
  311. expect(s)
  312. char *s;
  313.     {
  314.     if ( ! get_string(clean(s, 0)))
  315.     {
  316.     fprintf(stderr, "Failed\n");
  317.     fflush(stderr);
  318.     unlock();
  319.     exit(1);
  320.     }
  321.     }
  322.  
  323. /*
  324.  *
  325.  */
  326. send(s)
  327. char *s;
  328.     {
  329.     if ( ! put_string(clean(s, 1)))
  330.     {
  331.     fprintf(stderr, "Failed\n");
  332.     fflush(stderr);
  333.     unlock();
  334.     exit(1);
  335.     }
  336.     }
  337.  
  338. char *character(c)
  339. char c;
  340.     {
  341.     static char string[10];
  342.  
  343.     if (isgraph(c) || c == ' ')
  344.     sprintf(string, "%c", c);
  345.     else
  346.     if (c < 32)
  347.         sprintf(string, "^%c", (int)c + 'A' - 1);
  348.     else
  349.         sprintf(string, "\\%03o", (int)c & 0xFF);
  350.  
  351.     return (string);
  352.     }
  353.  
  354. int get_char()
  355.     {
  356.     int status;
  357.     char c;
  358.  
  359.     status = read(0, &c, 1);
  360.  
  361.     switch (status)
  362.     {
  363.     case 1:
  364.         return ((int)c & 0x7F);
  365.  
  366.     default:
  367.         warning("read() on stdin returned %d", status);
  368.  
  369.     case -1:
  370.         if ((status = fcntl(0, F_GETFL, 0)) == -1)
  371.         sysfatal("Can't get file mode flags on stdin");
  372.         else
  373.         if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1)
  374.             sysfatal("Can't set file mode flags on stdin");
  375.  
  376.         return (-1);
  377.     }
  378.     }
  379.  
  380. int put_char(c)
  381. char c;
  382.     {
  383.     int status;
  384.  
  385.     delay();
  386.  
  387.     status = write(1, &c, 1);
  388.  
  389.     switch (status)
  390.     {
  391.     case 1:
  392.         return (0);
  393.  
  394.     default:
  395.         warning("write() on stdout returned %d", status);
  396.  
  397.     case -1:
  398.         if ((status = fcntl(0, F_GETFL, 0)) == -1)
  399.         sysfatal("Can't get file mode flags on stdin");
  400.         else
  401.         if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1)
  402.             sysfatal("Can't set file mode flags on stdin");
  403.  
  404.         return (-1);
  405.     }
  406.     }
  407.  
  408. int put_string(s)
  409. register char *s;
  410.     {
  411.     register char *orig_s = s;
  412.  
  413.     if (verbose)
  414.     {
  415.     fprintf(stderr, "send (");
  416.  
  417.     if (quiet)
  418.         fprintf(stderr, "??????");
  419.     else
  420.         for (orig_s = s; *orig_s; ++orig_s)
  421.         fprintf(stderr, "%s", character(*orig_s));
  422.  
  423.     fprintf(stderr, ")\n");
  424.     fflush(stderr);
  425.     }
  426.  
  427.     alarm(timeout); alarmed = 0;
  428.  
  429.     for ( ; *s; ++s)
  430.     if (alarmed || put_char(*s) < 0)
  431.         {
  432.         extern int errno;
  433.  
  434.         alarm(0); alarmed = 0;
  435.  
  436.         if (verbose)
  437.         {
  438.         if (errno == EINTR || errno == EWOULDBLOCK)
  439.             fprintf(stderr, " -- write timed out\n");
  440.         else
  441.             perror(" -- write failed");
  442.  
  443.         fflush(stderr);
  444.         }
  445.  
  446.         return (0);
  447.         }
  448.  
  449.     alarm(0); alarmed = 0;
  450.     return (1);
  451.     }
  452.  
  453. /*
  454.  *    'Wait for' this string to appear on this file descriptor.
  455.  */
  456. int get_string(string)
  457. register char *string;
  458.     {
  459.     int c, printed = 0;
  460.     register char *orig_s, *s = string;
  461.  
  462.     if (verbose)
  463.     {
  464.     fprintf(stderr, "expect (");
  465.  
  466.     for (orig_s = s; *orig_s; ++orig_s)
  467.         fprintf(stderr, "%s", character(*orig_s));
  468.  
  469.     fprintf(stderr, ")\n");
  470.     fflush(stderr);
  471.     }
  472.  
  473.     if (*s == '\0')
  474.     {
  475.     if (verbose)
  476.         {
  477.         fprintf(stderr, "got it\n");
  478.         fflush(stderr);
  479.         }
  480.  
  481.     return (1);
  482.     }
  483.  
  484.     alarm(timeout); alarmed = 0;
  485.  
  486.     while ( ! alarmed && (c = get_char()) >= 0)
  487.     {
  488.     if (verbose)
  489.         {
  490.         if (c == '\n')
  491.         fprintf(stderr, "\n");
  492.         else
  493.         fprintf(stderr, "%s", character(c));
  494.  
  495.         fflush(stderr);
  496.         }
  497.  
  498.     if (c == *s)
  499.         ++s;
  500.     else
  501.         s = string;
  502.  
  503.     if (*s == '\0')
  504.         {
  505.         if (verbose)
  506.         {
  507.         fprintf(stderr, "got it\n");
  508.         fflush(stderr);
  509.         }
  510.  
  511.         alarm(0); alarmed = 0;
  512.         return (1);
  513.         }
  514.  
  515.     if (alarmed && verbose)
  516.         warning("Warning: get_string() has 'alarmed' on before read");
  517.     }
  518.  
  519.     alarm(0);
  520.     
  521.     if (verbose && printed)
  522.     {
  523.     extern int errno;
  524.  
  525.     if (alarmed)
  526.         fprintf(stderr, " -- read timed out\n");
  527.     else
  528.         perror(" -- read failed");
  529.  
  530.     fflush(stderr);
  531.     }
  532.  
  533.     alarmed = 0;
  534.     return (0);
  535.     }
  536.  
  537. /*
  538.  *    Delay an amount appropriate for between typed characters.
  539.  */
  540. delay()
  541.     {
  542.     register int i;
  543.  
  544. # ifdef NO_USLEEP
  545.     for (i = 0; i < 30000; ++i)        /* ... did we just say appropriate? */
  546.     ;
  547. # else /* NO_USLEEP */
  548.     usleep(100);
  549. # endif /* NO_USLEEP */
  550.     }
  551.