|
|
1.1 root 1: /* chat.c
2: Chat routine for the UUCP package.
3:
4: Copyright (C) 1991, 1992 Ian Lance Taylor
5:
6: This file is part of the Taylor UUCP package.
7:
8: This program is free software; you can redistribute it and/or
9: modify it under the terms of the GNU General Public License as
10: published by the Free Software Foundation; either version 2 of the
11: License, or (at your option) any later version.
12:
13: This program is distributed in the hope that it will be useful, but
14: WITHOUT ANY WARRANTY; without even the implied warranty of
15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16: General Public License for more details.
17:
18: You should have received a copy of the GNU General Public License
19: along with this program; if not, write to the Free Software
20: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21:
22: The author of the program may be contacted at [email protected] or
23: c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
24: */
25:
26: #include "uucp.h"
27:
28: #if USE_RCS_ID
29: const char chat_rcsid[] = "$Id: chat.c,v 1.1 93/07/30 07:52:38 bin Exp Locker: bin $";
30: #endif
31:
32: #include <ctype.h>
33: #include <errno.h>
34:
35: #include "uudefs.h"
36: #include "uuconf.h"
37: #include "conn.h"
38: #include "prot.h"
39: #include "system.h"
40:
41: /* Local functions. */
42:
43: static int icexpect P((struct sconnection *qconn, int cstrings,
44: char **azstrings, size_t *aclens,
45: int ctimeout, boolean fstrip));
46: static boolean fcsend P((struct sconnection *qconn, pointer puuconf,
47: const char *zsend,
48: const struct uuconf_system *qsys,
49: const struct uuconf_dialer *qdial,
50: const char *zphone,
51: boolean ftranslate, boolean fstrip));
52: static boolean fcecho_send_strip P((struct sconnection *qconn,
53: const char *z, size_t clen));
54: static boolean fcecho_send_nostrip P((struct sconnection *qconn,
55: const char *z, size_t clen));
56: static boolean fcecho_send P((struct sconnection *qconn, const char *z,
57: size_t clen, boolean fstrip));
58: static boolean fcphone P((struct sconnection *qconn,
59: pointer puuconf,
60: const struct uuconf_dialer *qdial,
61: const char *zphone,
62: boolean (*pfwrite) P((struct sconnection *qc,
63: const char *zwrite,
64: size_t cwrite)),
65: boolean ftranslate, boolean *pfquote));
66: static boolean fctranslate P((pointer puuconf, const char *zphone,
67: const char **pzprefix,
68: const char **pzsuffix));
69: static boolean fcprogram P((struct sconnection *qconn, pointer puuconf,
70: char **pzprogram,
71: const struct uuconf_system *qsys,
72: const struct uuconf_dialer *qdial,
73: const char *zphone, const char *zport,
74: long ibaud));
75:
76: /* Run a chat script with the other system. The chat script is a
77: series of expect send pairs. We wait for the expect string to show
78: up, and then we send the send string. The chat string for a system
79: holds the expect and send strings separated by a single space. */
80:
81: boolean
82: fchat (qconn, puuconf, qchat, qsys, qdial, zphone, ftranslate, zport, ibaud)
83: struct sconnection *qconn;
84: pointer puuconf;
85: const struct uuconf_chat *qchat;
86: const struct uuconf_system *qsys;
87: const struct uuconf_dialer *qdial;
88: const char *zphone;
89: boolean ftranslate;
90: const char *zport;
91: long ibaud;
92: {
93: int cstrings;
94: char **azstrings;
95: size_t *aclens;
96: char **pzchat;
97: char *zbuf;
98: size_t cbuflen;
99: boolean fret;
100: int i;
101:
102: /* First run the program, if any. */
103: if (qchat->uuconf_pzprogram != NULL)
104: {
105: if (! fcprogram (qconn, puuconf, qchat->uuconf_pzprogram, qsys, qdial,
106: zphone, zport, ibaud))
107: return FALSE;
108: }
109:
110: /* If there's no chat script, we're done. */
111: if (qchat->uuconf_pzchat == NULL)
112: return TRUE;
113:
114: if (qchat->uuconf_pzfail == NULL)
115: {
116: cstrings = 1;
117: azstrings = (char **) xmalloc (sizeof (char *));
118: aclens = (size_t *) xmalloc (sizeof (size_t));
119: }
120: else
121: {
122: char **pz;
123:
124: /* We leave string number 0 for the chat script. */
125: cstrings = 1;
126: for (pz = qchat->uuconf_pzfail; *pz != NULL; pz++)
127: ++cstrings;
128:
129: azstrings = (char **) xmalloc (cstrings * sizeof (char *));
130: aclens = (size_t *) xmalloc (cstrings * sizeof (size_t));
131:
132: /* Get the strings into the array, and handle all the escape
133: characters. */
134: for (cstrings = 1, pz = qchat->uuconf_pzfail;
135: *pz != NULL;
136: cstrings++, pz++)
137: {
138: azstrings[cstrings] = zbufcpy (*pz);
139: aclens[cstrings] = cescape (azstrings[cstrings]);
140: }
141: }
142:
143: cbuflen = 0;
144: zbuf = NULL;
145: fret = TRUE;
146:
147: pzchat = qchat->uuconf_pzchat;
148:
149: while (*pzchat != NULL)
150: {
151: size_t clen;
152:
153: /* Loop over subexpects and subsends. */
154: while (TRUE)
155: {
156: /* Copy the expect string into the buffer so that we can
157: modify it in cescape. */
158: clen = strlen (*pzchat);
159: if (clen >= cbuflen)
160: {
161: ubuffree (zbuf);
162: zbuf = zbufalc (clen + 1);
163: cbuflen = clen;
164: }
165: memcpy (zbuf, *pzchat, clen + 1);
166:
167: azstrings[0] = zbuf;
168: if (azstrings[0][0] == '-')
169: ++azstrings[0];
170: aclens[0] = cescape (azstrings[0]);
171:
172: if (aclens[0] == 0
173: || (aclens[0] == 2
174: && strcmp (azstrings[0], "\"\"") == 0))
175: {
176: /* There is no subexpect sequence. If there is a
177: subsend sequence we move on to it. Otherwise we let
178: this expect succeed. This is somewhat inconsistent,
179: but it seems to be the traditional approach. */
180: if (pzchat[1] == NULL || pzchat[1][0] != '-')
181: break;
182: }
183: else
184: {
185: int istr;
186:
187: istr = icexpect (qconn, cstrings, azstrings, aclens,
188: qchat->uuconf_ctimeout,
189: qchat->uuconf_fstrip);
190:
191: /* If we found the string, break out of the
192: subexpect/subsend loop. */
193: if (istr == 0)
194: break;
195:
196: /* If we got an error, return FALSE. */
197: if (istr < -1)
198: {
199: fret = FALSE;
200: break;
201: }
202:
203: /* If we found a failure string, log it and get out. */
204: if (istr > 0)
205: {
206: ulog (LOG_ERROR, "Chat script failed: Got \"%s\"",
207: qchat->uuconf_pzfail[istr - 1]);
208: fret = FALSE;
209: break;
210: }
211:
212: /* We timed out; look for a send subsequence. If none,
213: the chat script has failed. */
214: if (pzchat[1] == NULL || pzchat[1][0] != '-')
215: {
216: ulog (LOG_ERROR, "Timed out in chat script");
217: fret = FALSE;
218: break;
219: }
220: }
221:
222: /* Send the send subsequence without the leading '-'. A
223: \"\" will send nothing. An empty string will send a
224: carriage return. */
225: ++pzchat;
226: if (! fcsend (qconn, puuconf, *pzchat + 1, qsys, qdial, zphone,
227: ftranslate, qchat->uuconf_fstrip))
228: {
229: fret = FALSE;
230: break;
231: }
232:
233: /* If there is no expect subsequence, we are done. */
234: if (pzchat[1] == NULL || pzchat[1][0] != '-')
235: break;
236:
237: /* Move on to next expect subsequence. */
238: ++pzchat;
239: }
240:
241: if (! fret)
242: break;
243:
244: /* Move on to the send string. If there is none, we have
245: succeeded. */
246: do
247: {
248: ++pzchat;
249: }
250: while (*pzchat != NULL && (*pzchat)[0] == '-');
251:
252: if (*pzchat == NULL)
253: break;
254:
255: if (**pzchat != '\0')
256: {
257: if (! fcsend (qconn, puuconf, *pzchat, qsys, qdial, zphone,
258: ftranslate, qchat->uuconf_fstrip))
259: {
260: fret = FALSE;
261: break;
262: }
263: }
264:
265: ++pzchat;
266: }
267:
268: ubuffree (zbuf);
269: for (i = 1; i < cstrings; i++)
270: ubuffree (azstrings[i]);
271: xfree ((pointer) azstrings);
272: xfree ((pointer) aclens);
273:
274: return fret;
275: }
276:
277: /* Read characters and wait for one of a set of memory strings to come
278: in. This returns the index into the array of the string that
279: arrives, or -1 on timeout, or -2 on error. */
280:
281: static int
282: icexpect (qconn, cstrings, azstrings, aclens, ctimeout, fstrip)
283: struct sconnection *qconn;
284: int cstrings;
285: char **azstrings;
286: size_t *aclens;
287: int ctimeout;
288: boolean fstrip;
289: {
290: int i;
291: size_t cmax;
292: char *zhave;
293: size_t chave;
294: long iendtime;
295: #if DEBUG > 1
296: int cchars;
297: int iolddebug;
298: #endif
299:
300: cmax = aclens[0];
301: for (i = 1; i < cstrings; i++)
302: if (cmax < aclens[i])
303: cmax = aclens[i];
304:
305: zhave = zbufalc (cmax);
306: chave = 0;
307:
308: iendtime = ixsysdep_time ((long *) NULL) + ctimeout;
309:
310: #if DEBUG > 1
311: cchars = 0;
312: iolddebug = iDebug;
313: if (FDEBUGGING (DEBUG_CHAT))
314: {
315: udebug_buffer ("icexpect: Looking for", azstrings[0],
316: aclens[0]);
317: ulog (LOG_DEBUG_START, "icexpect: Got \"");
318: iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT);
319: }
320: #endif
321:
322: while (TRUE)
323: {
324: int bchar;
325:
326: /* If we have no more time, get out. */
327: if (ctimeout <= 0)
328: {
329: #if DEBUG > 1
330: if (FDEBUGGING (DEBUG_CHAT))
331: {
332: ulog (LOG_DEBUG_END, "\" (timed out)");
333: iDebug = iolddebug;
334: }
335: #endif
336: ubuffree (zhave);
337: return -1;
338: }
339:
340: /* Read one character at a time. We could use a more complex
341: algorithm to read in larger batches, but it's probably not
342: worth it. If the buffer is full, shift it left; we already
343: know that no string matches, and the buffer holds the largest
344: string, so this can't lose a match. */
345: if (chave >= cmax)
346: {
347: size_t imove;
348:
349: for (imove = 0; imove < cmax - 1; imove++)
350: zhave[imove] = zhave[imove + 1];
351: --chave;
352: }
353:
354: /* The timeout/error return values from breceive_char are the
355: same as for this function. */
356: bchar = breceive_char (qconn, ctimeout, TRUE);
357: if (bchar < 0)
358: {
359: #if DEBUG > 1
360: if (FDEBUGGING (DEBUG_CHAT))
361: {
362: /* If there was an error, it will probably be logged in
363: the middle of our string, but this is only debugging
364: so it's not a big deal. */
365: ulog (LOG_DEBUG_END, "\" (%s)",
366: bchar == -1 ? "timed out" : "error");
367: iDebug = iolddebug;
368: }
369: #endif
370: ubuffree (zhave);
371: return bchar;
372: }
373:
374: /* Strip the parity bit if desired. */
375: if (fstrip)
376: bchar &= 0x7f;
377:
378: zhave[chave] = (char) bchar;
379: ++chave;
380:
381: #if DEBUG > 1
382: if (FDEBUGGING (DEBUG_CHAT))
383: {
384: char ab[5];
385:
386: ++cchars;
387: if (cchars > 60)
388: {
389: ulog (LOG_DEBUG_END, "\"");
390: ulog (LOG_DEBUG_START, "icexpect: Got \"");
391: cchars = 0;
392: }
393: (void) cdebug_char (ab, bchar);
394: ulog (LOG_DEBUG_CONTINUE, "%s", ab);
395: }
396: #endif
397:
398: /* See if any of the strings can be found in the buffer. Since
399: we read one character at a time, the string can only be found
400: at the end of the buffer. */
401: for (i = 0; i < cstrings; i++)
402: {
403: if (aclens[i] <= chave
404: && memcmp (zhave + chave - aclens[i], azstrings[i],
405: aclens[i]) == 0)
406: {
407: #if DEBUG > 1
408: if (FDEBUGGING (DEBUG_CHAT))
409: {
410: if (i == 0)
411: ulog (LOG_DEBUG_END, "\" (found it)");
412: else
413: {
414: ulog (LOG_DEBUG_END, "\"");
415: udebug_buffer ("icexpect: Found", azstrings[i],
416: aclens[i]);
417: }
418: iDebug = iolddebug;
419: }
420: #endif
421: ubuffree (zhave);
422: return i;
423: }
424: }
425:
426: ctimeout = (int) (iendtime - ixsysdep_time ((long *) NULL));
427: }
428: }
429:
430: #if DEBUG > 1
431:
432: /* Debugging function for fcsend. This takes the fquote variable, the
433: length of the string (0 if this an informational string which can
434: be printed directly) and the string itself. It returns the new
435: value for fquote. The fquote variable is TRUE if the debugging
436: output is in the middle of a quoted string. */
437:
438: static size_t cCsend_chars;
439: static int iColddebug;
440:
441: static boolean fcsend_debug P((boolean, size_t, const char *));
442:
443: static boolean
444: fcsend_debug (fquote, clen, zbuf)
445: boolean fquote;
446: size_t clen;
447: const char *zbuf;
448: {
449: size_t cwas;
450:
451: if (! FDEBUGGING (DEBUG_CHAT))
452: return TRUE;
453:
454: cwas = cCsend_chars;
455: if (clen > 0)
456: cCsend_chars += clen;
457: else
458: cCsend_chars += strlen (zbuf);
459: if (cCsend_chars > 60 && cwas > 10)
460: {
461: ulog (LOG_DEBUG_END, "%s", fquote ? "\"" : "");
462: fquote = FALSE;
463: ulog (LOG_DEBUG_START, "fcsend: Writing");
464: cCsend_chars = 0;
465: }
466:
467: if (clen == 0)
468: {
469: ulog (LOG_DEBUG_CONTINUE, "%s %s", fquote ? "\"" : "", zbuf);
470: return FALSE;
471: }
472: else
473: {
474: int i;
475:
476: if (! fquote)
477: ulog (LOG_DEBUG_CONTINUE, " \"");
478: for (i = 0; i < clen; i++)
479: {
480: char ab[5];
481:
482: (void) cdebug_char (ab, zbuf[i]);
483: ulog (LOG_DEBUG_CONTINUE, "%s", ab);
484: }
485:
486: return TRUE;
487: }
488: }
489:
490: /* Finish up the debugging information for fcsend. */
491:
492: static void ucsend_debug_end P((boolean, boolean));
493:
494: static void
495: ucsend_debug_end (fquote, ferr)
496: boolean fquote;
497: boolean ferr;
498: {
499: if (! FDEBUGGING (DEBUG_CHAT))
500: return;
501:
502: if (fquote)
503: ulog (LOG_DEBUG_CONTINUE, "\"");
504:
505: if (ferr)
506: ulog (LOG_DEBUG_CONTINUE, " (error)");
507:
508: ulog (LOG_DEBUG_END, "%s", "");
509:
510: iDebug = iColddebug;
511: }
512:
513: #else /* DEBUG <= 1 */
514:
515: /* Use macro definitions to make fcsend look neater. */
516:
517: #define fcsend_debug(fquote, clen, zbuf) TRUE
518:
519: #define ucsend_debug_end(fquote, ferror)
520:
521: #endif /* DEBUG <= 1 */
522:
523: /* Send a string out. This has to parse escape sequences as it goes.
524: Note that it handles the dialer escape sequences (\e, \E, \D, \T)
525: although they make no sense for chatting with a system. */
526:
527: static boolean
528: fcsend (qconn, puuconf, z, qsys, qdial, zphone, ftranslate, fstrip)
529: struct sconnection *qconn;
530: pointer puuconf;
531: const char *z;
532: const struct uuconf_system *qsys;
533: const struct uuconf_dialer *qdial;
534: const char *zphone;
535: boolean ftranslate;
536: boolean fstrip;
537: {
538: boolean fnocr;
539: boolean (*pfwrite) P((struct sconnection *, const char *, size_t));
540: char *zcallout_login;
541: char *zcallout_pass;
542: boolean fquote;
543:
544: if (strcmp (z, "\"\"") == 0)
545: return TRUE;
546:
547: fnocr = FALSE;
548: pfwrite = fconn_write;
549: zcallout_login = NULL;
550: zcallout_pass = NULL;
551:
552: #if DEBUG > 1
553: if (FDEBUGGING (DEBUG_CHAT))
554: {
555: ulog (LOG_DEBUG_START, "fcsend: Writing");
556: fquote = FALSE;
557: cCsend_chars = 0;
558: iColddebug = iDebug;
559: iDebug &=~ (DEBUG_OUTGOING | DEBUG_PORT);
560: }
561: #endif
562:
563: while (*z != '\0')
564: {
565: const char *zlook;
566: boolean fsend;
567: char bsend;
568:
569: zlook = z + strcspn ((char *) z, "\\BE");
570:
571: if (zlook > z)
572: {
573: size_t c;
574:
575: c = zlook - z;
576: fquote = fcsend_debug (fquote, c, z);
577: if (! (*pfwrite) (qconn, z, c))
578: {
579: ucsend_debug_end (fquote, TRUE);
580: return FALSE;
581: }
582: }
583:
584: if (*zlook == '\0')
585: break;
586:
587: z = zlook;
588:
589: fsend = FALSE;
590: switch (*z)
591: {
592: case 'B':
593: if (strncmp (z, "BREAK", 5) == 0)
594: {
595: fquote = fcsend_debug (fquote, (size_t) 0, "break");
596: if (! fconn_break (qconn))
597: {
598: ucsend_debug_end (fquote, TRUE);
599: return FALSE;
600: }
601: fnocr = TRUE;
602: z += 5;
603: }
604: else
605: {
606: fsend = TRUE;
607: bsend = 'B';
608: ++z;
609: }
610: break;
611: case 'E':
612: if (strncmp (z, "EOT", 3) == 0)
613: {
614: fsend = TRUE;
615: bsend = '\004';
616: fnocr = TRUE;
617: z += 3;
618: }
619: else
620: {
621: fsend = TRUE;
622: bsend = 'E';
623: ++z;
624: }
625: break;
626: case '\\':
627: ++z;
628: switch (*z)
629: {
630: case '-':
631: fsend = TRUE;
632: bsend = '-';
633: break;
634: case 'b':
635: fsend = TRUE;
636: bsend = '\b';
637: break;
638: case 'c':
639: fnocr = TRUE;
640: break;
641: case 'd':
642: fquote = fcsend_debug (fquote, (size_t) 0, "sleep");
643: usysdep_sleep (2);
644: break;
645: case 'e':
646: fquote = fcsend_debug (fquote, (size_t) 0, "echo-check-off");
647: pfwrite = fconn_write;
648: break;
649: case 'E':
650: fquote = fcsend_debug (fquote, (size_t) 0, "echo-check-on");
651: if (fstrip)
652: pfwrite = fcecho_send_strip;
653: else
654: pfwrite = fcecho_send_nostrip;
655: break;
656: case 'K':
657: fquote = fcsend_debug (fquote, (size_t) 0, "break");
658: if (! fconn_break (qconn))
659: {
660: ucsend_debug_end (fquote, TRUE);
661: return FALSE;
662: }
663: break;
664: case 'n':
665: fsend = TRUE;
666: bsend = '\n';
667: break;
668: case 'N':
669: fsend = TRUE;
670: bsend = '\0';
671: break;
672: case 'p':
673: fquote = fcsend_debug (fquote, (size_t) 0, "pause");
674: usysdep_pause ();
675: break;
676: case 'r':
677: fsend = TRUE;
678: bsend = '\r';
679: break;
680: case 's':
681: fsend = TRUE;
682: bsend = ' ';
683: break;
684: case 't':
685: fsend = TRUE;
686: bsend = '\t';
687: break;
688: case '\0':
689: --z;
690: /* Fall through. */
691: case '\\':
692: fsend = TRUE;
693: bsend = '\\';
694: break;
695: case '0': case '1': case '2': case '3': case '4':
696: case '5': case '6': case '7': case '8': case '9':
697: fsend = TRUE;
698: bsend = *z - '0';
699: if (z[1] >= '0' && z[1] <= '7')
700: bsend = (char) (8 * bsend + *++z - '0');
701: if (z[1] >= '0' && z[1] <= '7')
702: bsend = (char) (8 * bsend + *++z - '0');
703: break;
704: case 'x':
705: fsend = TRUE;
706: bsend = 0;
707: while (isxdigit (BUCHAR (z[1])))
708: {
709: if (isdigit (BUCHAR (z[1])))
710: bsend = (char) (16 * bsend + *++z - '0');
711: else if (isupper (BUCHAR (z[1])))
712: bsend = (char) (16 * bsend + *++z - 'A');
713: else
714: bsend = (char) (16 * bsend + *++z - 'a');
715: }
716: break;
717: case 'L':
718: {
719: const char *zlog;
720:
721: if (qsys == NULL)
722: {
723: ucsend_debug_end (fquote, TRUE);
724: ulog (LOG_ERROR, "Illegal use of \\L");
725: return FALSE;
726: }
727: zlog = qsys->uuconf_zcall_login;
728: if (zlog == NULL)
729: {
730: ucsend_debug_end (fquote, TRUE);
731: ulog (LOG_ERROR, "No login defined");
732: return FALSE;
733: }
734: if (zlog[0] == '*' && zlog[1] == '\0')
735: {
736: if (zcallout_login == NULL)
737: {
738: int iuuconf;
739:
740: iuuconf = uuconf_callout (puuconf, qsys,
741: &zcallout_login,
742: &zcallout_pass);
743: if (iuuconf == UUCONF_NOT_FOUND
744: || zcallout_login == NULL)
745: {
746: ucsend_debug_end (fquote, TRUE);
747: ulog (LOG_ERROR, "No login defined");
748: return FALSE;
749: }
750: else if (iuuconf != UUCONF_SUCCESS)
751: {
752: ucsend_debug_end (fquote, TRUE);
753: ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
754: return FALSE;
755: }
756: }
757: zlog = zcallout_login;
758: }
759: fquote = fcsend_debug (fquote, (size_t) 0, "login");
760: fquote = fcsend_debug (fquote, strlen (zlog), zlog);
761: if (! (*pfwrite) (qconn, zlog, strlen (zlog)))
762: {
763: ucsend_debug_end (fquote, TRUE);
764: return FALSE;
765: }
766: }
767: break;
768: case 'P':
769: {
770: const char *zpass;
771:
772: if (qsys == NULL)
773: {
774: ucsend_debug_end (fquote, TRUE);
775: ulog (LOG_ERROR, "Illegal use of \\P");
776: return FALSE;
777: }
778: zpass = qsys->uuconf_zcall_password;
779: if (zpass == NULL)
780: {
781: ucsend_debug_end (fquote, TRUE);
782: ulog (LOG_ERROR, "No password defined");
783: return FALSE;
784: }
785: if (zpass[0] == '*' && zpass[1] == '\0')
786: {
787: if (zcallout_pass == NULL)
788: {
789: int iuuconf;
790:
791: iuuconf = uuconf_callout (puuconf, qsys,
792: &zcallout_login,
793: &zcallout_pass);
794: if (iuuconf == UUCONF_NOT_FOUND
795: || zcallout_pass == NULL)
796: {
797: ucsend_debug_end (fquote, TRUE);
798: ulog (LOG_ERROR, "No password defined");
799: return FALSE;
800: }
801: else if (iuuconf != UUCONF_SUCCESS)
802: {
803: ucsend_debug_end (fquote, TRUE);
804: ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
805: return FALSE;
806: }
807: }
808: zpass = zcallout_pass;
809: }
810: fquote = fcsend_debug (fquote, (size_t) 0, "password");
811: fquote = fcsend_debug (fquote, strlen (zpass), zpass);
812: if (! (*pfwrite) (qconn, zpass, strlen (zpass)))
813: {
814: ucsend_debug_end (fquote, TRUE);
815: return FALSE;
816: }
817: }
818: break;
819: case 'D':
820: if (qdial == NULL || zphone == NULL)
821: {
822: ucsend_debug_end (fquote, TRUE);
823: ulog (LOG_ERROR, "Illegal use of \\D");
824: return FALSE;
825: }
826: fquote = fcsend_debug (fquote, (size_t) 0, "\\D");
827: if (! fcphone (qconn, puuconf, qdial, zphone, pfwrite,
828: ftranslate, &fquote))
829: {
830: ucsend_debug_end (fquote, TRUE);
831: return FALSE;
832: }
833: break;
834: case 'T':
835: if (qdial == NULL || zphone == NULL)
836: {
837: ucsend_debug_end (fquote, TRUE);
838: ulog (LOG_ERROR, "Illegal use of \\T");
839: return FALSE;
840: }
841: fquote = fcsend_debug (fquote, (size_t) 0, "\\T");
842: if (! fcphone (qconn, puuconf, qdial, zphone, pfwrite, TRUE,
843: &fquote))
844: {
845: ucsend_debug_end (fquote, TRUE);
846: return FALSE;
847: }
848: break;
849: case 'M':
850: if (qdial == NULL)
851: {
852: ucsend_debug_end (fquote, TRUE);
853: ulog (LOG_ERROR, "Illegal use of \\M");
854: return FALSE;
855: }
856: fquote = fcsend_debug (fquote, (size_t) 0, "ignore-carrier");
857: if (! fconn_carrier (qconn, FALSE))
858: {
859: ucsend_debug_end (fquote, TRUE);
860: return FALSE;
861: }
862: break;
863: case 'm':
864: if (qdial == NULL)
865: {
866: ucsend_debug_end (fquote, TRUE);
867: ulog (LOG_ERROR, "Illegal use of \\m");
868: return FALSE;
869: }
870: if (qdial->uuconf_fcarrier)
871: {
872: fquote = fcsend_debug (fquote, (size_t) 0, "need-carrier");
873: if (! fconn_carrier (qconn, TRUE))
874: {
875: ucsend_debug_end (fquote, TRUE);
876: return FALSE;
877: }
878: }
879: break;
880: default:
881: /* This error message will screw up any debugging
882: information, but it's easily avoidable. */
883: ulog (LOG_ERROR,
884: "Unrecognized escape sequence \\%c in send string",
885: *z);
886: fsend = TRUE;
887: bsend = *z;
888: break;
889: }
890: ++z;
891: break;
892: #if DEBUG > 0
893: default:
894: ulog (LOG_FATAL, "fcsend: Can't happen");
895: break;
896: #endif
897: }
898:
899: if (fsend)
900: {
901: fquote = fcsend_debug (fquote, (size_t) 1, &bsend);
902: if (! (*pfwrite) (qconn, &bsend, (size_t) 1))
903: {
904: ucsend_debug_end (fquote, TRUE);
905: return FALSE;
906: }
907: }
908: }
909:
910: xfree ((pointer) zcallout_login);
911: xfree ((pointer) zcallout_pass);
912:
913: /* Output a final carriage return, unless there was a \c. Don't
914: bother to check for an echo. */
915: if (! fnocr)
916: {
917: char b;
918:
919: b = '\r';
920: fquote = fcsend_debug (fquote, (size_t) 1, &b);
921: if (! fconn_write (qconn, &b, (size_t) 1))
922: {
923: ucsend_debug_end (fquote, TRUE);
924: return FALSE;
925: }
926: }
927:
928: ucsend_debug_end (fquote, FALSE);
929:
930: return TRUE;
931: }
932:
933: /* Write out a phone number with optional dialcode translation. The
934: pfquote argument is only used for debugging. */
935:
936: static boolean
937: fcphone (qconn, puuconf, qdial, zphone, pfwrite, ftranslate, pfquote)
938: struct sconnection *qconn;
939: pointer puuconf;
940: const struct uuconf_dialer *qdial;
941: const char *zphone;
942: boolean (*pfwrite) P((struct sconnection *qc, const char *zwrite,
943: size_t cwrite));
944: boolean ftranslate;
945: boolean *pfquote;
946: {
947: const char *zprefix, *zsuffix;
948:
949: if (ftranslate)
950: {
951: if (! fctranslate (puuconf, zphone, &zprefix, &zsuffix))
952: return FALSE;
953: }
954: else
955: {
956: zprefix = zphone;
957: zsuffix = NULL;
958: }
959:
960: while (zprefix != NULL)
961: {
962: while (TRUE)
963: {
964: const char *z;
965: const char *zstr;
966:
967: z = zprefix + strcspn ((char *) zprefix, "=-");
968: if (z > zprefix)
969: {
970: size_t clen;
971:
972: clen = z - zprefix;
973: *pfquote = fcsend_debug (*pfquote, clen, zprefix);
974: if (! (*pfwrite) (qconn, zprefix, clen))
975: return FALSE;
976: }
977:
978: if (*z == '=')
979: zstr = qdial->uuconf_zdialtone;
980: else if (*z == '-')
981: zstr = qdial->uuconf_zpause;
982: else /* *z == '\0' */
983: break;
984:
985: if (zstr != NULL)
986: {
987: *pfquote = fcsend_debug (*pfquote, strlen (zstr), zstr);
988: if (! (*pfwrite) (qconn, zstr, strlen (zstr)))
989: return FALSE;
990: }
991:
992: zprefix = z + 1;
993: }
994:
995: zprefix = zsuffix;
996: zsuffix = NULL;
997: }
998:
999: return TRUE;
1000: }
1001:
1002: /* Given a phone number, run it through dial code translation
1003: returning two strings. */
1004:
1005: static boolean
1006: fctranslate (puuconf, zphone, pzprefix, pzsuffix)
1007: pointer puuconf;
1008: const char *zphone;
1009: const char **pzprefix;
1010: const char **pzsuffix;
1011: {
1012: int iuuconf;
1013: char *zdialcode, *zto;
1014: const char *zfrom;
1015: char *ztrans;
1016:
1017: *pzprefix = zphone;
1018: *pzsuffix = NULL;
1019:
1020: zdialcode = zbufalc (strlen (zphone) + 1);
1021: zfrom = zphone;
1022: zto = zdialcode;
1023: while (*zfrom != '\0' && isalpha (BUCHAR (*zfrom)))
1024: *zto++ = *zfrom++;
1025: *zto = '\0';
1026:
1027: if (*zdialcode == '\0')
1028: {
1029: ubuffree (zdialcode);
1030: return TRUE;
1031: }
1032:
1033: iuuconf = uuconf_dialcode (puuconf, zdialcode, &ztrans);
1034:
1035: ubuffree (zdialcode);
1036:
1037: if (iuuconf == UUCONF_NOT_FOUND)
1038: return TRUE;
1039: else if (iuuconf != UUCONF_SUCCESS)
1040: {
1041: ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
1042: return FALSE;
1043: }
1044: else
1045: {
1046: /* We really should figure out a way to free up ztrans here. */
1047: *pzprefix = ztrans;
1048: *pzsuffix = zfrom;
1049: return TRUE;
1050: }
1051: }
1052:
1053: /* Write out a string making sure the each character is echoed back.
1054: There are two versions of this function, one which strips the
1055: parity bit from the characters and one which does not. This is so
1056: that I can use a single function pointer in fcsend, and to avoid
1057: using any static variables so that I can put chat scripts in a
1058: library some day. */
1059:
1060: static boolean
1061: fcecho_send_strip (qconn, zwrite, cwrite)
1062: struct sconnection *qconn;
1063: const char *zwrite;
1064: size_t cwrite;
1065: {
1066: return fcecho_send (qconn, zwrite, cwrite, TRUE);
1067: }
1068:
1069: static boolean
1070: fcecho_send_nostrip (qconn, zwrite, cwrite)
1071: struct sconnection *qconn;
1072: const char *zwrite;
1073: size_t cwrite;
1074: {
1075: return fcecho_send (qconn, zwrite, cwrite, FALSE);
1076: }
1077:
1078: static boolean
1079: fcecho_send (qconn, zwrite, cwrite, fstrip)
1080: struct sconnection *qconn;
1081: const char *zwrite;
1082: size_t cwrite;
1083: boolean fstrip;
1084: {
1085: const char *zend;
1086:
1087: zend = zwrite + cwrite;
1088:
1089: for (; zwrite < zend; zwrite++)
1090: {
1091: int b;
1092: char bwrite;
1093:
1094: bwrite = *zwrite;
1095: if (! fconn_write (qconn, &bwrite, (size_t) 1))
1096: return FALSE;
1097: if (fstrip)
1098: bwrite &= 0x7f;
1099: do
1100: {
1101: /* We arbitrarily wait five seconds for the echo. */
1102: b = breceive_char (qconn, 5, TRUE);
1103: /* Now b == -1 on timeout, -2 on error. */
1104: if (b < 0)
1105: {
1106: if (b == -1)
1107: ulog (LOG_ERROR, "Character not echoed");
1108: return FALSE;
1109: }
1110: if (fstrip)
1111: b &= 0x7f;
1112: }
1113: while (b != BUCHAR (bwrite));
1114: }
1115:
1116: return TRUE;
1117: }
1118:
1119: /* Run a chat program. Expand any escape sequences and call a system
1120: dependent program to run it. */
1121:
1122: static boolean
1123: fcprogram (qconn, puuconf, pzprogram, qsys, qdial, zphone, zport, ibaud)
1124: struct sconnection *qconn;
1125: pointer puuconf;
1126: char **pzprogram;
1127: const struct uuconf_system *qsys;
1128: const struct uuconf_dialer *qdial;
1129: const char *zphone;
1130: const char *zport;
1131: long ibaud;
1132: {
1133: size_t cargs;
1134: char **pzpass, **pzarg;
1135: char **pz;
1136: char *zcallout_login;
1137: char *zcallout_pass;
1138: boolean fret;
1139:
1140: cargs = 1;
1141: for (pz = pzprogram; *pz != NULL; pz++)
1142: ++cargs;
1143:
1144: pzpass = (char **) xmalloc (cargs * sizeof (char *));
1145:
1146: zcallout_login = NULL;
1147: zcallout_pass = NULL;
1148: fret = TRUE;
1149:
1150: /* Copy the string into memory expanding escape sequences. */
1151: for (pz = pzprogram, pzarg = pzpass; *pz != NULL; pz++, pzarg++)
1152: {
1153: const char *zfrom;
1154: size_t calc, clen;
1155: char *zto;
1156:
1157: if (strchr (*pz, '\\') == NULL)
1158: {
1159: *pzarg = zbufcpy (*pz);
1160: continue;
1161: }
1162:
1163: *pzarg = NULL;
1164: zto = NULL;
1165: calc = 0;
1166: clen = 0;
1167:
1168: for (zfrom = *pz; *zfrom != '\0'; zfrom++)
1169: {
1170: const char *zadd = NULL;
1171: size_t cadd;
1172: char abadd[15];
1173:
1174: if (*zfrom != '\\')
1175: {
1176: if (clen + 2 > calc)
1177: {
1178: char *znew;
1179:
1180: calc = clen + 50;
1181: znew = zbufalc (calc);
1182: memcpy (znew, *pzarg, clen);
1183: ubuffree (*pzarg);
1184: *pzarg = znew;
1185: zto = znew + clen;
1186: }
1187: *zto++ = *zfrom;
1188: ++clen;
1189: continue;
1190: }
1191:
1192: ++zfrom;
1193: switch (*zfrom)
1194: {
1195: case '\0':
1196: --zfrom;
1197: /* Fall through. */
1198: case '\\':
1199: zadd = "\\";
1200: break;
1201: case 'L':
1202: {
1203: const char *zlog;
1204:
1205: if (qsys == NULL)
1206: {
1207: ulog (LOG_ERROR, "chat-program: Illegal use of \\L");
1208: fret = FALSE;
1209: break;
1210: }
1211: zlog = qsys->uuconf_zcall_login;
1212: if (zlog == NULL)
1213: {
1214: ulog (LOG_ERROR, "chat-program: No login defined");
1215: fret = FALSE;
1216: break;
1217: }
1218: if (zlog[0] == '*' && zlog[1] == '\0')
1219: {
1220: if (zcallout_login == NULL)
1221: {
1222: int iuuconf;
1223:
1224: iuuconf = uuconf_callout (puuconf, qsys,
1225: &zcallout_login,
1226: &zcallout_pass);
1227: if (iuuconf == UUCONF_NOT_FOUND
1228: || zcallout_login == NULL)
1229: {
1230: ulog (LOG_ERROR,
1231: "chat-program: No login defined");
1232: fret = FALSE;
1233: break;
1234: }
1235: else if (iuuconf != UUCONF_SUCCESS)
1236: {
1237: ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
1238: fret = FALSE;
1239: break;
1240: }
1241: }
1242: zlog = zcallout_login;
1243: }
1244: zadd = zlog;
1245: }
1246: break;
1247: case 'P':
1248: {
1249: const char *zpass;
1250:
1251: if (qsys == NULL)
1252: {
1253: ulog (LOG_ERROR, "chat-program: Illegal use of \\P");
1254: fret = FALSE;
1255: break;
1256: }
1257: zpass = qsys->uuconf_zcall_password;
1258: if (zpass == NULL)
1259: {
1260: ulog (LOG_ERROR, "chat-program: No password defined");
1261: fret = FALSE;
1262: break;
1263: }
1264: if (zpass[0] == '*' && zpass[1] == '\0')
1265: {
1266: if (zcallout_pass == NULL)
1267: {
1268: int iuuconf;
1269:
1270: iuuconf = uuconf_callout (puuconf, qsys,
1271: &zcallout_login,
1272: &zcallout_pass);
1273: if (iuuconf == UUCONF_NOT_FOUND
1274: || zcallout_pass == NULL)
1275: {
1276: ulog (LOG_ERROR,
1277: "chat-program: No password defined");
1278: fret = FALSE;
1279: break;
1280: }
1281: else if (iuuconf != UUCONF_SUCCESS)
1282: {
1283: ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
1284: fret = FALSE;
1285: break;
1286: }
1287: }
1288: zpass = zcallout_pass;
1289: }
1290: zadd = zpass;
1291: }
1292: break;
1293: case 'D':
1294: if (qdial == NULL || zphone == NULL)
1295: {
1296: ulog (LOG_ERROR, "chat-program: Illegal use of \\D");
1297: fret = FALSE;
1298: break;
1299: }
1300: zadd = zphone;
1301: break;
1302: case 'T':
1303: {
1304: const char *zprefix, *zsuffix;
1305:
1306: if (qdial == NULL || zphone == NULL)
1307: {
1308: ulog (LOG_ERROR, "chat-program: Illegal use of \\T");
1309: fret = FALSE;
1310: break;
1311: }
1312:
1313: if (! fctranslate (puuconf, zphone, &zprefix, &zsuffix))
1314: {
1315: fret = FALSE;
1316: break;
1317: }
1318:
1319: if (zsuffix == NULL)
1320: zadd = zprefix;
1321: else
1322: {
1323: size_t cprefix;
1324:
1325: cprefix = strlen (zprefix);
1326: if (clen + cprefix + 1 > calc)
1327: {
1328: char *znew;
1329:
1330: calc = clen + cprefix + 20;
1331: znew = zbufalc (calc);
1332: memcpy (znew, *pzarg, clen);
1333: ubuffree (*pzarg);
1334: *pzarg = znew;
1335: zto = znew + clen;
1336: }
1337: memcpy (zto, zprefix, cprefix);
1338: zto += cprefix;
1339: clen += cprefix;
1340: zadd = zsuffix;
1341: }
1342: }
1343: break;
1344: case 'Y':
1345: if (zLdevice == NULL && zport == NULL)
1346: {
1347: ulog (LOG_ERROR, "chat-program: Illegal use of \\Y");
1348: fret = FALSE;
1349: break;
1350: }
1351: /* zLdevice will generally make more sense than zport, but
1352: it might not be set yet. */
1353: zadd = zLdevice;
1354: if (zadd == NULL)
1355: zadd = zport;
1356: break;
1357: case 'Z':
1358: if (qsys == NULL)
1359: {
1360: ulog (LOG_ERROR, "chat-program: Illegal use of \\Z");
1361: fret = FALSE;
1362: break;
1363: }
1364: zadd = qsys->uuconf_zname;
1365: break;
1366: case 'S':
1367: {
1368: if (ibaud == 0)
1369: {
1370: ulog (LOG_ERROR, "chat-program: Illegal use of \\S");
1371: fret = FALSE;
1372: break;
1373: }
1374: sprintf (abadd, "%ld", ibaud);
1375: zadd = abadd;
1376: }
1377: break;
1378: default:
1379: {
1380: ulog (LOG_ERROR,
1381: "chat-program: Unrecognized escape sequence \\%c",
1382: *zfrom);
1383: abadd[0] = *zfrom;
1384: abadd[1] = '\0';
1385: zadd = abadd;
1386: }
1387: break;
1388: }
1389:
1390: if (! fret)
1391: break;
1392:
1393: cadd = strlen (zadd);
1394: if (clen + cadd + 1 > calc)
1395: {
1396: char *znew;
1397:
1398: calc = clen + cadd + 20;
1399: znew = zbufalc (calc);
1400: memcpy (znew, *pzarg, clen);
1401: ubuffree (*pzarg);
1402: *pzarg = znew;
1403: zto = znew + clen;
1404: }
1405: memcpy (zto, zadd, cadd + 1);
1406: zto += cadd;
1407: clen += cadd;
1408: }
1409:
1410: if (! fret)
1411: break;
1412:
1413: *zto++ = '\0';
1414: ++clen;
1415: }
1416:
1417: *pzarg = NULL;
1418:
1419: if (fret)
1420: fret = fconn_run_chat (qconn, pzpass);
1421:
1422: for (pz = pzpass; *pz != NULL; pz++)
1423: ubuffree (*pz);
1424: xfree ((pointer) pzpass);
1425: xfree ((pointer) zcallout_login);
1426: xfree ((pointer) zcallout_pass);
1427:
1428: return fret;
1429: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.