* Copyright (c) 1983 The Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid[] = "@(#)cmds.c 5.15 (Berkeley) 3/4/91";
int quant[] = { 60, 60, 24 };
char *sep[] = { "second", "minute", "hour" };
static char *argv[10]; /* argument vector for take and put */
void timeout(); /* timeout function called on alarm */
void stopsnd(); /* SIGINT handler during file transfers */
void intcopy(); /* interrupt routine for file transfers */
* get a file from the remote host
char buf[256], *cp, *expand();
* get the UNIX receiving file's name
if (prompt("Local file name? ", copyname))
if ((sfd = creat(cp, 0666)) < 0) {
printf("\r\n%s: cannot creat\r\n", copyname);
if (prompt("List command for remote system? ", buf)) {
transfer(buf, sfd, value(EOFREAD));
char line[BUFSIZ], *expand(), *cp;
if (prompt("[take] ", copyname))
if ((argc = args(copyname, argv)) < 1 || argc > 2) {
printf("usage: <take> from [to]\r\n");
if ((fd = creat(cp, 0666)) < 0) {
printf("\r\n%s: cannot create\r\n", argv[1]);
sprintf(line, "cat %s;echo \01", argv[0]);
transfer(line, fd, "\01");
* Bulk transfer routine --
* used by getfl(), cu_take(), and pipefile()
transfer(buf, fd, eofchars)
register char *p = buffer;
pwrite(FD, buf, size(buf));
read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
while ((c&0177) != '\n');
ioctl(0, TIOCSETC, &defchars);
f = signal(SIGINT, intcopy);
eof = read(FD, &c, 1) <= 0;
if (eof || any(c, eofchars))
continue; /* ignore nulls */
if (c == '\n' && boolean(value(VERBOSE)))
if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
if (write(fd, buffer, cnt) != cnt) {
printf("\r\nwrite error\r\n");
if (write(fd, buffer, cnt) != cnt)
printf("\r\nwrite error\r\n");
if (boolean(value(VERBOSE)))
prtime(" lines transferred in ", time(0)-start);
ioctl(0, TIOCSETC, &tchars);
write(fildes[1], (char *)&ccc, 1);
* FTP - remote ==> local process
* send remote input to local process via pipe
if (prompt("Local command? ", buf))
printf("can't establish pipe\r\n");
if ((cpid = fork()) < 0) {
printf("can't fork!\r\n");
if (prompt("List command for remote system? ", buf)) {
close(pdes[0]), close(pdes[1]);
signal(SIGPIPE, intcopy);
transfer(buf, pdes[1], value(EOFREAD));
signal(SIGPIPE, SIG_DFL);
while ((p = wait(&status)) > 0 && p != cpid)
printf("can't execl!\r\n");
* Interrupt service routine for FTP
* send local file to remote host
* terminate transmission with pseudo EOF sequence
if (prompt("Local file name? ", fname))
if ((fd = fopen(fnamex, "r")) == NULL) {
printf("%s: cannot open\r\n", fname);
transmit(fd, value(EOFWRITE), NULL);
if (!boolean(value(ECHOCHECK))) {
ioctl(FD, TIOCGETP, &buf); /* this does a */
ioctl(FD, TIOCSETP, &buf); /* wflushtty */
* Bulk transfer routine to remote host --
* used by sendfile() and cu_put()
transmit(fd, eofchars, command)
char *eofchars, *command;
kill(pid, SIGIOT); /* put TIPOUT into a wait state */
f = signal(SIGINT, stopsnd);
ioctl(0, TIOCSETC, &defchars);
read(repdes[0], (char *)&ccc, 1);
for (pc = command; *pc; pc++)
if (boolean(value(ECHOCHECK)))
read(FD, (char *)&c, 1); /* trailing \n */
ioctl(FD, TIOCGETP, &buf); /* this does a */
ioctl(FD, TIOCSETP, &buf); /* wflushtty */
sleep(5); /* wait for remote stty to take effect */
if (c == 0177 && !boolean(value(RAWFTP)))
if (!boolean(value(RAWFTP)))
if (!boolean(value(RAWFTP))) {
if (boolean(value(TABEXPAND))) {
while ((++ccount % 8) != 0)
if (!boolean(value(RAWFTP)))
} while (c != '\r' && !boolean(value(RAWFTP)));
if (boolean(value(VERBOSE)))
printf("\r%d", ++lcount);
if (boolean(value(ECHOCHECK))) {
alarm((int)value(ETIMEOUT));
do { /* wait for prompt */
printf("\r\ntimed out at eol\r\n");
} while ((c&0177) != character(value(PROMPT)));
if (lastc != '\n' && !boolean(value(RAWFTP)))
for (pc = eofchars; *pc; pc++)
if (boolean(value(VERBOSE)))
if (boolean(value(RAWFTP)))
prtime(" chars transferred in ", stop_t-start_t);
prtime(" lines transferred in ", stop_t-start_t);
write(fildes[1], (char *)&ccc, 1);
ioctl(0, TIOCSETC, &tchars);
if (prompt("[put] ", copyname))
if ((argc = args(copyname, argv)) < 1 || argc > 2) {
printf("usage: <put> from [to]\r\n");
copynamex = expand(argv[0]);
if ((fd = fopen(copynamex, "r")) == NULL) {
printf("%s: cannot open\r\n", copynamex);
if (boolean(value(ECHOCHECK)))
sprintf(line, "cat>%s\r", argv[1]);
sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
transmit(fd, "\04", line);
* FTP - send single character
* wait for echo & handle timeout
if (number(value(CDELAY)) > 0 && c != '\r')
nap(number(value(CDELAY)));
if (!boolean(value(ECHOCHECK))) {
if (number(value(LDELAY)) > 0 && c == '\r')
nap(number(value(LDELAY)));
alarm((int)value(ETIMEOUT));
printf("\r\ntimeout error (%s)\r\n", ctrl(c));
pwrite(FD, &null, 1); /* poke it */
signal(SIGALRM, timeout);
* Stolen from consh() -- puts a remote file on the output of a local command.
* Identical to consh() except for where stdout goes.
if (prompt("Local command? ", buf))
kill(pid, SIGIOT); /* put TIPOUT into a wait state */
signal(SIGQUIT, SIG_IGN);
ioctl(0, TIOCSETC, &defchars);
read(repdes[0], (char *)&ccc, 1);
* Set up file descriptors in the child and
printf("can't fork!\r\n");
while ((p = wait(&status)) > 0 && p != cpid)
signal(SIGQUIT, SIG_DFL);
printf("can't find `%s'\r\n", buf);
if (boolean(value(VERBOSE)))
prtime("away for ", time(0)-start);
write(fildes[1], (char *)&ccc, 1);
ioctl(0, TIOCSETC, &tchars);
signal(SIGQUIT, SIG_DFL);
if (prompt("Local command? ", buf))
kill(pid, SIGIOT); /* put TIPOUT into a wait state */
signal(SIGQUIT, SIG_IGN);
ioctl(0, TIOCSETC, &defchars);
read(repdes[0], (char *)&ccc, 1);
* Set up file descriptors in the child and
printf("can't fork!\r\n");
while ((p = wait(&status)) > 0 && p != cpid)
signal(SIGQUIT, SIG_DFL);
printf("can't find `%s'\r\n", buf);
if (boolean(value(VERBOSE)))
prtime("away for ", time(0)-start);
write(fildes[1], (char *)&ccc, 1);
ioctl(0, TIOCSETC, &tchars);
signal(SIGQUIT, SIG_DFL);
signal(SIGQUIT, SIG_IGN);
while (shpid != wait(&status));
signal(SIGQUIT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
if ((cp = rindex(value(SHELL), '/')) == NULL)
execl(value(SHELL), cp, 0);
printf("\r\ncan't execl!\r\n");
* TIPIN portion of scripting
* initiate the conversation with TIPOUT
* enable TIPOUT side for dialogue
if (boolean(value(SCRIPT)))
write(fildes[1], value(RECORD), size(value(RECORD)));
write(fildes[1], "\n", 1);
* wait for TIPOUT to finish
printf("can't create %s\r\n", value(RECORD));
* Change current working directory of
register char *cp = dirname;
if (prompt("[cd] ", dirname)) {
printf("%s: bad directory\r\n", cp);
(void)uu_unlock(uucplock);
if ((dismsg = value(DISCONNECT)) != NOSTR) {
write(FD, dismsg, strlen(dismsg));
if ((cp = rindex(value(SHELL), '/')) == NULL)
execl(value(SHELL), cp, "-c", s, 0);
register char *p = buf, *start;
register char **parg = a;
while (*p && (*p == ' ' || *p == '\t'))
while (*p && (*p != ' ' && *p != '\t'))
for (i = 0; i < 3; i++) {
nums[i] = (int)(a % quant[i]);
if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
printf("%d %s%c ", nums[i], sep[i],
nums[i] == 1 ? '\0' : 's');
if (prompt("[set] ", buf))
if (vtable[BEAUTIFY].v_access&CHANGED) {
vtable[BEAUTIFY].v_access &= ~CHANGED;
if (vtable[SCRIPT].v_access&CHANGED) {
vtable[SCRIPT].v_access &= ~CHANGED;
* So that "set record=blah script" doesn't
* cause two transactions to occur.
if (vtable[RECORD].v_access&CHANGED)
vtable[RECORD].v_access &= ~CHANGED;
if (vtable[RECORD].v_access&CHANGED) {
vtable[RECORD].v_access &= ~CHANGED;
if (boolean(value(SCRIPT)))
if (vtable[TAND].v_access&CHANGED) {
vtable[TAND].v_access &= ~CHANGED;
if (boolean(value(TAND)))
if (vtable[LECHO].v_access&CHANGED) {
vtable[LECHO].v_access &= ~CHANGED;
HD = boolean(value(LECHO));
if (vtable[PARITY].v_access&CHANGED) {
vtable[PARITY].v_access &= ~CHANGED;
* Turn tandem mode on or off for remote tty.
ioctl(FD, TIOCGETP, &rmtty);
if (strcmp(option,"on") == 0) {
rmtty.sg_flags |= TANDEM;
rmtty.sg_flags &= ~TANDEM;
ioctl(FD, TIOCSETP, &rmtty);
ioctl(0, TIOCSETP, &arg);
ioctl(FD, TIOCSBRK, NULL);
ioctl(FD, TIOCCBRK, NULL);
kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
* expand a file name if it includes shell meta characters
static char xname[BUFSIZ];
register char *cp, *Shell;
int s, pivec[2], (*sigint)();
if (!anyof(name, "~{[*?$`'\"\\"))
/* sigint = signal(SIGINT, SIG_IGN); */
/* signal(SIGINT, sigint) */
sprintf(cmdbuf, "echo %s", name);
if ((pid = vfork()) == 0) {
execl(Shell, Shell, "-c", cmdbuf, 0);
l = read(pivec[0], xname, BUFSIZ);
if (s != 0 && s != SIGPIPE) {
fprintf(stderr, "\"Echo\" failed\n");
fprintf(stderr, "\"%s\": No match\n", name);
fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
* Are any of the characters in the two strings the same?