home *** CD-ROM | disk | FTP | other *** search
- /*
- * Chat -- a program for automatic session establishment (i.e. dial
- * the phone and log in).
- *
- * This software is in the public domain.
- *
- * Please send all bug reports, requests for information, etc. to:
- *
- * Karl Fox <karl@MorningStar.Com>
- * Morning Star Technologies, Inc.
- * 1760 Zollinger Road
- * Columbus, OH 43221
- * (614)451-1883
- */
-
- static char sccs_id[] = "@(#)chat.c 1.1";
-
- # include <stdio.h>
- # include <termio.h>
- # include <fcntl.h>
- # include <signal.h>
- # include <errno.h>
- # include <sys/types.h>
- # include <sys/stat.h>
- # include <ctype.h>
-
- # define STR_LEN 1024
-
- # define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
- (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
- &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
- # define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
- (_O=4,(char*)0):(char*)0)
- # define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
- # define ARG(c,v) (c?(--c,*v++):(char*)0)
-
- static int _O = 0; /* Internal state */
- char *program_name;
-
- extern char *strcpy(), *strcat(), *malloc();
- extern int strlen();
- # define copyof(s) ((s) ? strcpy(malloc(strlen(s) + 1), s) : (s))
-
- # ifndef LOCK_DIR
- # ifdef HDB
- # define LOCK_DIR "/usr/spool/locks"
- # else /* HDB */
- # define LOCK_DIR "/usr/spool/uucp"
- # endif /* HDB */
- # endif /* LOCK_DIR */
-
- int verbose = 0;
- int quiet = 0;
- char *lock_file = (char *)0;
- int timeout = 30;
-
- /*
- * chat [ -v ] [ -l lock-file ] [...[[expect[-say[-expect...]] say \
- * expect[-say[-expect]] ...]]]
- *
- * Perform a UUCP-dialer-like chat script on stdin and stdout.
- */
- main(argc, argv)
- int argc;
- char **argv;
- {
- int option, n;
- char *arg;
-
- program_name = *argv;
-
- while (option = OPTION(argc, argv))
- switch (option)
- {
- case 'v':
- ++verbose;
- break;
-
- case 'l':
- if (arg = OPTARG(argc, argv))
- lock_file = copyof(arg);
- else
- usage();
-
- break;
-
- case 't':
- if (arg = OPTARG(argc, argv))
- timeout = atoi(arg);
- else
- usage();
-
- break;
-
- default:
- usage();
- }
-
- init();
-
- while (arg = ARG(argc, argv))
- {
- expect(arg);
-
- if (arg = ARG(argc, argv))
- send(arg);
- }
-
- exit(0);
- }
-
- /*
- * We got an error parsing the command line.
- */
- usage()
- {
- fprintf(stderr, "Usage: %s [ -v ] [ -l lock-file ] [-t timeout ]\n", program_name);
- exit(1);
- }
-
- /*
- * Print a warning message.
- */
- /*VARARGS1*/
- warning(format, arg1, arg2, arg3, arg4)
- char *format;
- int arg1, arg2, arg3, arg4;
- {
- fprintf(stderr, "%s: Warning: ", program_name);
- fprintf(stderr, format, arg1, arg2, arg3, arg4);
- fprintf(stderr, "\n");
- }
-
- /*
- * Print an error message and terminate.
- */
- /*VARARGS1*/
- fatal(format, arg1, arg2, arg3, arg4)
- char *format;
- int arg1, arg2, arg3, arg4;
- {
- fprintf(stderr, "%s: ", program_name);
- fprintf(stderr, format, arg1, arg2, arg3, arg4);
- fprintf(stderr, "\n");
- unlock();
- exit(1);
- }
-
- /*
- * Print an error message along with the system error message and
- * terminate.
- */
- /*VARARGS1*/
- sysfatal(format, arg1, arg2, arg3, arg4)
- char *format;
- int arg1, arg2, arg3, arg4;
- {
- char message[STR_LEN];
-
- sprintf(message, "%s: ", program_name);
- sprintf(message + strlen(message), format, arg1, arg2, arg3, arg4);
- perror(message);
- unlock();
- exit(1);
- }
-
- int alarmed = 0;
-
- sigalrm()
- {
- int flags;
-
- alarm(1); alarmed = 1; /* Reset alarm to avoid race window */
- signal(SIGALRM, sigalrm); /* that can cause hanging in read() */
-
- if ((flags = fcntl(0, F_GETFL, 0)) == -1)
- sysfatal("Can't get file mode flags on stdin");
- else
- if (fcntl(0, F_SETFL, flags | FNDELAY) == -1)
- sysfatal("Can't set file mode flags on stdin");
-
- if (verbose)
- {
- fprintf(stderr, "alarm\n");
- fflush(stderr);
- }
- }
-
- unalarm()
- {
- int flags;
-
- if ((flags = fcntl(0, F_GETFL, 0)) == -1)
- sysfatal("Can't get file mode flags on stdin");
- else
- if (fcntl(0, F_SETFL, flags & ~FNDELAY) == -1)
- sysfatal("Can't set file mode flags on stdin");
- }
-
- init()
- {
- if (lock_file)
- lock();
-
- set_tty_parameters();
- signal(SIGALRM, sigalrm);
- alarm(0); alarmed = 0;
- }
-
- set_tty_parameters()
- {
- struct termio t;
-
- if (ioctl(0, TCGETA, &t) < 0)
- sysfatal("Can't get terminal parameters");
-
- t.c_iflag = IXOFF | IXON | ISTRIP | IGNPAR | IGNBRK;
- t.c_cflag = CLOCAL | CREAD | CS8 | (t.c_cflag & CBAUD) | HUPCL;
- t.c_lflag = 0;
- t.c_cc[VERASE] = 0;
- t.c_cc[VKILL] = 0;
- t.c_cc[VMIN] = 1;
- t.c_cc[VTIME] = 0;
-
- if (ioctl(0, TCSETA, &t) < 0)
- sysfatal("Can't set terminal parameters");
- }
-
- /*
- * Create a lock file for the named lock device
- */
- lock()
- {
- char hdb_lock_buffer[12];
- int fd, pid;
-
- lock_file = strcat(strcat(strcpy(malloc(strlen(LOCK_DIR)
- + 1 + strlen(lock_file) + 1),
- LOCK_DIR), "/"), lock_file);
-
- if ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0)
- sysfatal("Can't get lock file '%s'", lock_file);
-
- # ifdef HDB
- sprintf(hdb_lock_buffer, "%10d\n", getpid());
- write(fd, hdb_lock_buffer, 11);
- # else /* HDB */
- pid = getpid();
- write(fd, &pid, sizeof pid);
- # endif /* HDB */
-
- close(fd);
- }
-
- /*
- * Remove our lockfile
- */
- unlock()
- {
- if (lock_file)
- {
- unlink(lock_file);
- lock_file = (char *)0;
- }
- }
-
- /*
- * 'Clean up' this string.
- */
- char *clean(s, add_newline)
- register char *s;
- int add_newline;
- {
- char temp[STR_LEN];
- register char *s1;
-
- for (s1 = temp; *s; ++s)
- switch (*s)
- {
- case '\\':
- switch (*++s)
- {
- case 'q': quiet = ! quiet; break;
- case 'r': *s1++ = '\r'; break;
- case 'n': *s1++ = '\n'; break;
- case 's': *s1++ = ' '; break;
- case 'c': add_newline = 0; break;
- default: *s1++ = *s;
- }
-
- break;
-
- case '^':
- *s1++ = (int)(*++s) & 0x1F;
- break;
-
- default:
- *s1++ = *s;
- }
-
- if (add_newline)
- *s1++ = '\n';
-
- *s1 = '\0';
- return (copyof(temp));
- }
-
- /*
- *
- */
- expect(s)
- char *s;
- {
- if ( ! get_string(clean(s, 0)))
- {
- fprintf(stderr, "Failed\n");
- fflush(stderr);
- unlock();
- exit(1);
- }
- }
-
- /*
- *
- */
- send(s)
- char *s;
- {
- if ( ! put_string(clean(s, 1)))
- {
- fprintf(stderr, "Failed\n");
- fflush(stderr);
- unlock();
- exit(1);
- }
- }
-
- char *character(c)
- char c;
- {
- static char string[10];
-
- if (isgraph(c) || c == ' ')
- sprintf(string, "%c", c);
- else
- if (c < 32)
- sprintf(string, "^%c", (int)c + 'A' - 1);
- else
- sprintf(string, "\\%03o", (int)c & 0xFF);
-
- return (string);
- }
-
- int get_char()
- {
- int status;
- char c;
-
- status = read(0, &c, 1);
-
- switch (status)
- {
- case 1:
- return ((int)c & 0x7F);
-
- default:
- warning("read() on stdin returned %d", status);
-
- case -1:
- if ((status = fcntl(0, F_GETFL, 0)) == -1)
- sysfatal("Can't get file mode flags on stdin");
- else
- if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1)
- sysfatal("Can't set file mode flags on stdin");
-
- return (-1);
- }
- }
-
- int put_char(c)
- char c;
- {
- int status;
-
- delay();
-
- status = write(1, &c, 1);
-
- switch (status)
- {
- case 1:
- return (0);
-
- default:
- warning("write() on stdout returned %d", status);
-
- case -1:
- if ((status = fcntl(0, F_GETFL, 0)) == -1)
- sysfatal("Can't get file mode flags on stdin");
- else
- if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1)
- sysfatal("Can't set file mode flags on stdin");
-
- return (-1);
- }
- }
-
- int put_string(s)
- register char *s;
- {
- register char *orig_s = s;
-
- if (verbose)
- {
- fprintf(stderr, "send (");
-
- if (quiet)
- fprintf(stderr, "??????");
- else
- for (orig_s = s; *orig_s; ++orig_s)
- fprintf(stderr, "%s", character(*orig_s));
-
- fprintf(stderr, ")\n");
- fflush(stderr);
- }
-
- alarm(timeout); alarmed = 0;
-
- for ( ; *s; ++s)
- if (alarmed || put_char(*s) < 0)
- {
- extern int errno;
-
- alarm(0); alarmed = 0;
-
- if (verbose)
- {
- if (errno == EINTR || errno == EWOULDBLOCK)
- fprintf(stderr, " -- write timed out\n");
- else
- perror(" -- write failed");
-
- fflush(stderr);
- }
-
- return (0);
- }
-
- alarm(0); alarmed = 0;
- return (1);
- }
-
- /*
- * 'Wait for' this string to appear on this file descriptor.
- */
- int get_string(string)
- register char *string;
- {
- int c, printed = 0;
- register char *orig_s, *s = string;
-
- if (verbose)
- {
- fprintf(stderr, "expect (");
-
- for (orig_s = s; *orig_s; ++orig_s)
- fprintf(stderr, "%s", character(*orig_s));
-
- fprintf(stderr, ")\n");
- fflush(stderr);
- }
-
- if (*s == '\0')
- {
- if (verbose)
- {
- fprintf(stderr, "got it\n");
- fflush(stderr);
- }
-
- return (1);
- }
-
- alarm(timeout); alarmed = 0;
-
- while ( ! alarmed && (c = get_char()) >= 0)
- {
- if (verbose)
- {
- if (c == '\n')
- fprintf(stderr, "\n");
- else
- fprintf(stderr, "%s", character(c));
-
- fflush(stderr);
- }
-
- if (c == *s)
- ++s;
- else
- s = string;
-
- if (*s == '\0')
- {
- if (verbose)
- {
- fprintf(stderr, "got it\n");
- fflush(stderr);
- }
-
- alarm(0); alarmed = 0;
- return (1);
- }
-
- if (alarmed && verbose)
- warning("Warning: get_string() has 'alarmed' on before read");
- }
-
- alarm(0);
-
- if (verbose && printed)
- {
- extern int errno;
-
- if (alarmed)
- fprintf(stderr, " -- read timed out\n");
- else
- perror(" -- read failed");
-
- fflush(stderr);
- }
-
- alarmed = 0;
- return (0);
- }
-
- /*
- * Delay an amount appropriate for between typed characters.
- */
- delay()
- {
- register int i;
-
- # ifdef NO_USLEEP
- for (i = 0; i < 30000; ++i) /* ... did we just say appropriate? */
- ;
- # else /* NO_USLEEP */
- usleep(100);
- # endif /* NO_USLEEP */
- }
-