Advertisement
Guest User

Untitled

a guest
May 18th, 2017
668
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 30.57 KB | None | 0 0
  1. /*
  2. * Chat -- a program for automatic session establishment (i.e. dial
  3. * the phone and log in).
  4. *
  5. * Standard termination codes:
  6. * 0 - successful completion of the script
  7. * 1 - invalid argument, expect string too large, etc.
  8. * 2 - error on an I/O operation or fatal error condition.
  9. * 3 - timeout waiting for a simple string.
  10. * 4 - the first string declared as "ABORT"
  11. * 5 - the second string declared as "ABORT"
  12. * 6 - ... and so on for successive ABORT strings.
  13. *
  14. * This software is in the public domain.
  15. *
  16. * -----------------
  17. * added -T and -U option and \T and \U substitution to pass a phone
  18. * number into chat script. Two are needed for some ISDN TA applications.
  19. * Keith Dart <kdart@cisco.com>
  20. *
  21. *
  22. * Added SAY keyword to send output to stderr.
  23. * This allows to turn ECHO OFF and to output specific, user selected,
  24. * text to give progress messages. This best works when stderr
  25. * exists (i.e.: pppd in nodetach mode).
  26. *
  27. * Added HANGUP directives to allow for us to be called
  28. * back. When HANGUP is set to NO, chat will not hangup at HUP signal.
  29. * We rely on timeouts in that case.
  30. *
  31. * Added CLR_ABORT to clear previously set ABORT string. This has been
  32. * dictated by the HANGUP above as "NO CARRIER" (for example) must be
  33. * an ABORT condition until we know the other host is going to close
  34. * the connection for call back. As soon as we have completed the
  35. * first stage of the call back sequence, "NO CARRIER" is a valid, non
  36. * fatal string. As soon as we got called back (probably get "CONNECT"),
  37. * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command.
  38. * Note that CLR_ABORT packs the abort_strings[] array so that we do not
  39. * have unused entries not being reclaimed.
  40. *
  41. * In the same vein as above, added CLR_REPORT keyword.
  42. *
  43. * Allow for comments. Line starting with '#' are comments and are
  44. * ignored. If a '#' is to be expected as the first character, the
  45. * expect string must be quoted.
  46. *
  47. *
  48. * Francis Demierre <Francis@SwissMail.Com>
  49. * Thu May 15 17:15:40 MET DST 1997
  50. *
  51. *
  52. * Added -r "report file" switch & REPORT keyword.
  53. * Robert Geer <bgeer@xmission.com>
  54. *
  55. * Added -s "use stderr" and -S "don't use syslog" switches.
  56. * June 18, 1997
  57. * Karl O. Pinc <kop@meme.com>
  58. *
  59. *
  60. * Added -e "echo" switch & ECHO keyword
  61. * Dick Streefland <dicks@tasking.nl>
  62. *
  63. *
  64. * Considerable updates and modifications by
  65. * Al Longyear <longyear@pobox.com>
  66. * Paul Mackerras <paulus@cs.anu.edu.au>
  67. *
  68. *
  69. * The original author is:
  70. *
  71. * Karl Fox <karl@MorningStar.Com>
  72. * Morning Star Technologies, Inc.
  73. * 1760 Zollinger Road
  74. * Columbus, OH 43221
  75. * (614)451-1883
  76. *
  77. *
  78. */
  79.  
  80. #include <sys/cdefs.h>
  81. __FBSDID("$FreeBSD: src/usr.bin/chat/chat.c,v 1.21 2003/10/31 06:22:03 kientzle Exp $");
  82.  
  83. #include <sys/types.h>
  84. #include <sys/stat.h>
  85. #include <ctype.h>
  86. #include <errno.h>
  87. #include <fcntl.h>
  88. #include <signal.h>
  89. #include <stdarg.h>
  90. #include <stdio.h>
  91. #include <stdlib.h>
  92. #include <string.h>
  93. #include <syslog.h>
  94. #include <termios.h>
  95. #include <time.h>
  96. #include <unistd.h>
  97.  
  98. #define STR_LEN 1024
  99.  
  100. #ifndef SIGTYPE
  101. #define SIGTYPE void
  102. #endif
  103.  
  104. #ifndef O_NONBLOCK
  105. #define O_NONBLOCK O_NDELAY
  106. #endif
  107.  
  108. /*************** Micro getopt() *********************************************/
  109. #define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
  110. (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
  111. &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
  112. #define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
  113. (_O=4,(char*)0):(char*)0)
  114. #define ARG(c,v) (c?(--c,*v++):(char*)0)
  115.  
  116. static int _O = 0; /* Internal state */
  117. /*************** Micro getopt() *********************************************/
  118.  
  119. #define MAX_ABORTS 50
  120. #define MAX_REPORTS 50
  121. #define DEFAULT_CHAT_TIMEOUT 45
  122.  
  123. int echo = 0;
  124. int verbose = 0;
  125. int to_log = 1;
  126. int to_stderr = 0;
  127. int Verbose = 0;
  128. int quiet = 0;
  129. int exit_code = 0;
  130. FILE* report_fp = (FILE *) 0;
  131. char *report_file = (char *) 0;
  132. char *chat_file = (char *) 0;
  133. char *phone_num = (char *) 0;
  134. char *phone_num2 = (char *) 0;
  135. int timeout = DEFAULT_CHAT_TIMEOUT;
  136.  
  137. static char blank[] = "";
  138.  
  139. int have_tty_parameters = 0;
  140.  
  141. #define term_parms struct termios
  142. #define get_term_param(param) tcgetattr(0, param)
  143. #define set_term_param(param) tcsetattr(0, TCSANOW, param)
  144. struct termios saved_tty_parameters;
  145.  
  146. char *abort_string[MAX_ABORTS], *fail_reason = (char *)0,
  147. fail_buffer[50];
  148. int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0;
  149. int clear_abort_next = 0;
  150.  
  151. char *report_string[MAX_REPORTS] ;
  152. char report_buffer[50] ;
  153. int n_reports = 0, report_next = 0, report_gathering = 0 ;
  154. int clear_report_next = 0;
  155.  
  156. int say_next = 0, hup_next = 0;
  157.  
  158. void *dup_mem(void *b, size_t c);
  159. void *copy_of(char *s);
  160. static void usage(void);
  161. void chat_logf(const char *fmt, ...);
  162. void fatal(int code, const char *fmt, ...);
  163. SIGTYPE sigalrm(int signo);
  164. SIGTYPE sigint(int signo);
  165. SIGTYPE sigterm(int signo);
  166. SIGTYPE sighup(int signo);
  167. void init(void);
  168. void set_tty_parameters(void);
  169. void echo_stderr(int);
  170. void break_sequence(void);
  171. void terminate(int status);
  172. void do_file(char *chatfile);
  173. int get_string(char *string);
  174. int put_string(char *s);
  175. int write_char(int c);
  176. int put_char(int c);
  177. int get_char(void);
  178. void chat_send(char *s);
  179. char *character(int c);
  180. void chat_expect(char *s);
  181. char *clean(char *s, int sending);
  182. void pack_array(char **array, int end);
  183. char *expect_strtok(char *, const char *);
  184. int vfmtmsg(char *, int, const char *, va_list); /* vsprintf++ */
  185.  
  186. void *
  187. dup_mem(void *b, size_t c)
  188. {
  189. void *ans = malloc (c);
  190. if (!ans)
  191. fatal(2, "memory error!");
  192.  
  193. memcpy (ans, b, c);
  194. return ans;
  195. }
  196.  
  197. void *
  198. copy_of(char *s)
  199. {
  200. return dup_mem (s, strlen (s) + 1);
  201. }
  202.  
  203. /*
  204. * chat [ -v ] [-T number] [-U number] [ -t timeout ] [ -f chat-file ] \
  205. * [ -r report-file ] \
  206. * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
  207. *
  208. * Perform a UUCP-dialer-like chat script on stdin and stdout.
  209. */
  210. int
  211. main(int argc, char *argv[])
  212. {
  213. int option;
  214. char *arg;
  215.  
  216. tzset();
  217.  
  218. while ((option = OPTION(argc, argv)) != 0) {
  219. switch (option) {
  220. case 'e':
  221. ++echo;
  222. break;
  223.  
  224. case 'v':
  225. ++verbose;
  226. break;
  227.  
  228. case 'V':
  229. ++Verbose;
  230. break;
  231.  
  232. case 's':
  233. ++to_stderr;
  234. break;
  235.  
  236. case 'S':
  237. to_log = 0;
  238. break;
  239.  
  240. case 'f':
  241. if ((arg = OPTARG(argc, argv)) != NULL)
  242. chat_file = copy_of(arg);
  243. else
  244. usage();
  245. break;
  246.  
  247. case 't':
  248. if ((arg = OPTARG(argc, argv)) != NULL)
  249. timeout = atoi(arg);
  250. else
  251. usage();
  252. break;
  253.  
  254. case 'r':
  255. arg = OPTARG (argc, argv);
  256. if (arg) {
  257. if (report_fp != NULL)
  258. fclose (report_fp);
  259. report_file = copy_of (arg);
  260. report_fp = fopen (report_file, "a");
  261. if (report_fp != NULL) {
  262. if (verbose)
  263. fprintf (report_fp, "Opening \"%s\"...\n",
  264. report_file);
  265. }
  266. }
  267. break;
  268.  
  269. case 'T':
  270. if ((arg = OPTARG(argc, argv)) != NULL)
  271. phone_num = copy_of(arg);
  272. else
  273. usage();
  274. break;
  275.  
  276. case 'U':
  277. if ((arg = OPTARG(argc, argv)) != NULL)
  278. phone_num2 = copy_of(arg);
  279. else
  280. usage();
  281. break;
  282.  
  283. default:
  284. usage();
  285. break;
  286. }
  287. }
  288. /*
  289. * Default the report file to the stderr location
  290. */
  291. if (report_fp == NULL)
  292. report_fp = stderr;
  293.  
  294. if (to_log) {
  295. openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2);
  296.  
  297. if (verbose)
  298. setlogmask(LOG_UPTO(LOG_INFO));
  299. else
  300. setlogmask(LOG_UPTO(LOG_WARNING));
  301. }
  302.  
  303. init();
  304.  
  305. if (chat_file != NULL) {
  306. arg = ARG(argc, argv);
  307. if (arg != NULL)
  308. usage();
  309. else
  310. do_file (chat_file);
  311. } else {
  312. while ((arg = ARG(argc, argv)) != NULL) {
  313. chat_expect(arg);
  314.  
  315. if ((arg = ARG(argc, argv)) != NULL)
  316. chat_send(arg);
  317. }
  318. }
  319.  
  320. terminate(0);
  321. return 0;
  322. }
  323.  
  324. /*
  325. * Process a chat script when read from a file.
  326. */
  327.  
  328. void
  329. do_file(char *chatfile)
  330. {
  331. int linect, sendflg;
  332. char *sp, *arg, quote;
  333. char buf [STR_LEN];
  334. FILE *cfp;
  335.  
  336. cfp = fopen (chatfile, "r");
  337. if (cfp == NULL)
  338. fatal(1, "%s -- open failed: %m", chatfile);
  339.  
  340. linect = 0;
  341. sendflg = 0;
  342.  
  343. while (fgets(buf, STR_LEN, cfp) != NULL) {
  344. sp = strchr (buf, '\n');
  345. if (sp)
  346. *sp = '\0';
  347.  
  348. linect++;
  349. sp = buf;
  350.  
  351. /* lines starting with '#' are comments. If a real '#'
  352. is to be expected, it should be quoted .... */
  353. if ( *sp == '#' )
  354. continue;
  355.  
  356. while (*sp != '\0') {
  357. if (*sp == ' ' || *sp == '\t') {
  358. ++sp;
  359. continue;
  360. }
  361.  
  362. if (*sp == '"' || *sp == '\'') {
  363. quote = *sp++;
  364. arg = sp;
  365. while (*sp != quote) {
  366. if (*sp == '\0')
  367. fatal(1, "unterminated quote (line %d)", linect);
  368.  
  369. if (*sp++ == '\\') {
  370. if (*sp != '\0')
  371. ++sp;
  372. }
  373. }
  374. }
  375. else {
  376. arg = sp;
  377. while (*sp != '\0' && *sp != ' ' && *sp != '\t')
  378. ++sp;
  379. }
  380.  
  381. if (*sp != '\0')
  382. *sp++ = '\0';
  383.  
  384. if (sendflg)
  385. chat_send (arg);
  386. else
  387. chat_expect (arg);
  388. sendflg = !sendflg;
  389. }
  390. }
  391. fclose (cfp);
  392. }
  393.  
  394. /*
  395. * We got an error parsing the command line.
  396. */
  397. static void
  398. usage(void)
  399. {
  400. fprintf(stderr, "\
  401. Usage: chat [-e] [-v] [-V] [-t timeout] [-r report-file] [-T phone-number]\n\
  402. [-U phone-number2] {-f chat-file | chat-script}\n");
  403. exit(1);
  404. }
  405.  
  406. char line[1024];
  407.  
  408. /*
  409. * Send a message to syslog and/or stderr.
  410. */
  411. void
  412. chat_logf(const char *fmt, ...)
  413. {
  414. va_list args;
  415.  
  416. va_start(args, fmt);
  417. vfmtmsg(line, sizeof(line), fmt, args);
  418. if (to_log)
  419. syslog(LOG_INFO, "%s", line);
  420. if (to_stderr)
  421. fprintf(stderr, "%s\n", line);
  422. }
  423.  
  424. /*
  425. * Print an error message and terminate.
  426. */
  427.  
  428. void
  429. fatal(int code, const char *fmt, ...)
  430. {
  431. va_list args;
  432.  
  433. va_start(args, fmt);
  434. vfmtmsg(line, sizeof(line), fmt, args);
  435. if (to_log)
  436. syslog(LOG_ERR, "%s", line);
  437. if (to_stderr)
  438. fprintf(stderr, "%s\n", line);
  439. terminate(code);
  440. }
  441.  
  442. int alarmed = 0;
  443.  
  444. SIGTYPE sigalrm(int signo __unused)
  445. {
  446. int flags;
  447.  
  448. alarm(1);
  449. alarmed = 1; /* Reset alarm to avoid race window */
  450. signal(SIGALRM, sigalrm); /* that can cause hanging in read() */
  451.  
  452. if ((flags = fcntl(0, F_GETFL, 0)) == -1)
  453. fatal(2, "Can't get file mode flags on stdin: %m");
  454.  
  455. if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
  456. fatal(2, "Can't set file mode flags on stdin: %m");
  457.  
  458. if (verbose)
  459. chat_logf("alarm");
  460. }
  461.  
  462. SIGTYPE sigint(int signo __unused)
  463. {
  464. fatal(2, "SIGINT");
  465. }
  466.  
  467. SIGTYPE sigterm(int signo __unused)
  468. {
  469. fatal(2, "SIGTERM");
  470. }
  471.  
  472. SIGTYPE sighup(int signo __unused)
  473. {
  474. fatal(2, "SIGHUP");
  475. }
  476.  
  477. void init(void)
  478. {
  479. signal(SIGINT, sigint);
  480. signal(SIGTERM, sigterm);
  481. signal(SIGHUP, sighup);
  482.  
  483. set_tty_parameters();
  484. signal(SIGALRM, sigalrm);
  485. alarm(0);
  486. alarmed = 0;
  487. }
  488.  
  489. void set_tty_parameters(void)
  490. {
  491. #if defined(get_term_param)
  492. term_parms t;
  493.  
  494. if (get_term_param (&t) < 0)
  495. fatal(2, "Can't get terminal parameters: %m");
  496.  
  497. saved_tty_parameters = t;
  498. have_tty_parameters = 1;
  499.  
  500. t.c_iflag |= IGNBRK | ISTRIP | IGNPAR;
  501. t.c_oflag = 0;
  502. t.c_lflag = 0;
  503. t.c_cc[VERASE] =
  504. t.c_cc[VKILL] = 0;
  505. t.c_cc[VMIN] = 1;
  506. t.c_cc[VTIME] = 0;
  507.  
  508. if (set_term_param (&t) < 0)
  509. fatal(2, "Can't set terminal parameters: %m");
  510. #endif
  511. }
  512.  
  513. void break_sequence(void)
  514. {
  515. tcsendbreak (0, 0);
  516. }
  517.  
  518. void terminate(int status)
  519. {
  520. echo_stderr(-1);
  521. if (report_file != (char *) 0 && report_fp != (FILE *) NULL) {
  522. /*
  523. * Allow the last of the report string to be gathered before we terminate.
  524. */
  525. if (report_gathering) {
  526. int c;
  527. size_t rep_len;
  528.  
  529. rep_len = strlen(report_buffer);
  530. while (rep_len + 1 <= sizeof(report_buffer)) {
  531. alarm(1);
  532. c = get_char();
  533. alarm(0);
  534. if (c < 0 || iscntrl(c))
  535. break;
  536. report_buffer[rep_len] = c;
  537. ++rep_len;
  538. }
  539. report_buffer[rep_len] = 0;
  540. fprintf (report_fp, "chat: %s\n", report_buffer);
  541. }
  542. if (verbose)
  543. fprintf (report_fp, "Closing \"%s\".\n", report_file);
  544. fclose (report_fp);
  545. report_fp = (FILE *) NULL;
  546. }
  547.  
  548. #if defined(get_term_param)
  549. if (have_tty_parameters) {
  550. if (set_term_param (&saved_tty_parameters) < 0)
  551. fatal(2, "Can't restore terminal parameters: %m");
  552. }
  553. #endif
  554.  
  555. exit(status);
  556. }
  557.  
  558. /*
  559. * 'Clean up' this string.
  560. */
  561. char *
  562. clean(char *s, int sending)
  563. {
  564. char temp[STR_LEN], cur_chr;
  565. char *s1, *phchar;
  566. int add_return = sending;
  567. #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
  568.  
  569. s1 = temp;
  570. /* Don't overflow buffer, leave room for chars we append later */
  571. while (*s && s1 - temp < (off_t)(sizeof(temp) - 2 - add_return)) {
  572. cur_chr = *s++;
  573. if (cur_chr == '^') {
  574. cur_chr = *s++;
  575. if (cur_chr == '\0') {
  576. *s1++ = '^';
  577. break;
  578. }
  579. cur_chr &= 0x1F;
  580. if (cur_chr != 0) {
  581. *s1++ = cur_chr;
  582. }
  583. continue;
  584. }
  585.  
  586. if (cur_chr != '\\') {
  587. *s1++ = cur_chr;
  588. continue;
  589. }
  590.  
  591. cur_chr = *s++;
  592. if (cur_chr == '\0') {
  593. if (sending) {
  594. *s1++ = '\\';
  595. *s1++ = '\\';
  596. }
  597. break;
  598. }
  599.  
  600. switch (cur_chr) {
  601. case 'b':
  602. *s1++ = '\b';
  603. break;
  604.  
  605. case 'c':
  606. if (sending && *s == '\0')
  607. add_return = 0;
  608. else
  609. *s1++ = cur_chr;
  610. break;
  611.  
  612. case '\\':
  613. case 'K':
  614. case 'p':
  615. case 'd':
  616. if (sending)
  617. *s1++ = '\\';
  618.  
  619. *s1++ = cur_chr;
  620. break;
  621.  
  622. case 'T':
  623. if (sending && phone_num) {
  624. for ( phchar = phone_num; *phchar != '\0'; phchar++)
  625. *s1++ = *phchar;
  626. }
  627. else {
  628. *s1++ = '\\';
  629. *s1++ = 'T';
  630. }
  631. break;
  632.  
  633. case 'U':
  634. if (sending && phone_num2) {
  635. for ( phchar = phone_num2; *phchar != '\0'; phchar++)
  636. *s1++ = *phchar;
  637. }
  638. else {
  639. *s1++ = '\\';
  640. *s1++ = 'U';
  641. }
  642. break;
  643.  
  644. case 'q':
  645. quiet = 1;
  646. break;
  647.  
  648. case 'r':
  649. *s1++ = '\r';
  650. break;
  651.  
  652. case 'n':
  653. *s1++ = '\n';
  654. break;
  655.  
  656. case 's':
  657. *s1++ = ' ';
  658. break;
  659.  
  660. case 't':
  661. *s1++ = '\t';
  662. break;
  663.  
  664. case 'N':
  665. if (sending) {
  666. *s1++ = '\\';
  667. *s1++ = '\0';
  668. }
  669. else
  670. *s1++ = 'N';
  671. break;
  672.  
  673. default:
  674. if (isoctal (cur_chr)) {
  675. cur_chr &= 0x07;
  676. if (isoctal (*s)) {
  677. cur_chr <<= 3;
  678. cur_chr |= *s++ - '0';
  679. if (isoctal (*s)) {
  680. cur_chr <<= 3;
  681. cur_chr |= *s++ - '0';
  682. }
  683. }
  684.  
  685. if (cur_chr != 0 || sending) {
  686. if (sending && (cur_chr == '\\' || cur_chr == 0))
  687. *s1++ = '\\';
  688. *s1++ = cur_chr;
  689. }
  690. break;
  691. }
  692.  
  693. if (sending)
  694. *s1++ = '\\';
  695. *s1++ = cur_chr;
  696. break;
  697. }
  698. }
  699.  
  700. if (add_return)
  701. *s1++ = '\r';
  702.  
  703. *s1++ = '\0'; /* guarantee closure */
  704. *s1++ = '\0'; /* terminate the string */
  705. return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
  706. }
  707.  
  708. /*
  709. * A modified version of 'strtok'. This version skips \ sequences.
  710. */
  711.  
  712. char *
  713. expect_strtok (char *s, const char *term)
  714. {
  715. static char *str = blank;
  716. int escape_flag = 0;
  717. char *result;
  718.  
  719. /*
  720. * If a string was specified then do initial processing.
  721. */
  722. if (s)
  723. str = s;
  724.  
  725. /*
  726. * If this is the escape flag then reset it and ignore the character.
  727. */
  728. if (*str)
  729. result = str;
  730. else
  731. result = (char *) 0;
  732.  
  733. while (*str) {
  734. if (escape_flag) {
  735. escape_flag = 0;
  736. ++str;
  737. continue;
  738. }
  739.  
  740. if (*str == '\\') {
  741. ++str;
  742. escape_flag = 1;
  743. continue;
  744. }
  745.  
  746. /*
  747. * If this is not in the termination string, continue.
  748. */
  749. if (strchr (term, *str) == (char *) 0) {
  750. ++str;
  751. continue;
  752. }
  753.  
  754. /*
  755. * This is the terminator. Mark the end of the string and stop.
  756. */
  757. *str++ = '\0';
  758. break;
  759. }
  760. return (result);
  761. }
  762.  
  763. /*
  764. * Process the expect string
  765. */
  766.  
  767. void
  768. chat_expect(char *s)
  769. {
  770. char *expect;
  771. char *reply;
  772.  
  773. if (strcmp(s, "HANGUP") == 0) {
  774. ++hup_next;
  775. return;
  776. }
  777.  
  778. if (strcmp(s, "ABORT") == 0) {
  779. ++abort_next;
  780. return;
  781. }
  782.  
  783. if (strcmp(s, "CLR_ABORT") == 0) {
  784. ++clear_abort_next;
  785. return;
  786. }
  787.  
  788. if (strcmp(s, "REPORT") == 0) {
  789. ++report_next;
  790. return;
  791. }
  792.  
  793. if (strcmp(s, "CLR_REPORT") == 0) {
  794. ++clear_report_next;
  795. return;
  796. }
  797.  
  798. if (strcmp(s, "TIMEOUT") == 0) {
  799. ++timeout_next;
  800. return;
  801. }
  802.  
  803. if (strcmp(s, "ECHO") == 0) {
  804. ++echo_next;
  805. return;
  806. }
  807.  
  808. if (strcmp(s, "SAY") == 0) {
  809. ++say_next;
  810. return;
  811. }
  812.  
  813. /*
  814. * Fetch the expect and reply string.
  815. */
  816. for (;;) {
  817. expect = expect_strtok (s, "-");
  818. s = (char *) 0;
  819.  
  820. if (expect == (char *) 0)
  821. return;
  822.  
  823. reply = expect_strtok (s, "-");
  824.  
  825. /*
  826. * Handle the expect string. If successful then exit.
  827. */
  828. if (get_string (expect))
  829. return;
  830.  
  831. /*
  832. * If there is a sub-reply string then send it. Otherwise any condition
  833. * is terminal.
  834. */
  835. if (reply == (char *) 0 || exit_code != 3)
  836. break;
  837.  
  838. chat_send (reply);
  839. }
  840.  
  841. /*
  842. * The expectation did not occur. This is terminal.
  843. */
  844. if (fail_reason)
  845. chat_logf("Failed (%s)", fail_reason);
  846. else
  847. chat_logf("Failed");
  848. terminate(exit_code);
  849. }
  850.  
  851. /*
  852. * Translate the input character to the appropriate string for printing
  853. * the data.
  854. */
  855.  
  856. char *
  857. character(int c)
  858. {
  859. static char string[10];
  860. const char *meta;
  861.  
  862. meta = (c & 0x80) ? "M-" : "";
  863. c &= 0x7F;
  864.  
  865. if (c < 32)
  866. sprintf(string, "%s^%c", meta, (int)c + '@');
  867. else if (c == 127)
  868. sprintf(string, "%s^?", meta);
  869. else
  870. sprintf(string, "%s%c", meta, c);
  871.  
  872. return (string);
  873. }
  874.  
  875. /*
  876. * process the reply string
  877. */
  878. void
  879. chat_send(char *s)
  880. {
  881. if (say_next) {
  882. say_next = 0;
  883. s = clean(s,0);
  884. write(STDERR_FILENO, s, strlen(s));
  885. free(s);
  886. return;
  887. }
  888.  
  889. if (hup_next) {
  890. hup_next = 0;
  891. if (strcmp(s, "OFF") == 0)
  892. signal(SIGHUP, SIG_IGN);
  893. else
  894. signal(SIGHUP, sighup);
  895. return;
  896. }
  897.  
  898. if (echo_next) {
  899. echo_next = 0;
  900. echo = (strcmp(s, "ON") == 0);
  901. return;
  902. }
  903.  
  904. if (abort_next) {
  905. char *s1;
  906.  
  907. abort_next = 0;
  908.  
  909. if (n_aborts >= MAX_ABORTS)
  910. fatal(2, "Too many ABORT strings");
  911.  
  912. s1 = clean(s, 0);
  913.  
  914. if (strlen(s1) > strlen(s)
  915. || strlen(s1) + 1 > sizeof(fail_buffer))
  916. fatal(1, "Illegal or too-long ABORT string ('%v')", s);
  917.  
  918. abort_string[n_aborts++] = s1;
  919.  
  920. if (verbose)
  921. chat_logf("abort on (%v)", s);
  922. return;
  923. }
  924.  
  925. if (clear_abort_next) {
  926. char *s1;
  927. int i;
  928. int old_max;
  929. int pack = 0;
  930.  
  931. clear_abort_next = 0;
  932.  
  933. s1 = clean(s, 0);
  934.  
  935. if (strlen(s1) > strlen(s)
  936. || strlen(s1) + 1 > sizeof(fail_buffer))
  937. fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s);
  938.  
  939. old_max = n_aborts;
  940. for (i=0; i < n_aborts; i++) {
  941. if ( strcmp(s1,abort_string[i]) == 0 ) {
  942. free(abort_string[i]);
  943. abort_string[i] = NULL;
  944. pack++;
  945. n_aborts--;
  946. if (verbose)
  947. chat_logf("clear abort on (%v)", s);
  948. }
  949. }
  950. free(s1);
  951. if (pack)
  952. pack_array(abort_string,old_max);
  953. return;
  954. }
  955.  
  956. if (report_next) {
  957. char *s1;
  958.  
  959. report_next = 0;
  960. if (n_reports >= MAX_REPORTS)
  961. fatal(2, "Too many REPORT strings");
  962.  
  963. s1 = clean(s, 0);
  964.  
  965. if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
  966. fatal(1, "Illegal or too-long REPORT string ('%v')", s);
  967.  
  968. report_string[n_reports++] = s1;
  969.  
  970. if (verbose)
  971. chat_logf("report (%v)", s);
  972. return;
  973. }
  974.  
  975. if (clear_report_next) {
  976. char *s1;
  977. int i;
  978. int old_max;
  979. int pack = 0;
  980.  
  981. clear_report_next = 0;
  982.  
  983. s1 = clean(s, 0);
  984.  
  985. if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
  986. fatal(1, "Illegal or too-long REPORT string ('%v')", s);
  987.  
  988. old_max = n_reports;
  989. for (i=0; i < n_reports; i++) {
  990. if ( strcmp(s1,report_string[i]) == 0 ) {
  991. free(report_string[i]);
  992. report_string[i] = NULL;
  993. pack++;
  994. n_reports--;
  995. if (verbose)
  996. chat_logf("clear report (%v)", s);
  997. }
  998. }
  999. free(s1);
  1000. if (pack)
  1001. pack_array(report_string,old_max);
  1002.  
  1003. return;
  1004. }
  1005.  
  1006. if (timeout_next) {
  1007. timeout_next = 0;
  1008. timeout = atoi(s);
  1009.  
  1010. if (timeout <= 0)
  1011. timeout = DEFAULT_CHAT_TIMEOUT;
  1012.  
  1013. if (verbose)
  1014. chat_logf("timeout set to %d seconds", timeout);
  1015.  
  1016. return;
  1017. }
  1018.  
  1019. if (strcmp(s, "EOT") == 0)
  1020. s = strdup("^D\\c");
  1021. else if (strcmp(s, "BREAK") == 0)
  1022. s = strdup("\\K\\c");
  1023.  
  1024. if (!put_string(s))
  1025. fatal(1, "Failed");
  1026. }
  1027.  
  1028. int
  1029. get_char(void)
  1030. {
  1031. int status;
  1032. char c;
  1033.  
  1034. status = read(STDIN_FILENO, &c, 1);
  1035.  
  1036. switch (status) {
  1037. case 1:
  1038. return ((int)c & 0x7F);
  1039.  
  1040. default:
  1041. chat_logf("warning: read() on stdin returned %d", status);
  1042.  
  1043. case -1:
  1044. if ((status = fcntl(0, F_GETFL, 0)) == -1)
  1045. fatal(2, "Can't get file mode flags on stdin: %m");
  1046.  
  1047. if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
  1048. fatal(2, "Can't set file mode flags on stdin: %m");
  1049.  
  1050. return (-1);
  1051. }
  1052. }
  1053.  
  1054. int put_char(int c)
  1055. {
  1056. int status;
  1057. char ch = c;
  1058.  
  1059. usleep(10000); /* inter-character typing delay (?) */
  1060.  
  1061. status = write(STDOUT_FILENO, &ch, 1);
  1062.  
  1063. switch (status) {
  1064. case 1:
  1065. return (0);
  1066.  
  1067. default:
  1068. chat_logf("warning: write() on stdout returned %d", status);
  1069.  
  1070. case -1:
  1071. if ((status = fcntl(0, F_GETFL, 0)) == -1)
  1072. fatal(2, "Can't get file mode flags on stdin, %m");
  1073.  
  1074. if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
  1075. fatal(2, "Can't set file mode flags on stdin: %m");
  1076.  
  1077. return (-1);
  1078. }
  1079. }
  1080.  
  1081. int
  1082. write_char(int c)
  1083. {
  1084. if (alarmed || put_char(c) < 0) {
  1085. alarm(0);
  1086. alarmed = 0;
  1087.  
  1088. if (verbose) {
  1089. if (errno == EINTR || errno == EWOULDBLOCK)
  1090. chat_logf(" -- write timed out");
  1091. else
  1092. chat_logf(" -- write failed: %m");
  1093. }
  1094. return (0);
  1095. }
  1096. return (1);
  1097. }
  1098.  
  1099. int
  1100. put_string(char *s)
  1101. {
  1102. quiet = 0;
  1103. s = clean(s, 1);
  1104.  
  1105. if (verbose)
  1106. chat_logf("send (%v)", quiet ? "??????" : s);
  1107.  
  1108. alarm(timeout); alarmed = 0;
  1109.  
  1110. while (*s) {
  1111. char c = *s++;
  1112.  
  1113. if (c != '\\') {
  1114. if (!write_char (c))
  1115. return 0;
  1116. continue;
  1117. }
  1118.  
  1119. c = *s++;
  1120. switch (c) {
  1121. case 'd':
  1122. sleep(1);
  1123. break;
  1124.  
  1125. case 'K':
  1126. break_sequence();
  1127. break;
  1128.  
  1129. case 'p':
  1130. usleep(10000); /* 1/100th of a second (arg is microseconds) */
  1131. break;
  1132.  
  1133. default:
  1134. if (!write_char (c))
  1135. return 0;
  1136. break;
  1137. }
  1138. }
  1139.  
  1140. alarm(0);
  1141. alarmed = 0;
  1142. return (1);
  1143. }
  1144.  
  1145. /*
  1146. * Echo a character to stderr.
  1147. * When called with -1, a '\n' character is generated when
  1148. * the cursor is not at the beginning of a line.
  1149. */
  1150. void
  1151. echo_stderr(int n)
  1152. {
  1153. static int need_lf;
  1154. char *s;
  1155.  
  1156. switch (n) {
  1157. case '\r': /* ignore '\r' */
  1158. break;
  1159. case -1:
  1160. if (need_lf == 0)
  1161. break;
  1162. /* FALLTHROUGH */
  1163. case '\n':
  1164. write(STDERR_FILENO, "\n", 1);
  1165. need_lf = 0;
  1166. break;
  1167. default:
  1168. s = character(n);
  1169. write(STDERR_FILENO, s, strlen(s));
  1170. need_lf = 1;
  1171. break;
  1172. }
  1173. }
  1174.  
  1175. /*
  1176. * 'Wait for' this string to appear on this file descriptor.
  1177. */
  1178. int
  1179. get_string(char *string)
  1180. {
  1181. char temp[STR_LEN];
  1182. int c, printed = 0;
  1183. size_t len, minlen;
  1184. char *s = temp, *end = s + STR_LEN;
  1185. char *logged = temp;
  1186.  
  1187. fail_reason = (char *)0;
  1188.  
  1189. if (strlen(string) > STR_LEN) {
  1190. chat_logf("expect string is too long");
  1191. exit_code = 1;
  1192. return 0;
  1193. }
  1194.  
  1195. string = clean(string, 0);
  1196. len = strlen(string);
  1197. minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
  1198.  
  1199. if (verbose)
  1200. chat_logf("expect (%v)", string);
  1201.  
  1202. if (len == 0) {
  1203. if (verbose)
  1204. chat_logf("got it");
  1205. return (1);
  1206. }
  1207.  
  1208. alarm(timeout);
  1209. alarmed = 0;
  1210.  
  1211. while ( ! alarmed && (c = get_char()) >= 0) {
  1212. int n, abort_len, report_len;
  1213.  
  1214. if (echo)
  1215. echo_stderr(c);
  1216. if (verbose && c == '\n') {
  1217. if (s == logged)
  1218. chat_logf(""); /* blank line */
  1219. else
  1220. chat_logf("%0.*v", s - logged, logged);
  1221. logged = s + 1;
  1222. }
  1223.  
  1224. *s++ = c;
  1225.  
  1226. if (verbose && s >= logged + 80) {
  1227. chat_logf("%0.*v", s - logged, logged);
  1228. logged = s;
  1229. }
  1230.  
  1231. if (Verbose) {
  1232. if (c == '\n')
  1233. fputc( '\n', stderr );
  1234. else if (c != '\r')
  1235. fprintf( stderr, "%s", character(c) );
  1236. }
  1237.  
  1238. if (!report_gathering) {
  1239. for (n = 0; n < n_reports; ++n) {
  1240. if ((report_string[n] != (char*) NULL) &&
  1241. s - temp >= (report_len = strlen(report_string[n])) &&
  1242. strncmp(s - report_len, report_string[n], report_len) == 0) {
  1243. time_t time_now = time ((time_t*) NULL);
  1244. struct tm* tm_now = localtime (&time_now);
  1245.  
  1246. strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now);
  1247. strcat (report_buffer, report_string[n]);
  1248.  
  1249. report_string[n] = (char *) NULL;
  1250. report_gathering = 1;
  1251. break;
  1252. }
  1253. }
  1254. }
  1255. else {
  1256. if (!iscntrl (c)) {
  1257. int rep_len = strlen (report_buffer);
  1258. report_buffer[rep_len] = c;
  1259. report_buffer[rep_len + 1] = '\0';
  1260. }
  1261. else {
  1262. report_gathering = 0;
  1263. fprintf (report_fp, "chat: %s\n", report_buffer);
  1264. }
  1265. }
  1266.  
  1267. if ((size_t)(s - temp) >= len &&
  1268. c == string[len - 1] &&
  1269. strncmp(s - len, string, len) == 0) {
  1270. if (verbose) {
  1271. if (s > logged)
  1272. chat_logf("%0.*v", s - logged, logged);
  1273. chat_logf(" -- got it\n");
  1274. }
  1275.  
  1276. alarm(0);
  1277. alarmed = 0;
  1278. return (1);
  1279. }
  1280.  
  1281. for (n = 0; n < n_aborts; ++n) {
  1282. if (s - temp >= (abort_len = strlen(abort_string[n])) &&
  1283. strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
  1284. if (verbose) {
  1285. if (s > logged)
  1286. chat_logf("%0.*v", s - logged, logged);
  1287. chat_logf(" -- failed");
  1288. }
  1289.  
  1290. alarm(0);
  1291. alarmed = 0;
  1292. exit_code = n + 4;
  1293. strcpy(fail_reason = fail_buffer, abort_string[n]);
  1294. return (0);
  1295. }
  1296. }
  1297.  
  1298. if (s >= end) {
  1299. if (logged < s - minlen) {
  1300. chat_logf("%0.*v", s - logged, logged);
  1301. logged = s;
  1302. }
  1303. s -= minlen;
  1304. memmove(temp, s, minlen);
  1305. logged = temp + (logged - s);
  1306. s = temp + minlen;
  1307. }
  1308.  
  1309. if (alarmed && verbose)
  1310. chat_logf("warning: alarm synchronization problem");
  1311. }
  1312.  
  1313. alarm(0);
  1314.  
  1315. if (verbose && printed) {
  1316. if (alarmed)
  1317. chat_logf(" -- read timed out");
  1318. else
  1319. chat_logf(" -- read failed: %m");
  1320. }
  1321.  
  1322. exit_code = 3;
  1323. alarmed = 0;
  1324. return (0);
  1325. }
  1326.  
  1327. void
  1328. pack_array(char **array, int end)
  1329. {
  1330. int i, j;
  1331.  
  1332. for (i = 0; i < end; i++) {
  1333. if (array[i] == NULL) {
  1334. for (j = i+1; j < end; ++j)
  1335. if (array[j] != NULL)
  1336. array[i++] = array[j];
  1337. for (; i < end; ++i)
  1338. array[i] = NULL;
  1339. break;
  1340. }
  1341. }
  1342. }
  1343.  
  1344. /*
  1345. * vfmtmsg - format a message into a buffer. Like vsprintf except we
  1346. * also specify the length of the output buffer, and we handle the
  1347. * %m (error message) format.
  1348. * Doesn't do floating-point formats.
  1349. * Returns the number of chars put into buf.
  1350. */
  1351. #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
  1352.  
  1353. int
  1354. vfmtmsg(char *buf, int buflen, const char *fmt, va_list args)
  1355. {
  1356. int c, i, n;
  1357. int width, prec, fillch;
  1358. int base, len, neg, quoted;
  1359. unsigned long val = 0;
  1360. char *str, *buf0;
  1361. const char *f;
  1362. unsigned char *p;
  1363. char num[32];
  1364. static char hexchars[] = "0123456789abcdef";
  1365.  
  1366. buf0 = buf;
  1367. --buflen;
  1368. while (buflen > 0) {
  1369. for (f = fmt; *f != '%' && *f != 0; ++f)
  1370. ;
  1371. if (f > fmt) {
  1372. len = f - fmt;
  1373. if (len > buflen)
  1374. len = buflen;
  1375. memcpy(buf, fmt, len);
  1376. buf += len;
  1377. buflen -= len;
  1378. fmt = f;
  1379. }
  1380. if (*fmt == 0)
  1381. break;
  1382. c = *++fmt;
  1383. width = prec = 0;
  1384. fillch = ' ';
  1385. if (c == '0') {
  1386. fillch = '0';
  1387. c = *++fmt;
  1388. }
  1389. if (c == '*') {
  1390. width = va_arg(args, int);
  1391. c = *++fmt;
  1392. } else {
  1393. while (isdigit(c)) {
  1394. width = width * 10 + c - '0';
  1395. c = *++fmt;
  1396. }
  1397. }
  1398. if (c == '.') {
  1399. c = *++fmt;
  1400. if (c == '*') {
  1401. prec = va_arg(args, int);
  1402. c = *++fmt;
  1403. } else {
  1404. while (isdigit(c)) {
  1405. prec = prec * 10 + c - '0';
  1406. c = *++fmt;
  1407. }
  1408. }
  1409. }
  1410. str = 0;
  1411. base = 0;
  1412. neg = 0;
  1413. ++fmt;
  1414. switch (c) {
  1415. case 'd':
  1416. i = va_arg(args, int);
  1417. if (i < 0) {
  1418. neg = 1;
  1419. val = -i;
  1420. } else
  1421. val = i;
  1422. base = 10;
  1423. break;
  1424. case 'o':
  1425. val = va_arg(args, unsigned int);
  1426. base = 8;
  1427. break;
  1428. case 'x':
  1429. val = va_arg(args, unsigned int);
  1430. base = 16;
  1431. break;
  1432. case 'p':
  1433. val = (unsigned long) va_arg(args, void *);
  1434. base = 16;
  1435. neg = 2;
  1436. break;
  1437. case 's':
  1438. str = va_arg(args, char *);
  1439. break;
  1440. case 'c':
  1441. num[0] = va_arg(args, int);
  1442. num[1] = 0;
  1443. str = num;
  1444. break;
  1445. case 'm':
  1446. str = strerror(errno);
  1447. break;
  1448. case 'v': /* "visible" string */
  1449. case 'q': /* quoted string */
  1450. quoted = c == 'q';
  1451. p = va_arg(args, unsigned char *);
  1452. if (fillch == '0' && prec > 0) {
  1453. n = prec;
  1454. } else {
  1455. n = strlen((char *)p);
  1456. if (prec > 0 && prec < n)
  1457. n = prec;
  1458. }
  1459. while (n > 0 && buflen > 0) {
  1460. c = *p++;
  1461. --n;
  1462. if (!quoted && c >= 0x80) {
  1463. OUTCHAR('M');
  1464. OUTCHAR('-');
  1465. c -= 0x80;
  1466. }
  1467. if (quoted && (c == '"' || c == '\\'))
  1468. OUTCHAR('\\');
  1469. if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
  1470. if (quoted) {
  1471. OUTCHAR('\\');
  1472. switch (c) {
  1473. case '\t': OUTCHAR('t'); break;
  1474. case '\n': OUTCHAR('n'); break;
  1475. case '\b': OUTCHAR('b'); break;
  1476. case '\f': OUTCHAR('f'); break;
  1477. default:
  1478. OUTCHAR('x');
  1479. OUTCHAR(hexchars[c >> 4]);
  1480. OUTCHAR(hexchars[c & 0xf]);
  1481. }
  1482. } else {
  1483. if (c == '\t')
  1484. OUTCHAR(c);
  1485. else {
  1486. OUTCHAR('^');
  1487. OUTCHAR(c ^ 0x40);
  1488. }
  1489. }
  1490. } else
  1491. OUTCHAR(c);
  1492. }
  1493. continue;
  1494. default:
  1495. *buf++ = '%';
  1496. if (c != '%')
  1497. --fmt; /* so %z outputs %z etc. */
  1498. --buflen;
  1499. continue;
  1500. }
  1501. if (base != 0) {
  1502. str = num + sizeof(num);
  1503. *--str = 0;
  1504. while (str > num + neg) {
  1505. *--str = hexchars[val % base];
  1506. val = val / base;
  1507. if (--prec <= 0 && val == 0)
  1508. break;
  1509. }
  1510. switch (neg) {
  1511. case 1:
  1512. *--str = '-';
  1513. break;
  1514. case 2:
  1515. *--str = 'x';
  1516. *--str = '0';
  1517. break;
  1518. }
  1519. len = num + sizeof(num) - 1 - str;
  1520. } else {
  1521. len = strlen(str);
  1522. if (prec > 0 && len > prec)
  1523. len = prec;
  1524. }
  1525. if (width > 0) {
  1526. if (width > buflen)
  1527. width = buflen;
  1528. if ((n = width - len) > 0) {
  1529. buflen -= n;
  1530. for (; n > 0; --n)
  1531. *buf++ = fillch;
  1532. }
  1533. }
  1534. if (len > buflen)
  1535. len = buflen;
  1536. memcpy(buf, str, len);
  1537. buf += len;
  1538. buflen -= len;
  1539. }
  1540. *buf = 0;
  1541. return buf - buf0;
  1542. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement