/* * Copyright (c) 1985, 1989 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * FTP User Program -- Command Interface. */ #include "precomp.h" #include #ifndef lint char copyright[] = "@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)main.c based on 5.13 (Berkeley) 3/14/89"; #endif /* not lint */ #if defined(sun) && !defined(FD_SET) typedef int uid_t; #endif uid_t getuid(void); void intr(void); void lostpeer(void); char *getlogin(void); short portnum; char home[128]; char *globerr; int autologin; /* Lot's of options... */ /* * Options and other state info. */ int trace; /* trace packets exchanged */ int hash; /* print # for each buffer transferred */ //int sendport; /* use PORT cmd for each data connection */ int verbose; /* print messages coming back from server */ int connected; /* connected to server */ int fromatty; /* input is from a terminal */ int interactive; /* interactively prompt on m* cmds */ int debug; /* debugging level */ int bell; /* ring bell on cmd completion */ int doglob; /* glob local file names */ int proxy; /* proxy server connection active */ int passivemode; int proxflag; /* proxy connection exists */ int sunique; /* store files on server with unique name */ int runique; /* store local files with unique name */ int mcase; /* map upper to lower case for mget names */ int ntflag; /* use ntin ntout tables for name translation */ int mapflag; /* use mapin mapout templates on file names */ int code; /* return/reply code for ftp command */ int crflag; /* if 1, strip car. rets. on ascii gets */ char pasv[64]; /* passive port for proxy data connection */ char *altarg; /* argv[1] with no shell-like preprocessing */ char ntin[17]; /* input translation table */ char ntout[17]; /* output translation table */ // #include char mapin[MAXPATHLEN]; /* input map template */ char mapout[MAXPATHLEN]; /* output map template */ char typename[32]; /* name of file transfer type */ int type; /* file transfer type */ char structname[32]; /* name of file transfer structure */ int stru; /* file transfer structure */ char formname[32]; /* name of file transfer format */ int form; /* file transfer format */ char modename[32]; /* name of file transfer mode */ int mode; /* file transfer mode */ char bytename[32]; /* local byte size in ascii */ int bytesize; /* local byte size in binary */ jmp_buf toplevel; /* non-local goto stuff for cmd scanner */ char line[200]; /* input line buffer */ char *stringbase; /* current scan point in line buffer */ char argbuf[200]; /* argument storage buffer */ char *argbase; /* current storage point in arg buffer */ int margc; /* count of arguments on input line */ const char *margv[20]; /* args parsed from input line */ int cpend; /* flag: if != 0, then pending server reply */ int mflag; /* flag: if != 0, then active multi command */ int options; /* used during socket creation */ int macnum; /* number of defined macros */ struct macel macros[16]; char macbuf[4096]; /* * Need to start a listen on the data channel * before we send the command, otherwise the * server's connect may fail. */ int sendport = -1; static const char *slurpstring(); int main(int argc, const char *argv[]) { const char *cp; int top; #if 0 char homedir[MAXPATHLEN]; #endif int err; WORD wVerReq; WSADATA WSAData; struct servent *sp; /* service spec for tcp/ftp */ /* Disable output buffering, for the benefit of Emacs. */ //setbuf(stdout, NULL); _fmode = O_BINARY; // This causes an error somewhere. wVerReq = MAKEWORD(1,1); err = WSAStartup(wVerReq, &WSAData); if (err != 0) { fprintf(stderr, "Could not initialize Windows socket interface."); exit(1); } sp = getservbyname("ftp", "tcp"); if (sp == 0) { fprintf(stderr, "ftp: ftp/tcp: unknown service\n"); exit(1); } portnum = sp->s_port; doglob = 1; interactive = 1; autologin = 1; argc--, argv++; while (argc > 0 && **argv == '-') { for (cp = *argv + 1; *cp; cp++) switch (*cp) { case 'd': options |= SO_DEBUG; debug++; break; case 'v': verbose++; break; case 't': trace++; break; case 'i': interactive = 0; break; case 'n': autologin = 0; break; case 'g': doglob = 0; break; default: fprintf(stdout, "ftp: %c: unknown option\n", *cp); exit(1); } argc--, argv++; } // fromatty = isatty(fileno(stdin)); fromatty = 1; // Strengthen this test /* * Set up defaults for FTP. */ (void) strcpy(typename, "ascii"), type = TYPE_A; (void) strcpy(formname, "non-print"), form = FORM_N; (void) strcpy(modename, "stream"), mode = MODE_S; (void) strcpy(structname, "file"), stru = STRU_F; (void) strcpy(bytename, "8"), bytesize = 8; if (fromatty) verbose++; cpend = 0; /* no pending replies */ proxy = 0; /* proxy not active */ passivemode = 1; /* passive mode *is* active */ crflag = 1; /* strip c.r. on ascii gets */ /* * Set up the home directory in case we're globbing. */ #if 0 cp = getlogin(); if (cp != NULL) { pw = getpwnam(cp); } if (pw == NULL) pw = getpwuid(getuid()); if (pw != NULL) { home = homedir; (void) strcpy(home, pw->pw_dir); } #endif cp = getenv("SystemDrive"); if (cp != NULL && *cp != 0) { strcpy(home, cp); strcat(home, "/"); } else { strcpy(home, "C:/"); } if (argc > 0) { if (setjmp(toplevel)) exit(0); // (void) signal(SIGINT, intr); // (void) signal(SIGPIPE, lostpeer); setpeer(argc + 1, argv - 1); } top = setjmp(toplevel) == 0; if (top) { // (void) signal(SIGINT, intr); // (void) signal(SIGPIPE, lostpeer); } for (;;) { cmdscanner(top); top = 1; } } void intr(void) { longjmp(toplevel, 1); } void lostpeer(void) { extern SOCKET cout; extern int data; if (connected) { if (cout) { closesocket(cout); cout = 0; } if (data >= 0) { (void) shutdown(data, 1+1); (void) close(data); data = -1; } connected = 0; } pswitch(1); if (connected) { if (cout) { closesocket(cout); cout = 0; } connected = 0; } proxflag = 0; pswitch(0); } /*char * tail(char *filename) { register char *s; while (*filename) { s = rindex(filename, '/'); if (s == NULL) break; if (s[1]) return (s + 1); *s = '\0'; } return (filename); } */ /* * Command parser. */ void cmdscanner(int top) { register struct cmd *c; if (!top) (void) putchar('\n'); for (;;) { (void) fflush(stdout); if (fromatty) { printf("ftp> "); (void) fflush(stdout); } if (gets(line) == 0) { if (feof(stdin) || ferror(stdin)) quit(0, NULL); break; } if (line[0] == 0) 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) (void) putchar('\007'); if (c->c_handler != help) break; } (void) fflush(stdout); // (void) signal(SIGINT, intr); // (void) signal(SIGPIPE, lostpeer); } struct cmd * getcmd(const char *name) { extern struct cmd cmdtab[]; const 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) /* exact match? */ return (c); if (!*q) { /* the name was a prefix */ 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); } /* * Slice a string up into argc/argv. */ int slrflag; void makeargv(void) { const char **argp; margc = 0; argp = margv; stringbase = line; /* scan from first of buffer */ argbase = argbuf; /* store from first of buffer */ slrflag = 0; while ((*argp++ = slurpstring())) margc++; } /* * Parse string into argbuf; * implemented with FSM to * handle quoting and strings */ static const char * slurpstring(void) { int got_one = 0; register char *sb = stringbase; register char *ap = argbase; char *tmp = argbase; /* will return this if token found */ if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ switch (slrflag) { /* and $ as token for macro invoke */ case 0: slrflag++; stringbase++; return ((*sb == '!') ? "!" : "$"); /* NOTREACHED */ case 1: slrflag++; altarg = stringbase; break; default: break; } } S0: switch (*sb) { case '\0': goto OUT1; 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 OUT1; /* end of token */ case '\\': sb++; goto S2; /* slurp next character */ case '"': sb++; goto S3; /* slurp quoted string */ default: *ap++ = *sb++; /* add character to token */ got_one = 1; goto S1; } S2: switch (*sb) { case '\0': goto OUT1; default: *ap++ = *sb++; got_one = 1; goto S1; } S3: switch (*sb) { case '\0': goto OUT1; case '"': sb++; goto S1; default: *ap++ = *sb++; got_one = 1; goto S3; } OUT1: if (got_one) *ap++ = '\0'; argbase = ap; /* update storage pointer */ stringbase = sb; /* update scan pointer */ if (got_one) { return(tmp); } switch (slrflag) { case 0: slrflag++; break; case 1: slrflag++; altarg = (char *) 0; break; default: break; } return((char *)0); } #define HELPINDENT (sizeof ("directory")) /* * Help command. * Call each command handler with argc == 0 and argv[0] == name. */ void help(int argc, const char *argv[]) { extern struct cmd cmdtab[]; struct cmd *c; if (argc == 1) { register int i, j, w, k; int columns, width = 0, lines; extern int NCMDS; 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 (c->c_name && (!proxy || c->c_proxy)) { printf("%s", c->c_name); } else if (c->c_name) { for (k=0; k < (int) strlen(c->c_name); k++) { (void) putchar(' '); } } if (c + lines >= &cmdtab[NCMDS]) { printf("\n"); break; } w = strlen(c->c_name); while (w < width) { w = (w + 8) &~ 7; (void) putchar('\t'); } } } (void) fflush(stdout); return; } while (--argc > 0) { const 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", (int)HELPINDENT, c->c_name, c->c_help); } (void) fflush(stdout); }