#include "ftp_locl.h"
#include <getarg.h>
RCSID("$Id$");
static int help_flag;
static int version_flag;
static int debug_flag;
struct getargs getargs[] = {
{ NULL, 'd', arg_flag, &debug_flag,
"debug", NULL },
{ NULL, 'g', arg_negative_flag, &doglob,
"disables globbing", NULL},
{ NULL, 'i', arg_negative_flag, &interactive,
"Turn off interactive prompting", NULL},
{ NULL, 'l', arg_negative_flag, &lineedit,
"Turn off line editing", NULL},
{ NULL, 'n', arg_negative_flag, &autologin,
"Turn off auto-login", NULL},
{ NULL, 'p', arg_flag, &passivemode,
"passive mode", NULL},
{ NULL, 't', arg_counter, &trace,
"Packet tracing", NULL},
#ifdef KRB5
{ "gss-bindings", 0, arg_negative_flag, &ftp_do_gss_bindings,
"Don't use GSS-API bindings", NULL},
{ "gss-delegate", 0, arg_negative_flag, &ftp_do_gss_delegate,
"Disable delegation of GSS-API credentials", NULL},
#endif
{ NULL, 'v', arg_counter, &verbose,
"verbosity", NULL},
{ NULL, 'K', arg_negative_flag, &use_kerberos,
"Disable kerberos authentication", NULL},
{ "encrypt", 'x', arg_flag, &doencrypt,
"Encrypt command and data channel if possible" },
{ "version", 0, arg_flag, &version_flag },
{ "help", 'h', arg_flag, &help_flag },
};
static int num_args = sizeof(getargs) / sizeof(getargs[0]);
static void
usage(int ecode)
{
arg_printusage(getargs, num_args, NULL, "[host [port]]");
exit(ecode);
}
int
main(int argc, char **argv)
{
int top;
struct passwd *pw = NULL;
char homedir[MaxPathLen];
struct servent *sp;
int optind = 0;
setprogname(argv[0]);
sp = getservbyname("ftp", "tcp");
if (sp == 0)
errx(1, "ftp/tcp: unknown service");
doglob = 1;
interactive = 1;
autologin = 1;
lineedit = 1;
passivemode = 0;
use_kerberos = 1;
#ifdef KRB5
ftp_do_gss_bindings = 1;
#endif
if(getarg(getargs, num_args, argc, argv, &optind))
usage(1);
if(help_flag)
usage(0);
if(version_flag) {
print_version(NULL);
exit(0);
}
if (debug_flag) {
options |= SO_DEBUG;
debug++;
}
argc -= optind;
argv += optind;
fromatty = isatty(fileno(stdin));
if (fromatty)
verbose++;
cpend = 0;
proxy = 0;
crflag = 1;
sendport = -1;
pw = k_getpwuid(getuid());
if (pw != NULL) {
strlcpy(homedir, pw->pw_dir, sizeof(homedir));
home = homedir;
}
if (argc > 0) {
char *xargv[5];
if (setjmp(toplevel))
exit(0);
signal(SIGINT, intr);
signal(SIGPIPE, lostpeer);
xargv[0] = (char*)getprogname();
xargv[1] = argv[0];
xargv[2] = argv[1];
xargv[3] = argv[2];
xargv[4] = NULL;
setpeer(argc+1, xargv);
}
if(setjmp(toplevel) == 0)
top = 1;
else
top = 0;
if (top) {
signal(SIGINT, intr);
signal(SIGPIPE, lostpeer);
}
for (;;) {
cmdscanner(top);
top = 1;
}
}
void
intr(int sig)
{
longjmp(toplevel, 1);
}
#ifndef SHUT_RDWR
#define SHUT_RDWR 2
#endif
RETSIGTYPE
lostpeer(int sig)
{
if (connected) {
if (cout != NULL) {
shutdown(fileno(cout), SHUT_RDWR);
fclose(cout);
cout = NULL;
}
if (data >= 0) {
shutdown(data, SHUT_RDWR);
close(data);
data = -1;
}
connected = 0;
}
pswitch(1);
if (connected) {
if (cout != NULL) {
shutdown(fileno(cout), SHUT_RDWR);
fclose(cout);
cout = NULL;
}
connected = 0;
}
proxflag = 0;
pswitch(0);
sec_end();
SIGRETURN(0);
}
static char *
simple_readline(char *prompt)
{
char buf[BUFSIZ];
printf ("%s", prompt);
fflush (stdout);
if(fgets(buf, sizeof(buf), stdin) == NULL)
return NULL;
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
return strdup(buf);
}
#ifndef HAVE_READLINE
static char *
readline(char *prompt)
{
return simple_readline (prompt);
}
static void
add_history(char *p)
{
}
#else
char *readline(char *);
void add_history(char *);
#endif
void
cmdscanner(int top)
{
struct cmd *c;
int l;
if (!top)
putchar('\n');
for (;;) {
if (fromatty) {
char *p;
if (lineedit)
p = readline("ftp> ");
else
p = simple_readline("ftp> ");
if(p == NULL) {
printf("\n");
quit(0, 0);
}
strlcpy(line, p, sizeof(line));
if (lineedit)
add_history(p);
free(p);
} else{
if (fgets(line, sizeof line, stdin) == NULL)
quit(0, 0);
}
l = strlen(line);
if (l == 0)
break;
if (line[--l] == '\n') {
if (l == 0)
break;
line[l] = '\0';
} else if (l == sizeof(line) - 2) {
printf("sorry, input line too long\n");
while ((l = getchar()) != '\n' && l != EOF)
;
break;
}
makeargv();
if (margc == 0) {
continue;
}
c = getcmd(margv[0]);
if (c == (struct cmd *)-1) {
printf("?Ambiguous command\n");
continue;
}
if (c == 0) {
printf("?Invalid command\n");
continue;
}
if (c->c_conn && !connected) {
printf("Not connected.\n");
continue;
}
(*c->c_handler)(margc, margv);
if (bell && c->c_bell)
putchar('\007');
if (c->c_handler != help)
break;
}
signal(SIGINT, intr);
signal(SIGPIPE, lostpeer);
}
struct cmd *
getcmd(char *name)
{
char *p, *q;
struct cmd *c, *found;
int nmatches, longest;
longest = 0;
nmatches = 0;
found = 0;
for (c = cmdtab; (p = c->c_name); c++) {
for (q = name; *q == *p++; q++)
if (*q == 0)
return (c);
if (!*q) {
if (q - name > longest) {
longest = q - name;
nmatches = 1;
found = c;
} else if (q - name == longest)
nmatches++;
}
}
if (nmatches > 1)
return ((struct cmd *)-1);
return (found);
}
int slrflag;
void
makeargv(void)
{
char **argp;
argp = margv;
stringbase = line;
argbase = argbuf;
slrflag = 0;
for (margc = 0; ; margc++) {
if (margc == margvlen) {
int i;
margv = (margvlen == 0)
? (char **)malloc(20 * sizeof(char *))
: (char **)realloc(margv,
(margvlen + 20)*sizeof(char *));
if (margv == NULL)
errx(1, "cannot realloc argv array");
for(i = margvlen; i < margvlen + 20; ++i)
margv[i] = NULL;
margvlen += 20;
argp = margv + margc;
}
if ((*argp++ = slurpstring()) == NULL)
break;
}
}
char *
slurpstring(void)
{
int got_one = 0;
char *sb = stringbase;
char *ap = argbase;
char *tmp = argbase;
if (*sb == '!' || *sb == '$') {
switch (slrflag) {
case 0:
slrflag++;
stringbase++;
return ((*sb == '!') ? "!" : "$");
case 1:
slrflag++;
altarg = stringbase;
break;
default:
break;
}
}
S0:
switch (*sb) {
case '\0':
goto OUT;
case ' ':
case '\t':
sb++; goto S0;
default:
switch (slrflag) {
case 0:
slrflag++;
break;
case 1:
slrflag++;
altarg = sb;
break;
default:
break;
}
goto S1;
}
S1:
switch (*sb) {
case ' ':
case '\t':
case '\0':
goto OUT;
case '\\':
sb++; goto S2;
case '"':
sb++; goto S3;
default:
*ap++ = *sb++;
got_one = 1;
goto S1;
}
S2:
switch (*sb) {
case '\0':
goto OUT;
default:
*ap++ = *sb++;
got_one = 1;
goto S1;
}
S3:
switch (*sb) {
case '\0':
goto OUT;
case '"':
sb++; goto S1;
default:
*ap++ = *sb++;
got_one = 1;
goto S3;
}
OUT:
if (got_one)
*ap++ = '\0';
argbase = ap;
stringbase = sb;
if (got_one) {
return (tmp);
}
switch (slrflag) {
case 0:
slrflag++;
break;
case 1:
slrflag++;
altarg = (char *) 0;
break;
default:
break;
}
return NULL;
}
#define HELPINDENT ((int) sizeof ("directory"))
void
help(int argc, char **argv)
{
struct cmd *c;
if (argc == 1) {
int i, j, w, k;
int columns, width = 0, lines;
printf("Commands may be abbreviated. Commands are:\n\n");
for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
int len = strlen(c->c_name);
if (len > width)
width = len;
}
width = (width + 8) &~ 7;
columns = 80 / width;
if (columns == 0)
columns = 1;
lines = (NCMDS + columns - 1) / columns;
for (i = 0; i < lines; i++) {
for (j = 0; j < columns; j++) {
c = cmdtab + j * lines + i;
if ((!proxy || c->c_proxy)) {
printf("%s", c->c_name);
} else {
for (k=0; k < strlen(c->c_name); k++) {
putchar(' ');
}
}
if (c + lines >= &cmdtab[NCMDS]) {
printf("\n");
break;
}
w = strlen(c->c_name);
while (w < width) {
w = (w + 8) &~ 7;
putchar('\t');
}
}
}
return;
}
while (--argc > 0) {
char *arg;
arg = *++argv;
c = getcmd(arg);
if (c == (struct cmd *)-1)
printf("?Ambiguous help command %s\n", arg);
else if (c == (struct cmd *)0)
printf("?Invalid help command %s\n", arg);
else
printf("%-*s\t%s\n", HELPINDENT,
c->c_name, c->c_help);
}
}