summaryrefslogtreecommitdiff
path: root/gnu/libexec/uucp/cu
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /gnu/libexec/uucp/cu
initial import of NetBSD tree
Diffstat (limited to 'gnu/libexec/uucp/cu')
-rw-r--r--gnu/libexec/uucp/cu/Makefile16
-rw-r--r--gnu/libexec/uucp/cu/cu.1310
-rw-r--r--gnu/libexec/uucp/cu/cu.c2186
3 files changed, 2512 insertions, 0 deletions
diff --git a/gnu/libexec/uucp/cu/Makefile b/gnu/libexec/uucp/cu/Makefile
new file mode 100644
index 00000000000..150579b5ebd
--- /dev/null
+++ b/gnu/libexec/uucp/cu/Makefile
@@ -0,0 +1,16 @@
+# Makefile for cu
+# $Id: Makefile,v 1.1 1995/10/18 08:38:27 deraadt Exp $
+
+BINDIR= $(bindir)
+BINOWN= $(owner)
+BINMODE= 4555
+
+PROG= cu
+SRCS= cu.c prot.c log.c chat.c conn.c copy.c
+LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP)
+DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP)
+CFLAGS+= -I$(.CURDIR)/../common_sources\
+ -DVERSION=\"$(VERSION)\"
+
+.include <bsd.prog.mk>
+.PATH: $(.CURDIR)/../common_sources
diff --git a/gnu/libexec/uucp/cu/cu.1 b/gnu/libexec/uucp/cu/cu.1
new file mode 100644
index 00000000000..6424ee1d74a
--- /dev/null
+++ b/gnu/libexec/uucp/cu/cu.1
@@ -0,0 +1,310 @@
+''' $Id: cu.1,v 1.1 1995/10/18 08:38:27 deraadt Exp $
+.TH cu 1 "Taylor UUCP 1.06"
+.SH NAME
+cu \- Call up another system
+.SH SYNOPSIS
+.B cu
+[ options ] [ system | phone | "dir" ]
+.SH DESCRIPTION
+The
+.I cu
+command is used to call up another system and act as a dial in
+terminal. It can also do simple file transfers with no error
+checking.
+
+.I cu
+takes a single argument, besides the options. If the argument is the
+string "dir" cu will make a direct connection to the port. This may
+only be used by users with write access to the port, as it permits
+reprogramming the modem.
+
+Otherwise, if the argument begins with a digit, it is taken to be a
+phone number to call. Otherwise, it is taken to be the name of a
+system to call. The
+.B \-z
+or
+.B \-\-system
+option may be used to name a system beginning with a digit, and the
+.B \-c
+or
+.B \-\-phone
+option may be used to name a phone number that does not begin with a
+digit.
+
+.I cu
+locates a port to use in the UUCP configuration files. If a simple
+system name is given, it will select a port appropriate for that
+system. The
+.B \-p, \-\-port, \-l, \-\-line, \-s
+and
+.B \-\-speed
+options may be used to control the port selection.
+
+When a connection is made to the remote system,
+.I cu
+forks into two processes. One reads from the port and writes to the
+terminal, while the other reads from the terminal and writes to the
+port.
+
+.I cu
+provides several commands that may be used during the conversation.
+The commands all begin with an escape character, initially
+.B ~
+(tilde). The escape character is only recognized at the beginning of
+a line. To send an escape character to the remote system at the start
+of a line, it must be entered twice. All commands are either a single
+character or a word beginning with
+.B %
+(percent sign).
+
+.I cu
+recognizes the following commands:
+
+.TP 5
+.B ~.
+Terminate the conversation.
+.TP 5
+.B ~! command
+Run command in a shell. If command is empty, starts up a shell.
+.TP 5
+.B ~$ command
+Run command, sending the standard output to the remote system.
+.TP 5
+.B ~| command
+Run command, taking the standard input from the remote system.
+.TP 5
+.B ~+ command
+Run command, taking the standard input from the remote system and
+sending the standard output to the remote system.
+.TP 5
+.B ~#, ~%break
+Send a break signal, if possible.
+.TP 5
+.B ~c directory, ~%cd directory
+Change the local directory.
+.TP 5
+.B ~> file
+Send a file to the remote system. This just dumps the file over the
+communication line. It is assumed that the remote system is expecting
+it.
+.TP 5
+.B ~<
+Receive a file from the remote system. This prompts for the local
+file name and for the remote command to execute to begin the file
+transfer. It continues accepting data until the contents of the
+.B eofread
+variable are seen.
+.TP 5
+.B ~p from to, ~%put from to
+Send a file to a remote Unix system. This runs the appropriate
+commands on the remote system.
+.TP 5
+.B ~t from to, ~%take from to
+Retrieve a file from a remote Unix system. This runs the appropriate
+commands on the remote system.
+.TP 5
+.B ~s variable value
+Set a
+.I cu
+variable to the given value. If value is not given, the variable is
+set to
+.B true.
+.TP 5
+.B ~! variable
+Set a
+.I cu
+variable to
+.B false.
+.TP 5
+.B ~z
+Suspend the cu session. This is only supported on some systems. On
+systems for which ^Z may be used to suspend a job,
+.B ~^Z
+will also suspend the session.
+.TP 5
+.B ~%nostop
+Turn off XON/XOFF handling.
+.TP 5
+.B ~%stop
+Turn on XON/XOFF handling.
+.TP 5
+.B ~v
+List all the variables and their values.
+.TP 5
+.B ~?
+List all commands.
+
+.I cu
+also supports several variables. They may be listed with the
+.B ~v
+command, and set with the
+.B ~s
+or
+.B ~!
+commands.
+
+.TP 5
+.B escape
+The escape character. Initially
+.B ~
+(tilde).
+.TP 5
+.B delay
+If this variable is true,
+.I cu
+will delay for a second after recognizing the escape character before
+printing the name of the local system. The default is true.
+.TP 5
+.B eol
+The list of characters which are considered to finish a line. The
+escape character is only recognized after one of these is seen. The
+default is carriage return, ^U, ^C, ^O, ^D, ^S, ^Q, ^R.
+.TP 5
+.B binary
+Whether to transfer binary data when sending a file. If this is
+false, then newlines in the file being sent are converted to carriage
+returns. The default is false.
+.TP 5
+.B binary-prefix
+A string used before sending a binary character in a file transfer, if
+the
+.B binary
+variable is true. The default is ^V.
+.TP 5
+.B echo-check
+Whether to check file transfers by examining what the remote system
+echoes back. This probably doesn't work very well. The default is
+false.
+.TP 5
+.B echonl
+The character to look for after sending each line in a file. The
+default is carriage return.
+.TP 5
+.B timeout
+The timeout to use, in seconds, when looking for a character, either
+when doing echo checking or when looking for the
+.B echonl
+character. The default is 30.
+.TP 5
+.B kill
+The character to use delete a line if the echo check fails. The
+default is ^U.
+.TP 5
+.B resend
+The number of times to resend a line if the echo check continues to
+fail. The default is 10.
+.TP 5
+.B eofwrite
+The string to write after sending a file with the
+.B ~>
+command. The default is ^D.
+.TP 5
+.B eofread
+The string to look for when receiving a file with the
+.B ~<
+command. The default is $, which is intended to be a typical shell
+prompt.
+.TP 5
+.B verbose
+Whether to print accumulated information during a file transfer. The
+default is true.
+.SH OPTIONS
+The following options may be given to
+.I cu.
+.TP 5
+.B \-e, \-\-parity=even
+Use even parity.
+.TP 5
+.B \-o, \-\-parity=odd
+Use odd parity.
+.TP 5
+.B \-\-parity=none
+Use no parity. No parity is also used if both
+.B \-e
+and
+.B \-o
+are given.
+.TP 5
+.B \-h, \-\-halfduplex
+Echo characters locally (half-duplex mode).
+.TP 5
+.B \-\-nostop
+Turn off XON/XOFF handling (it is on by default).
+.TP 5
+.B \-E char, \-\-escape char
+Set the escape character. Initially
+.B ~
+(tilde). To eliminate the escape character, use
+.B -E ''.
+.TP 5
+.B \-z system, \-\-system system
+The system to call.
+.TP 5
+.B \-c phone-number, \-\-phone phone-number
+The phone number to call.
+.TP 5
+.B \-p port, \-\-port port
+Name the port to use.
+.TP 5
+.B \-a port
+Equivalent to
+.B \-\-port port.
+.TP 5
+.B \-l line, \-\-line line
+Name the line to use by giving a device name. This may be used to
+dial out on ports that are not listed in the UUCP configuration files.
+Write access to the device is required.
+.TP 5
+.B \-s speed, \-\-speed speed
+The speed (baud rate) to use.
+.TP 5
+.B \-#
+Where # is a number, equivalent to
+.B \-\-speed #.
+.TP 5
+.B \-n, \-\-prompt
+Prompt for the phone number to use.
+.TP 5
+.B \-d
+Enter debugging mode. Equivalent to
+.B \-\-debug all.
+.TP 5
+.B \-x type, \-\-debug type
+Turn on particular debugging types. The following types are
+recognized: abnormal, chat, handshake, uucp-proto, proto, port,
+config, spooldir, execute, incoming, outgoing. Only abnormal, chat,
+handshake, port, config, incoming and outgoing are meaningful for
+.I cu.
+
+Multiple types may be given, separated by commas, and the
+.B \-\-debug
+option may appear multiple times. A number may also be given, which
+will turn on that many types from the foregoing list; for example,
+.B \-\-debug 2
+is equivalent to
+.B \-\-debug abnormal,chat.
+.B \-\-debug all
+may be used to turn on all debugging options.
+.TP 5
+.B \-I file, \-\-config file
+Set configuration file to use. This option may not be available,
+depending upon how
+.I cu
+was compiled.
+.TP 5
+.B \-v, \-\-version
+Report version information and exit.
+.TP 5
+.B \-\-help
+Print a help message and exit.
+.SH BUGS
+This program does not work very well.
+.SH FILES
+The file name may be changed at compilation time, so this is only an
+approximation.
+
+.br
+/usr/lib/uucp/config - Configuration file.
+.SH AUTHOR
+Ian Lance Taylor
+<ian@airs.com>
diff --git a/gnu/libexec/uucp/cu/cu.c b/gnu/libexec/uucp/cu/cu.c
new file mode 100644
index 00000000000..78703f24a44
--- /dev/null
+++ b/gnu/libexec/uucp/cu/cu.c
@@ -0,0 +1,2186 @@
+/* cu.c
+ Call up a remote system.
+
+ Copyright (C) 1992, 1993, 1994, 1995 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char cu_rcsid[] = "$Id: cu.c,v 1.1 1995/10/18 08:38:27 deraadt Exp $";
+#endif
+
+#include "cu.h"
+#include "uudefs.h"
+#include "uuconf.h"
+#include "conn.h"
+#include "prot.h"
+#include "system.h"
+#include "sysdep.h"
+#include "getopt.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+/* Here are the user settable variables. The user is permitted to
+ change these while running the program, using ~s. */
+
+/* The escape character used to introduce a special command. The
+ escape character is the first character of this string. */
+const char *zCuvar_escape = "~";
+
+/* Whether to delay for a second before printing the host name after
+ seeing an escape character. */
+boolean fCuvar_delay = TRUE;
+
+/* The input characters which finish a line. The escape character is
+ only recognized following one of these characters. The default is
+ carriage return, ^U, ^C, ^O, ^D, ^S, ^Q, ^R, which I got from the
+ Ultrix /etc/remote file. */
+const char *zCuvar_eol = "\r\025\003\017\004\023\021\022";
+
+/* Whether to transfer binary data (nonprintable characters other than
+ newline and tab) when sending a file. If this is FALSE, then
+ newline is changed to carriage return. */
+boolean fCuvar_binary = FALSE;
+
+/* A prefix string to use before sending a binary character from a
+ file; this is only used if fCuvar_binary is TRUE. The default is
+ ^V. */
+const char *zCuvar_binary_prefix = "\026";
+
+/* Whether to check for echoes of characters sent when sending a file.
+ This is ignored if fCuvar_binary is TRUE. */
+boolean fCuvar_echocheck = FALSE;
+
+/* A character to look for after each newline is sent when sending a
+ file. The character is the first character in this string, except
+ that a '\0' means that no echo check is done. */
+const char *zCuvar_echonl = "\r";
+
+/* The timeout to use when looking for an character. */
+int cCuvar_timeout = 30;
+
+/* The character to use to kill a line if an echo check fails. The
+ first character in this string is sent. The default is ^U. */
+const char *zCuvar_kill = "\025";
+
+/* The number of times to try resending a line if the echo check keeps
+ failing. */
+int cCuvar_resend = 10;
+
+/* The string to send at the end of a file sent with ~>. The default
+ is ^D. */
+const char *zCuvar_eofwrite = "\004";
+
+/* The string to look for to finish a file received with ~<. For tip
+ this is a collection of single characters, but I don't want to do
+ that because it means that there are characters which cannot be
+ received. The default is a guess at a typical shell prompt. */
+const char *zCuvar_eofread = "$";
+
+/* Whether to provide verbose information when sending or receiving a
+ file. */
+boolean fCuvar_verbose = TRUE;
+
+/* The table used to give a value to a variable, and to print all the
+ variable values. */
+
+static const struct uuconf_cmdtab asCuvars[] =
+{
+ { "escape", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_escape, NULL },
+ { "delay", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_delay, NULL },
+ { "eol", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eol, NULL },
+ { "binary", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_binary, NULL },
+ { "binary-prefix", UUCONF_CMDTABTYPE_STRING,
+ (pointer) &zCuvar_binary_prefix, NULL },
+ { "echocheck", UUCONF_CMDTABTYPE_BOOLEAN,
+ (pointer) &fCuvar_echocheck, NULL },
+ { "echonl", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_echonl, NULL },
+ { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_timeout, NULL },
+ { "kill", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_kill, NULL },
+ { "resend", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_resend, NULL },
+ { "eofwrite", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofwrite, NULL },
+ { "eofread", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofread, NULL },
+ { "verbose", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_verbose, NULL },
+ { NULL, 0, NULL, NULL}
+};
+
+/* The string printed at the initial connect. */
+#if ANSI_C
+#define ZCONNMSG "\aConnected."
+#else
+#define ZCONNMSG "Connected."
+#endif
+
+/* The string printed when disconnecting. */
+#if ANSI_C
+#define ZDISMSG "\aDisconnected."
+#else
+#define ZDISMSG "Disconnected."
+#endif
+
+/* Local variables. */
+
+/* The string we print when the user is once again connected to the
+ port after transferring a file or taking some other action. */
+static const char abCuconnected[]
+#if ANSI_C
+ = "\a[connected]";
+#else
+ = "[connected]";
+#endif
+
+/* Global uuconf pointer. */
+static pointer pCuuuconf;
+
+/* Connection. */
+static struct sconnection *qCuconn;
+
+/* Whether to close the connection. */
+static boolean fCuclose_conn;
+
+/* Dialer used to dial out. */
+static struct uuconf_dialer *qCudialer;
+
+/* Whether we need to restore the terminal. */
+static boolean fCurestore_terminal;
+
+/* Whether we are doing local echoing. */
+static boolean fCulocalecho;
+
+/* Whether we need to call fsysdep_cu_finish. */
+static boolean fCustarted;
+
+/* Whether ZCONNMSG has been printed yet. */
+static boolean fCuconnprinted = FALSE;
+
+/* A structure used to pass information to icuport_lock. */
+struct sconninfo
+{
+ boolean fmatched;
+ boolean flocked;
+ struct sconnection *qconn;
+ const char *zline;
+};
+
+/* Local functions. */
+
+static void ucuusage P((void));
+static void ucuhelp P((void));
+static void ucuabort P((void));
+static void uculog_start P((void));
+static void uculog_end P((void));
+static int icuport_lock P((struct uuconf_port *qport, pointer pinfo));
+static boolean fcudo_cmd P((pointer puuconf, struct sconnection *qconn,
+ int bcmd));
+static boolean fcuset_var P((pointer puuconf, char *zline));
+static int icuunrecogvar P((pointer puuconf, int argc, char **argv,
+ pointer pvar, pointer pinfo));
+static int icuunrecogfn P((pointer puuconf, int argc, char **argv,
+ pointer pvar, pointer pinfo));
+static void uculist_vars P((void));
+static void uculist_fns P((const char *zescape));
+static boolean fcudo_subcmd P((pointer puuconf, struct sconnection *qconn,
+ char *zline));
+static boolean fcusend_buf P((struct sconnection *qconn, const char *zbuf,
+ size_t cbuf));
+
+#define ucuputs(zline) \
+ do { if (! fsysdep_terminal_puts (zline)) ucuabort (); } while (0)
+
+/* Long getopt options. */
+static const struct option asCulongopts[] =
+{
+ { "phone", required_argument, NULL, 'c' },
+ { "escape", required_argument, NULL, 'E' },
+ { "parity", required_argument, NULL, 2 },
+ { "halfduplex", no_argument, NULL, 'h' },
+ { "prompt", no_argument, NULL, 'n' },
+ { "line", required_argument, NULL, 'l' },
+ { "port", required_argument, NULL, 'p' },
+ { "speed", required_argument, NULL, 's' },
+ { "baud", required_argument, NULL, 's' },
+ { "mapcr", no_argument, NULL, 't' },
+ { "nostop", no_argument, NULL, 3 },
+ { "system", required_argument, NULL, 'z' },
+ { "config", required_argument, NULL, 'I' },
+ { "debug", required_argument, NULL, 'x' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 1 },
+ { NULL, 0, NULL, 0 }
+};
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ /* -c: phone number. */
+ char *zphone = NULL;
+ /* -e: even parity. */
+ boolean feven = FALSE;
+ /* -l: line. */
+ char *zline = NULL;
+ /* -n: prompt for phone number. */
+ boolean fprompt = FALSE;
+ /* -o: odd parity. */
+ boolean fodd = FALSE;
+ /* -p: port name. */
+ const char *zport = NULL;
+ /* -s: speed. */
+ long ibaud = 0L;
+ /* -t: map cr to crlf. */
+ boolean fmapcr = FALSE;
+ /* -z: system. */
+ const char *zsystem = NULL;
+ /* --nostop: turn off XON/XOFF. */
+ enum txonxoffsetting txonxoff = XONXOFF_ON;
+ /* -I: configuration file name. */
+ const char *zconfig = NULL;
+ int iopt;
+ pointer puuconf;
+ int iuuconf;
+ const char *zlocalname;
+ int i;
+ struct uuconf_system ssys;
+ const struct uuconf_system *qsys = NULL;
+ boolean flooped;
+ struct uuconf_port sport;
+ struct sconnection sconn;
+ struct sconninfo sinfo;
+ long ihighbaud;
+ struct uuconf_dialer sdialer;
+ struct uuconf_dialer *qdialer;
+ char bcmd;
+
+ zProgram = argv[0];
+
+ /* We want to accept -# as a speed. It's easiest to look through
+ the arguments, replace -# with -s#, and let getopt handle it. */
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-'
+ && isdigit (BUCHAR (argv[i][1])))
+ {
+ size_t clen;
+ char *z;
+
+ clen = strlen (argv[i]);
+ z = zbufalc (clen + 2);
+ z[0] = '-';
+ z[1] = 's';
+ memcpy (z + 2, argv[i] + 1, clen);
+ argv[i] = z;
+ }
+ }
+
+ while ((iopt = getopt_long (argc, argv, "a:c:deE:hnI:l:op:s:tvx:z:",
+ asCulongopts, (int *) NULL)) != EOF)
+ {
+ switch (iopt)
+ {
+ case 'c':
+ /* Phone number. */
+ zphone = optarg;
+ break;
+
+ case 'd':
+ /* Set debugging level to maximum. */
+#if DEBUG > 1
+ iDebug = DEBUG_MAX;
+#endif
+ break;
+
+ case 'e':
+ /* Even parity. */
+ feven = TRUE;
+ break;
+
+ case 'E':
+ /* Escape character. */
+ zCuvar_escape = optarg;
+ break;
+
+ case 'h':
+ /* Local echo. */
+ fCulocalecho = TRUE;
+ break;
+
+ case 'n':
+ /* Prompt for phone number. */
+ fprompt = TRUE;
+ break;
+
+ case 'l':
+ /* Line name. */
+ zline = optarg;
+ break;
+
+ case 'o':
+ /* Odd parity. */
+ fodd = TRUE;
+ break;
+
+ case 'p':
+ case 'a':
+ /* Port name (-a is for compatibility). */
+ zport = optarg;
+ break;
+
+ case 's':
+ /* Speed. */
+ ibaud = strtol (optarg, (char **) NULL, 10);
+ break;
+
+ case 't':
+ /* Map cr to crlf. */
+ fmapcr = TRUE;
+ break;
+
+ case 'z':
+ /* System name. */
+ zsystem = optarg;
+ break;
+
+ case 'I':
+ /* Configuration file name. */
+ if (fsysdep_other_config (optarg))
+ zconfig = optarg;
+ break;
+
+ case 'x':
+#if DEBUG > 1
+ /* Set debugging level. */
+ iDebug |= idebug_parse (optarg);
+#endif
+ break;
+
+ case 'v':
+ /* Print version and exit. */
+ fprintf
+ (stderr,
+ "%s: Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995 Ian Lance Taylor\n",
+ zProgram, VERSION);
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 2:
+ /* --parity. */
+ if (strncmp (optarg, "even", strlen (optarg)) == 0)
+ feven = TRUE;
+ else if (strncmp (optarg, "odd", strlen (optarg)) == 0)
+ fodd = TRUE;
+ else if (strncmp (optarg, "none", strlen (optarg)) == 0)
+ {
+ feven = TRUE;
+ fodd = TRUE;
+ }
+ else
+ {
+ fprintf (stderr, "%s: --parity requires even, odd or none\n",
+ zProgram);
+ ucuusage ();
+ }
+ break;
+
+ case 3:
+ /* --nostop. */
+ txonxoff = XONXOFF_OFF;
+ break;
+
+ case 1:
+ /* --help. */
+ ucuhelp ();
+ exit (EXIT_SUCCESS);
+ /*NOTREACHED*/
+
+ case 0:
+ /* Long option found and flag set. */
+ break;
+
+ default:
+ ucuusage ();
+ /*NOTREACHED*/
+ }
+ }
+
+ /* There can be one more argument, which is either a system name, a
+ phone number, or "dir". We decide which it is based on the first
+ character. To call a UUCP system whose name begins with a digit,
+ or one which is named "dir", you must use -z. */
+ if (optind != argc)
+ {
+ if (optind != argc - 1
+ || zsystem != NULL
+ || zphone != NULL)
+ {
+ fprintf (stderr, "%s: too many arguments\n", zProgram);
+ ucuusage ();
+ }
+ if (strcmp (argv[optind], "dir") != 0)
+ {
+ if (isdigit (BUCHAR (argv[optind][0])))
+ zphone = argv[optind];
+ else
+ zsystem = argv[optind];
+ }
+ }
+
+ /* If the user doesn't give a system, port, line or speed, then
+ there's no basis on which to select a port. */
+ if (zsystem == NULL
+ && zport == NULL
+ && zline == NULL
+ && ibaud == 0L)
+ {
+ fprintf (stderr, "%s: must specify system, line, port or speed\n",
+ zProgram);
+ ucuusage ();
+ }
+
+ if (fprompt)
+ {
+ size_t cphone;
+
+ printf ("Phone number: ");
+ (void) fflush (stdout);
+ zphone = NULL;
+ cphone = 0;
+ if (getline (&zphone, &cphone, stdin) <= 0
+ || *zphone == '\0')
+ {
+ fprintf (stderr, "%s: no phone number entered\n", zProgram);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ iuuconf = uuconf_init (&puuconf, "cu", zconfig);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ pCuuuconf = puuconf;
+
+#if DEBUG > 1
+ {
+ const char *zdebug;
+
+ iuuconf = uuconf_debuglevel (puuconf, &zdebug);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ if (zdebug != NULL)
+ iDebug |= idebug_parse (zdebug);
+ }
+#endif
+
+ usysdep_initialize (puuconf, INIT_NOCHDIR | INIT_SUID);
+
+ iuuconf = uuconf_localname (puuconf, &zlocalname);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ zlocalname = zsysdep_localname ();
+ if (zlocalname == NULL)
+ exit (EXIT_FAILURE);
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ ulog_fatal_fn (ucuabort);
+ pfLstart = uculog_start;
+ pfLend = uculog_end;
+
+#ifdef SIGINT
+ usysdep_signal (SIGINT);
+#endif
+#ifdef SIGHUP
+ usysdep_signal (SIGHUP);
+#endif
+#ifdef SIGQUIT
+ usysdep_signal (SIGQUIT);
+#endif
+#ifdef SIGTERM
+ usysdep_signal (SIGTERM);
+#endif
+#ifdef SIGPIPE
+ usysdep_signal (SIGPIPE);
+#endif
+
+ if (zsystem != NULL)
+ {
+ iuuconf = uuconf_system_info (puuconf, zsystem, &ssys);
+ if (iuuconf != UUCONF_SUCCESS)
+ {
+ if (iuuconf != UUCONF_NOT_FOUND)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ ulog (LOG_FATAL, "%s: System not found", zsystem);
+ }
+ qsys = &ssys;
+ }
+
+ /* This loop is used if a system is specified. It loops over the
+ various alternates until it finds one for which the dial
+ succeeds. This is an ugly spaghetti construction, and it should
+ be broken up into different functions someday. */
+ flooped = FALSE;
+ while (TRUE)
+ {
+ enum tparitysetting tparity;
+ enum tstripsetting tstrip;
+ long iusebaud;
+
+ /* The uuconf_find_port function only selects directly on a port
+ name and a speed. To select based on the line name, we use a
+ function. If we can't find any defined port, and the user
+ specified a line name but did not specify a port name or a
+ system or a phone number, then we fake a direct port with
+ that line name (we don't fake a port if a system or phone
+ number were given because if we fake a port we have no way to
+ place a call; perhaps we should automatically look up a
+ particular dialer). This permits users to say cu -lttyd0
+ without having to put ttyd0 in the ports file, provided they
+ have read and write access to the port. */
+ sinfo.fmatched = FALSE;
+ sinfo.flocked = FALSE;
+ sinfo.qconn = &sconn;
+ sinfo.zline = zline;
+ if (zport != NULL || zline != NULL || ibaud != 0L)
+ {
+ iuuconf = uuconf_find_port (puuconf, zport, ibaud, 0L,
+ icuport_lock, (pointer) &sinfo,
+ &sport);
+ if (iuuconf != UUCONF_SUCCESS)
+ {
+ if (iuuconf != UUCONF_NOT_FOUND)
+ {
+ if (sinfo.flocked)
+ {
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+ }
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ }
+ if (zline == NULL
+ || zport != NULL
+ || zphone != NULL
+ || qsys != NULL)
+ {
+ if (sinfo.fmatched)
+ ulog (LOG_FATAL, "All matching ports in use");
+ else
+ ulog (LOG_FATAL, "No matching ports");
+ }
+
+ sport.uuconf_zname = zline;
+ sport.uuconf_ttype = UUCONF_PORTTYPE_DIRECT;
+ sport.uuconf_zprotocols = NULL;
+ sport.uuconf_qproto_params = NULL;
+ sport.uuconf_ireliable = 0;
+ sport.uuconf_zlockname = NULL;
+ sport.uuconf_palloc = NULL;
+ sport.uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL;
+ sport.uuconf_u.uuconf_sdirect.uuconf_ibaud = ibaud;
+
+ if (! fconn_init (&sport, &sconn, UUCONF_PORTTYPE_UNKNOWN))
+ ucuabort ();
+
+ if (! fconn_lock (&sconn, FALSE))
+ ulog (LOG_FATAL, "%s: Line in use", zline);
+
+ qCuconn = &sconn;
+
+ /* Check user access after locking the port, because on
+ some systems shared lines affect the ownership and
+ permissions. In such a case ``Line in use'' is more
+ clear than ``Permission denied.'' */
+ if (! fsysdep_port_access (&sport))
+ ulog (LOG_FATAL, "%s: Permission denied", zline);
+ }
+ iusebaud = ibaud;
+ ihighbaud = 0L;
+ }
+ else
+ {
+ for (; qsys != NULL; qsys = qsys->uuconf_qalternate)
+ {
+ if (! qsys->uuconf_fcall)
+ continue;
+ if (qsys->uuconf_qport != NULL)
+ {
+ if (fconn_init (qsys->uuconf_qport, &sconn,
+ UUCONF_PORTTYPE_UNKNOWN))
+ {
+ if (fconn_lock (&sconn, FALSE))
+ {
+ qCuconn = &sconn;
+ break;
+ }
+ uconn_free (&sconn);
+ }
+ }
+ else
+ {
+ sinfo.fmatched = FALSE;
+ sinfo.flocked = FALSE;
+ sinfo.qconn = &sconn;
+ iuuconf = uuconf_find_port (puuconf, qsys->uuconf_zport,
+ qsys->uuconf_ibaud,
+ qsys->uuconf_ihighbaud,
+ icuport_lock,
+ (pointer) &sinfo,
+ &sport);
+ if (iuuconf == UUCONF_SUCCESS)
+ break;
+ if (iuuconf != UUCONF_NOT_FOUND)
+ {
+ if (sinfo.flocked)
+ {
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+ }
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ }
+ }
+ }
+
+ if (qsys == NULL)
+ {
+ const char *zrem;
+
+ if (flooped)
+ zrem = "remaining ";
+ else
+ zrem = "";
+ if (sinfo.fmatched)
+ ulog (LOG_FATAL, "%s: All %smatching ports in use",
+ zsystem, zrem);
+ else
+ ulog (LOG_FATAL, "%s: No %smatching ports", zsystem, zrem);
+ }
+
+ iusebaud = qsys->uuconf_ibaud;
+ ihighbaud = qsys->uuconf_ihighbaud;
+ }
+
+ /* Here we have locked a connection to use. */
+ if (! fconn_open (&sconn, iusebaud, ihighbaud, FALSE))
+ ucuabort ();
+
+ fCuclose_conn = TRUE;
+
+ if (FGOT_SIGNAL ())
+ ucuabort ();
+
+ /* Set up the connection. */
+ if (fodd && feven)
+ {
+ tparity = PARITYSETTING_NONE;
+ tstrip = STRIPSETTING_SEVENBITS;
+ }
+ else if (fodd)
+ {
+ tparity = PARITYSETTING_ODD;
+ tstrip = STRIPSETTING_SEVENBITS;
+ }
+ else if (feven)
+ {
+ tparity = PARITYSETTING_EVEN;
+ tstrip = STRIPSETTING_SEVENBITS;
+ }
+ else
+ {
+ tparity = PARITYSETTING_DEFAULT;
+ tstrip = STRIPSETTING_DEFAULT;
+ }
+
+ if (! fconn_set (&sconn, tparity, tstrip, txonxoff))
+ ucuabort ();
+
+ if (qsys != NULL)
+ zphone = qsys->uuconf_zphone;
+
+ if (qsys != NULL || zphone != NULL)
+ {
+ enum tdialerfound tdialer;
+
+ if (! fconn_dial (&sconn, puuconf, qsys, zphone, &sdialer,
+ &tdialer))
+ {
+ if (zport != NULL
+ || zline != NULL
+ || ibaud != 0L
+ || qsys == NULL)
+ ucuabort ();
+
+ qsys = qsys->uuconf_qalternate;
+ if (qsys == NULL)
+ ulog (LOG_FATAL, "%s: No remaining alternates", zsystem);
+
+ fCuclose_conn = FALSE;
+ (void) fconn_close (&sconn, pCuuuconf, qCudialer, FALSE);
+ qCuconn = NULL;
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+
+ /* Loop around and try another alternate. */
+ flooped = TRUE;
+ continue;
+ }
+ if (tdialer == DIALERFOUND_FALSE)
+ qdialer = NULL;
+ else
+ qdialer = &sdialer;
+ }
+ else
+ {
+ /* If no system or phone number was specified, we connect
+ directly to the modem. We only permit this if the user
+ has access to the port, since it permits various
+ shenanigans such as reprogramming the automatic
+ callbacks. */
+ if (! fsysdep_port_access (sconn.qport))
+ ulog (LOG_FATAL, "Access to port denied");
+ qdialer = NULL;
+ if (! fconn_carrier (&sconn, FALSE))
+ ulog (LOG_FATAL, "Can't turn off carrier");
+ }
+
+ break;
+ }
+
+ qCudialer = qdialer;
+
+ if (FGOT_SIGNAL ())
+ ucuabort ();
+
+ /* Here we have connected, and can start the main cu protocol. The
+ program spends most of its time in system dependent code, and
+ only comes out when a special command is received from the
+ terminal. */
+ printf ("%s\n", ZCONNMSG);
+ fCuconnprinted = TRUE;
+
+ if (! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+
+ fCurestore_terminal = TRUE;
+
+ if (! fsysdep_cu_init (&sconn))
+ ucuabort ();
+
+ fCustarted = TRUE;
+
+ while (fsysdep_cu (&sconn, &bcmd, zlocalname))
+ if (! fcudo_cmd (puuconf, &sconn, bcmd))
+ break;
+
+ fCustarted = FALSE;
+ if (! fsysdep_cu_finish ())
+ ucuabort ();
+
+ fCurestore_terminal = FALSE;
+ (void) fsysdep_terminal_restore ();
+
+ (void) fconn_close (&sconn, puuconf, qdialer, TRUE);
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+
+ if (fCuconnprinted)
+ printf ("\n%s\n", ZDISMSG);
+
+ ulog_close ();
+
+ usysdep_exit (TRUE);
+
+ /* Avoid errors about not returning a value. */
+ return 0;
+}
+
+/* Print a usage message and die. */
+
+static void
+ucuusage ()
+{
+ fprintf (stderr, "Usage: %s [options] [system or phone-number]\n",
+ zProgram);
+ fprintf (stderr, "Use %s --help for help\n", zProgram);
+ exit (EXIT_FAILURE);
+}
+
+/* Print a help message. */
+
+static void
+ucuhelp ()
+{
+ fprintf (stderr,
+ "Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995 Ian Lance Taylor\n",
+ VERSION);
+ fprintf (stderr,
+ "Usage: %s [options] [system or phone-number]\n", zProgram);
+ fprintf (stderr,
+ " -a,-p,--port port: Use named port\n");
+ fprintf (stderr,
+ " -l,--line line: Use named device (e.g. tty0)\n");
+ fprintf (stderr,
+ " -s,--speed,--baud speed, -#: Use given speed\n");
+ fprintf (stderr,
+ " -c,--phone phone: Phone number to call\n");
+ fprintf (stderr,
+ " -z,--system system: System to call\n");
+ fprintf (stderr,
+ " -e: Set even parity\n");
+ fprintf (stderr,
+ " -o: Set odd parity\n");
+ fprintf (stderr,
+ " --parity={odd,even}: Set parity\n");
+ fprintf (stderr,
+ " -E,--escape char: Set escape character\n");
+ fprintf (stderr,
+ " -h,--halfduplex: Echo locally\n");
+ fprintf (stderr,
+ " --nostop: Turn off XON/XOFF handling\n");
+ fprintf (stderr,
+ " -t,--mapcr: Map carriage return to carriage return/linefeed\n");
+ fprintf (stderr,
+ " -n,--prompt: Prompt for phone number\n");
+ fprintf (stderr,
+ " -d: Set maximum debugging level\n");
+ fprintf (stderr,
+ " -x,--debug debug: Set debugging type\n");
+#if HAVE_TAYLOR_CONFIG
+ fprintf (stderr,
+ " -I,--config file: Set configuration file to use\n");
+#endif /* HAVE_TAYLOR_CONFIG */
+ fprintf (stderr,
+ " -v,--version: Print version and exit\n");
+ fprintf (stderr,
+ " --help: Print help and exit\n");
+}
+
+/* This function is called when a fatal error occurs. */
+
+static void
+ucuabort ()
+{
+ if (fCustarted)
+ {
+ fCustarted = FALSE;
+ (void) fsysdep_cu_finish ();
+ }
+
+ if (fCurestore_terminal)
+ {
+ fCurestore_terminal = FALSE;
+ (void) fsysdep_terminal_restore ();
+ }
+
+ if (qCuconn != NULL)
+ {
+ struct sconnection *qconn;
+
+ if (fCuclose_conn)
+ {
+ fCuclose_conn = FALSE;
+ (void) fconn_close (qCuconn, pCuuuconf, qCudialer, FALSE);
+ }
+ qconn = qCuconn;
+ qCuconn = NULL;
+ (void) fconn_unlock (qconn);
+ uconn_free (qconn);
+ }
+
+ ulog_close ();
+
+ if (fCuconnprinted)
+ printf ("\n%s\n", ZDISMSG);
+
+ usysdep_exit (FALSE);
+}
+
+/* This variable is just used to communicate between uculog_start and
+ uculog_end. */
+static boolean fCulog_restore;
+
+/* This function is called by ulog before it output anything. We use
+ it to restore the terminal, if necessary. ulog is only called for
+ errors or debugging in cu, so it's not too costly to do this. If
+ we didn't do it, then at least on Unix each line would leave the
+ cursor in the same column rather than wrapping back to the start,
+ since CRMOD will not be on. */
+
+static void
+uculog_start ()
+{
+ if (! fCurestore_terminal)
+ fCulog_restore = FALSE;
+ else
+ {
+ fCulog_restore = TRUE;
+ fCurestore_terminal = FALSE;
+ if (! fsysdep_terminal_restore ())
+ ucuabort ();
+ }
+}
+
+/* This function is called by ulog after everything is output. It
+ sets the terminal back, if necessary. */
+
+static void
+uculog_end ()
+{
+ if (fCulog_restore)
+ {
+ if (! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+ fCurestore_terminal = TRUE;
+ }
+}
+
+/* Check to see if this port has the desired line, to handle the -l
+ option. If it does, or if no line was specified, set up a
+ connection and lock it. */
+
+static int
+icuport_lock (qport, pinfo)
+ struct uuconf_port *qport;
+ pointer pinfo;
+{
+ struct sconninfo *q = (struct sconninfo *) pinfo;
+
+ if (q->zline != NULL
+ && ! fsysdep_port_is_line (qport, q->zline))
+ return UUCONF_NOT_FOUND;
+
+ q->fmatched = TRUE;
+
+ if (! fconn_init (qport, q->qconn, UUCONF_PORTTYPE_UNKNOWN))
+ return UUCONF_NOT_FOUND;
+ else if (! fconn_lock (q->qconn, FALSE))
+ {
+ uconn_free (q->qconn);
+ return UUCONF_NOT_FOUND;
+ }
+ else
+ {
+ qCuconn = q->qconn;
+ q->flocked = TRUE;
+ return UUCONF_SUCCESS;
+ }
+}
+
+/* Execute a cu escape command. Return TRUE if the connection should
+ continue, or FALSE if the connection should be terminated. */
+
+static boolean
+fcudo_cmd (puuconf, qconn, bcmd)
+ pointer puuconf;
+ struct sconnection *qconn;
+ int bcmd;
+{
+ char *zline;
+ char *z;
+ char abescape[5];
+ boolean fret;
+ size_t clen;
+ char abbuf[100];
+
+ /* Some commands take a string up to the next newline character. */
+ switch (bcmd)
+ {
+ default:
+ zline = NULL;
+ break;
+ case '!':
+ case '$':
+ case '|':
+ case '+':
+ case '%':
+ case 'c':
+ case '>':
+ case '<':
+ case 'p':
+ case 't':
+ case 's':
+ {
+ zline = zsysdep_terminal_line ((const char *) NULL);
+ if (zline == NULL)
+ ucuabort ();
+ zline[strcspn (zline, "\n")] = '\0';
+ }
+ break;
+ }
+
+ switch (bcmd)
+ {
+ default:
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", BUCHAR (*zCuvar_escape));
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ sprintf (abbuf, "[Unrecognized. Use %s%s to send %s]",
+ abescape, abescape, abescape);
+ ucuputs (abbuf);
+ return TRUE;
+
+ case '.':
+ /* Hangup. */
+ return FALSE;
+
+ case '!':
+ case '$':
+ case '|':
+ case '+':
+ /* Shell out. */
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_restore ())
+ ucuabort ();
+ fCurestore_terminal = FALSE;
+ {
+ enum tshell_cmd t;
+
+ switch (bcmd)
+ {
+ default:
+ case '!': t = SHELL_NORMAL; break;
+ case '$': t = SHELL_STDOUT_TO_PORT; break;
+ case '|': t = SHELL_STDIN_FROM_PORT; break;
+ case '+': t = SHELL_STDIO_ON_PORT; break;
+ }
+
+ (void) fsysdep_shell (qconn, zline, t);
+ }
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+ fCurestore_terminal = TRUE;
+ ubuffree (zline);
+ return TRUE;
+
+ case '%':
+ fret = fcudo_subcmd (puuconf, qconn, zline);
+ ubuffree (zline);
+ return fret;
+
+ case '#':
+ if (! fconn_break (qconn))
+ ucuabort ();
+ return TRUE;
+
+ case 'c':
+ (void) fsysdep_chdir (zline);
+ ubuffree (zline);
+ return TRUE;
+
+ case '>':
+ case '<':
+ case 'p':
+ case 't':
+ clen = strlen (zline);
+ z = zbufalc (clen + 3);
+ z[0] = bcmd;
+ z[1] = ' ';
+ memcpy (z + 2, zline, clen + 1);
+ ubuffree (zline);
+ fret = fcudo_subcmd (puuconf, qconn, z);
+ ubuffree (z);
+ return fret;
+
+ case 'z':
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_restore ())
+ ucuabort ();
+ fCurestore_terminal = FALSE;
+ if (! fsysdep_suspend ())
+ ucuabort ();
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+ fCurestore_terminal = TRUE;
+ return TRUE;
+
+ case 's':
+ fret = fcuset_var (puuconf, zline);
+ ubuffree (zline);
+ return fret;
+
+ case 'v':
+ uculist_vars ();
+ return TRUE;
+
+ case '?':
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", BUCHAR (*zCuvar_escape));
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ ucuputs ("");
+ ucuputs ("[Escape sequences]");
+ sprintf (abbuf,
+ "[%s. hangup] [%s!CMD run shell]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s$CMD stdout to remote] [%s|CMD stdin from remote]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s+CMD stdin and stdout to remote]",
+ abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s# send break] [%scDIR change directory]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s> send file] [%s< receive file]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%spFROM TO send to Unix] [%stFROM TO receive from Unix]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%ssVAR VAL set variable] [%ssVAR set boolean]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%ss!VAR unset boolean] [%sv list variables]",
+ abescape, abescape);
+ ucuputs (abbuf);
+#ifdef SIGTSTP
+ sprintf (abbuf,
+ "[%sz suspend]",
+ abescape);
+ ucuputs (abbuf);
+#endif
+ uculist_fns (abescape);
+ return TRUE;
+ }
+}
+
+/* List ~% functions. */
+
+static void
+uculist_fns (zescape)
+ const char *zescape;
+{
+ char abbuf[100];
+
+ sprintf (abbuf,
+ "[%s%%break send break] [%s%%cd DIR change directory]",
+ zescape, zescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s%%put FROM TO send file] [%s%%take FROM TO receive file]",
+ zescape, zescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s%%nostop no XON/XOFF] [%s%%stop use XON/XOFF]",
+ zescape, zescape);
+ ucuputs (abbuf);
+}
+
+/* Set a variable. */
+
+static boolean
+fcuset_var (puuconf, zline)
+ pointer puuconf;
+ char *zline;
+{
+ char *zvar, *zval;
+ char *azargs[2];
+ int iuuconf;
+
+ zvar = strtok (zline, "= \t");
+ if (zvar == NULL)
+ {
+ ucuputs (abCuconnected);
+ return TRUE;
+ }
+
+ zval = strtok ((char *) NULL, " \t");
+
+ if (zval == NULL)
+ {
+ azargs[0] = zvar;
+ if (azargs[0][0] != '!')
+ azargs[1] = zbufcpy ("t");
+ else
+ {
+ ++azargs[0];
+ azargs[1] = zbufcpy ("f");
+ }
+ }
+ else
+ {
+ azargs[0] = zvar;
+ azargs[1] = zbufcpy (zval);
+ }
+
+ iuuconf = uuconf_cmd_args (puuconf, 2, azargs, asCuvars,
+ (pointer) NULL, icuunrecogvar, 0,
+ (pointer) NULL);
+
+ if ((iuuconf & UUCONF_CMDTABRET_KEEP) == 0)
+ ubuffree (azargs[1]);
+
+ if ((iuuconf &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+
+ return TRUE;
+}
+
+/* Warn about an unknown variable. */
+
+/*ARGSUSED*/
+static int
+icuunrecogvar (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ char abescape[5];
+
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", BUCHAR (*zCuvar_escape));
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ ulog (LOG_ERROR, "%s: unknown variable (%sv lists variables)",
+ argv[0], abescape);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* List all the variables with their values. */
+
+static void
+uculist_vars ()
+{
+ const struct uuconf_cmdtab *q;
+ char abbuf[100];
+
+ ucuputs ("");
+ for (q = asCuvars; q->uuconf_zcmd != NULL; q++)
+ {
+ switch (UUCONF_TTYPE_CMDTABTYPE (q->uuconf_itype))
+ {
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_BOOLEAN):
+ if (*(boolean *) q->uuconf_pvar)
+ sprintf (abbuf, "%s true", q->uuconf_zcmd);
+ else
+ sprintf (abbuf, "%s false", q->uuconf_zcmd);
+ break;
+
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_INT):
+ sprintf (abbuf, "%s %d", q->uuconf_zcmd, *(int *) q->uuconf_pvar);
+ break;
+
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_LONG):
+ sprintf (abbuf, "%s %ld", q->uuconf_zcmd,
+ *(long *) q->uuconf_pvar);
+ break;
+
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_STRING):
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_FULLSTRING):
+ {
+ const char *z;
+ char abchar[5];
+ size_t clen;
+
+ sprintf (abbuf, "%s ", q->uuconf_zcmd);
+ clen = strlen (abbuf);
+ for (z = *(const char **) q->uuconf_pvar; *z != '\0'; z++)
+ {
+ int cchar;
+
+ if (! isprint (*z))
+ {
+ sprintf (abchar, "\\%03o", BUCHAR (*z));
+ cchar = 4;
+ }
+ else
+ {
+ abchar[0] = *z;
+ abchar[1] = '\0';
+ cchar = 1;
+ }
+ if (clen + cchar < sizeof (abbuf))
+ strcat (abbuf, abchar);
+ clen += cchar;
+ }
+ }
+ break;
+
+ default:
+ sprintf (abbuf, "%s [unprintable type]", q->uuconf_zcmd);
+ break;
+ }
+
+ ucuputs (abbuf);
+ }
+}
+
+/* Subcommands. These are commands that begin with ~%. */
+
+/* This variable is only used so that we can pass a non-NULL address
+ in pvar. It is never assigned to or examined. */
+
+static char bCutype;
+
+/* The command table for the subcommands. */
+
+static int icubreak P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icudebug P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icuchdir P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icuput P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icutake P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icunostop P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+
+static const struct uuconf_cmdtab asCucmds[] =
+{
+ { "break", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak },
+ { "b", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak },
+ { "cd", UUCONF_CMDTABTYPE_FN | 0, NULL, icuchdir },
+ { "d", UUCONF_CMDTABTYPE_FN | 1, NULL, icudebug },
+ { "put", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput },
+ { "take", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake },
+ { "nostop", UUCONF_CMDTABTYPE_FN | 1, NULL, icunostop },
+ { "stop", UUCONF_CMDTABTYPE_FN | 1, &bCutype, icunostop },
+ { ">", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icuput },
+ { "<", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icutake },
+ { "p", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput },
+ { "t", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake },
+ { NULL, 0, NULL, NULL }
+};
+
+/* Do a subcommand. This is called by commands beginning with ~%. */
+
+static boolean
+fcudo_subcmd (puuconf, qconn, zline)
+ pointer puuconf;
+ struct sconnection *qconn;
+ char *zline;
+{
+ char *azargs[3];
+ int iarg;
+ int iuuconf;
+
+ for (iarg = 0; iarg < 3; iarg++)
+ {
+ azargs[iarg] = strtok (iarg == 0 ? zline : (char *) NULL, " \t\n");
+ if (azargs[iarg] == NULL)
+ break;
+ }
+
+ if (iarg == 0)
+ {
+ ucuputs (abCuconnected);
+ return TRUE;
+ }
+
+ iuuconf = uuconf_cmd_args (puuconf, iarg, azargs, asCucmds,
+ (pointer) qconn, icuunrecogfn,
+ 0, (pointer) NULL);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+
+ return TRUE;
+}
+
+/* Warn about an unknown function. */
+
+/*ARGSUSED*/
+static int
+icuunrecogfn (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ char abescape[5];
+
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", BUCHAR (*zCuvar_escape));
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ if (argv[0][0] == '?')
+ uculist_fns (abescape);
+ else
+ ulog (LOG_ERROR, "%s: unknown (%s%%? lists choices)",
+ argv[0], abescape);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Send a break. */
+
+/*ARGSUSED*/
+static int
+icubreak (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+
+ if (! fconn_break (qconn))
+ ucuabort ();
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Change directories. */
+
+/*ARGSUSED*/
+static int
+icuchdir (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ const char *zarg;
+
+ if (argc <= 1)
+ zarg = NULL;
+ else
+ zarg = argv[1];
+ (void) fsysdep_chdir (zarg);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Toggle debugging. */
+
+/*ARGSUSED*/
+static int
+icudebug (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+#if DEBUG > 1
+ if (iDebug != 0)
+ iDebug = 0;
+ else
+ iDebug = DEBUG_MAX;
+#else
+ ucuputs ("[compiled without debugging]");
+#endif
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Control whether the port does xon/xoff handshaking. If pvar is not
+ NULL, this is "stop"; otherwise it is "nostop". */
+
+/*ARGSUSED*/
+static int
+icunostop (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+
+ if (! fconn_set (qconn, PARITYSETTING_DEFAULT, STRIPSETTING_DEFAULT,
+ pvar == NULL ? XONXOFF_OFF : XONXOFF_ON))
+ ucuabort ();
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Send a file to the remote system. The first argument is the file
+ to send. If that argument is not present, it is prompted for. The
+ second argument is to file name to use on the remote system. If
+ that argument is not present, the basename of the local filename is
+ used. If pvar is not NULL, then this is ~>, which is used to send
+ a command to a non-Unix system. We treat is the same as ~%put,
+ except that we assume the user has already entered the appropriate
+ command (for ~%put, we force ``cat >to'' to the other side). */
+
+/*ARGSUSED*/
+static int
+icuput (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+ char *zfrom;
+ char *zto = NULL;
+ char *zalc;
+ openfile_t e;
+ int cline;
+ char *zbuf;
+ size_t cbuf;
+
+ if (argc > 1)
+ zfrom = zbufcpy (argv[1]);
+ else
+ {
+ zfrom = zsysdep_terminal_line ("File to send: ");
+ if (zfrom == NULL)
+ ucuabort ();
+ zfrom[strcspn (zfrom, " \t\n")] = '\0';
+
+ if (*zfrom == '\0')
+ {
+ ubuffree (zfrom);
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ if (pvar == NULL)
+ {
+ if (argc > 2)
+ zto = zbufcpy (argv[2]);
+ else
+ {
+ char *zbase;
+ char *zprompt;
+
+ zbase = zsysdep_base_name (zfrom);
+ if (zbase == NULL)
+ ucuabort ();
+
+ zprompt = zbufalc (sizeof "Remote file name []: " +
+ strlen (zbase));
+ sprintf (zprompt, "Remote file name [%s]: ", zbase);
+ zto = zsysdep_terminal_line (zprompt);
+ ubuffree (zprompt);
+ if (zto == NULL)
+ ucuabort ();
+
+ zto[strcspn (zto, " \t\n")] = '\0';
+ if (*zto != '\0')
+ ubuffree (zbase);
+ else
+ {
+ ubuffree (zto);
+ zto = zbase;
+ }
+ }
+ }
+
+ e = esysdep_user_fopen (zfrom, TRUE, fCuvar_binary);
+ if (! ffileisopen (e))
+ {
+ const char *zerrstr;
+
+ if (pvar == NULL)
+ ubuffree (zto);
+ zerrstr = strerror (errno);
+ zalc = zbufalc (strlen (zfrom) + sizeof ": " + strlen (zerrstr));
+ sprintf (zalc, "%s: %s", zfrom, zerrstr);
+ ubuffree (zfrom);
+ ucuputs (zalc);
+ ubuffree (zalc);
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+
+ ubuffree (zfrom);
+
+ /* Tell the system dependent layer to stop copying data from the
+ port to the terminal. We want to read the echoes ourself. Also
+ permit the local user to generate signals. */
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_signals (TRUE))
+ ucuabort ();
+
+ /* If pvar is NULL, then we are sending a file to a Unix system. We
+ send over the command "cat > TO" to prepare it to receive. If
+ pvar is not NULL, the user is assumed to have set up whatever
+ action was needed to receive the file. */
+ if (pvar == NULL)
+ {
+ boolean fret;
+
+ zalc = zbufalc (sizeof "cat > \n" + strlen (zto));
+ sprintf (zalc, "cat > %s\n", zto);
+ ubuffree (zto);
+ fret = fcusend_buf (qconn, zalc, strlen (zalc));
+ ubuffree (zalc);
+ if (! fret)
+ {
+ (void) ffileclose (e);
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ cline = 0;
+
+ zbuf = NULL;
+ cbuf = 0;
+
+ while (TRUE)
+ {
+ char abbuf[512];
+ size_t c;
+
+#if USE_STDIO
+ if (fCuvar_binary)
+#endif
+ {
+ if (ffileeof (e))
+ break;
+ c = cfileread (e, abbuf, sizeof abbuf);
+ if (ffileioerror (e, c))
+ {
+ ucuputs ("[file read error]");
+ break;
+ }
+ if (c == 0)
+ break;
+ zbuf = abbuf;
+ }
+#if USE_STDIO
+ else
+ {
+ if (getline (&zbuf, &cbuf, e) <= 0)
+ {
+ xfree ((pointer) zbuf);
+ break;
+ }
+ c = strlen (zbuf);
+ }
+#endif
+
+ if (fCuvar_verbose)
+ {
+ ++cline;
+ printf ("%d ", cline);
+ (void) fflush (stdout);
+ }
+
+ if (! fcusend_buf (qconn, zbuf, c))
+ {
+ if (! fCuvar_binary)
+ xfree ((pointer) zbuf);
+ (void) fclose (e);
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ (void) ffileclose (e);
+
+ if (pvar == NULL)
+ {
+ char beof;
+
+ beof = '\004';
+ if (! fconn_write (qconn, &beof, 1))
+ ucuabort ();
+ }
+ else
+ {
+ if (*zCuvar_eofwrite != '\0')
+ {
+ if (! fconn_write (qconn, zCuvar_eofwrite,
+ strlen (zCuvar_eofwrite)))
+ ucuabort ();
+ }
+ }
+
+ if (fCuvar_verbose)
+ ucuputs ("");
+
+ ucuputs ("[file transfer complete]");
+
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Get a file from the remote side. This is ~%take, or ~t, or ~<.
+ The first two are assumed to be taking the file from a Unix system,
+ so we force the command "cat FROM; echo */
+
+/*ARGSUSED*/
+static int
+icutake (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+ const char *zeof;
+ char *zfrom, *zto, *zcmd;
+ char *zalc;
+ openfile_t e;
+ char bcr;
+ size_t ceoflen;
+ char *zlook = NULL;
+ size_t ceofhave;
+ boolean ferr;
+
+ if (argc > 1)
+ zfrom = zbufcpy (argv[1]);
+ else
+ {
+ zfrom = zsysdep_terminal_line ("Remote file to retreive: ");
+ if (zfrom == NULL)
+ ucuabort ();
+ zfrom[strcspn (zfrom, " \t\n")] = '\0';
+ if (*zfrom == '\0')
+ {
+ ubuffree (zfrom);
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ if (argc > 2)
+ zto = zbufcpy (argv[2]);
+ else
+ {
+ char *zbase;
+ char *zprompt;
+
+ zbase = zsysdep_base_name (zfrom);
+ if (zbase == NULL)
+ ucuabort ();
+
+ zprompt = zbufalc (sizeof "Local file name []: " + strlen (zbase));
+ sprintf (zprompt, "Local file name [%s]: ", zbase);
+ zto = zsysdep_terminal_line (zprompt);
+ ubuffree (zprompt);
+ if (zto == NULL)
+ ucuabort ();
+
+ zto[strcspn (zto, " \t\n")] = '\0';
+ if (*zto != '\0')
+ ubuffree (zbase);
+ else
+ {
+ ubuffree (zto);
+ zto = zbase;
+ }
+ }
+
+ if (pvar != NULL)
+ {
+ zcmd = zsysdep_terminal_line ("Remote command to execute: ");
+ if (zcmd == NULL)
+ ucuabort ();
+ zcmd[strcspn (zcmd, "\n")] = '\0';
+ zeof = zCuvar_eofread;
+ }
+ else
+ {
+ zcmd = zbufalc (sizeof "cat ; echo; echo ////cuend////"
+ + strlen (zfrom));
+ sprintf (zcmd, "cat %s; echo; echo ////cuend////", zfrom);
+ zeof = "\n////cuend////\n";
+ }
+
+ ubuffree (zfrom);
+
+ e = esysdep_user_fopen (zto, FALSE, fCuvar_binary);
+ if (! ffileisopen (e))
+ {
+ const char *zerrstr;
+
+ ubuffree (zcmd);
+ zerrstr = strerror (errno);
+ zalc = zbufalc (strlen (zto) + sizeof ": " + strlen (zerrstr));
+ sprintf (zalc, "%s: %s\n", zto, zerrstr);
+ ucuputs (zalc);
+ ubuffree (zalc);
+ ucuputs (abCuconnected);
+ ubuffree (zto);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_signals (TRUE))
+ ucuabort ();
+
+ if (! fconn_write (qconn, zcmd, strlen (zcmd)))
+ ucuabort ();
+ bcr = '\r';
+ if (! fconn_write (qconn, &bcr, 1))
+ ucuabort ();
+
+ ubuffree (zcmd);
+
+ /* Eliminated any previously echoed data to avoid confusion. */
+ iPrecstart = 0;
+ iPrecend = 0;
+
+ /* If we're dealing with a Unix system, we can reliably discard the
+ command. Otherwise, the command will probably wind up in the
+ file; too bad. */
+ if (pvar == NULL)
+ {
+ int b;
+
+ while ((b = breceive_char (qconn, cCuvar_timeout, TRUE)) != '\n')
+ {
+ if (b == -2)
+ ucuabort ();
+ if (b < 0)
+ {
+ ucuputs ("[timed out waiting for newline]");
+ ucuputs (abCuconnected);
+ ubuffree (zto);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+ }
+
+ ceoflen = strlen (zeof);
+ zlook = zbufalc (ceoflen);
+ ceofhave = 0;
+ ferr = FALSE;
+
+ while (TRUE)
+ {
+ int b;
+
+ if (FGOT_SIGNAL ())
+ {
+ /* Make sure the signal is logged. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ ucuputs ("[file receive aborted]");
+ /* Reset the SIGINT flag so that it does not confuse us in
+ the future. */
+ afSignal[INDEXSIG_SIGINT] = FALSE;
+ break;
+ }
+
+ b = breceive_char (qconn, cCuvar_timeout, TRUE);
+ if (b == -2)
+ ucuabort ();
+ if (b < 0)
+ {
+ if (ceofhave > 0)
+ (void) fwrite (zlook, sizeof (char), ceofhave, e);
+ ucuputs ("[timed out]");
+ break;
+ }
+
+ if (b == '\r' && ! fCuvar_binary)
+ continue;
+
+ if (ceoflen == 0)
+ {
+ if (cfilewrite (e, &b, 1) != 1)
+ {
+ ferr = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ zlook[ceofhave] = b;
+ ++ceofhave;
+ if (ceofhave == ceoflen)
+ {
+ size_t cmove;
+ char *zmove;
+
+ if (memcmp (zeof, zlook, ceoflen) == 0)
+ {
+ ucuputs ("[file transfer complete]");
+ break;
+ }
+
+ if (cfilewrite (e, zlook, 1) != 1)
+ {
+ ferr = TRUE;
+ break;
+ }
+
+ zmove = zlook;
+ for (cmove = ceoflen - 1, zmove = zlook;
+ cmove > 0;
+ cmove--, zmove++)
+ zmove[0] = zmove[1];
+
+ --ceofhave;
+ }
+ }
+ }
+
+ ubuffree (zlook);
+
+ if (! fsysdep_sync (e, zto))
+ {
+ (void) ffileclose (e);
+ ferr = TRUE;
+ }
+ else
+ {
+ if (! ffileclose (e))
+ ferr = TRUE;
+ }
+ if (ferr)
+ ucuputs ("[file write error]");
+
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+
+ ucuputs (abCuconnected);
+
+ ubuffree (zto);
+
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Send a buffer to the remote system. If fCuvar_binary is FALSE,
+ each buffer passed in will be a single line; in this case we can
+ check the echoed characters and kill the line if they do not match.
+ This returns FALSE if an echo check fails. If a port error
+ occurrs, it calls ucuabort. */
+
+static boolean
+fcusend_buf (qconn, zbufarg, cbufarg)
+ struct sconnection *qconn;
+ const char *zbufarg;
+ size_t cbufarg;
+{
+ const char *zbuf;
+ size_t cbuf;
+ int ctries;
+ size_t cbplen;
+ char *zsendbuf;
+
+ zbuf = zbufarg;
+ cbuf = cbufarg;
+ ctries = 0;
+
+ if (fCuvar_binary)
+ cbplen = strlen (zCuvar_binary_prefix);
+ else
+ cbplen = 1;
+ zsendbuf = zbufalc (64 * (cbplen + 1));
+
+ /* Loop while we still have characters to send. The value of cbuf
+ will be reset to cbufarg if an echo failure occurs while sending
+ a line in non-binary mode. */
+ while (cbuf > 0)
+ {
+ int csend;
+ char *zput;
+ const char *zget;
+ boolean fnl;
+ int i;
+
+ if (FGOT_SIGNAL ())
+ {
+ /* Make sure the signal is logged. */
+ ubuffree (zsendbuf);
+ ulog (LOG_ERROR, (const char *) NULL);
+ ucuputs ("[file send aborted]");
+ /* Reset the SIGINT flag so that it does not confuse us in
+ the future. */
+ afSignal[INDEXSIG_SIGINT] = FALSE;
+ return FALSE;
+ }
+
+ /* Discard anything we've read from the port up to now, to avoid
+ confusing the echo checking. */
+ iPrecstart = 0;
+ iPrecend = 0;
+
+ /* Send all characters up to a newline before actually sending
+ the newline. This makes it easier to handle the special
+ newline echo checking. Send up to 64 characters at a time
+ before doing echo checking. */
+ if (*zbuf == '\n')
+ csend = 1;
+ else
+ {
+ const char *znl;
+
+ znl = memchr (zbuf, '\n', cbuf);
+ if (znl == NULL)
+ csend = cbuf;
+ else
+ csend = znl - zbuf;
+ if (csend > 64)
+ csend = 64;
+ }
+
+ /* Translate this part of the buffer. If we are not in binary
+ mode, we translate \n to \r, and ignore any nonprintable
+ characters. */
+ zput = zsendbuf;
+ fnl = FALSE;
+ for (i = 0, zget = zbuf; i < csend; i++, zget++)
+ {
+ if (isprint (*zget)
+ || *zget == '\t')
+ *zput++ = *zget;
+ else if (*zget == '\n')
+ {
+ if (fCuvar_binary)
+ *zput++ = '\n';
+ else
+ *zput++ = '\r';
+ fnl = TRUE;
+ }
+ else if (fCuvar_binary)
+ {
+ strcpy (zput, zCuvar_binary_prefix);
+ zput += cbplen;
+ *zput++ = *zget;
+ }
+ }
+
+ zbuf += csend;
+ cbuf -= csend;
+
+ if (zput == zsendbuf)
+ continue;
+
+ /* Send the data over the port. */
+ if (! fsend_data (qconn, zsendbuf, (size_t) (zput - zsendbuf), TRUE))
+ ucuabort ();
+
+ /* We do echo checking if requested, unless we are in binary
+ mode. Echo checking of a newline is different from checking
+ of normal characters; when we send a newline we look for
+ *zCuvar_echonl. */
+ if ((fCuvar_echocheck && ! fCuvar_binary)
+ || (fnl && *zCuvar_echonl != '\0'))
+ {
+ long iend;
+
+ iend = ixsysdep_time ((long *) NULL) + (long) cCuvar_timeout;
+ for (zget = zsendbuf; zget < zput; zget++)
+ {
+ int bread;
+ int bwant;
+
+ if (fCuvar_binary ? *zget == '\n' : *zget == '\r')
+ {
+ bwant = *zCuvar_echonl;
+ if (bwant == '\0')
+ continue;
+ }
+ else
+ {
+ if (! fCuvar_echocheck || ! isprint (*zget))
+ continue;
+ bwant = *zget;
+ }
+
+ do
+ {
+ if (FGOT_SIGNAL ())
+ {
+ /* Make sure the signal is logged. */
+ ubuffree (zsendbuf);
+ ulog (LOG_ERROR, (const char *) NULL);
+ ucuputs ("[file send aborted]");
+ /* Reset the SIGINT flag so that it does not
+ confuse us in the future. */
+ afSignal[INDEXSIG_SIGINT] = FALSE;
+ return FALSE;
+ }
+
+ bread = breceive_char (qconn,
+ iend - ixsysdep_time ((long *) NULL),
+ TRUE);
+ if (bread < 0)
+ {
+ if (bread == -2)
+ ucuabort ();
+
+ /* If we timed out, and we're not in binary
+ mode, we kill the line and try sending it
+ again from the beginning. */
+ if (! fCuvar_binary && *zCuvar_kill != '\0')
+ {
+ ++ctries;
+ if (ctries < cCuvar_resend)
+ {
+ if (fCuvar_verbose)
+ {
+ printf ("R ");
+ (void) fflush (stdout);
+ }
+ if (! fsend_data (qconn, zCuvar_kill, 1,
+ TRUE))
+ ucuabort ();
+ zbuf = zbufarg;
+ cbuf = cbufarg;
+ break;
+ }
+ }
+ ubuffree (zsendbuf);
+ ucuputs ("[timed out looking for echo]");
+ return FALSE;
+ }
+ }
+ while (bread != *zget);
+
+ if (bread < 0)
+ break;
+ }
+ }
+ }
+
+ ubuffree (zsendbuf);
+
+ return TRUE;
+}