*
* This software is in the public domain.
*
- * Please send all bug reports, requests for information, etc. to:
+ * -----------------
+ *
+ * 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
*
- * Al Longyear (longyear@netcom.com)
- * (I was the last person to change this code.)
*
* Added -r "report file" switch & REPORT keyword.
* Robert Geer <bgeer@xmission.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>
* Columbus, OH 43221
* (614)451-1883
*
+ *
*/
-static char rcsid[] = "$Id: chat.c,v 1.12 1996/06/26 00:51:06 paulus Exp $";
+#ifndef lint
+static char rcsid[] = "$Id: chat.c,v 1.15 1997/07/14 03:50:22 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>
char *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 break_sequence __P((void));
void terminate __P((int status));
void die __P((void));
+void pack_array __P((char **array, int end));
+char *expect_strtok __P((char *, char *));
+
+int main __P((int, char *[]));
void *dup_mem(b, c)
void *b;
program_name = *argv;
tzset();
- while (option = OPTION(argc, argv))
+ while ((option = OPTION(argc, argv)) != 0)
{
switch (option)
{
break;
case 'f':
- if (arg = OPTARG(argc, argv))
+ if ((arg = OPTARG(argc, argv)) != NULL)
{
chat_file = copy_of(arg);
}
break;
case 't':
- if (arg = OPTARG(argc, argv))
+ if ((arg = OPTARG(argc, argv)) != NULL)
{
timeout = atoi(arg);
}
}
else
{
- while (arg = ARG(argc, argv))
+ while ((arg = ARG(argc, argv)) != NULL)
{
chat_expect(arg);
- if (arg = ARG(argc, argv))
+ if ((arg = ARG(argc, argv)) != NULL)
{
chat_send(arg);
}
}
}
-/*
- * Allow the last of the report string to be gathered before we terminate.
- */
- while (report_gathering)
- {
- int c;
- c = get_char();
- if (!iscntrl (c))
- {
- int rep_len = strlen (report_buffer);
- report_buffer[rep_len] = c;
- report_buffer[rep_len + 1] = '\0';
- }
- else
- {
- report_gathering = 0;
- fprintf (report_fp, "chat: %s\n", report_buffer);
- }
- }
terminate(0);
+ return 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')
void logf (str)
const char *str;
- {
- p = line + strlen(line);
- strcat (p, str);
+{
+ int l = strlen(line);
- if (str[strlen(str)-1] == '\n')
- {
+ if (l + strlen(str) >= sizeof(line)) {
+ syslog(LOG_INFO, "%s", line);
+ l = 0;
+ }
+ strcpy(line + l, str);
+
+ if (str[strlen(str)-1] == '\n') {
syslog (LOG_INFO, "%s", line);
line[0] = 0;
- }
}
+}
void logflush()
{
{
echo_stderr(-1);
if (report_file != (char *) 0 && report_fp != (FILE *) NULL)
- {
+ {
+/*
+ * Allow the last of the report string to be gathered before we terminate.
+ */
+ if (report_gathering) {
+ int c, rep_len;
+
+ rep_len = strlen(report_buffer);
+ while (rep_len + 1 <= sizeof(report_buffer)) {
+ alarm(1);
+ c = get_char();
+ alarm(0);
+ if (c < 0 || iscntrl(c))
+ break;
+ report_buffer[rep_len] = c;
+ ++rep_len;
+ }
+ report_buffer[rep_len] = 0;
+ fprintf (report_fp, "chat: %s\n", report_buffer);
+ }
if (verbose)
{
fprintf (report_fp, "Closing \"%s\".\n", report_file);
break;
case 'q':
- quiet = ! quiet;
+ quiet = 1;
break;
case 'r':
char *expect;
char *reply;
+ if (strcmp(s, "HANGUP") == 0)
+ {
+ ++hup_next;
+ return;
+ }
+
if (strcmp(s, "ABORT") == 0)
{
++abort_next;
return;
}
+ if (strcmp(s, "CLR_ABORT") == 0)
+ {
+ ++clear_abort_next;
+ return;
+ }
+
if (strcmp(s, "REPORT") == 0)
{
++report_next;
return;
}
+ if (strcmp(s, "CLR_REPORT") == 0)
+ {
+ ++clear_report_next;
+ return;
+ }
+
if (strcmp(s, "TIMEOUT") == 0)
{
++timeout_next;
++echo_next;
return;
}
+ if (strcmp(s, "SAY") == 0)
+ {
+ ++say_next;
+ return;
+ }
/*
* Fetch the expect and reply string.
*/
void chat_send (s)
register char *s;
{
+ if (say_next)
+ {
+ say_next = 0;
+ s = clean(s,0);
+ write(2, s, strlen(s));
+ free(s);
+ return;
+ }
+ if (hup_next)
+ {
+ hup_next = 0;
+ if (strcmp(s, "OFF") == 0)
+ signal(SIGHUP, SIG_IGN);
+ else
+ signal(SIGHUP, sighup);
+ return;
+ }
if (echo_next)
{
echo_next = 0;
return;
}
+ if (clear_abort_next)
+ {
+ char *s1;
+ char *s2 = s;
+ int i;
+ int old_max;
+ int pack = 0;
+
+ clear_abort_next = 0;
+
+ s1 = clean(s, 0);
+
+ if (strlen(s1) > strlen(s)
+ || strlen(s1) + 1 > sizeof(fail_buffer))
+ {
+ syslog(LOG_WARNING, "Illegal or too-long CLR_ABORT string ('%s')", s);
+ die();
+ }
+
+ old_max = n_aborts;
+ for (i=0; i < n_aborts; i++)
+ {
+ if ( strcmp(s1,abort_string[i]) == 0 )
+ {
+ free(abort_string[i]);
+ abort_string[i] = NULL;
+ pack++;
+ n_aborts--;
+ if (verbose)
+ {
+ logf("clear abort on (");
+
+ for (s2 = s; *s2; ++s2)
+ {
+ logf(character(*s2));
+ }
+
+ logf(")\n");
+ }
+ }
+ }
+ free(s1);
+ if (pack) pack_array(abort_string,old_max);
+ return;
+ }
+
if (report_next)
{
char *s1;
return;
}
+ if (clear_report_next)
+ {
+ char *s1;
+ char *s2 = s;
+ int i;
+ int old_max;
+ int pack = 0;
+
+ clear_report_next = 0;
+
+ s1 = clean(s, 0);
+
+ if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
+ {
+ syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s);
+ die();
+ }
+
+ old_max = n_reports;
+ for (i=0; i < n_reports; i++)
+ {
+ if ( strcmp(s1,report_string[i]) == 0 )
+ {
+ free(report_string[i]);
+ report_string[i] = NULL;
+ pack++;
+ n_reports--;
+ if (verbose)
+ {
+ logf("clear report (");
+
+ for (s2 = s; *s2; ++s2)
+ {
+ logf(character(*s2));
+ }
+
+ logf(")\n");
+ }
+ }
+ }
+ free(s1);
+ if (pack) pack_array(report_string,old_max);
+
+ return;
+ }
+
if (timeout_next)
{
timeout_next = 0;
int put_string (s)
register char *s;
{
+ quiet = 0;
s = clean(s, 1);
if (verbose)
return select( 0, (long *)0, (long *)0, (long *)0, &delay );
}
#endif
+
+void
+pack_array (array, end)
+ char **array; /* The address of the array of string pointers */
+ int end; /* The index of the next free entry before CLR_ */
+{
+ int i, j;
+
+ for (i = 0; i < end; i++) {
+ if (array[i] == NULL) {
+ for (j = i+1; j < end; ++j)
+ if (array[j] != NULL)
+ array[i++] = array[j];
+ for (; i < end; ++i)
+ array[i] = NULL;
+ break;
+ }
+ }
+}