|
|
1.1 root 1: /* cu.c
2: Call up a remote system.
3:
4: Copyright (C) 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 cu_rcsid[] = "$Id: cu.c,v 1.1 93/07/30 07:53:00 bin Exp Locker: bin $";
30: #endif
31:
32: #include "cu.h"
33: #include "uudefs.h"
34: #include "uuconf.h"
35: #include "conn.h"
36: #include "prot.h"
37: #include "system.h"
38: #include "sysdep.h"
39: #include "getopt.h"
40:
41: #include <stdio.h>
42: #include <ctype.h>
43: #include <errno.h>
44:
45: /* Here are the user settable variables. The user is permitted to
46: change these while running the program, using ~s. */
47:
48: /* The escape character used to introduce a special command. The
49: escape character is the first character of this string. */
50: const char *zCuvar_escape = "~";
51:
52: /* Whether to delay for a second before printing the host name after
53: seeing an escape character. */
54: boolean fCuvar_delay = TRUE;
55:
56: /* The input characters which finish a line. The escape character is
57: only recognized following one of these characters. The default is
58: carriage return, ^U, ^C, ^O, ^D, ^S, ^Q, ^R, which I got from the
59: Ultrix /etc/remote file. */
60: const char *zCuvar_eol = "\r\025\003\017\004\023\021\022";
61:
62: /* Whether to transfer binary data (nonprintable characters other than
63: newline and tab) when sending a file. If this is FALSE, then
64: newline is changed to carriage return. */
65: boolean fCuvar_binary = FALSE;
66:
67: /* A prefix string to use before sending a binary character from a
68: file; this is only used if fCuvar_binary is TRUE. The default is
69: ^Z. */
70: const char *zCuvar_binary_prefix = "\026";
71:
72: /* Whether to check for echoes of characters sent when sending a file.
73: This is ignored if fCuvar_binary is TRUE. */
74: boolean fCuvar_echocheck = FALSE;
75:
76: /* A character to look for after each newline is sent when sending a
77: file. The character is the first character in this string, except
78: that a '\0' means that no echo check is done. */
79: const char *zCuvar_echonl = "\r";
80:
81: /* The timeout to use when looking for an character. */
82: int cCuvar_timeout = 30;
83:
84: /* The character to use to kill a line if an echo check fails. The
85: first character in this string is sent. The default is ^U. */
86: const char *zCuvar_kill = "\025";
87:
88: /* The number of times to try resending a line if the echo check keeps
89: failing. */
90: int cCuvar_resend = 10;
91:
92: /* The string to send at the end of a file sent with ~>. The default
93: is ^D. */
94: const char *zCuvar_eofwrite = "\004";
95:
96: /* The string to look for to finish a file received with ~<. For tip
97: this is a collection of single characters, but I don't want to do
98: that because it means that there are characters which cannot be
99: received. The default is a guess at a typical shell prompt. */
100: const char *zCuvar_eofread = "$";
101:
102: /* Whether to provide verbose information when sending or receiving a
103: file. */
104: boolean fCuvar_verbose = TRUE;
105:
106: /* The table used to give a value to a variable, and to print all the
107: variable values. */
108:
109: static const struct uuconf_cmdtab asCuvars[] =
110: {
111: { "escape", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_escape, NULL },
112: { "delay", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_delay, NULL },
113: { "eol", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eol, NULL },
114: { "binary", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_binary, NULL },
115: { "binary-prefix", UUCONF_CMDTABTYPE_STRING,
116: (pointer) &zCuvar_binary_prefix, NULL },
117: { "echocheck", UUCONF_CMDTABTYPE_BOOLEAN,
118: (pointer) &fCuvar_echocheck, NULL },
119: { "echonl", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_echonl, NULL },
120: { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_timeout, NULL },
121: { "kill", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_kill, NULL },
122: { "resend", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_resend, NULL },
123: { "eofwrite", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofwrite, NULL },
124: { "eofread", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofread, NULL },
125: { "verbose", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_verbose, NULL },
126: { NULL, 0, NULL, NULL}
127: };
128:
129: /* The program name. */
130: char abProgram[] = "cu";
131:
132: /* The string printed at the initial connect. */
133: #if ANSI_C
134: #define ZCONNMSG "\aConnected."
135: #else
136: #define ZCONNMSG "Connected."
137: #endif
138:
139: /* The string printed when disconnecting. */
140: #if ANSI_C
141: #define ZDISMSG "\aDisconnected."
142: #else
143: #define ZDISMSG "Disconnected."
144: #endif
145:
146: /* Local variables. */
147:
148: /* The string we print when the user is once again connected to the
149: port after transferring a file or taking some other action. */
150: static const char abCuconnected[]
151: #if ANSI_C
152: = "\a[connected]";
153: #else
154: = "[connected]";
155: #endif
156:
157: /* Global uuconf pointer. */
158: static pointer pCuuuconf;
159:
160: /* Connection. */
161: static struct sconnection *qCuconn;
162:
163: /* Whether to close the connection. */
164: static boolean fCuclose_conn;
165:
166: /* Dialer used to dial out. */
167: static struct uuconf_dialer *qCudialer;
168:
169: /* Whether we need to restore the terminal. */
170: static boolean fCurestore_terminal;
171:
172: /* Whether we are doing local echoing. */
173: static boolean fCulocalecho;
174:
175: /* Whether we need to call fsysdep_cu_finish. */
176: static boolean fCustarted;
177:
178: /* A structure used to pass information to icuport_lock. */
179: struct sconninfo
180: {
181: boolean fmatched;
182: boolean flocked;
183: struct sconnection *qconn;
184: const char *zline;
185: };
186:
187: /* Local functions. */
188:
189: static void ucuusage P((void));
190: static void ucuabort P((void));
191: static void uculog_start P((void));
192: static void uculog_end P((void));
193: static int icuport_lock P((struct uuconf_port *qport, pointer pinfo));
194: static boolean fcudo_cmd P((pointer puuconf, struct sconnection *qconn,
195: int bcmd));
196: static boolean fcuset_var P((pointer puuconf, char *zline));
197: static int icuunrecogvar P((pointer puuconf, int argc, char **argv,
198: pointer pvar, pointer pinfo));
199: static int icuunrecogfn P((pointer puuconf, int argc, char **argv,
200: pointer pvar, pointer pinfo));
201: static void uculist_vars P((void));
202: static void uculist_fns P((const char *zescape));
203: static boolean fcudo_subcmd P((pointer puuconf, struct sconnection *qconn,
204: char *zline));
205: static boolean fcusend_buf P((struct sconnection *qconn, const char *zbuf,
206: size_t cbuf));
207:
208: #define ucuputs(zline) \
209: do { if (! fsysdep_terminal_puts (zline)) ucuabort (); } while (0)
210:
211: /* Long getopt options. */
212: static const struct option asCulongopts[] = { { NULL, 0, NULL, 0 } };
213:
214: int
215: main (argc, argv)
216: int argc;
217: char **argv;
218: {
219: /* -c: phone number. */
220: char *zphone = NULL;
221: /* -e: even parity. */
222: boolean feven = FALSE;
223: /* -l: line. */
224: char *zline = NULL;
225: /* -n: prompt for phone number. */
226: boolean fprompt = FALSE;
227: /* -o: odd parity. */
228: boolean fodd = FALSE;
229: /* -p: port name. */
230: const char *zport = NULL;
231: /* -s: speed. */
232: long ibaud = 0L;
233: /* -t: map cr to crlf. */
234: boolean fmapcr = FALSE;
235: /* -z: system. */
236: const char *zsystem = NULL;
237: /* -I: configuration file name. */
238: const char *zconfig = NULL;
239: int iopt;
240: pointer puuconf;
241: int iuuconf;
242: const char *zlocalname;
243: int i;
244: struct uuconf_system ssys;
245: const struct uuconf_system *qsys = NULL;
246: boolean flooped;
247: struct uuconf_port sport;
248: struct sconnection sconn;
249: struct sconninfo sinfo;
250: long ihighbaud;
251: struct uuconf_dialer sdialer;
252: struct uuconf_dialer *qdialer;
253: char bcmd;
254:
255: /* We want to accept -# as a speed. It's easiest to look through
256: the arguments, replace -# with -s#, and let getopt handle it. */
257: for (i = 1; i < argc; i++)
258: {
259: if (argv[i][0] == '-'
260: && isdigit (BUCHAR (argv[i][1])))
261: {
262: size_t clen;
263: char *z;
264:
265: clen = strlen (argv[i]);
266: z = zbufalc (clen + 2);
267: z[0] = '-';
268: z[1] = 's';
269: memcpy (z + 2, argv[i] + 1, clen);
270: argv[i] = z;
271: }
272: }
273:
274: while ((iopt = getopt_long (argc, argv, "a:c:dehnI:l:op:s:tx:z:",
275: asCulongopts, (int *) NULL)) != EOF)
276: {
277: switch (iopt)
278: {
279: case 'c':
280: /* Phone number. */
281: zphone = optarg;
282: break;
283:
284: case 'd':
285: /* Set debugging level to maximum. */
286: #if DEBUG > 1
287: iDebug = DEBUG_MAX;
288: #endif
289: break;
290:
291: case 'e':
292: /* Even parity. */
293: feven = TRUE;
294: break;
295:
296: case 'h':
297: /* Local echo. */
298: fCulocalecho = TRUE;
299: break;
300:
301: case 'n':
302: /* Prompt for phone number. */
303: fprompt = TRUE;
304: break;
305:
306: case 'l':
307: /* Line name. */
308: zline = optarg;
309: break;
310:
311: case 'o':
312: /* Odd parity. */
313: fodd = TRUE;
314: break;
315:
316: case 'p':
317: case 'a':
318: /* Port name (-a is for compatibility). */
319: zport = optarg;
320: break;
321:
322: case 's':
323: /* Speed. */
324: ibaud = strtol (optarg, (char **) NULL, 10);
325: break;
326:
327: case 't':
328: /* Map cr to crlf. */
329: fmapcr = TRUE;
330: break;
331:
332: case 'z':
333: /* System name. */
334: zsystem = optarg;
335: break;
336:
337: case 'I':
338: /* Configuration file name. */
339: if (fsysdep_other_config (optarg))
340: zconfig = optarg;
341: break;
342:
343: case 'x':
344: #if DEBUG > 1
345: /* Set debugging level. */
346: iDebug |= idebug_parse (optarg);
347: #endif
348: break;
349:
350: case 0:
351: /* Long option found and flag set. */
352: break;
353:
354: default:
355: ucuusage ();
356: break;
357: }
358: }
359:
360: /* There can be one more argument, which is either a system name, a
361: phone number, or "dir". We decide which it is based on the first
362: character. To call a UUCP system whose name begins with a digit,
363: or one which is named "dir", you must use -z. */
364: if (optind != argc)
365: {
366: if (optind != argc - 1
367: || zsystem != NULL
368: || zphone != NULL)
369: ucuusage ();
370: if (strcmp (argv[optind], "dir") != 0)
371: {
372: if (isdigit (BUCHAR (argv[optind][0])))
373: zphone = argv[optind];
374: else
375: zsystem = argv[optind];
376: }
377: }
378:
379: /* If the user doesn't give a system, port, line or speed, then
380: there's no basis on which to select a port. */
381: if (zsystem == NULL
382: && zport == NULL
383: && zline == NULL
384: && ibaud == 0L)
385: ucuusage ();
386:
387: if (fprompt)
388: {
389: size_t cphone;
390:
391: printf ("Phone number: ");
392: (void) fflush (stdout);
393: zphone = NULL;
394: cphone = 0;
395: if (getline (&zphone, &cphone, stdin) <= 0
396: || *zphone == '\0')
397: {
398: fprintf (stderr, "%s: No phone number entered\n", abProgram);
399: exit (EXIT_FAILURE);
400: }
401: }
402:
403: iuuconf = uuconf_init (&puuconf, "cu", zconfig);
404: if (iuuconf != UUCONF_SUCCESS)
405: ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
406: pCuuuconf = puuconf;
407:
408: #if DEBUG > 1
409: {
410: const char *zdebug;
411:
412: iuuconf = uuconf_debuglevel (puuconf, &zdebug);
413: if (iuuconf != UUCONF_SUCCESS)
414: ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
415: if (zdebug != NULL)
416: iDebug |= idebug_parse (zdebug);
417: }
418: #endif
419:
420: usysdep_initialize (puuconf, INIT_NOCHDIR | INIT_SUID);
421:
422: iuuconf = uuconf_localname (puuconf, &zlocalname);
423: if (iuuconf == UUCONF_NOT_FOUND)
424: {
425: zlocalname = zsysdep_localname ();
426: if (zlocalname == NULL)
427: exit (EXIT_FAILURE);
428: }
429: else if (iuuconf != UUCONF_SUCCESS)
430: ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
431:
432: ulog_fatal_fn (ucuabort);
433: pfLstart = uculog_start;
434: pfLend = uculog_end;
435:
436: #ifdef SIGINT
437: usysdep_signal (SIGINT);
438: #endif
439: #ifdef SIGHUP
440: usysdep_signal (SIGHUP);
441: #endif
442: #ifdef SIGQUIT
443: usysdep_signal (SIGQUIT);
444: #endif
445: #ifdef SIGTERM
446: usysdep_signal (SIGTERM);
447: #endif
448: #ifdef SIGPIPE
449: usysdep_signal (SIGPIPE);
450: #endif
451:
452: if (zsystem != NULL)
453: {
454: iuuconf = uuconf_system_info (puuconf, zsystem, &ssys);
455: if (iuuconf != UUCONF_SUCCESS)
456: {
457: if (iuuconf != UUCONF_NOT_FOUND)
458: ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
459: ulog (LOG_FATAL, "%s: System not found", zsystem);
460: }
461: qsys = &ssys;
462: }
463:
464: /* This loop is used if a system is specified. It loops over the
465: various alternates until it finds one for which the dial
466: succeeds. This is an ugly spaghetti construction, and it should
467: be broken up into different functions someday. */
468: flooped = FALSE;
469: while (TRUE)
470: {
471: enum tparitysetting tparity;
472: enum tstripsetting tstrip;
473:
474: /* The uuconf_find_port function only selects directly on a port
475: name and a speed. To select based on the line name, we use a
476: function. If we can't find any defined port, and the user
477: specified a line name but did not specify a port name or a
478: system or a phone number, then we fake a direct port with
479: that line name (we don't fake a port if a system or phone
480: number were given because if we fake a port we have no way to
481: place a call; perhaps we should automatically look up a
482: particular dialer). This permits users to say cu -lttyd0
483: without having to put ttyd0 in the ports file, provided they
484: have read and write access to the port. */
485: sinfo.fmatched = FALSE;
486: sinfo.flocked = FALSE;
487: sinfo.qconn = &sconn;
488: sinfo.zline = zline;
489: if (zport != NULL || zline != NULL || ibaud != 0L)
490: {
491: iuuconf = uuconf_find_port (puuconf, zport, ibaud, 0L,
492: icuport_lock, (pointer) &sinfo,
493: &sport);
494: if (iuuconf != UUCONF_SUCCESS)
495: {
496: if (iuuconf != UUCONF_NOT_FOUND)
497: {
498: if (sinfo.flocked)
499: {
500: (void) fconn_unlock (&sconn);
501: uconn_free (&sconn);
502: }
503: ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
504: }
505: if (zline == NULL
506: || zport != NULL
507: || zphone != NULL
508: || qsys != NULL)
509: {
510: if (sinfo.fmatched)
511: ulog (LOG_FATAL, "All matching ports in use");
512: else
513: ulog (LOG_FATAL, "No matching ports");
514: }
515:
516: sport.uuconf_zname = zline;
517: sport.uuconf_ttype = UUCONF_PORTTYPE_DIRECT;
518: sport.uuconf_zprotocols = NULL;
519: sport.uuconf_qproto_params = NULL;
520: sport.uuconf_ireliable = 0;
521: sport.uuconf_zlockname = NULL;
522: sport.uuconf_palloc = NULL;
523: sport.uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL;
524: sport.uuconf_u.uuconf_sdirect.uuconf_ibaud = ibaud;
525:
526: if (! fsysdep_port_access (&sport))
527: ulog (LOG_FATAL, "%s: Permission denied", zline);
528:
529: if (! fconn_init (&sport, &sconn))
530: ucuabort ();
531:
532: if (! fconn_lock (&sconn, FALSE))
533: ulog (LOG_FATAL, "%s: Line in use", zline);
534:
535: qCuconn = &sconn;
536: }
537: ihighbaud = 0L;
538: }
539: else
540: {
541: for (; qsys != NULL; qsys = qsys->uuconf_qalternate)
542: {
543: if (! qsys->uuconf_fcall)
544: continue;
545: if (qsys->uuconf_qport != NULL)
546: {
547: if (fconn_init (qsys->uuconf_qport, &sconn))
548: {
549: if (fconn_lock (&sconn, FALSE))
550: {
551: qCuconn = &sconn;
552: break;
553: }
554: uconn_free (&sconn);
555: }
556: }
557: else
558: {
559: sinfo.fmatched = FALSE;
560: sinfo.flocked = FALSE;
561: sinfo.qconn = &sconn;
562: iuuconf = uuconf_find_port (puuconf, qsys->uuconf_zport,
563: qsys->uuconf_ibaud,
564: qsys->uuconf_ihighbaud,
565: icuport_lock,
566: (pointer) &sinfo,
567: &sport);
568: if (iuuconf == UUCONF_SUCCESS)
569: break;
570: if (iuuconf != UUCONF_NOT_FOUND)
571: {
572: if (sinfo.flocked)
573: {
574: (void) fconn_unlock (&sconn);
575: uconn_free (&sconn);
576: }
577: ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
578: }
579: }
580: }
581:
582: if (qsys == NULL)
583: {
584: const char *zrem;
585:
586: if (flooped)
587: zrem = "remaining ";
588: else
589: zrem = "";
590: if (sinfo.fmatched)
591: ulog (LOG_FATAL, "%s: All %smatching ports in use",
592: zsystem, zrem);
593: else
594: ulog (LOG_FATAL, "%s: No %smatching ports", zsystem, zrem);
595: }
596:
597: ibaud = qsys->uuconf_ibaud;
598: ihighbaud = qsys->uuconf_ihighbaud;
599: }
600:
601: /* Here we have locked a connection to use. */
602: if (! fconn_open (&sconn, ibaud, ihighbaud, FALSE))
603: ucuabort ();
604:
605: fCuclose_conn = TRUE;
606:
607: if (FGOT_SIGNAL ())
608: ucuabort ();
609:
610: /* Set up the connection. */
611: if (fodd && feven)
612: {
613: tparity = PARITYSETTING_NONE;
614: tstrip = STRIPSETTING_SEVENBITS;
615: }
616: else if (fodd)
617: {
618: tparity = PARITYSETTING_ODD;
619: tstrip = STRIPSETTING_SEVENBITS;
620: }
621: else if (feven)
622: {
623: tparity = PARITYSETTING_EVEN;
624: tstrip = STRIPSETTING_SEVENBITS;
625: }
626: else
627: {
628: tparity = PARITYSETTING_DEFAULT;
629: tstrip = STRIPSETTING_DEFAULT;
630: }
631:
632: if (! fconn_set (&sconn, tparity, tstrip, XONXOFF_ON))
633: ucuabort ();
634:
635: if (qsys != NULL)
636: zphone = qsys->uuconf_zphone;
637:
638: if (qsys != NULL || zphone != NULL)
639: {
640: enum tdialerfound tdialer;
641:
642: if (! fconn_dial (&sconn, puuconf, qsys, zphone, &sdialer,
643: &tdialer))
644: {
645: if (zport != NULL
646: || zline != NULL
647: || ibaud != 0L
648: || qsys == NULL)
649: ucuabort ();
650:
651: if (qsys->uuconf_qalternate == NULL)
652: ulog (LOG_FATAL, "%s: No remaining alternates", zsystem);
653:
654: fCuclose_conn = FALSE;
655: (void) fconn_close (&sconn, pCuuuconf, qCudialer, FALSE);
656: qCuconn = NULL;
657: (void) fconn_unlock (&sconn);
658: uconn_free (&sconn);
659:
660: /* Loop around and try another alternate. */
661: flooped = TRUE;
662: continue;
663: }
664: if (tdialer == DIALERFOUND_FALSE)
665: qdialer = NULL;
666: else
667: qdialer = &sdialer;
668: }
669: else
670: {
671: /* If no system or phone number was specified, we connect
672: directly to the modem. We only permit this if the user
673: has access to the port, since it permits various
674: shenanigans such as reprogramming the automatic
675: callbacks. */
676: if (! fsysdep_port_access (sconn.qport))
677: ulog (LOG_FATAL, "Access to port denied");
678: qdialer = NULL;
679: if (! fconn_carrier (&sconn, FALSE))
680: ulog (LOG_FATAL, "Can't turn off carrier");
681: }
682:
683: break;
684: }
685:
686: qCudialer = qdialer;
687:
688: if (FGOT_SIGNAL ())
689: ucuabort ();
690:
691: /* Here we have connected, and can start the main cu protocol. The
692: program spends most of its time in system dependent code, and
693: only comes out when a special command is received from the
694: terminal. */
695: printf ("%s\n", ZCONNMSG);
696:
697: if (! fsysdep_terminal_raw (fCulocalecho))
698: ucuabort ();
699:
700: fCurestore_terminal = TRUE;
701:
702: if (! fsysdep_cu_init (&sconn))
703: ucuabort ();
704:
705: fCustarted = TRUE;
706:
707: while (fsysdep_cu (&sconn, &bcmd, zlocalname))
708: if (! fcudo_cmd (puuconf, &sconn, bcmd))
709: break;
710:
711: fCustarted = FALSE;
712: if (! fsysdep_cu_finish ())
713: ucuabort ();
714:
715: fCurestore_terminal = FALSE;
716: (void) fsysdep_terminal_restore ();
717:
718: (void) fconn_close (&sconn, puuconf, qdialer, TRUE);
719: (void) fconn_unlock (&sconn);
720: uconn_free (&sconn);
721:
722: printf ("\n%s\n", ZDISMSG);
723:
724: ulog_close ();
725:
726: usysdep_exit (TRUE);
727:
728: /* Avoid errors about not returning a value. */
729: return 0;
730: }
731:
732: /* Print a usage message and die. */
733:
734: static void
735: ucuusage ()
736: {
737: fprintf (stderr,
738: "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
739: VERSION);
740: fprintf (stderr,
741: "Usage: cu [options] [system or phone-number]\n");
742: fprintf (stderr,
743: " -a port, -p port: Use named port\n");
744: fprintf (stderr,
745: " -l line: Use named device (e.g. tty0)\n");
746: fprintf (stderr,
747: " -s speed, -#: Use given speed\n");
748: fprintf (stderr,
749: " -c phone: Phone number to call\n");
750: fprintf (stderr,
751: " -z system: System to call\n");
752: fprintf (stderr,
753: " -e: Set even parity\n");
754: fprintf (stderr,
755: " -o: Set odd parity\n");
756: fprintf (stderr,
757: " -h: Echo locally\n");
758: fprintf (stderr,
759: " -t: Map carriage return to carriage return/linefeed\n");
760: fprintf (stderr,
761: " -n: Prompt for phone number\n");
762: fprintf (stderr,
763: " -d: Set maximum debugging level\n");
764: fprintf (stderr,
765: " -x debug: Set debugging type\n");
766: #if HAVE_TAYLOR_CONFIG
767: fprintf (stderr,
768: " -I file: Set configuration file to use\n");
769: #endif /* HAVE_TAYLOR_CONFIG */
770:
771: exit (EXIT_FAILURE);
772: }
773:
774: /* This function is called when a fatal error occurs. */
775:
776: static void
777: ucuabort ()
778: {
779: if (fCustarted)
780: {
781: fCustarted = FALSE;
782: (void) fsysdep_cu_finish ();
783: }
784:
785: if (fCurestore_terminal)
786: {
787: fCurestore_terminal = FALSE;
788: (void) fsysdep_terminal_restore ();
789: }
790:
791: if (qCuconn != NULL)
792: {
793: struct sconnection *qconn;
794:
795: if (fCuclose_conn)
796: {
797: fCuclose_conn = FALSE;
798: (void) fconn_close (qCuconn, pCuuuconf, qCudialer, FALSE);
799: }
800: qconn = qCuconn;
801: qCuconn = NULL;
802: (void) fconn_unlock (qconn);
803: uconn_free (qconn);
804: }
805:
806: ulog_close ();
807:
808: printf ("\n%s\n", ZDISMSG);
809:
810: usysdep_exit (FALSE);
811: }
812:
813: /* This variable is just used to communicate between uculog_start and
814: uculog_end. */
815: static boolean fCulog_restore;
816:
817: /* This function is called by ulog before it output anything. We use
818: it to restore the terminal, if necessary. ulog is only called for
819: errors or debugging in cu, so it's not too costly to do this. If
820: we didn't do it, then at least on Unix each line would leave the
821: cursor in the same column rather than wrapping back to the start,
822: since CRMOD will not be on. */
823:
824: static void
825: uculog_start ()
826: {
827: if (! fCurestore_terminal)
828: fCulog_restore = FALSE;
829: else
830: {
831: fCulog_restore = TRUE;
832: fCurestore_terminal = FALSE;
833: if (! fsysdep_terminal_restore ())
834: ucuabort ();
835: }
836: }
837:
838: /* This function is called by ulog after everything is output. It
839: sets the terminal back, if necessary. */
840:
841: static void
842: uculog_end ()
843: {
844: if (fCulog_restore)
845: {
846: if (! fsysdep_terminal_raw (fCulocalecho))
847: ucuabort ();
848: fCurestore_terminal = TRUE;
849: }
850: }
851:
852: /* Check to see if this port has the desired line, to handle the -l
853: option. If it does, or if no line was specified, set up a
854: connection and lock it. */
855:
856: static int
857: icuport_lock (qport, pinfo)
858: struct uuconf_port *qport;
859: pointer pinfo;
860: {
861: struct sconninfo *q = (struct sconninfo *) pinfo;
862:
863: if (q->zline != NULL
864: && ! fsysdep_port_is_line (qport, q->zline))
865: return UUCONF_NOT_FOUND;
866:
867: q->fmatched = TRUE;
868:
869: if (! fconn_init (qport, q->qconn))
870: return UUCONF_NOT_FOUND;
871: else if (! fconn_lock (q->qconn, FALSE))
872: {
873: uconn_free (q->qconn);
874: return UUCONF_NOT_FOUND;
875: }
876: else
877: {
878: qCuconn = q->qconn;
879: q->flocked = TRUE;
880: return UUCONF_SUCCESS;
881: }
882: }
883:
884: /* Execute a cu escape command. Return TRUE if the connection should
885: continue, or FALSE if the connection should be terminated. */
886:
887: static boolean
888: fcudo_cmd (puuconf, qconn, bcmd)
889: pointer puuconf;
890: struct sconnection *qconn;
891: int bcmd;
892: {
893: char *zline;
894: char *z;
895: char abescape[5];
896: boolean fret;
897: size_t clen;
898: char abbuf[100];
899:
900: /* Some commands take a string up to the next newline character. */
901: switch (bcmd)
902: {
903: default:
904: zline = NULL;
905: break;
906: case '!':
907: case '$':
908: case '|':
909: case '+':
910: case '%':
911: case 'c':
912: case '>':
913: case '<':
914: case 'p':
915: case 't':
916: case 's':
917: {
918: zline = zsysdep_terminal_line ((const char *) NULL);
919: if (zline == NULL)
920: ucuabort ();
921: zline[strcspn (zline, "\n")] = '\0';
922: }
923: break;
924: }
925:
926: switch (bcmd)
927: {
928: default:
929: if (! isprint (*zCuvar_escape))
930: sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
931: else
932: {
933: abescape[0] = *zCuvar_escape;
934: abescape[1] = '\0';
935: }
936: sprintf (abbuf, "[Unrecognized. Use %s%s to send %s]",
937: abescape, abescape, abescape);
938: ucuputs (abbuf);
939: return TRUE;
940:
941: case '.':
942: /* Hangup. */
943: return FALSE;
944:
945: case '!':
946: case '$':
947: case '|':
948: case '+':
949: /* Shell out. */
950: if (! fsysdep_cu_copy (FALSE)
951: || ! fsysdep_terminal_restore ())
952: ucuabort ();
953: fCurestore_terminal = FALSE;
954: {
955: enum tshell_cmd t;
956:
957: switch (bcmd)
958: {
959: default:
960: case '!': t = SHELL_NORMAL; break;
961: case '$': t = SHELL_STDOUT_TO_PORT; break;
962: case '|': t = SHELL_STDIN_FROM_PORT; break;
963: case '+': t = SHELL_STDIO_ON_PORT; break;
964: }
965:
966: (void) fsysdep_shell (qconn, zline, t);
967: }
968: if (! fsysdep_cu_copy (TRUE)
969: || ! fsysdep_terminal_raw (fCulocalecho))
970: ucuabort ();
971: fCurestore_terminal = TRUE;
972: ubuffree (zline);
973: return TRUE;
974:
975: case '%':
976: fret = fcudo_subcmd (puuconf, qconn, zline);
977: ubuffree (zline);
978: return fret;
979:
980: case '#':
981: if (! fconn_break (qconn))
982: ucuabort ();
983: return TRUE;
984:
985: case 'c':
986: (void) fsysdep_chdir (zline);
987: ubuffree (zline);
988: return TRUE;
989:
990: case '>':
991: case '<':
992: case 'p':
993: case 't':
994: clen = strlen (zline);
995: z = zbufalc (clen + 3);
996: z[0] = bcmd;
997: z[1] = ' ';
998: memcpy (z + 2, zline, clen + 1);
999: ubuffree (zline);
1000: fret = fcudo_subcmd (puuconf, qconn, z);
1001: ubuffree (z);
1002: return fret;
1003:
1004: case 'z':
1005: if (! fsysdep_cu_copy (FALSE)
1006: || ! fsysdep_terminal_restore ())
1007: ucuabort ();
1008: fCurestore_terminal = FALSE;
1009: if (! fsysdep_suspend ())
1010: ucuabort ();
1011: if (! fsysdep_cu_copy (TRUE)
1012: || ! fsysdep_terminal_raw (fCulocalecho))
1013: ucuabort ();
1014: fCurestore_terminal = TRUE;
1015: return TRUE;
1016:
1017: case 's':
1018: fret = fcuset_var (puuconf, zline);
1019: ubuffree (zline);
1020: return fret;
1021:
1022: case 'v':
1023: uculist_vars ();
1024: return TRUE;
1025:
1026: case '?':
1027: if (! isprint (*zCuvar_escape))
1028: sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
1029: else
1030: {
1031: abescape[0] = *zCuvar_escape;
1032: abescape[1] = '\0';
1033: }
1034: ucuputs ("");
1035: ucuputs ("[Escape sequences]");
1036: sprintf (abbuf,
1037: "[%s. hangup] [%s!CMD run shell]",
1038: abescape, abescape);
1039: ucuputs (abbuf);
1040: sprintf (abbuf,
1041: "[%s$CMD stdout to remote] [%s|CMD stdin from remote]",
1042: abescape, abescape);
1043: ucuputs (abbuf);
1044: sprintf (abbuf,
1045: "[%s+CMD stdin and stdout to remote]",
1046: abescape);
1047: ucuputs (abbuf);
1048: sprintf (abbuf,
1049: "[%s# send break] [%scDIR change directory]",
1050: abescape, abescape);
1051: ucuputs (abbuf);
1052: sprintf (abbuf,
1053: "[%s> send file] [%s< receive file]",
1054: abescape, abescape);
1055: ucuputs (abbuf);
1056: sprintf (abbuf,
1057: "[%spFROM TO send to Unix] [%stFROM TO receive from Unix]",
1058: abescape, abescape);
1059: ucuputs (abbuf);
1060: sprintf (abbuf,
1061: "[%ssVAR VAL set variable] [%ssVAR set boolean]",
1062: abescape, abescape);
1063: ucuputs (abbuf);
1064: sprintf (abbuf,
1065: "[%ss!VAR unset boolean] [%sv list variables]",
1066: abescape, abescape);
1067: ucuputs (abbuf);
1068: #ifdef SIGTSTP
1069: sprintf (abbuf,
1070: "[%sz suspend]",
1071: abescape);
1072: ucuputs (abbuf);
1073: #endif
1074: uculist_fns (abescape);
1075: return TRUE;
1076: }
1077: }
1078:
1079: /* List ~% functions. */
1080:
1081: static void
1082: uculist_fns (zescape)
1083: const char *zescape;
1084: {
1085: char abbuf[100];
1086:
1087: sprintf (abbuf,
1088: "[%s%%break send break] [%s%%cd DIR change directory]",
1089: zescape, zescape);
1090: ucuputs (abbuf);
1091: sprintf (abbuf,
1092: "[%s%%put FROM TO send file] [%s%%take FROM TO receive file]",
1093: zescape, zescape);
1094: ucuputs (abbuf);
1095: sprintf (abbuf,
1096: "[%s%%nostop no XON/XOFF] [%s%%stop use XON/XOFF]",
1097: zescape, zescape);
1098: ucuputs (abbuf);
1099: }
1100:
1101: /* Set a variable. */
1102:
1103: static boolean
1104: fcuset_var (puuconf, zline)
1105: pointer puuconf;
1106: char *zline;
1107: {
1108: char *zvar, *zval;
1109: char *azargs[2];
1110: char azbool[2];
1111: int iuuconf;
1112:
1113: zvar = strtok (zline, "= \t");
1114: if (zvar == NULL)
1115: {
1116: ucuputs (abCuconnected);
1117: return TRUE;
1118: }
1119:
1120: zval = strtok ((char *) NULL, " \t");
1121:
1122: if (zval == NULL)
1123: {
1124: azargs[0] = zvar;
1125: if (azargs[0][0] != '!')
1126: azbool[0] = 't';
1127: else
1128: {
1129: ++azargs[0];
1130: azbool[0] = 'f';
1131: }
1132: azbool[1] = '\0';
1133: azargs[1] = azbool;
1134: }
1135: else
1136: {
1137: azargs[0] = zvar;
1138: azargs[1] = zval;
1139: }
1140:
1141: iuuconf = uuconf_cmd_args (puuconf, 2, azargs, asCuvars,
1142: (pointer) NULL, icuunrecogvar, 0,
1143: (pointer) NULL);
1144: if (iuuconf != UUCONF_SUCCESS)
1145: ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
1146:
1147: return TRUE;
1148: }
1149:
1150: /* Warn about an unknown variable. */
1151:
1152: /*ARGSUSED*/
1153: static int
1154: icuunrecogvar (puuconf, argc, argv, pvar, pinfo)
1155: pointer puuconf;
1156: int argc;
1157: char **argv;
1158: pointer pvar;
1159: pointer pinfo;
1160: {
1161: char abescape[5];
1162:
1163: if (! isprint (*zCuvar_escape))
1164: sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
1165: else
1166: {
1167: abescape[0] = *zCuvar_escape;
1168: abescape[1] = '\0';
1169: }
1170: ulog (LOG_ERROR, "%s: unknown variable (%sv lists variables)",
1171: argv[0], abescape);
1172: return UUCONF_CMDTABRET_CONTINUE;
1173: }
1174:
1175: /* List all the variables with their values. */
1176:
1177: static void
1178: uculist_vars ()
1179: {
1180: const struct uuconf_cmdtab *q;
1181: char abbuf[100];
1182:
1183: ucuputs ("");
1184: for (q = asCuvars; q->uuconf_zcmd != NULL; q++)
1185: {
1186: switch (UUCONF_TTYPE_CMDTABTYPE (q->uuconf_itype))
1187: {
1188: case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_BOOLEAN):
1189: if (*(boolean *) q->uuconf_pvar)
1190: sprintf (abbuf, "%s true", q->uuconf_zcmd);
1191: else
1192: sprintf (abbuf, "%s false", q->uuconf_zcmd);
1193: break;
1194:
1195: case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_INT):
1196: sprintf (abbuf, "%s %d", q->uuconf_zcmd, *(int *) q->uuconf_pvar);
1197: break;
1198:
1199: case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_LONG):
1200: sprintf (abbuf, "%s %ld", q->uuconf_zcmd,
1201: *(long *) q->uuconf_pvar);
1202: break;
1203:
1204: case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_STRING):
1205: case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_FULLSTRING):
1206: {
1207: const char *z;
1208: char abchar[5];
1209: size_t clen;
1210:
1211: sprintf (abbuf, "%s ", q->uuconf_zcmd);
1212: clen = strlen (abbuf);
1213: for (z = *(const char **) q->uuconf_pvar; *z != '\0'; z++)
1214: {
1215: int cchar;
1216:
1217: if (! isprint (*z))
1218: {
1219: sprintf (abchar, "\\%03o", (unsigned int) *z);
1220: cchar = 4;
1221: }
1222: else
1223: {
1224: abchar[0] = *z;
1225: abchar[1] = '\0';
1226: cchar = 1;
1227: }
1228: if (clen + cchar < sizeof (abbuf))
1229: strcat (abbuf, abchar);
1230: clen += cchar;
1231: }
1232: }
1233: break;
1234:
1235: default:
1236: sprintf (abbuf, "%s [unprintable type]", q->uuconf_zcmd);
1237: break;
1238: }
1239:
1240: ucuputs (abbuf);
1241: }
1242: }
1243:
1244: /* Subcommands. These are commands that begin with ~%. */
1245:
1246: /* This variable is only used so that we can pass a non-NULL address
1247: in pvar. It is never assigned to or examined. */
1248:
1249: static char bCutype;
1250:
1251: /* The command table for the subcommands. */
1252:
1253: static int icubreak P((pointer puuconf, int argc, char **argv, pointer pvar,
1254: pointer pinfo));
1255: static int icudebug P((pointer puuconf, int argc, char **argv, pointer pvar,
1256: pointer pinfo));
1257: static int icuchdir P((pointer puuconf, int argc, char **argv, pointer pvar,
1258: pointer pinfo));
1259: static int icuput P((pointer puuconf, int argc, char **argv, pointer pvar,
1260: pointer pinfo));
1261: static int icutake P((pointer puuconf, int argc, char **argv, pointer pvar,
1262: pointer pinfo));
1263: static int icunostop P((pointer puuconf, int argc, char **argv, pointer pvar,
1264: pointer pinfo));
1265:
1266: static const struct uuconf_cmdtab asCucmds[] =
1267: {
1268: { "break", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak },
1269: { "b", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak },
1270: { "cd", UUCONF_CMDTABTYPE_FN | 0, NULL, icuchdir },
1271: { "d", UUCONF_CMDTABTYPE_FN | 1, NULL, icudebug },
1272: { "put", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput },
1273: { "take", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake },
1274: { "nostop", UUCONF_CMDTABTYPE_FN | 1, NULL, icunostop },
1275: { "stop", UUCONF_CMDTABTYPE_FN | 1, &bCutype, icunostop },
1276: { ">", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icuput },
1277: { "<", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icutake },
1278: { "p", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput },
1279: { "t", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake },
1280: { NULL, 0, NULL, NULL }
1281: };
1282:
1283: /* Do a subcommand. This is called by commands beginning with ~%. */
1284:
1285: static boolean
1286: fcudo_subcmd (puuconf, qconn, zline)
1287: pointer puuconf;
1288: struct sconnection *qconn;
1289: char *zline;
1290: {
1291: char *azargs[3];
1292: int iarg;
1293: int iuuconf;
1294:
1295: for (iarg = 0; iarg < 3; iarg++)
1296: {
1297: azargs[iarg] = strtok (iarg == 0 ? zline : (char *) NULL, " \t\n");
1298: if (azargs[iarg] == NULL)
1299: break;
1300: }
1301:
1302: if (iarg == 0)
1303: {
1304: ucuputs (abCuconnected);
1305: return TRUE;
1306: }
1307:
1308: iuuconf = uuconf_cmd_args (puuconf, iarg, azargs, asCucmds,
1309: (pointer) qconn, icuunrecogfn,
1310: 0, (pointer) NULL);
1311: if (iuuconf != UUCONF_SUCCESS)
1312: ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
1313:
1314: return TRUE;
1315: }
1316:
1317: /* Warn about an unknown function. */
1318:
1319: /*ARGSUSED*/
1320: static int
1321: icuunrecogfn (puuconf, argc, argv, pvar, pinfo)
1322: pointer puuconf;
1323: int argc;
1324: char **argv;
1325: pointer pvar;
1326: pointer pinfo;
1327: {
1328: char abescape[5];
1329:
1330: if (! isprint (*zCuvar_escape))
1331: sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
1332: else
1333: {
1334: abescape[0] = *zCuvar_escape;
1335: abescape[1] = '\0';
1336: }
1337: if (argv[0][0] == '?')
1338: uculist_fns (abescape);
1339: else
1340: ulog (LOG_ERROR, "%s: unknown (%s%%? lists choices)",
1341: argv[0], abescape);
1342: return UUCONF_CMDTABRET_CONTINUE;
1343: }
1344:
1345: /* Send a break. */
1346:
1347: /*ARGSUSED*/
1348: static int
1349: icubreak (puuconf, argc, argv, pvar, pinfo)
1350: pointer puuconf;
1351: int argc;
1352: char **argv;
1353: pointer pvar;
1354: pointer pinfo;
1355: {
1356: struct sconnection *qconn = (struct sconnection *) pinfo;
1357:
1358: if (! fconn_break (qconn))
1359: ucuabort ();
1360: return UUCONF_CMDTABRET_CONTINUE;
1361: }
1362:
1363: /* Change directories. */
1364:
1365: /*ARGSUSED*/
1366: static int
1367: icuchdir (puuconf, argc, argv, pvar, pinfo)
1368: pointer puuconf;
1369: int argc;
1370: char **argv;
1371: pointer pvar;
1372: pointer pinfo;
1373: {
1374: const char *zarg;
1375:
1376: if (argc <= 1)
1377: zarg = NULL;
1378: else
1379: zarg = argv[1];
1380: (void) fsysdep_chdir (zarg);
1381: return UUCONF_CMDTABRET_CONTINUE;
1382: }
1383:
1384: /* Toggle debugging. */
1385:
1386: /*ARGSUSED*/
1387: static int
1388: icudebug (puuconf, argc, argv, pvar, pinfo)
1389: pointer puuconf;
1390: int argc;
1391: char **argv;
1392: pointer pvar;
1393: pointer pinfo;
1394: {
1395: #if DEBUG > 1
1396: if (iDebug != 0)
1397: iDebug = 0;
1398: else
1399: iDebug = DEBUG_MAX;
1400: #else
1401: ucuputs ("[compiled without debugging]");
1402: #endif
1403: return UUCONF_CMDTABRET_CONTINUE;
1404: }
1405:
1406: /* Control whether the port does xon/xoff handshaking. If pvar is not
1407: NULL, this is "stop"; otherwise it is "nostop". */
1408:
1409: /*ARGSUSED*/
1410: static int
1411: icunostop (puuconf, argc, argv, pvar, pinfo)
1412: pointer puuconf;
1413: int argc;
1414: char **argv;
1415: pointer pvar;
1416: pointer pinfo;
1417: {
1418: struct sconnection *qconn = (struct sconnection *) pinfo;
1419:
1420: if (! fconn_set (qconn, PARITYSETTING_DEFAULT, STRIPSETTING_DEFAULT,
1421: pvar == NULL ? XONXOFF_OFF : XONXOFF_ON))
1422: ucuabort ();
1423: return UUCONF_CMDTABRET_CONTINUE;
1424: }
1425:
1426: /* Send a file to the remote system. The first argument is the file
1427: to send. If that argument is not present, it is prompted for. The
1428: second argument is to file name to use on the remote system. If
1429: that argument is not present, the basename of the local filename is
1430: used. If pvar is not NULL, then this is ~>, which is used to send
1431: a command to a non-Unix system. We treat is the same as ~%put,
1432: except that we assume the user has already entered the appropriate
1433: command (for ~%put, we force ``cat >to'' to the other side). */
1434:
1435: /*ARGSUSED*/
1436: static int
1437: icuput (puuconf, argc, argv, pvar, pinfo)
1438: pointer puuconf;
1439: int argc;
1440: char **argv;
1441: pointer pvar;
1442: pointer pinfo;
1443: {
1444: struct sconnection *qconn = (struct sconnection *) pinfo;
1445: char *zfrom;
1446: char *zto = NULL;
1447: char *zalc;
1448: openfile_t e;
1449: int cline;
1450: char *zbuf;
1451: size_t cbuf;
1452:
1453: if (argc > 1)
1454: zfrom = zbufcpy (argv[1]);
1455: else
1456: {
1457: zfrom = zsysdep_terminal_line ("File to send: ");
1458: if (zfrom == NULL)
1459: ucuabort ();
1460: zfrom[strcspn (zfrom, " \t\n")] = '\0';
1461:
1462: if (*zfrom == '\0')
1463: {
1464: ubuffree (zfrom);
1465: ucuputs (abCuconnected);
1466: return UUCONF_CMDTABRET_CONTINUE;
1467: }
1468: }
1469:
1470: if (pvar == NULL)
1471: {
1472: if (argc > 2)
1473: zto = zbufcpy (argv[2]);
1474: else
1475: {
1476: char *zbase;
1477: char *zprompt;
1478:
1479: zbase = zsysdep_base_name (zfrom);
1480: if (zbase == NULL)
1481: ucuabort ();
1482:
1483: zprompt = zbufalc (sizeof "Remote file name []: " +
1484: strlen (zbase));
1485: sprintf (zprompt, "Remote file name [%s]: ", zbase);
1486: zto = zsysdep_terminal_line (zprompt);
1487: ubuffree (zprompt);
1488: if (zto == NULL)
1489: ucuabort ();
1490:
1491: zto[strcspn (zto, " \t\n")] = '\0';
1492: if (*zto != '\0')
1493: ubuffree (zbase);
1494: else
1495: {
1496: ubuffree (zto);
1497: zto = zbase;
1498: }
1499: }
1500: }
1501:
1502: e = esysdep_user_fopen (zfrom, TRUE, fCuvar_binary);
1503: if (! ffileisopen (e))
1504: {
1505: const char *zerrstr;
1506:
1507: if (pvar == NULL)
1508: ubuffree (zto);
1509: zerrstr = strerror (errno);
1510: zalc = zbufalc (strlen (zfrom) + sizeof ": " + strlen (zerrstr));
1511: sprintf (zalc, "%s: %s", zfrom, zerrstr);
1512: ubuffree (zfrom);
1513: ucuputs (zalc);
1514: ubuffree (zalc);
1515: ucuputs (abCuconnected);
1516: return UUCONF_CMDTABRET_CONTINUE;
1517: }
1518:
1519: ubuffree (zfrom);
1520:
1521: /* Tell the system dependent layer to stop copying data from the
1522: port to the terminal. We want to read the echoes ourself. Also
1523: permit the local user to generate signals. */
1524: if (! fsysdep_cu_copy (FALSE)
1525: || ! fsysdep_terminal_signals (TRUE))
1526: ucuabort ();
1527:
1528: /* If pvar is NULL, then we are sending a file to a Unix system. We
1529: send over the command "cat > TO" to prepare it to receive. If
1530: pvar is not NULL, the user is assumed to have set up whatever
1531: action was needed to receive the file. */
1532: if (pvar == NULL)
1533: {
1534: boolean fret;
1535:
1536: zalc = zbufalc (sizeof "cat > \n" + strlen (zto));
1537: sprintf (zalc, "cat > %s\n", zto);
1538: ubuffree (zto);
1539: fret = fcusend_buf (qconn, zalc, strlen (zalc));
1540: ubuffree (zalc);
1541: if (! fret)
1542: {
1543: (void) ffileclose (e);
1544: if (! fsysdep_cu_copy (TRUE)
1545: || ! fsysdep_terminal_signals (FALSE))
1546: ucuabort ();
1547: ucuputs (abCuconnected);
1548: return UUCONF_CMDTABRET_CONTINUE;
1549: }
1550: }
1551:
1552: cline = 0;
1553:
1554: zbuf = NULL;
1555: cbuf = 0;
1556:
1557: while (TRUE)
1558: {
1559: char abbuf[512];
1560: size_t c;
1561:
1562: #if USE_STDIO
1563: if (fCuvar_binary)
1564: #endif
1565: {
1566: if (ffileeof (e))
1567: break;
1568: c = cfileread (e, abbuf, sizeof abbuf);
1569: if (ffilereaderror (e, c))
1570: {
1571: ucuputs ("[file read error]");
1572: break;
1573: }
1574: if (c == 0)
1575: break;
1576: zbuf = abbuf;
1577: }
1578: #if USE_STDIO
1579: else
1580: {
1581: if (getline (&zbuf, &cbuf, e) <= 0)
1582: {
1583: xfree ((pointer) zbuf);
1584: break;
1585: }
1586: c = strlen (zbuf);
1587: }
1588: #endif
1589:
1590: if (fCuvar_verbose)
1591: {
1592: ++cline;
1593: printf ("%d ", cline);
1594: (void) fflush (stdout);
1595: }
1596:
1597: if (! fcusend_buf (qconn, zbuf, c))
1598: {
1599: if (! fCuvar_binary)
1600: xfree ((pointer) zbuf);
1601: (void) fclose (e);
1602: if (! fsysdep_cu_copy (TRUE)
1603: || ! fsysdep_terminal_signals (FALSE))
1604: ucuabort ();
1605: ucuputs (abCuconnected);
1606: return UUCONF_CMDTABRET_CONTINUE;
1607: }
1608: }
1609:
1610: (void) ffileclose (e);
1611:
1612: if (pvar == NULL)
1613: {
1614: char beof;
1615:
1616: beof = '\004';
1617: if (! fconn_write (qconn, &beof, 1))
1618: ucuabort ();
1619: }
1620: else
1621: {
1622: if (*zCuvar_eofwrite != '\0')
1623: {
1624: if (! fconn_write (qconn, zCuvar_eofwrite,
1625: strlen (zCuvar_eofwrite)))
1626: ucuabort ();
1627: }
1628: }
1629:
1630: if (fCuvar_verbose)
1631: ucuputs ("");
1632:
1633: ucuputs ("[file transfer complete]");
1634:
1635: if (! fsysdep_cu_copy (TRUE)
1636: || ! fsysdep_terminal_signals (FALSE))
1637: ucuabort ();
1638:
1639: ucuputs (abCuconnected);
1640: return UUCONF_CMDTABRET_CONTINUE;
1641: }
1642:
1643: /* Get a file from the remote side. This is ~%take, or ~t, or ~<.
1644: The first two are assumed to be taking the file from a Unix system,
1645: so we force the command "cat FROM; echo */
1646:
1647: /*ARGSUSED*/
1648: static int
1649: icutake (puuconf, argc, argv, pvar, pinfo)
1650: pointer puuconf;
1651: int argc;
1652: char **argv;
1653: pointer pvar;
1654: pointer pinfo;
1655: {
1656: struct sconnection *qconn = (struct sconnection *) pinfo;
1657: const char *zeof;
1658: char *zfrom, *zto, *zcmd;
1659: char *zalc;
1660: openfile_t e;
1661: char bcr;
1662: size_t ceoflen;
1663: char *zlook = NULL;
1664: size_t ceofhave;
1665: boolean ferr;
1666:
1667: if (argc > 1)
1668: zfrom = zbufcpy (argv[1]);
1669: else
1670: {
1671: zfrom = zsysdep_terminal_line ("Remote file to retreive: ");
1672: if (zfrom == NULL)
1673: ucuabort ();
1674: zfrom[strcspn (zfrom, " \t\n")] = '\0';
1675: if (*zfrom == '\0')
1676: {
1677: ubuffree (zfrom);
1678: ucuputs (abCuconnected);
1679: return UUCONF_CMDTABRET_CONTINUE;
1680: }
1681: }
1682:
1683: if (argc > 2)
1684: zto = zbufcpy (argv[2]);
1685: else
1686: {
1687: char *zbase;
1688: char *zprompt;
1689:
1690: zbase = zsysdep_base_name (zfrom);
1691: if (zbase == NULL)
1692: ucuabort ();
1693:
1694: zprompt = zbufalc (sizeof "Local file name []: " + strlen (zbase));
1695: sprintf (zprompt, "Local file name [%s]: ", zbase);
1696: zto = zsysdep_terminal_line (zprompt);
1697: ubuffree (zprompt);
1698: if (zto == NULL)
1699: ucuabort ();
1700:
1701: zto[strcspn (zto, " \t\n")] = '\0';
1702: if (*zto != '\0')
1703: ubuffree (zbase);
1704: else
1705: {
1706: ubuffree (zto);
1707: zto = zbase;
1708: }
1709: }
1710:
1711: if (pvar != NULL)
1712: {
1713: zcmd = zsysdep_terminal_line ("Remote command to execute: ");
1714: if (zcmd == NULL)
1715: ucuabort ();
1716: zcmd[strcspn (zcmd, "\n")] = '\0';
1717: zeof = zCuvar_eofread;
1718: }
1719: else
1720: {
1721: zcmd = zbufalc (sizeof "cat ; echo; echo ////cuend////"
1722: + strlen (zfrom));
1723: sprintf (zcmd, "cat %s; echo; echo ////cuend////", zfrom);
1724: zeof = "\n////cuend////\n";
1725: }
1726:
1727: ubuffree (zfrom);
1728:
1729: e = esysdep_user_fopen (zto, FALSE, fCuvar_binary);
1730: if (! ffileisopen (e))
1731: {
1732: const char *zerrstr;
1733:
1734: ubuffree (zcmd);
1735: zerrstr = strerror (errno);
1736: zalc = zbufalc (strlen (zto) + sizeof ": " + strlen (zerrstr));
1737: sprintf (zalc, "%s: %s\n", zto, zerrstr);
1738: ucuputs (zalc);
1739: ubuffree (zalc);
1740: ucuputs (abCuconnected);
1741: ubuffree (zto);
1742: return UUCONF_CMDTABRET_CONTINUE;
1743: }
1744:
1745: ubuffree (zto);
1746:
1747: if (! fsysdep_cu_copy (FALSE)
1748: || ! fsysdep_terminal_signals (TRUE))
1749: ucuabort ();
1750:
1751: if (! fconn_write (qconn, zcmd, strlen (zcmd)))
1752: ucuabort ();
1753: bcr = '\r';
1754: if (! fconn_write (qconn, &bcr, 1))
1755: ucuabort ();
1756:
1757: ubuffree (zcmd);
1758:
1759: /* Eliminated any previously echoed data to avoid confusion. */
1760: iPrecstart = 0;
1761: iPrecend = 0;
1762:
1763: /* If we're dealing with a Unix system, we can reliably discard the
1764: command. Otherwise, the command will probably wind up in the
1765: file; too bad. */
1766: if (pvar == NULL)
1767: {
1768: int b;
1769:
1770: while ((b = breceive_char (qconn, cCuvar_timeout, TRUE)) != '\n')
1771: {
1772: if (b == -2)
1773: ucuabort ();
1774: if (b < 0)
1775: {
1776: ucuputs ("[timed out waiting for newline]");
1777: ucuputs (abCuconnected);
1778: return UUCONF_CMDTABRET_CONTINUE;
1779: }
1780: }
1781: }
1782:
1783: ceoflen = strlen (zeof);
1784: zlook = zbufalc (ceoflen);
1785: ceofhave = 0;
1786: ferr = FALSE;
1787:
1788: while (TRUE)
1789: {
1790: int b;
1791:
1792: if (FGOT_SIGNAL ())
1793: {
1794: /* Make sure the signal is logged. */
1795: ulog (LOG_ERROR, (const char *) NULL);
1796: ucuputs ("[file receive aborted]");
1797: /* Reset the SIGINT flag so that it does not confuse us in
1798: the future. */
1799: afSignal[INDEXSIG_SIGINT] = FALSE;
1800: break;
1801: }
1802:
1803: b = breceive_char (qconn, cCuvar_timeout, TRUE);
1804: if (b == -2)
1805: ucuabort ();
1806: if (b < 0)
1807: {
1808: if (ceofhave > 0)
1809: (void) fwrite (zlook, sizeof (char), ceofhave, e);
1810: ucuputs ("[timed out]");
1811: break;
1812: }
1813:
1814: if (ceoflen == 0)
1815: {
1816: if (cfilewrite (e, &b, 1) != 1)
1817: {
1818: ferr = TRUE;
1819: break;
1820: }
1821: }
1822: else
1823: {
1824: zlook[ceofhave] = b;
1825: ++ceofhave;
1826: if (ceofhave == ceoflen)
1827: {
1828: size_t cmove;
1829: char *zmove;
1830:
1831: if (memcmp (zeof, zlook, ceoflen) == 0)
1832: {
1833: ucuputs ("[file transfer complete]");
1834: break;
1835: }
1836:
1837: if (cfilewrite (e, zlook, 1) != 1)
1838: {
1839: ferr = TRUE;
1840: break;
1841: }
1842:
1843: zmove = zlook;
1844: for (cmove = ceoflen - 1, zmove = zlook;
1845: cmove > 0;
1846: cmove--, zmove++)
1847: zmove[0] = zmove[1];
1848:
1849: --ceofhave;
1850: }
1851: }
1852: }
1853:
1854: ubuffree (zlook);
1855:
1856: if (! ffileclose (e))
1857: ferr = TRUE;
1858: if (ferr)
1859: ucuputs ("[file write error]");
1860:
1861: if (! fsysdep_cu_copy (TRUE)
1862: || ! fsysdep_terminal_signals (FALSE))
1863: ucuabort ();
1864:
1865: ucuputs (abCuconnected);
1866:
1867: return UUCONF_CMDTABRET_CONTINUE;
1868: }
1869:
1870: /* Send a buffer to the remote system. If fCuvar_binary is FALSE,
1871: each buffer passed in will be a single line; in this case we can
1872: check the echoed characters and kill the line if they do not match.
1873: This returns FALSE if an echo check fails. If a port error
1874: occurrs, it calls ucuabort. */
1875:
1876: static boolean
1877: fcusend_buf (qconn, zbufarg, cbufarg)
1878: struct sconnection *qconn;
1879: const char *zbufarg;
1880: size_t cbufarg;
1881: {
1882: const char *zbuf;
1883: size_t cbuf;
1884: int ctries;
1885: size_t cbplen;
1886: char *zsendbuf;
1887:
1888: zbuf = zbufarg;
1889: cbuf = cbufarg;
1890: ctries = 0;
1891:
1892: if (fCuvar_binary)
1893: cbplen = strlen (zCuvar_binary_prefix);
1894: else
1895: cbplen = 1;
1896: zsendbuf = zbufalc (64 * (cbplen + 1));
1897:
1898: /* Loop while we still have characters to send. The value of cbuf
1899: will be reset to cbufarg if an echo failure occurs while sending
1900: a line in non-binary mode. */
1901: while (cbuf > 0)
1902: {
1903: int csend;
1904: char *zput;
1905: const char *zget;
1906: boolean fnl;
1907: int i;
1908:
1909: if (FGOT_SIGNAL ())
1910: {
1911: /* Make sure the signal is logged. */
1912: ubuffree (zsendbuf);
1913: ulog (LOG_ERROR, (const char *) NULL);
1914: ucuputs ("[file send aborted]");
1915: /* Reset the SIGINT flag so that it does not confuse us in
1916: the future. */
1917: afSignal[INDEXSIG_SIGINT] = FALSE;
1918: return FALSE;
1919: }
1920:
1921: /* Discard anything we've read from the port up to now, to avoid
1922: confusing the echo checking. */
1923: iPrecstart = 0;
1924: iPrecend = 0;
1925:
1926: /* Send all characters up to a newline before actually sending
1927: the newline. This makes it easier to handle the special
1928: newline echo checking. Send up to 64 characters at a time
1929: before doing echo checking. */
1930: if (*zbuf == '\n')
1931: csend = 1;
1932: else
1933: {
1934: const char *znl;
1935:
1936: znl = memchr (zbuf, '\n', cbuf);
1937: if (znl == NULL)
1938: csend = cbuf;
1939: else
1940: csend = znl - zbuf;
1941: if (csend > 64)
1942: csend = 64;
1943: }
1944:
1945: /* Translate this part of the buffer. If we are not in binary
1946: mode, we translate \n to \r, and ignore any nonprintable
1947: characters. */
1948: zput = zsendbuf;
1949: fnl = FALSE;
1950: for (i = 0, zget = zbuf; i < csend; i++, zget++)
1951: {
1952: if (isprint (*zget)
1953: || *zget == '\t')
1954: *zput++ = *zget;
1955: else if (*zget == '\n')
1956: {
1957: if (fCuvar_binary)
1958: *zput++ = '\n';
1959: else
1960: *zput++ = '\r';
1961: fnl = TRUE;
1962: }
1963: else if (fCuvar_binary)
1964: {
1965: strcpy (zput, zCuvar_binary_prefix);
1966: zput += cbplen;
1967: *zput++ = *zget;
1968: }
1969: }
1970:
1971: zbuf += csend;
1972: cbuf -= csend;
1973:
1974: if (zput == zsendbuf)
1975: continue;
1976:
1977: /* Send the data over the port. */
1978: if (! fsend_data (qconn, zsendbuf, (size_t) (zput - zsendbuf), TRUE))
1979: ucuabort ();
1980:
1981: /* We do echo checking if requested, unless we are in binary
1982: mode. Echo checking of a newline is different from checking
1983: of normal characters; when we send a newline we look for
1984: *zCuvar_echonl. */
1985: if ((fCuvar_echocheck && ! fCuvar_binary)
1986: || (fnl && *zCuvar_echonl != '\0'))
1987: {
1988: long iend;
1989:
1990: iend = ixsysdep_time ((long *) NULL) + (long) cCuvar_timeout;
1991: for (zget = zsendbuf; zget < zput; zget++)
1992: {
1993: int bread;
1994: int bwant;
1995:
1996: if (fCuvar_binary ? *zget == '\n' : *zget == '\r')
1997: {
1998: bwant = *zCuvar_echonl;
1999: if (bwant == '\0')
2000: continue;
2001: }
2002: else
2003: {
2004: if (! fCuvar_echocheck || ! isprint (*zget))
2005: continue;
2006: bwant = *zget;
2007: }
2008:
2009: do
2010: {
2011: if (FGOT_SIGNAL ())
2012: {
2013: /* Make sure the signal is logged. */
2014: ubuffree (zsendbuf);
2015: ulog (LOG_ERROR, (const char *) NULL);
2016: ucuputs ("[file send aborted]");
2017: /* Reset the SIGINT flag so that it does not
2018: confuse us in the future. */
2019: afSignal[INDEXSIG_SIGINT] = FALSE;
2020: return FALSE;
2021: }
2022:
2023: bread = breceive_char (qconn,
2024: iend - ixsysdep_time ((long *) NULL),
2025: TRUE);
2026: if (bread < 0)
2027: {
2028: if (bread == -2)
2029: ucuabort ();
2030:
2031: /* If we timed out, and we're not in binary
2032: mode, we kill the line and try sending it
2033: again from the beginning. */
2034: if (! fCuvar_binary && *zCuvar_kill != '\0')
2035: {
2036: ++ctries;
2037: if (ctries < cCuvar_resend)
2038: {
2039: if (fCuvar_verbose)
2040: {
2041: printf ("R ");
2042: (void) fflush (stdout);
2043: }
2044: if (! fsend_data (qconn, zCuvar_kill, 1,
2045: TRUE))
2046: ucuabort ();
2047: zbuf = zbufarg;
2048: cbuf = cbufarg;
2049: break;
2050: }
2051: }
2052: ubuffree (zsendbuf);
2053: ucuputs ("[timed out looking for echo]");
2054: return FALSE;
2055: }
2056: }
2057: while (bread != *zget);
2058:
2059: if (bread < 0)
2060: break;
2061: }
2062: }
2063: }
2064:
2065: ubuffree (zsendbuf);
2066:
2067: return TRUE;
2068: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.