📄 chat.c
字号:
/* * Chat -- a program for automatic session establishment (i.e. dial * the phone and log in). * * Standard termination codes: * 0 - successful completion of the script * 1 - invalid argument, expect string too large, etc. * 2 - error on an I/O operation or fatal error condition. * 3 - timeout waiting for a simple string. * 4 - the first string declared as "ABORT" * 5 - the second string declared as "ABORT" * 6 - ... and so on for successive ABORT strings. * * This software is in the public domain. * * ----------------- * 22-May-99 added environment substitutuion, enabled with -E switch. * Andreas Arens <andras@cityweb.de>. * * 12-May-99 added a feature to read data to be sent from a file, * if the send string starts with @. Idea from gpk <gpk@onramp.net>. * * added -T and -U option and \T and \U substitution to pass a phone * number into chat script. Two are needed for some ISDN TA applications. * Keith Dart <kdart@cisco.com> * * * Added SAY keyword to send output to stderr. * This allows to turn ECHO OFF and to output specific, user selected, * text to give progress messages. This best works when stderr * exists (i.e.: pppd in nodetach mode). * * Added HANGUP directives to allow for us to be called * back. When HANGUP is set to NO, chat will not hangup at HUP signal. * We rely on timeouts in that case. * * Added CLR_ABORT to clear previously set ABORT string. This has been * dictated by the HANGUP above as "NO CARRIER" (for example) must be * an ABORT condition until we know the other host is going to close * the connection for call back. As soon as we have completed the * first stage of the call back sequence, "NO CARRIER" is a valid, non * fatal string. As soon as we got called back (probably get "CONNECT"), * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command. * Note that CLR_ABORT packs the abort_strings[] array so that we do not * have unused entries not being reclaimed. * * In the same vein as above, added CLR_REPORT keyword. * * Allow for comments. Line starting with '#' are comments and are * ignored. If a '#' is to be expected as the first character, the * expect string must be quoted. * * * Francis Demierre <Francis@SwissMail.Com> * Thu May 15 17:15:40 MET DST 1997 * * * Added -r "report file" switch & REPORT keyword. * Robert Geer <bgeer@xmission.com> * * Added -s "use stderr" and -S "don't use syslog" switches. * June 18, 1997 * Karl O. Pinc <kop@meme.com> * * * Added -e "echo" switch & ECHO keyword * Dick Streefland <dicks@tasking.nl> * * * Considerable updates and modifications by * Al Longyear <longyear@pobox.com> * Paul Mackerras <paulus@cs.anu.edu.au> * * * The original author is: * * Karl Fox <karl@MorningStar.Com> * Morning Star Technologies, Inc. * 1760 Zollinger Road * Columbus, OH 43221 * (614)451-1883 * */#ifndef __STDC__#define const#endif#ifndef lintstatic const char rcsid[] = "$Id: chat.c,v 1.26 1999/12/23 01:39:54 paulus Exp $";#endif#include <stdio.h>#include <ctype.h>#include <time.h>#include <fcntl.h>#include <signal.h>#include <errno.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <syslog.h>#ifndef TERMIO#undef TERMIOS#define TERMIOS#endif#ifdef TERMIO#include <termio.h>#endif#ifdef TERMIOS#include <termios.h>#endif#define STR_LEN 1024#ifndef SIGTYPE#define SIGTYPE void#endif#undef __P#undef __V#ifdef __STDC__#include <stdarg.h>#define __V(x) x#define __P(x) x#else#include <varargs.h>#define __V(x) (va_alist) va_dcl#define __P(x) ()#define const#endif#ifndef O_NONBLOCK#define O_NONBLOCK O_NDELAY#endif#ifdef SUNOSextern int sys_nerr;extern char *sys_errlist[];#define memmove(to, from, n) bcopy(from, to, n)#define strerror(n) ((unsigned)(n) < sys_nerr? sys_errlist[(n)] :\ "unknown error")#endif/*************** Micro getopt() *********************************************/#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 *//*************** Micro getopt() *********************************************/char *program_name;#define MAX_ABORTS 50#define MAX_REPORTS 50#define DEFAULT_CHAT_TIMEOUT 45int echo = 0;int verbose = 0;int to_log = 1;int to_stderr = 0;int Verbose = 0;int quiet = 0;int report = 0;int use_env = 0;int exit_code = 0;FILE* report_fp = (FILE *) 0;char *report_file = (char *) 0;char *chat_file = (char *) 0;char *phone_num = (char *) 0;char *phone_num2 = (char *) 0;int timeout = DEFAULT_CHAT_TIMEOUT;int have_tty_parameters = 0;#ifdef TERMIO#define term_parms struct termio#define get_term_param(param) ioctl(0, TCGETA, param)#define set_term_param(param) ioctl(0, TCSETA, param)struct termio saved_tty_parameters;#endif#ifdef TERMIOS#define term_parms struct termios#define get_term_param(param) tcgetattr(0, param)#define set_term_param(param) tcsetattr(0, TCSANOW, param)struct termios saved_tty_parameters;#endifchar *abort_string[MAX_ABORTS], *fail_reason = (char *)0, fail_buffer[50];int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0;int clear_abort_next = 0;char *report_string[MAX_REPORTS] ;char report_buffer[50] ;int n_reports = 0, report_next = 0, report_gathering = 0 ; int clear_report_next = 0;int say_next = 0, hup_next = 0;void *dup_mem __P((void *b, size_t c));void *copy_of __P((char *s));void usage __P((void));void logf __P((const char *fmt, ...));void fatal __P((int code, const char *fmt, ...));SIGTYPE sigalrm __P((int signo));SIGTYPE sigint __P((int signo));SIGTYPE sigterm __P((int signo));SIGTYPE sighup __P((int signo));void unalarm __P((void));void init __P((void));void set_tty_parameters __P((void));void echo_stderr __P((int));void break_sequence __P((void));void terminate __P((int status));void do_file __P((char *chat_file));int get_string __P((register char *string));int put_string __P((register char *s));int write_char __P((int c));int put_char __P((int c));int get_char __P((void));void chat_send __P((register char *s));char *character __P((int c));void chat_expect __P((register char *s));char *clean __P((register char *s, int sending));void break_sequence __P((void));void terminate __P((int status));void pack_array __P((char **array, int end));char *expect_strtok __P((char *, char *));int vfmtmsg __P((char *, int, const char *, va_list)); /* vsprintf++ */int main __P((int, char *[]));void *dup_mem(b, c)void *b;size_t c;{ void *ans = malloc (c); if (!ans) fatal(2, "memory error!"); memcpy (ans, b, c); return ans;}void *copy_of (s)char *s;{ return dup_mem (s, strlen (s) + 1);}/* * chat [ -v ] [ -E ] [ -T number ] [ -U number ] [ -t timeout ] [ -f chat-file ] \ * [ -r report-file ] \ * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] * * Perform a UUCP-dialer-like chat script on stdin and stdout. */intmain(argc, argv) int argc; char **argv;{ int option; char *arg; program_name = *argv; tzset(); while ((option = OPTION(argc, argv)) != 0) { switch (option) { case 'e': ++echo; break; case 'E': ++use_env; break; case 'v': ++verbose; break; case 'V': ++Verbose; break; case 's': ++to_stderr; break; case 'S': to_log = 0; break; case 'f': if ((arg = OPTARG(argc, argv)) != NULL) chat_file = copy_of(arg); else usage(); break; case 't': if ((arg = OPTARG(argc, argv)) != NULL) timeout = atoi(arg); else usage(); break; case 'r': arg = OPTARG (argc, argv); if (arg) { if (report_fp != NULL) fclose (report_fp); report_file = copy_of (arg); report_fp = fopen (report_file, "a"); if (report_fp != NULL) { if (verbose) fprintf (report_fp, "Opening \"%s\"...\n", report_file); report = 1; } } break; case 'T': if ((arg = OPTARG(argc, argv)) != NULL) phone_num = copy_of(arg); else usage(); break; case 'U': if ((arg = OPTARG(argc, argv)) != NULL) phone_num2 = copy_of(arg); else usage(); break; default: usage(); break; } }/* * Default the report file to the stderr location */ if (report_fp == NULL) report_fp = stderr; if (to_log) {#ifdef ultrix openlog("chat", LOG_PID);#else openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); if (verbose) setlogmask(LOG_UPTO(LOG_INFO)); else setlogmask(LOG_UPTO(LOG_WARNING));#endif } init(); if (chat_file != NULL) { arg = ARG(argc, argv); if (arg != NULL) usage(); else do_file (chat_file); } else { while ((arg = ARG(argc, argv)) != NULL) { chat_expect(arg); if ((arg = ARG(argc, argv)) != NULL) chat_send(arg); } } terminate(0); return 0;}/* * Process a chat script when read from a file. */void do_file (chat_file)char *chat_file;{ int linect, sendflg; char *sp, *arg, quote; char buf [STR_LEN]; FILE *cfp; cfp = fopen (chat_file, "r"); if (cfp == NULL) fatal(1, "%s -- open failed: %m", chat_file); linect = 0; sendflg = 0; while (fgets(buf, STR_LEN, cfp) != NULL) { sp = strchr (buf, '\n'); if (sp) *sp = '\0'; linect++; sp = buf; /* lines starting with '#' are comments. If a real '#' is to be expected, it should be quoted .... */ if ( *sp == '#' ) continue; while (*sp != '\0') { if (*sp == ' ' || *sp == '\t') { ++sp; continue; } if (*sp == '"' || *sp == '\'') { quote = *sp++; arg = sp; while (*sp != quote) { if (*sp == '\0') fatal(1, "unterminated quote (line %d)", linect); if (*sp++ == '\\') { if (*sp != '\0') ++sp; } } } else { arg = sp; while (*sp != '\0' && *sp != ' ' && *sp != '\t') ++sp; } if (*sp != '\0') *sp++ = '\0'; if (sendflg) chat_send (arg); else chat_expect (arg); sendflg = !sendflg; } } fclose (cfp);}/* * We got an error parsing the command line. */void usage(){ fprintf(stderr, "\Usage: %s [-e] [-E] [-v] [-V] [-t timeout] [-r report-file]\n\ [-T phone-number] [-U phone-number2] {-f chat-file | chat-script}\n", program_name); exit(1);}char line[1024];/* * Send a message to syslog and/or stderr. */void logf __V((const char *fmt, ...)){ va_list args;#ifdef __STDC__ va_start(args, fmt);#else char *fmt; va_start(args); fmt = va_arg(args, char *);#endif vfmtmsg(line, sizeof(line), fmt, args); if (to_log) syslog(LOG_INFO, "%s", line); if (to_stderr) fprintf(stderr, "%s\n", line);}/* * Print an error message and terminate. */void fatal __V((int code, const char *fmt, ...)){ va_list args;#ifdef __STDC__ va_start(args, fmt);#else int code; char *fmt; va_start(args); code = va_arg(args, int); fmt = va_arg(args, char *);#endif vfmtmsg(line, sizeof(line), fmt, args); if (to_log) syslog(LOG_ERR, "%s", line); if (to_stderr) fprintf(stderr, "%s\n", line); terminate(code);}int alarmed = 0;SIGTYPE sigalrm(signo)int signo;{ 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) fatal(2, "Can't get file mode flags on stdin: %m"); if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) fatal(2, "Can't set file mode flags on stdin: %m"); if (verbose) logf("alarm");}void unalarm(){ int flags; if ((flags = fcntl(0, F_GETFL, 0)) == -1) fatal(2, "Can't get file mode flags on stdin: %m"); if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) fatal(2, "Can't set file mode flags on stdin: %m");}SIGTYPE sigint(signo)int signo;{ fatal(2, "SIGINT");}SIGTYPE sigterm(signo)int signo;{ fatal(2, "SIGTERM");}SIGTYPE sighup(signo)int signo;{ fatal(2, "SIGHUP");}void init(){ signal(SIGINT, sigint); signal(SIGTERM, sigterm); signal(SIGHUP, sighup); set_tty_parameters(); signal(SIGALRM, sigalrm); alarm(0); alarmed = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -