]> git.ozlabs.org Git - ppp.git/blobdiff - chat/chat.c
mods from Francis Demierre: add SAY, HANGUP, CLR_ABORT, CLR_REPORT keywords
[ppp.git] / chat / chat.c
index 115ab2d8bdcbba115d25ad4b93cde0b491c2ead3..f298c6af4eed612159fef3e7e3a25daa45c4faab 100644 (file)
  *
  *     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>
@@ -125,10 +164,14 @@ struct termios saved_tty_parameters;
 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));
@@ -160,6 +203,10 @@ char *clean __P((register char *s, int sending));
 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;
@@ -197,7 +244,7 @@ char **argv;
     program_name = *argv;
     tzset();
 
-    while (option = OPTION(argc, argv))
+    while ((option = OPTION(argc, argv)) != 0)
         {
        switch (option)
            {
@@ -214,7 +261,7 @@ char **argv;
                break;
 
            case 'f':
-               if (arg = OPTARG(argc, argv))
+               if ((arg = OPTARG(argc, argv)) != NULL)
                    {
                    chat_file = copy_of(arg);
                    }
@@ -225,7 +272,7 @@ char **argv;
                break;
 
            case 't':
-               if (arg = OPTARG(argc, argv))
+               if ((arg = OPTARG(argc, argv)) != NULL)
                    {
                    timeout = atoi(arg);
                    }
@@ -301,37 +348,19 @@ char **argv;
        }
     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;
     }
 
 /*
@@ -366,6 +395,11 @@ char *chat_file;
 
        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')
@@ -440,16 +474,20 @@ char *p;
 
 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()
     {
@@ -608,7 +646,26 @@ int status;
     {
     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);
@@ -710,7 +767,7 @@ int sending;
            break;
 
        case 'q':
-           quiet = ! quiet;
+           quiet = 1;
            break;
 
        case 'r':
@@ -857,18 +914,36 @@ char *s;
     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;
@@ -880,6 +955,11 @@ char *s;
        ++echo_next;
        return;
        }
+    if (strcmp(s, "SAY") == 0)
+       {
+       ++say_next;
+       return;
+       }
 /*
  * Fetch the expect and reply string.
  */
@@ -965,6 +1045,23 @@ int c;
 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;
@@ -1007,6 +1104,52 @@ register char *s;
        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;
@@ -1041,6 +1184,52 @@ register char *s;
        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;
@@ -1175,6 +1364,7 @@ int c;
 int put_string (s)
 register char *s;
     {
+    quiet = 0;
     s = clean(s, 1);
 
     if (verbose)
@@ -1473,3 +1663,22 @@ usleep( usec )                             /* returns 0 if ok, else -1 */
     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;
+       }
+    }
+}