chat.c revision 6059
1/* 2 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 3 * 4 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 5 * 6 * Most of codes are derived from chat.c by Karl Fox (karl@MorningStar.Com). 7 * 8 * Chat -- a program for automatic session establishment (i.e. dial 9 * the phone and log in). 10 * 11 * This software is in the public domain. 12 * 13 * Please send all bug reports, requests for information, etc. to: 14 * 15 * Karl Fox <karl@MorningStar.Com> 16 * Morning Star Technologies, Inc. 17 * 1760 Zollinger Road 18 * Columbus, OH 43221 19 * (614)451-1883 20 * 21 * $Id:$ 22 * 23 * TODO: 24 * o Support more UUCP compatible control sequences. 25 * o Dialing shoud not block monitor process. 26 */ 27#include "defs.h" 28#include <ctype.h> 29#include <sys/uio.h> 30#ifndef isblank 31#define isblank(c) ((c) == '\t' || (c) == ' ') 32#endif 33#include <sys/time.h> 34#include <fcntl.h> 35#include "timeout.h" 36#include "vars.h" 37 38static int TimeoutSec; 39static int abort_next, timeout_next; 40static int numaborts; 41char *AbortStrings[50]; 42 43extern int ChangeParity(char *); 44 45#define MATCH 1 46#define NOMATCH 0 47#define ABORT -1 48 49static char * 50findblank(p, instring) 51char *p; 52int instring; 53{ 54 if (instring) { 55 while (*p) { 56 if (*p == '\\') { 57 strcpy(p, p + 1); 58 if (!*p) 59 break; 60 } else if (*p == '"') 61 return(p); 62 p++; 63 } 64 } else { 65 while (*p) { 66 if (isblank(*p)) 67 return(p); 68 p++; 69 } 70 } 71 return p; 72} 73 74int 75MakeArgs(script, pvect) 76char *script; 77char **pvect; 78{ 79 int nargs, nb; 80 int instring; 81 82 nargs = 0; 83 while (*script) { 84 nb = strspn(script, " \t"); 85 script += nb; 86 if (*script) { 87 if (*script == '"') { 88 instring = 1; 89 script++; 90 if (*script == '\0') 91 return(nargs); 92 } else 93 instring = 0; 94 *pvect++ = script; 95 nargs++; 96 script = findblank(script, instring); 97 if (*script) 98 *script++ = '\0'; 99 } 100 } 101 *pvect = NULL; 102 return nargs; 103} 104 105/* 106 * \r Carrige return character 107 * \s Space character 108 * \n Line feed character 109 * \T Telephone number (defined via `set phone' 110 * \t Tab character 111 */ 112char * 113ExpandString(str, result, sendmode) 114char *str; 115char *result; 116int sendmode; 117{ 118 int addcr = 0; 119 120 if (sendmode) 121 addcr = 1; 122 while (*str) { 123 switch (*str) { 124 case '\\': 125 str++; 126 switch (*str) { 127 case 'c': 128 if (sendmode) 129 addcr = 0; 130 break; 131 case 'd': /* Delay 2 seconds */ 132 sleep(2); break; 133 case 'p': 134 usleep(250000); break; /* Pause 0.25 sec */ 135 case 'n': 136 *result++ = '\n'; break; 137 case 'r': 138 *result++ = '\r'; break; 139 case 's': 140 *result++ = ' '; break; 141 case 't': 142 *result++ = '\t'; break; 143 case 'P': 144 bcopy(VarAuthKey, result, strlen(VarAuthKey)); 145 result += strlen(VarAuthKey); 146 break; 147 case 'T': 148 bcopy(VarPhone, result, strlen(VarPhone)); 149 result += strlen(VarPhone); 150 break; 151 case 'U': 152 bcopy(VarAuthName, result, strlen(VarAuthName)); 153 result += strlen(VarAuthName); 154 break; 155 default: 156 *result++ = *str; break; 157 } 158 if (*str) str++; 159 break; 160 case '^': 161 str++; 162 if (*str) 163 *result++ = *str++ & 0x1f; 164 break; 165 default: 166 *result++ = *str++; 167 break; 168 } 169 } 170 if (addcr) 171 *result++ = '\r'; 172 *result++ = '\0'; 173 return(result); 174} 175 176int 177WaitforString(estr) 178char *estr; 179{ 180#define IBSIZE 200 181 struct timeval timeout; 182 char *s, *str, ch; 183 char *inp; 184 fd_set rfds; 185 int i, nfds; 186 char buff[200]; 187 char inbuff[IBSIZE]; 188 189 (void) ExpandString(estr, buff, 0); 190 LogPrintf(LOG_CHAT, "Wait for (%d): %s --> %s\n", TimeoutSec, estr, buff); 191 str = buff; 192 inp = inbuff; 193 194 nfds = modem + 1; 195 s = str; 196 for (;;) { 197 FD_ZERO(&rfds); 198 FD_SET(modem, &rfds); 199 /* 200 * Because it is not clear whether select() modifies timeout value, 201 * it is better to initialize timeout values everytime. 202 */ 203 timeout.tv_sec = TimeoutSec; 204 timeout.tv_usec = 0; 205 206 i = select(nfds, &rfds, NULL, NULL, &timeout); 207#ifdef notdef 208 TimerService(); 209#endif 210 if (i < 0) { 211 perror("select"); 212 return(NOMATCH); 213 } else if (i == 0) { /* Timeout reached! */ 214 LogPrintf(LOG_CHAT, "can't get (%d).\n", timeout.tv_sec); 215 return(NOMATCH); 216 } 217 if (FD_ISSET(modem, &rfds)) { /* got something */ 218 read(modem, &ch, 1); 219 *inp++ = ch; 220 if (ch == *s) { 221 s++; 222 if (*s == '\0') { 223 return(MATCH); 224 } 225 } else { 226 s = str; 227 if (inp == inbuff+ IBSIZE) { 228 bcopy(inp - 100, inbuff, 100); 229 inp = inbuff + 100; 230 } 231 for (i = 0; i < numaborts; i++) { /* Look for Abort strings */ 232 int len; 233 char *s1; 234 235 s1 = AbortStrings[i]; 236 len = strlen(s1); 237 if ((len <= inp - inbuff) && (strncmp(inp - len, s1, len) == 0)) { 238 LogPrintf(LOG_CHAT, "Abort: %s\n", s1); 239 return(ABORT); 240 } 241 } 242 } 243 } 244 } 245} 246 247void 248SendString(str) 249char *str; 250{ 251 char buff[200]; 252 253 if (abort_next) { 254 abort_next = 0; 255 ExpandString(str, buff, 0); 256 AbortStrings[numaborts++] = strdup(buff); 257 } else if (timeout_next) { 258 timeout_next = 0; 259 TimeoutSec = atoi(str); 260 if (TimeoutSec <= 0) 261 TimeoutSec = 30; 262 } else { 263 (void) ExpandString(str, buff, 1); 264 LogPrintf(LOG_CHAT, "sending: %s\n", buff); 265 write(modem, buff, strlen(buff)); 266 } 267} 268 269int 270ExpectString(str) 271char *str; 272{ 273 char *minus; 274 int state; 275 276 if (strcmp(str, "ABORT") == 0) { 277 ++abort_next; 278 return(MATCH); 279 } 280 if (strcmp(str, "TIMEOUT") == 0) { 281 ++timeout_next; 282 return(MATCH); 283 } 284 LogPrintf(LOG_CHAT, "Expecting %s\n", str); 285 while (*str) { 286 /* 287 * Check whether if string contains sub-send-expect. 288 */ 289 for (minus = str; *minus; minus++) { 290 if (*minus == '-') { 291 if (minus == str || minus[-1] != '\\') 292 break; 293 } 294 } 295 if (*minus == '-') { /* We have sub-send-expect. */ 296 *minus++ = '\0'; 297 state = WaitforString(str); 298 if (state != NOMATCH) 299 return(state); 300 /* 301 * Can't get expect string. Sendout send part. 302 */ 303 str = minus; 304 for (minus = str; *minus; minus++) { 305 if (*minus == '-') { 306 if (minus == str || minus[-1] != '\\') 307 break; 308 } 309 } 310 if (*minus == '-') { 311 *minus++ = '\0'; 312 SendString(str); 313 str = minus; 314 } else { 315 SendString(str); 316 return(MATCH); 317 } 318 } else { 319 /* 320 * Simple case. Wait for string. 321 */ 322 return(WaitforString(str)); 323 } 324 } 325 return(MATCH); 326} 327 328int 329DoChat(script) 330char *script; 331{ 332 char *vector[20]; 333 char **argv; 334 int argc, n, state; 335#ifdef DEBUG 336 int i; 337#endif 338 339 timeout_next = abort_next = 0; 340 for (n = 0; AbortStrings[n]; n++) { 341 free(AbortStrings[n]); 342 AbortStrings[n] = NULL; 343 } 344 numaborts = 0; 345 346 bzero(vector, sizeof(vector)); 347 n = MakeArgs(script, &vector); 348#ifdef DEBUG 349 logprintf("n = %d\n", n); 350 for (i = 0; i < n; i++) 351 logprintf(" %s\n", vector[i]); 352#endif 353 argc = n; 354 argv = vector; 355 TimeoutSec = 30; 356 while (*argv) { 357 if (strcmp(*argv, "P_ZERO") == 0 || 358 strcmp(*argv, "P_ODD") == 0 || strcmp(*argv, "P_EVEN") == 0) { 359 ChangeParity(*argv++); 360 continue; 361 } 362 state = ExpectString(*argv++); 363 switch (state) { 364 case MATCH: 365 if (*argv) 366 SendString(*argv++); 367 break; 368 case ABORT: 369#ifdef notdef 370 HangupModem(); 371#endif 372 case NOMATCH: 373 return(NOMATCH); 374 } 375 } 376 return(MATCH); 377} 378