#include "uucp.h"
#include <locale.h>
#include <stropts.h>
#define MID BUFSIZ/2
#define RUB '\177'
#define XON '\21'
#define XOFF '\23'
#define TTYIN 0
#define TTYOUT 1
#define TTYERR 2
#define HUNGUP 2
#define YES 1
#define NO 0
#define IOERR 4
#define MAXPATH 100
#define NPL 50
int Sflag=0;
int Cn;
jmp_buf Sjbuf;
#define WIOFD(fd) (fd == TTYOUT ? 0 : (fd == Cn ? 1 : 2))
#define RIOFD(fd) (fd == TTYIN ? 0 : 1)
#define WMASK(fd) (fd == Cn ? line_mask : term_mask)
#define RMASK(fd) (fd == Cn ? line_mask : term_mask)
#define WRIOBSZ 256
static char Riobuf[2*WRIOBSZ];
static char Wiobuf[3*WRIOBSZ];
static int Riocnt[2] = {0, 0};
static char *Riop[2];
static char *Wiop[3];
extern int optind;
extern char
*optarg;
static struct call Cucall;
static int Saved_tty;
static int Saved_termios;
static struct termio _Tv, _Tv0;
static struct termios _Tv0s;
static struct termio _Lv;
static struct termios _Lvs;
static char prompt[BUFSIZ]= "[";
static struct utsname utsn;
static int command_line_hups = 0;
static char filename[BUFSIZ] = "/dev/null";
static char
_Cxc,
_Tintr,
_Tquit,
_Terase,
_Tkill,
_Teol,
_Myeof,
term_mask,
line_mask;
int
Echoe,
Echok,
Intrupt=NO,
Ifc=YES,
Ofc=YES,
Rtn_code=0,
Divert=NO,
OldStyle=NO,
Takeflag=NO,
Dologin=NO,
Docmd=NO;
EXTERN int
Terminal,
Oddflag,
Evenflag,
Duplex,
term_8bit,
line_8bit;
EXTERN int clear_hup();
pid_t
Child,
Shell;
static pid_t
dofork();
static int
r_char(),
w_char(),
wioflsh();
static void
_onintrpt(),
_rcvdead(),
_quit(),
_bye();
extern void cleanup();
extern void tdmp();
extern int conn(), altconn(), transmit(), tilda();
static void
recfork(),
sysname(),
blckcnt(),
_flush(),
_shell(),
_dopercen(),
_receive(),
_mode(),
_w_str();
extern char *Myline;
extern char *Mytype;
static char *P_USAGE= "Usage: %s [-dhtnLC] [-c device] [-s speed] [-l line] [-b 7|8]\n\t[-o | -e] telno | systemname [local-cmd]\n";
static char *P_CON_FAILED = "Connect failed: %s\r\n";
static char *P_Ct_OPEN = "Cannot open: %s\r\n";
static char *P_LINE_GONE = "Remote line gone\r\n";
static char *P_Ct_EXSH = "Can't execute shell\r\n";
static char *P_Ct_DIVERT = "Can't divert to %s\r\n";
static char *P_Ct_UNDIVERT = "Can't end diversion to %s\r\n";
static char *P_Bad_DIVERT = "Won't divert to %s. Unsolicited.\r\n";
static char *P_STARTWITH = "Use `~~' to start line with `~'\r\n";
static char *P_CNTAFTER = "File transmission interrupted after %ld bytes.\r\n";
static char *P_CNTLINES = "%d lines/";
static char *P_CNTCHAR = "%ld characters\r\n";
static char *P_FILEINTR = "File transmission interrupted\r\n";
static char *P_Ct_FK = "Can't fork -- try later\r\n";
static char *P_Ct_SPECIAL = "r\nCan't transmit special character `%#o'\r\n";
static char *P_TOOLONG = "\nLine too long\r\n";
static char *P_IOERR = "r\nIO error\r\n";
static char *P_USECMD = "Use `~$'cmd \r\n";
#ifdef forfutureuse
static char *P_USEPLUSCMD ="Use `~+'cmd \r\n";
#endif
#ifdef u3b
static char *P_NOTERMSTAT = "Can't get terminal status\r\n";
static char *P_3BCONSOLE = "Sorry, you can't cu from a 3B console\r\n";
#endif
static char *P_TELLENGTH = "Telno cannot exceed 58 digits!\r\n";
int
main(int argc, char *argv[])
{
extern void setservice();
extern int sysaccess();
char s[MAXPH];
char *string;
int i;
int errflag=0;
int lflag=0;
int nflag=0;
int systemname = 0;
char vdisable;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
Riop[0] = &Riobuf[0];
Riop[1] = &Riobuf[WRIOBSZ];
Wiop[0] = &Wiobuf[0];
Wiop[1] = &Wiobuf[WRIOBSZ];
Wiop[2] = &Wiobuf[2*WRIOBSZ];
Verbose = 1;
if ((string = strrchr(argv[0], '/')) != NULL)
string++;
else
string = argv[0];
if (strlcpy(Progname, string, NAMESIZE) >= NAMESIZE) {
errno = ENAMETOOLONG;
perror("cu");
exit(1);
}
setservice(Progname);
if ( sysaccess(EACCESS_SYSTEMS) != 0 ) {
(void)fprintf(stderr,
gettext("%s: Cannot read Systems files\n"), Progname);
exit(1);
}
if ( sysaccess(EACCESS_DEVICES) != 0 ) {
(void)fprintf(stderr,
gettext("%s: Cannot read Devices files\n"), Progname);
exit(1);
}
if ( sysaccess(EACCESS_DIALERS) != 0 ) {
(void)fprintf(stderr,
gettext("%s: Cannot read Dialers files\n"), Progname);
exit(1);
}
Cucall.speed = "Any";
Cucall.line = CNULL;
Cucall.telno = CNULL;
Cucall.type = CNULL;
while((i = getopt(argc, argv, "dhteons:l:c:b:LCH")) != EOF)
switch(i) {
case 'd':
Debug = 9;
break;
case 'h':
Duplex = NO;
Ifc = NO;
Ofc = NO;
break;
case 't':
Terminal = YES;
break;
case 'e':
if ( Oddflag ) {
(void)fprintf(stderr,
gettext("%s: Cannot have both even and odd parity\n"),
argv[0]);
exit(1);
}
Evenflag = 1;
break;
case 'o':
if ( Evenflag ) {
(void)fprintf(stderr,
gettext("%s: Cannot have both even and odd parity\n"),
argv[0]);
exit(1);
}
Oddflag = 1;
break;
case 'n':
nflag++;
printf(gettext("Please enter the number: "));
if (fgets(s, sizeof(s), stdin) != NULL &&
strchr(s, '\n') != NULL)
s[strlen(s)-1] = '\0';
break;
case 's':
Sflag++;
Cucall.speed = optarg;
break;
case 'l':
lflag++;
Cucall.line = optarg;
break;
case 'c':
Cucall.type = optarg;
Mytype = optarg;
break;
case 'b':
line_8bit = ((*optarg=='7') ? NO : ((*optarg=='8') ? YES : -1));
if ( line_8bit == -1 ) {
(void) fprintf(stderr,
gettext("%s: b option value must be '7' or '8'\n"),
argv[0]);
exit(1);
}
break;
case 'L':
Dologin++;
break;
case 'C':
Docmd++;
break;
case 'H':
command_line_hups++;
break;
case '?':
++errflag;
}
#ifdef u3b
{
struct stat buff;
if(fstat(TTYIN, &buff) < 0) {
VERBOSE(gettext(P_NOTERMSTAT),"");
exit(1);
} else if ( (buff.st_mode & S_IFMT) == S_IFCHR && buff.st_rdev == 0 ) {
VERBOSE(gettext(P_3BCONSOLE),"");
exit(1);
}
}
#endif
if((optind < argc && optind > 0) || (nflag && optind > 0)) {
if(nflag)
string=s;
else
string = strdup(argv[optind++]);
Cucall.telno = string;
if ( strlen(string) != strspn(string, "0123456789=-*#") ) {
if ( nflag ) {
(void)fprintf(stderr, gettext("%s: Bad phone number %s\n"),
argv[0], string);
(void) fprintf(stderr, gettext("Phone numbers may contain "
"only the digits 0 through 9 and the special\n"
"characters =, -, * and #.\n"));
exit(1);
}
systemname++;
}
} else
if(Cucall.line == CNULL)
++errflag;
if(errflag) {
VERBOSE(gettext(P_USAGE), argv[0]);
exit(1);
}
if ((Cucall.telno != CNULL) &&
(strlen(Cucall.telno) >= (size_t)(MAXPH - 1))) {
VERBOSE(gettext(P_TELLENGTH),"");
exit(0);
}
if (!(Saved_termios = ( ioctl(TTYIN, TCGETS, &_Tv0s) >= 0 ))) {
Saved_tty = ( ioctl(TTYIN, TCGETA, &_Tv0) == 0 );
_Tv0s.c_lflag = _Tv0.c_lflag;
_Tv0s.c_oflag = _Tv0.c_oflag;
_Tv0s.c_iflag = _Tv0.c_iflag;
_Tv0s.c_cflag = _Tv0.c_cflag;
for(i = 0; i < NCC; i++)
_Tv0s.c_cc[i] = _Tv0.c_cc[i];
}
if (Saved_termios || Saved_tty) {
char *p;
term_8bit = ( (_Tv0s.c_cflag & CS8) && !(_Tv0s.c_iflag & ISTRIP) &&
((p = setlocale(LC_CTYPE, NULL)) != NULL) && (strcmp(p, "C") != 0) );
if ( !Oddflag && !Evenflag )
if (_Tv0s.c_cflag & PARENB)
if (_Tv0s.c_cflag & PARODD)
Oddflag = 1;
else
Evenflag = 1;
}
if (line_8bit == -1)
line_8bit = term_8bit;
term_mask = ( term_8bit ? 0377 : 0177 );
line_mask = ( line_8bit ? 0377 : 0177 );
#ifdef _POSIX_VDISABLE
vdisable = _POSIX_VDISABLE;
#else
vdisable = fpathconf(TTYIN, _PC_VDISABLE);
#endif
_Tintr = _Tv0s.c_cc[VINTR] ? _Tv0s.c_cc[VINTR] : vdisable;
_Tquit = _Tv0s.c_cc[VQUIT] ? _Tv0s.c_cc[VQUIT] : vdisable;
_Terase = _Tv0s.c_cc[VERASE] ? _Tv0s.c_cc[VERASE] : vdisable;
_Tkill = _Tv0s.c_cc[VKILL] ? _Tv0s.c_cc[VKILL] : vdisable;
_Teol = _Tv0s.c_cc[VEOL] ? _Tv0s.c_cc[VEOL] : vdisable;
_Myeof = _Tv0s.c_cc[VEOF] ? _Tv0s.c_cc[VEOF] : '\04';
Echoe = _Tv0s.c_lflag & ECHOE;
Echok = _Tv0s.c_lflag & ECHOK;
(void)signal(SIGHUP, cleanup);
(void)signal(SIGQUIT, cleanup);
(void)signal(SIGINT, cleanup);
if(systemname) {
if ( lflag )
(void)fprintf(stderr,
gettext("%s: Warning: -l flag ignored when system name used\n"),
argv[0]);
if ( Sflag )
(void)fprintf(stderr,
gettext("%s: Warning: -s flag ignored when system name used\n"),
argv[0]);
Cn = conn(string);
if ( (Cn < 0) && (Cucall.type != CNULL) )
Cn = altconn(&Cucall);
} else
Cn = altconn(&Cucall);
if(Cn < 0) {
VERBOSE(gettext(P_CON_FAILED),UERRORTEXT);
cleanup(-Cn);
} else {
struct stat Cnsbuf;
if ( fstat(Cn, &Cnsbuf) == 0 )
Dev_mode = Cnsbuf.st_mode;
else
Dev_mode = R_DEVICEMODE;
fchmod(Cn, M_DEVICEMODE);
}
if ((Docmd) && (argv[optind] == NULL)) {
(void) fprintf(stderr,gettext("cu: local cmd is required, -C is ignored.\n"));
VERBOSE(gettext(P_USAGE), argv[0]);
Docmd=NO;
}
if (!Docmd) {
Euid = geteuid();
if((setuid(getuid()) < 0) || (setgid(getgid()) < 0)) {
VERBOSE("Unable to setuid/gid\n%s", "");
cleanup(101);
}
}
if(Debug)
tdmp(Cn);
if (!Docmd) {
(void)signal(SIGINT,_onintrpt);
_mode(1);
VERBOSE("Connected\007\r\n%s", "");
(void)signal(SIGUSR1, _bye);
(void)signal(SIGHUP, cleanup);
(void)signal(SIGQUIT, _onintrpt);
sysname(&prompt[1]);
(void) strcat(prompt, "]");
recfork();
if(Child > 0) {
command_line_hups = 0;
Rtn_code = transmit();
_quit(Rtn_code);
}
} else {
Child = dofork();
if (Child == 0) {
close(0);
close(1);
dup(Cn);
dup(Cn);
close(Cn);
setgid(getgid());
setuid(getuid());
execvp(argv[optind], &argv[optind]);
exit(-1);
}
wait(0);
}
cleanup(Cn);
return (0);
}
static void
recfork(void)
{
int ret, status;
if (Child) {
kill(Child, SIGKILL);
while ( (ret = wait(&status)) != Child )
if (ret == -1 && errno != EINTR)
break;
}
Child = dofork();
if(Child == 0) {
(void)signal(SIGUSR1, SIG_DFL);
(void)signal(SIGHUP, _rcvdead);
(void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGINT, SIG_IGN);
_receive();
}
return;
}
#ifdef forfutureuse
#endif
int
transmit(void)
{
char b[BUFSIZ];
char *p;
int escape;
int id = 0;
CDEBUG(4,"transmit started\n\r%s", "");
for (;;) {
p = b;
while(r_char(TTYIN) == YES) {
if(p == b)
escape = (_Cxc == '~');
if(p == b+1)
escape &= (_Cxc != '~');
if(escape) {
if(_Cxc == '\n' || _Cxc == '\r' || _Cxc == _Teol) {
*p = '\0';
if(tilda(b+1) == YES)
return(0);
id = 0;
break;
}
if(_Cxc == _Tintr || _Cxc == _Tkill || _Cxc == _Tquit ||
(Intrupt && _Cxc == '\0')) {
if(_Cxc == _Tkill) {
if(Echok)
VERBOSE("\r\n%s", "");
} else {
_Cxc = '\r';
if( w_char(Cn) == NO) {
VERBOSE(gettext(P_LINE_GONE),"");
return(IOERR);
}
id=0;
}
break;
}
if((p == b+1) && (_Cxc != _Terase) && (!id)) {
id = 1;
VERBOSE("%s", prompt);
}
if(_Cxc == _Terase) {
p = (--p < b)? b:p;
if(p > b)
if(Echoe) {
VERBOSE("\b \b%s", "");
} else
(void)w_char(TTYOUT);
} else {
(void)w_char(TTYOUT);
if(p-b < BUFSIZ)
*p++ = _Cxc;
else {
VERBOSE(gettext(P_TOOLONG),"");
break;
}
}
} else {
if(Intrupt && _Cxc == '\0') {
CDEBUG(4,"got break in transmit\n\r%s", "");
Intrupt = NO;
(*genbrk)(Cn);
_flush();
break;
}
if(w_char(Cn) == NO) {
VERBOSE(gettext(P_LINE_GONE),"");
return(IOERR);
}
if(Duplex == NO) {
if((w_char(TTYERR) == NO) || (wioflsh(TTYERR) == NO))
return(IOERR);
}
if ((_Cxc == _Tintr) || (_Cxc == _Tquit) ||
( (p==b) && (_Cxc == _Myeof) ) ) {
CDEBUG(4,"got a tintr\n\r%s", "");
_flush();
break;
}
if(_Cxc == '\n' || _Cxc == '\r' ||
_Cxc == _Teol || _Cxc == _Tkill) {
id=0;
Takeflag = NO;
break;
}
p = (char*)0;
}
}
}
}
static void
_flush(void)
{
(void)ioctl(TTYOUT, TCXONC, 0);
(void)ioctl(Cn, TCFLSH, 0);
(void)ioctl(TTYOUT, TCFLSH, 1);
(void)ioctl(TTYOUT, TCXONC, 1);
if(Takeflag == NO) {
return;
}
VERBOSE(gettext(P_FILEINTR),"");
(void)sleep(3);
_w_str("echo '\n~>\n';mesg y;stty echo\n");
Takeflag = NO;
return;
}
int
tilda(cmd)
char *cmd;
{
VERBOSE("\r\n%s", "");
CDEBUG(4,"call tilda(%s)\r\n", cmd);
switch(cmd[0]) {
case CSUSP:
case CDSUSP:
_mode(0);
kill(cmd[0] == CDSUSP ? getpid() : (pid_t) 0, SIGTSTP);
_mode(1);
break;
case '.':
if(Cucall.telno == CNULL)
if(cmd[1] != '.') {
_w_str("\04\04\04\04\04");
if (Child)
kill(Child, SIGKILL);
if (ioctl (Cn, TCGETS, &_Lvs) < 0) {
(void) ioctl (Cn, TCGETA, &_Lv);
_Lv.c_cflag = 0;
(void) ioctl (Cn, TCSETAW, &_Lv);
} else {
_Lvs.c_cflag &= 0xffff0000;
cfsetospeed(&_Lvs, B0);
(void) ioctl (Cn, TCSETSW, &_Lvs);
}
(void) sleep (2);
}
return(YES);
case '!':
_shell(cmd);
VERBOSE("\r%c\r\n", *cmd);
VERBOSE("(continue)%s", "");
break;
case '$':
if(cmd[1] == '\0') {
VERBOSE(gettext(P_USECMD),"");
VERBOSE("(continue)%s", "");
} else {
_shell(cmd);
VERBOSE("\r%c\r\n", *cmd);
}
break;
#ifdef forfutureuse
case '+':
if(cmd[1] == '\0') {
VERBOSE(gettext(P_USEPLUSCMD), "");
VERBOSE("(continue)%s", "");
} else {
if (*cmd == '+')
kill(Child, SIGKILL);
_shell(cmd);
if (*cmd == '+')
recfork();
VERBOSE("\r%c\r\n", *cmd);
}
break;
#endif
case '%':
_dopercen(++cmd);
break;
case 't':
tdmp(TTYIN);
VERBOSE("(continue)%s", "");
break;
case 'l':
tdmp(Cn);
VERBOSE("(continue)%s", "");
break;
default:
VERBOSE(gettext(P_STARTWITH),"");
VERBOSE("(continue)%s", "");
break;
}
return(NO);
}
#ifdef forfutureuse
#endif
static void
_shell(char *str)
{
pid_t fk, w_ret;
void (*xx)(), (*yy)();
CDEBUG(4,"call _shell(%s)\r\n", str);
fk = dofork();
if(fk < 0)
return;
Shell = fk;
_mode(0);
xx = signal(SIGINT, SIG_IGN);
yy = signal(SIGQUIT, SIG_IGN);
if(fk == 0) {
char *shell;
if( (shell = getenv("SHELL")) == NULL)
shell = SHELL;
(void)close(TTYOUT);
#ifdef forfutureuse
#endif
(void)fcntl((*str == '!')? TTYERR:Cn,F_DUPFD,TTYOUT);
#ifdef forfutureuse
if (*str == '+') {
(void)close(TTYIN);
(void)fcntl(Cn,F_DUPFD,TTYIN);
}
#endif
(void)close(Cn);
(void)signal(SIGINT, SIG_DFL);
(void)signal(SIGHUP, SIG_DFL);
(void)signal(SIGQUIT, SIG_DFL);
(void)signal(SIGUSR1, SIG_DFL);
if(*++str == '\0')
(void)execl(shell,shell,(char*) 0,(char*) 0,(char *) 0);
else
(void)execl(shell,"sh","-c",str,(char *) 0);
VERBOSE(gettext(P_Ct_EXSH),"");
exit(0);
}
while ((w_ret = wait((int*)0)) != fk)
if (w_ret == -1 && errno != EINTR)
break;
Shell = 0;
(void)signal(SIGINT, xx);
(void)signal(SIGQUIT, yy);
_mode(1);
return;
}
static void
_dopercen(char *cmd)
{
char *arg[5];
char *getpath;
char mypath[MAXPATH];
int narg;
blckcnt((long)(-1));
CDEBUG(4,"call _dopercen(\"%s\")\r\n", cmd);
arg[narg=0] = strtok(cmd, " \t\n");
while((arg[++narg] = strtok((char*) NULL, " \t\n")) != NULL) {
if(narg < 4)
continue;
else
break;
}
if(EQUALS(arg[0], "take")) {
if(narg < 2 || narg > 3) {
VERBOSE("usage: ~%%take from [to]\r\n%s", "");
VERBOSE("(continue)%s", "");
return;
}
if(narg == 2)
arg[2] = arg[1];
(void) strcpy(filename, arg[2]);
recfork();
_w_str("stty -echo;if test -r ");
_w_str(arg[1]);
_w_str("; then (echo '~");
_w_str(prompt);
_w_str(">'");
_w_str(arg[2]);
_w_str(";cat ");
_w_str(arg[1]);
_w_str(";echo '~");
_w_str(prompt);
_w_str(">'); else echo cant\\'t open: ");
_w_str(arg[1]);
_w_str("; fi;stty echo\n");
Takeflag = YES;
return;
}
if(EQUALS(arg[0], "put")) {
FILE *file;
char ch, buf[BUFSIZ], spec[NCC+1], *b, *p, *q;
int i, j, len, tc=0, lines=0;
long chars=0L;
if(narg < 2 || narg > 3) {
VERBOSE("usage: ~%%put from [to]\r\n%s", "");
VERBOSE("(continue)%s", "");
return;
}
if(narg == 2)
arg[2] = arg[1];
if((file = fopen(arg[1], "r")) == NULL) {
VERBOSE(gettext(P_Ct_OPEN), arg[1]);
VERBOSE("(continue)%s", "");
return;
}
_w_str("stty -echo;(cat - >");
_w_str(arg[2]);
_w_str(")||cat - >/dev/null;stty echo\n");
Intrupt = NO;
for(i=0,j=0; i < NCC; ++i)
if((ch=_Tv0s.c_cc[i]) != '\0')
spec[j++] = ch;
spec[j] = '\0';
_mode(2);
(void)sleep(5);
while(Intrupt == NO &&
fgets(b= &buf[MID],MID,file) != NULL) {
len = strlen(b);
chars += len;
p = b;
while(q = strpbrk(p, spec)) {
if(*q == _Tintr || *q == _Tquit || *q == _Teol) {
VERBOSE(gettext(P_Ct_SPECIAL), *q);
(void)strcpy(q, q+1);
Intrupt = YES;
} else {
b = strncpy(b-1, b, q-b);
*(q-1) = '\\';
}
p = q+1;
}
if((tc += len) >= MID) {
(void)sleep(1);
tc = len;
}
if(write(Cn, b, (unsigned)strlen(b)) < 0) {
VERBOSE(gettext(P_IOERR),"");
Intrupt = YES;
break;
}
++lines;
blckcnt((long)chars);
}
_mode(1);
blckcnt((long)(-2));
(void)fclose(file);
if(Intrupt == YES) {
Intrupt = NO;
_w_str("\n");
VERBOSE(gettext(P_CNTAFTER), ++chars);
} else {
VERBOSE(gettext(P_CNTLINES), lines);
VERBOSE(gettext(P_CNTCHAR),chars);
}
(void)sleep(3);
_w_str("\04");
return;
}
if(EQUALS(arg[0], "b") || EQUALS(arg[0], "break")) {
(*genbrk)(Cn);
return;
}
if(EQUALS(arg[0], "d") || EQUALS(arg[0], "debug")) {
if(Debug == 0)
Debug = 9;
else
Debug = 0;
VERBOSE("(continue)%s", "");
return;
}
if( EQUALS(arg[0], "ifc") || EQUALS(arg[0], "nostop") ) {
(void)ioctl(Cn, TCGETA, &_Tv);
Ifc = !Ifc;
if(Ifc == YES)
_Tv.c_iflag |= IXOFF;
else
_Tv.c_iflag &= ~IXOFF;
(void)ioctl(Cn, TCSETAW, &_Tv);
_mode(1);
VERBOSE("(ifc %s)", (Ifc ? "enabled" : "disabled"));
VERBOSE("(continue)%s", "");
return;
}
if( EQUALS(arg[0], "ofc") || EQUALS(arg[0], "noostop") ) {
(void)ioctl(Cn, TCGETA, &_Tv);
Ofc = !Ofc;
if(Ofc == YES)
_Tv.c_iflag |= IXON;
else
_Tv.c_iflag &= ~IXON;
(void)ioctl(Cn, TCSETAW, &_Tv);
_mode(1);
VERBOSE("(ofc %s)", (Ofc ? "enabled" : "disabled"));
VERBOSE("(continue)%s", "");
return;
}
if( EQUALS(arg[0], "divert") ) {
Divert = !Divert;
recfork();
VERBOSE("(unsolicited diversion %s)", (Divert ? "enabled" : "disabled"));
VERBOSE("(continue)%s", "");
return;
}
if( EQUALS(arg[0], "old") ) {
OldStyle = !OldStyle;
recfork();
VERBOSE("(old-style diversion %s)", (OldStyle ? "enabled" : "disabled"));
VERBOSE("(continue)%s", "");
return;
}
if(EQUALS(arg[0], "cd")) {
if (narg < 2) {
getpath = getenv("HOME");
strlcpy(mypath, getpath, sizeof (mypath));
if(chdir(mypath) < 0) {
VERBOSE("Cannot change to %s\r\n", mypath);
VERBOSE("(continue)%s", "");
return;
}
} else if (chdir(arg[1]) < 0) {
VERBOSE("Cannot change to %s\r\n", arg[1]);
VERBOSE("(continue)%s", "");
return;
}
recfork();
VERBOSE("(continue)%s", "");
return;
}
if (arg[0] == (char *) NULL)
arg[0] = "";
VERBOSE("~%%%s unknown to cu\r\n", arg[0]);
VERBOSE("(continue)%s", "");
return;
}
static void
_receive(void)
{
int silent = NO, file = -1;
char *p;
int tic;
int for_me = NO;
char b[BUFSIZ];
char *b_p;
long count;
int line_ok = 1, rval;
CDEBUG(4,"_receive started\r\n%s", "");
b[0] = '\0';
b_p = p = b;
while(line_ok) {
rval = r_char(Cn);
if (rval == NO) {
line_ok = 0;
continue;
}
if (rval == HUNGUP) {
if (command_line_hups > 0) {
CDEBUG(4, "Ignoring device hangup\n%s", "");
command_line_hups--;
(void) setuid(Euid);
if (clear_hup(Cn) != SUCCESS) {
DEBUG(4, "Unable to clear hup on device\n%s", "");
line_ok = 0;
}
(void) setuid(getuid());
} else
line_ok = 0;
continue;
}
if(silent == NO)
if(w_char(TTYOUT) == NO)
_rcvdead(IOERR);
if(_Cxc == '\0' || _Cxc == RUB || _Cxc == '\r')
continue;
*p++ = _Cxc;
if(_Cxc != '\n' && (p-b) < BUFSIZ)
continue;
if (b[0] == '~') {
int append;
if (EQUALSN(&b[1],prompt,strlen(prompt))) {
b_p = b + 1 + strlen(prompt);
for_me = YES;
} else {
b_p = b + 1;
for_me = NO;
}
if ( (for_me || OldStyle) && (*b_p == '>') ) {
b_p++;
if ( (*b_p == '\n') && (silent == YES) ) {
*b_p = '\0';
(void) strcpy(filename, "/dev/null");
if ( file >= 0 && close(file) ) {
VERBOSE(gettext(P_Ct_UNDIVERT), b_p);
perror(gettext("cu: close failed"));
VERBOSE("%s","\r");
}
silent = NO;
blckcnt((long)(-2));
VERBOSE("%s\r\n", b);
VERBOSE(gettext(P_CNTLINES), tic);
VERBOSE(gettext(P_CNTCHAR), count);
file = -1;
p = b;
continue;
} else if (*b_p != '\n') {
if ( *b_p == '>' ) {
append = 1;
b_p++;
}
if ( (for_me || (OldStyle && (*b_p == ':'))) && (silent == NO) ) {
*(p-1) = '\0';
if ( *b_p == ':' )
b_p++;
if ( !EQUALS(filename, b_p) ) {
if ( !Divert || !EQUALS(filename, "/dev/null") ) {
VERBOSE(gettext(P_Bad_DIVERT), b_p);
(void) strcpy(filename, "/dev/null");
append = 1;
} else {
(void) strcpy(filename, b_p);
}
}
if ( append && ((file=open(filename,O_WRONLY)) >= 0) )
(void)lseek(file, 0L, 2);
else
file = creat(filename, PUB_FILEMODE);
if (file < 0) {
VERBOSE(gettext(P_Ct_DIVERT), filename);
perror(gettext("cu: open|creat failed"));
VERBOSE("%s","\r");
(void)sleep(5);
}
silent = YES;
count = tic = 0;
p = b;
continue;
}
}
}
}
if ( silent == YES ) {
if ( file >= 0)
(void)write(file, b, (unsigned)(p-b));
count += p-b;
++tic;
blckcnt((long)count);
}
p = b;
}
_rcvdead(IOERR);
return;
}
static void
_mode(int arg)
{
int i;
CDEBUG(4,"call _mode(%d)\r\n", arg);
if(arg == 0) {
if ( Saved_termios )
(void)ioctl(TTYIN, TCSETSW, &_Tv0s);
else if ( Saved_tty ) {
_Tv0.c_lflag = _Tv0s.c_lflag;
_Tv0.c_oflag = _Tv0s.c_oflag;
_Tv0.c_iflag = _Tv0s.c_iflag;
_Tv0.c_cflag = _Tv0s.c_cflag;
for(i = 0; i < NCC; i++)
_Tv0.c_cc[i] = _Tv0s.c_cc[i];
(void)ioctl(TTYIN, TCSETAW, &_Tv0);
}
} else {
(void)ioctl(TTYIN, TCGETA, &_Tv);
if(arg == 1) {
_Tv.c_iflag &= ~(INLCR | ICRNL | IGNCR | IUCLC);
if ( !term_8bit )
_Tv.c_iflag |= ISTRIP;
_Tv.c_oflag |= OPOST;
_Tv.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONOCR | ONLRET);
_Tv.c_lflag &= ~(ICANON | ISIG | ECHO);
if(Ifc == NO)
_Tv.c_iflag &= ~IXON;
else
_Tv.c_iflag |= IXON;
if(Ofc == NO)
_Tv.c_iflag &= ~IXOFF;
else
_Tv.c_iflag |= IXOFF;
if(Terminal) {
_Tv.c_oflag |= ONLCR;
_Tv.c_iflag |= ICRNL;
}
_Tv.c_cc[VEOF] = '\01';
_Tv.c_cc[VEOL] = '\0';
}
if(arg == 2) {
_Tv.c_iflag |= IXON;
_Tv.c_lflag |= ISIG;
}
(void)ioctl(TTYIN, TCSETAW, &_Tv);
}
return;
}
static pid_t
dofork(void)
{
int i;
pid_t x;
for(i = 0; i < 6; ++i) {
if((x = fork()) >= 0) {
return(x);
}
}
if(Debug) perror("dofork");
VERBOSE(gettext(P_Ct_FK),"");
return(x);
}
static int
r_char(int fd)
{
int rtn = 1, rfd;
char *riobuf;
rfd = RIOFD(fd);
riobuf = &Riobuf[rfd*WRIOBSZ];
if (Riop[rfd] >= &riobuf[Riocnt[rfd]]) {
if ( (wioflsh(Cn) == NO ) || (wioflsh(TTYOUT) == NO) )
return(NO);
while((rtn = read(fd, riobuf, WRIOBSZ)) < 0){
if(errno == EINTR) {
if(Intrupt == YES) {
_Cxc = '\0';
return(YES);
} else {
continue;
}
} else {
CDEBUG(4,"got read error, not EINTR\n\r%s", "");
break;
}
}
if (rtn > 0) {
Riop[rfd] = riobuf;
Riocnt[rfd] = rtn;
}
}
if ( rtn > 0 ) {
_Cxc = *(Riop[rfd]++) & RMASK(fd);
return(YES);
} else if (rtn == 0) {
_Cxc = '\0';
return (HUNGUP);
} else {
_Cxc = '\0';
return(NO);
}
}
static int
w_char(int fd)
{
int wfd;
char *wiobuf;
wfd = WIOFD(fd);
wiobuf = &Wiobuf[wfd*WRIOBSZ];
if (Wiop[wfd] >= &wiobuf[WRIOBSZ]) {
if ( wioflsh(fd) == NO )
return(NO);
}
*(Wiop[wfd]++) = _Cxc & WMASK(fd);
return(YES);
}
static int
wioflsh(int fd)
{
int wfd;
char *wiobuf;
wfd = WIOFD(fd);
wiobuf = &Wiobuf[wfd*WRIOBSZ];
if (Wiop[wfd] > wiobuf) {
while(write(fd, wiobuf, (Wiop[wfd] - wiobuf)) < 0) {
if(errno == EINTR) {
if(Intrupt == YES) {
VERBOSE("\ncu: Output blocked\r\n%s", "");
_quit(IOERR);
} else
continue;
} else {
Wiop[wfd] = wiobuf;
return(NO);
}
}
}
Wiop[wfd] = wiobuf;
return(YES);
}
static void
_w_str(char *string)
{
int len;
len = strlen(string);
if ( write(Cn, string, (unsigned)len) != len )
VERBOSE(gettext(P_LINE_GONE),"");
return;
}
static void
_onintrpt(int sig __unused)
{
(void)signal(SIGINT, _onintrpt);
(void)signal(SIGQUIT, _onintrpt);
Intrupt = YES;
return;
}
static void
_rcvdead(int arg)
{
CDEBUG(4,"call _rcvdead(%d)\r\n", arg);
(void)kill(getppid(), SIGUSR1);
exit((arg == SIGHUP)? SIGHUP: arg);
}
static void
_quit(int arg)
{
CDEBUG(4,"call _quit(%d)\r\n", arg);
(void)kill(Child, SIGKILL);
_bye(arg);
}
static void
_bye(int arg)
{
int status;
pid_t obit;
if ( Shell > 0 )
while ((obit = wait(&status)) != Shell) {
if (obit == -1 && errno != EINTR)
break;
if (obit == Child)
Child = 0;
}
if (arg == SIGUSR1)
VERBOSE("\r\nLost Carrier\r\n%s", "");
CDEBUG(4,"call _bye(%d)\r\n", arg);
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGQUIT, SIG_IGN);
if ( Child != 0 )
while ((obit = wait(&status)) != Child)
if (obit == -1 && errno != EINTR)
break;
VERBOSE("\r\nDisconnected\007\r\n%s", "");
cleanup((arg == SIGUSR1)? (status >>= 8): arg);
}
void
cleanup(int code)
{
CDEBUG(4,"call cleanup(%d)\r\n", code);
if (Docmd) {
if (Child > 0)
(void)kill(Child, SIGTERM);
} else
(void) setuid(Euid);
if(Cn > 0) {
fchmod(Cn, Dev_mode);
fd_rmlock(Cn);
(void)close(Cn);
}
rmlock((char*) NULL);
if (!Docmd)
_mode(0);
exit(code);
}
void
tdmp(int arg)
{
struct termio xv;
int i;
VERBOSE("\rdevice status for fd=%d\r\n", arg);
VERBOSE("F_GETFL=%o,", fcntl(arg, F_GETFL,1));
if(ioctl(arg, TCGETA, &xv) < 0) {
char buf[100];
i = errno;
(void)snprintf(buf, sizeof (buf), gettext("\rtdmp for fd=%d"), arg);
errno = i;
perror(buf);
return;
}
VERBOSE("iflag=`%o',", xv.c_iflag);
VERBOSE("oflag=`%o',", xv.c_oflag);
VERBOSE("cflag=`%o',", xv.c_cflag);
VERBOSE("lflag=`%o',", xv.c_lflag);
VERBOSE("line=`%o'\r\n", xv.c_line);
VERBOSE("cc[0]=`%o',", xv.c_cc[0]);
for(i=1; i<8; ++i) {
VERBOSE("[%d]=", i);
VERBOSE("`%o',",xv.c_cc[i]);
}
VERBOSE("\r\n%s", "");
return;
}
static void
sysname(char *name)
{
char *s;
if(uname(&utsn) < 0)
s = "Local";
else
s = utsn.nodename;
strcpy(name, s);
return;
}
static void
blckcnt(long count)
{
static long lcharcnt = 0;
long c1, c2;
int i;
char c;
if(count == (long) (-1)) {
lcharcnt = 0;
return;
}
c1 = lcharcnt/BUFSIZ;
if(count != (long)(-2)) {
c2 = count/BUFSIZ;
for(i = c1; i++ < c2;) {
c = '0' + i%10;
write(2, &c, 1);
if(i%NPL == 0)
write(2, "\n\r", 2);
}
lcharcnt = count;
} else {
c2 = (lcharcnt + BUFSIZ -1)/BUFSIZ;
if(c1 != c2)
write(2, "+\n\r", 3);
else if(c2%NPL != 0)
write(2, "\n\r", 2);
lcharcnt = 0;
}
return;
}
void
assert (char *s1 __unused, char *s2 __unused, int i1 __unused,
char *s3 __unused, int i2 __unused)
{
}
void
logent (char *s1 __unused, char *s2 __unused)
{
}