#endif
#ifndef lint
-static const char rcsid[] = "$Id: chat.c,v 1.27 2002/01/11 18:05:44 etbe Exp $";
+static const char rcsid[] = "$Id: chat.c,v 1.30 2004/01/17 05:47:55 carlsonj Exp $";
#endif
#include <stdio.h>
void *dup_mem __P((void *b, size_t c));
void *copy_of __P((char *s));
+char *grow __P((char *s, char **p, size_t len));
void usage __P((void));
-void logf __P((const char *fmt, ...));
+void msgf __P((const char *fmt, ...));
void fatal __P((int code, const char *fmt, ...));
SIGTYPE sigalrm __P((int signo));
SIGTYPE sigint __P((int signo));
return dup_mem (s, strlen (s) + 1);
}
+/* grow a char buffer and keep a pointer offset */
+char *grow(s, p, len)
+char *s;
+char **p;
+size_t len;
+{
+ size_t l = *p - s; /* save p as distance into s */
+
+ s = realloc(s, len);
+ if (!s)
+ fatal(2, "memory error!");
+ *p = s + l; /* restore p */
+ return s;
+}
+
/*
* chat [ -v ] [ -E ] [ -T number ] [ -U number ] [ -t timeout ] [ -f chat-file ] \
* [ -r report-file ] \
/*
* Send a message to syslog and/or stderr.
*/
-void logf __V((const char *fmt, ...))
+void msgf __V((const char *fmt, ...))
{
va_list args;
fatal(2, "Can't set file mode flags on stdin: %m");
if (verbose)
- logf("alarm");
+ msgf("alarm");
}
void unalarm()
register char *s;
int sending; /* set to 1 when sending (putting) this string. */
{
- char temp[STR_LEN], env_str[STR_LEN], cur_chr;
- register char *s1, *phchar;
+ char cur_chr;
+ char *s1, *p, *phchar;
int add_return = sending;
+ size_t len = strlen(s) + 3; /* see len comments below */
+
#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
#define isalnumx(chr) ((((chr) >= '0') && ((chr) <= '9')) \
|| (((chr) >= 'a') && ((chr) <= 'z')) \
|| (((chr) >= 'A') && ((chr) <= 'Z')) \
|| (chr) == '_')
- s1 = temp;
+ p = s1 = malloc(len);
+ if (!p)
+ fatal(2, "memory error!");
while (*s) {
cur_chr = *s++;
if (cur_chr == '^') {
cur_chr = *s++;
if (cur_chr == '\0') {
- *s1++ = '^';
+ *p++ = '^';
break;
}
cur_chr &= 0x1F;
if (cur_chr != 0) {
- *s1++ = cur_chr;
+ *p++ = cur_chr;
}
continue;
}
-
+
if (use_env && cur_chr == '$') { /* ARI */
- phchar = env_str;
+ char c;
+
+ phchar = s;
while (isalnumx(*s))
- *phchar++ = *s++;
- *phchar = '\0';
- phchar = getenv(env_str);
- if (phchar)
+ s++;
+ c = *s; /* save */
+ *s = '\0';
+ phchar = getenv(phchar);
+ *s = c; /* restore */
+ if (phchar) {
+ len += strlen(phchar);
+ s1 = grow(s1, &p, len);
while (*phchar)
- *s1++ = *phchar++;
+ *p++ = *phchar++;
+ }
continue;
}
if (cur_chr != '\\') {
- *s1++ = cur_chr;
+ *p++ = cur_chr;
continue;
}
cur_chr = *s++;
if (cur_chr == '\0') {
if (sending) {
- *s1++ = '\\';
- *s1++ = '\\';
+ *p++ = '\\';
+ *p++ = '\\'; /* +1 for len */
}
break;
}
switch (cur_chr) {
case 'b':
- *s1++ = '\b';
+ *p++ = '\b';
break;
case 'c':
if (sending && *s == '\0')
add_return = 0;
else
- *s1++ = cur_chr;
+ *p++ = cur_chr;
break;
case '\\':
case 'p':
case 'd':
if (sending)
- *s1++ = '\\';
- *s1++ = cur_chr;
+ *p++ = '\\';
+ *p++ = cur_chr;
break;
case 'T':
if (sending && phone_num) {
+ len += strlen(phone_num);
+ s1 = grow(s1, &p, len);
for (phchar = phone_num; *phchar != '\0'; phchar++)
- *s1++ = *phchar;
+ *p++ = *phchar;
}
else {
- *s1++ = '\\';
- *s1++ = 'T';
+ *p++ = '\\';
+ *p++ = 'T';
}
break;
case 'U':
if (sending && phone_num2) {
+ len += strlen(phone_num2);
+ s1 = grow(s1, &p, len);
for (phchar = phone_num2; *phchar != '\0'; phchar++)
- *s1++ = *phchar;
+ *p++ = *phchar;
}
else {
- *s1++ = '\\';
- *s1++ = 'U';
+ *p++ = '\\';
+ *p++ = 'U';
}
break;
break;
case 'r':
- *s1++ = '\r';
+ *p++ = '\r';
break;
case 'n':
- *s1++ = '\n';
+ *p++ = '\n';
break;
case 's':
- *s1++ = ' ';
+ *p++ = ' ';
break;
case 't':
- *s1++ = '\t';
+ *p++ = '\t';
break;
case 'N':
if (sending) {
- *s1++ = '\\';
- *s1++ = '\0';
+ *p++ = '\\';
+ *p++ = '\0';
}
else
- *s1++ = 'N';
+ *p++ = 'N';
break;
-
+
case '$': /* ARI */
if (use_env) {
- *s1++ = cur_chr;
+ *p++ = cur_chr;
break;
}
/* FALL THROUGH */
if (cur_chr != 0 || sending) {
if (sending && (cur_chr == '\\' || cur_chr == 0))
- *s1++ = '\\';
- *s1++ = cur_chr;
+ *p++ = '\\';
+ *p++ = cur_chr;
}
break;
}
if (sending)
- *s1++ = '\\';
- *s1++ = cur_chr;
+ *p++ = '\\';
+ *p++ = cur_chr;
break;
}
}
if (add_return)
- *s1++ = '\r';
+ *p++ = '\r'; /* +2 for len */
- *s1++ = '\0'; /* guarantee closure */
- *s1++ = '\0'; /* terminate the string */
- return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
+ *p = '\0'; /* +3 for len */
+ return s1;
}
/*
* The expectation did not occur. This is terminal.
*/
if (fail_reason)
- logf("Failed (%s)", fail_reason);
+ msgf("Failed (%s)", fail_reason);
else
- logf("Failed");
+ msgf("Failed");
terminate(exit_code);
}
abort_string[n_aborts++] = s1;
if (verbose)
- logf("abort on (%v)", s);
+ msgf("abort on (%v)", s);
return;
}
pack++;
n_aborts--;
if (verbose)
- logf("clear abort on (%v)", s);
+ msgf("clear abort on (%v)", s);
}
}
free(s1);
fatal(2, "Too many REPORT strings");
s1 = clean(s, 0);
-
- if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
+ if (strlen(s1) > strlen(s)
+ || strlen(s1) + 1 > sizeof(fail_buffer))
fatal(1, "Illegal or too-long REPORT string ('%v')", s);
report_string[n_reports++] = s1;
if (verbose)
- logf("report (%v)", s);
+ msgf("report (%v)", s);
return;
}
s1 = clean(s, 0);
- if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
+ if (strlen(s1) > strlen(s)
+ || strlen(s1) + 1 > sizeof(fail_buffer))
fatal(1, "Illegal or too-long REPORT string ('%v')", s);
old_max = n_reports;
pack++;
n_reports--;
if (verbose)
- logf("clear report (%v)", s);
+ msgf("clear report (%v)", s);
}
}
free(s1);
timeout = DEFAULT_CHAT_TIMEOUT;
if (verbose)
- logf("timeout set to %d seconds", timeout);
+ msgf("timeout set to %d seconds", timeout);
return;
}
return ((int)c & 0x7F);
default:
- logf("warning: read() on stdin returned %d", status);
+ msgf("warning: read() on stdin returned %d", status);
case -1:
if ((status = fcntl(0, F_GETFL, 0)) == -1)
return (0);
default:
- logf("warning: write() on stdout returned %d", status);
+ msgf("warning: write() on stdout returned %d", status);
case -1:
if ((status = fcntl(0, F_GETFL, 0)) == -1)
if (verbose) {
if (errno == EINTR || errno == EWOULDBLOCK)
- logf(" -- write timed out");
+ msgf(" -- write timed out");
else
- logf(" -- write failed: %m");
+ msgf(" -- write failed: %m");
}
return (0);
}
if (verbose) {
if (quiet)
- logf("send (??????)");
+ msgf("send (??????)");
else
- logf("send (%v)", s);
+ msgf("send (%v)", s);
}
alarm(timeout); alarmed = 0;
minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
if (verbose)
- logf("expect (%v)", string);
+ msgf("expect (%v)", string);
if (len > STR_LEN) {
- logf("expect string is too long");
+ msgf("expect string is too long");
exit_code = 1;
return 0;
}
if (len == 0) {
if (verbose)
- logf("got it");
+ msgf("got it");
return (1);
}
echo_stderr(c);
if (verbose && c == '\n') {
if (s == logged)
- logf(""); /* blank line */
+ msgf(""); /* blank line */
else
- logf("%0.*v", s - logged, logged);
+ msgf("%0.*v", s - logged, logged);
logged = s + 1;
}
*s++ = c;
if (verbose && s >= logged + 80) {
- logf("%0.*v", s - logged, logged);
+ msgf("%0.*v", s - logged, logged);
logged = s;
}
strncmp(s - len, string, len) == 0) {
if (verbose) {
if (s > logged)
- logf("%0.*v", s - logged, logged);
- logf(" -- got it\n");
+ msgf("%0.*v", s - logged, logged);
+ msgf(" -- got it\n");
}
alarm(0);
strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
if (verbose) {
if (s > logged)
- logf("%0.*v", s - logged, logged);
- logf(" -- failed");
+ msgf("%0.*v", s - logged, logged);
+ msgf(" -- failed");
}
alarm(0);
if (s >= end) {
if (logged < s - minlen) {
if (verbose)
- logf("%0.*v", s - logged, logged);
+ msgf("%0.*v", s - logged, logged);
logged = s;
}
s -= minlen;
}
if (alarmed && verbose)
- logf("warning: alarm synchronization problem");
+ msgf("warning: alarm synchronization problem");
}
alarm(0);
if (verbose && printed) {
if (alarmed)
- logf(" -- read timed out");
+ msgf(" -- read timed out");
else
- logf(" -- read failed: %m");
+ msgf(" -- read failed: %m");
}
exit_code = 3;