110294Ssam #ifndef lint 2*11650Ssam static char sccsid[] = "@(#)cmds.c 4.4 (Berkeley) 03/23/83"; 310294Ssam #endif 410294Ssam 510294Ssam /* 610294Ssam * FTP User Program -- Command Routines. 710294Ssam */ 811353Ssam #include <sys/param.h> 910294Ssam #include <sys/socket.h> 1010294Ssam 1110294Ssam #include <signal.h> 1210294Ssam #include <stdio.h> 1310294Ssam #include <errno.h> 1410294Ssam #include <netdb.h> 1511353Ssam #include <stat.h> 1610294Ssam 1710294Ssam #include "ftp.h" 1810294Ssam #include "ftp_var.h" 1910294Ssam 2011353Ssam extern char *globerr; 2111353Ssam extern char **glob(); 2211353Ssam extern short gflag; 2310294Ssam 2410294Ssam /* 2510294Ssam * Connect to peer server and 2610294Ssam * auto-login, if possible. 2710294Ssam */ 2810294Ssam setpeer(argc, argv) 2910294Ssam int argc; 3010294Ssam char *argv[]; 3110294Ssam { 3210294Ssam struct hostent *host, *hookup(); 3310294Ssam int port; 3410294Ssam 3510294Ssam if (connected) { 3610294Ssam printf("Already connected to %s, use disconnect first.\n", 3710294Ssam hostname); 3810294Ssam return; 3910294Ssam } 4010294Ssam if (argc < 2) { 4110294Ssam strcat(line, " "); 4210294Ssam printf("(to) "); 4310294Ssam gets(&line[strlen(line)]); 4410294Ssam makeargv(); 4510294Ssam argc = margc; 4610294Ssam argv = margv; 4710294Ssam } 4810294Ssam if (argc > 3) { 4910294Ssam printf("usage: %s host-name [port]\n", argv[0]); 5010294Ssam return; 5110294Ssam } 5210294Ssam port = sp->s_port; 5310294Ssam if (argc > 2) { 5411218Ssam port = atoi(argv[2]); 5510294Ssam if (port <= 0) { 5611218Ssam printf("%s: bad port number-- %s\n", argv[1], argv[2]); 5711218Ssam printf ("usage: %s host-name [port]\n", argv[0]); 5810294Ssam return; 5910294Ssam } 6010294Ssam port = htons(port); 6110294Ssam } 6210294Ssam host = hookup(argv[1], port); 6310294Ssam if (host) { 6410294Ssam connected = 1; 6510294Ssam if (autologin) 6610294Ssam login(host); 6710294Ssam } 6810294Ssam } 6910294Ssam 7010294Ssam struct types { 7110294Ssam char *t_name; 7210294Ssam char *t_mode; 7310294Ssam int t_type; 7411218Ssam char *t_arg; 7510294Ssam } types[] = { 7611218Ssam { "ascii", "A", TYPE_A, 0 }, 7711218Ssam { "binary", "I", TYPE_I, 0 }, 7811218Ssam { "image", "I", TYPE_I, 0 }, 7911218Ssam { "ebcdic", "E", TYPE_E, 0 }, 8011218Ssam { "tenex", "L", TYPE_L, bytename }, 8110294Ssam 0 8210294Ssam }; 8310294Ssam 8410294Ssam /* 8510294Ssam * Set transfer type. 8610294Ssam */ 8710294Ssam settype(argc, argv) 8810294Ssam char *argv[]; 8910294Ssam { 9010294Ssam register struct types *p; 9111218Ssam int comret; 9210294Ssam 9310294Ssam if (argc > 2) { 9410294Ssam char *sep; 9510294Ssam 9610294Ssam printf("usage: %s [", argv[0]); 9710294Ssam sep = " "; 9810294Ssam for (p = types; p->t_name; p++) { 9910294Ssam printf("%s%s", sep, p->t_name); 10010294Ssam if (*sep == ' ') 10110294Ssam sep = " | "; 10210294Ssam } 10310294Ssam printf(" ]\n"); 10410294Ssam return; 10510294Ssam } 10610294Ssam if (argc < 2) { 10710294Ssam printf("Using %s mode to transfer files.\n", typename); 10810294Ssam return; 10910294Ssam } 11010294Ssam for (p = types; p->t_name; p++) 11110294Ssam if (strcmp(argv[1], p->t_name) == 0) 11210294Ssam break; 11310294Ssam if (p->t_name == 0) { 11410294Ssam printf("%s: unknown mode\n", argv[1]); 11510294Ssam return; 11610294Ssam } 11711218Ssam if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 11811218Ssam comret = command ("TYPE %s %s", p->t_mode, p->t_arg); 11911218Ssam else 12011218Ssam comret = command("TYPE %s", p->t_mode); 12111218Ssam if (comret == COMPLETE) { 12210294Ssam strcpy(typename, p->t_name); 12310294Ssam type = p->t_type; 12410294Ssam } 12510294Ssam } 12610294Ssam 12710294Ssam /* 12810294Ssam * Set binary transfer type. 12910294Ssam */ 13010294Ssam /*VARARGS*/ 13110294Ssam setbinary() 13210294Ssam { 13310294Ssam 13410294Ssam call(settype, "type", "binary", 0); 13510294Ssam } 13610294Ssam 13710294Ssam /* 13810294Ssam * Set ascii transfer type. 13910294Ssam */ 14010294Ssam /*VARARGS*/ 14110294Ssam setascii() 14210294Ssam { 14310294Ssam 14410294Ssam call(settype, "type", "ascii", 0); 14510294Ssam } 14610294Ssam 14710294Ssam /* 14810294Ssam * Set tenex transfer type. 14910294Ssam */ 15010294Ssam /*VARARGS*/ 15110294Ssam settenex() 15210294Ssam { 15310294Ssam 15410294Ssam call(settype, "type", "tenex", 0); 15510294Ssam } 15610294Ssam 15710294Ssam /* 15810294Ssam * Set ebcdic transfer type. 15910294Ssam */ 16010294Ssam /*VARARGS*/ 16110294Ssam setebcdic() 16210294Ssam { 16310294Ssam 16410294Ssam call(settype, "type", "ebcdic", 0); 16510294Ssam } 16610294Ssam 16710294Ssam /* 16810294Ssam * Set file transfer mode. 16910294Ssam */ 17010294Ssam setmode(argc, argv) 17110294Ssam char *argv[]; 17210294Ssam { 17310294Ssam 17410294Ssam printf("We only support %s mode, sorry.\n", modename); 17510294Ssam } 17610294Ssam 17710294Ssam /* 17810294Ssam * Set file transfer format. 17910294Ssam */ 18010294Ssam setform(argc, argv) 18110294Ssam char *argv[]; 18210294Ssam { 18310294Ssam 18410294Ssam printf("We only support %s format, sorry.\n", formname); 18510294Ssam } 18610294Ssam 18710294Ssam /* 18810294Ssam * Set file transfer structure. 18910294Ssam */ 19010294Ssam setstruct(argc, argv) 19110294Ssam char *argv[]; 19210294Ssam { 19310294Ssam 19410294Ssam printf("We only support %s structure, sorry.\n", structname); 19510294Ssam } 19610294Ssam 19710294Ssam /* 19810294Ssam * Send a single file. 19910294Ssam */ 200*11650Ssam append(argc, argv) 201*11650Ssam char *argv[]; 202*11650Ssam { 203*11650Ssam 204*11650Ssam return (put1("APPE", argc, argv)); 205*11650Ssam } 206*11650Ssam 20710294Ssam put(argc, argv) 20810294Ssam char *argv[]; 20910294Ssam { 21010294Ssam 211*11650Ssam return (put1("STOR", argc, argv)); 212*11650Ssam } 213*11650Ssam 214*11650Ssam put1(cmd, argc, argv) 215*11650Ssam char *cmd; 216*11650Ssam int argc; 217*11650Ssam char *argv[]; 218*11650Ssam { 219*11650Ssam 22010294Ssam if (argc == 2) 22110294Ssam argc++, argv[2] = argv[1]; 22210294Ssam if (argc < 2) { 22310294Ssam strcat(line, " "); 22410294Ssam printf("(local-file) "); 22510294Ssam gets(&line[strlen(line)]); 22610294Ssam makeargv(); 22710294Ssam argc = margc; 22810294Ssam argv = margv; 22910294Ssam } 23010294Ssam if (argc < 2) { 23110294Ssam usage: 23210294Ssam printf("%s local-file remote-file\n", argv[0]); 23310294Ssam return; 23410294Ssam } 23510294Ssam if (argc < 3) { 23610294Ssam strcat(line, " "); 23710294Ssam printf("(remote-file) "); 23810294Ssam gets(&line[strlen(line)]); 23910294Ssam makeargv(); 24010294Ssam argc = margc; 24110294Ssam argv = margv; 24210294Ssam } 24310294Ssam if (argc < 3) 24410294Ssam goto usage; 24511353Ssam if (!globulize(&argv[1])) 24611353Ssam return; 247*11650Ssam sendrequest(cmd, argv[1], argv[2]); 24810294Ssam } 24910294Ssam 25010294Ssam /* 25111353Ssam * Send one or more files. 25210294Ssam */ 25311353Ssam mput(argc, argv) 25411353Ssam char *argv[]; 25511353Ssam { 256*11650Ssam char **cpp, **gargs = NULL; 25711353Ssam int i; 25811353Ssam 259*11650Ssam if (argc < 2) { 260*11650Ssam strcat(line, " "); 261*11650Ssam printf("(local-files) "); 262*11650Ssam gets(&line[strlen(line)]); 263*11650Ssam makeargv(); 264*11650Ssam argc = margc; 265*11650Ssam argv = margv; 26611353Ssam } 26711353Ssam if (argc < 2) { 26811353Ssam printf("%s local-files\n", argv[0]); 26911353Ssam return; 27011353Ssam } 271*11650Ssam cpp = argv + 1; 272*11650Ssam if (doglob) { 273*11650Ssam gargs = glob(cpp); 274*11650Ssam if (globerr != NULL) { 275*11650Ssam printf("%s\n", globerr); 276*11650Ssam if (gargs) 277*11650Ssam blkfree(gargs); 27811353Ssam return; 27911353Ssam } 28011353Ssam } 281*11650Ssam if (gargs != NULL) 282*11650Ssam cpp = gargs; 283*11650Ssam for (; *cpp != NULL; cpp++) 284*11650Ssam if (confirm(argv[0], *cpp)) 285*11650Ssam sendrequest("STOR", *cpp, *cpp); 286*11650Ssam if (gargs != NULL) 287*11650Ssam blkfree(gargs); 28811353Ssam } 28911353Ssam 29011353Ssam /* 29111353Ssam * Receive one file. 29211353Ssam */ 29310294Ssam get(argc, argv) 29410294Ssam char *argv[]; 29510294Ssam { 29610294Ssam 29710294Ssam if (argc == 2) 29810294Ssam argc++, argv[2] = argv[1]; 29910294Ssam if (argc < 2) { 30010294Ssam strcat(line, " "); 30110294Ssam printf("(remote-file) "); 30210294Ssam gets(&line[strlen(line)]); 30310294Ssam makeargv(); 30410294Ssam argc = margc; 30510294Ssam argv = margv; 30610294Ssam } 30710294Ssam if (argc < 2) { 30810294Ssam usage: 30911353Ssam printf("%s remote-file [ local-file ]\n", argv[0]); 31010294Ssam return; 31110294Ssam } 31210294Ssam if (argc < 3) { 31310294Ssam strcat(line, " "); 31410294Ssam printf("(local-file) "); 31510294Ssam gets(&line[strlen(line)]); 31610294Ssam makeargv(); 31710294Ssam argc = margc; 31810294Ssam argv = margv; 31910294Ssam } 32010294Ssam if (argc < 3) 32110294Ssam goto usage; 32211353Ssam if (!globulize(&argv[2])) 32311353Ssam return; 324*11650Ssam recvrequest("RETR", argv[2], argv[1], "w"); 32510294Ssam } 32610294Ssam 32711353Ssam /* 32811353Ssam * Get multiple files. 32911353Ssam */ 33011353Ssam mget(argc, argv) 33111353Ssam char *argv[]; 33211353Ssam { 333*11650Ssam register char *cp; 33411353Ssam 33511353Ssam if (argc < 2) { 33611353Ssam strcat(line, " "); 33711353Ssam printf("(remote-directory) "); 33811353Ssam gets(&line[strlen(line)]); 33911353Ssam makeargv(); 34011353Ssam argc = margc; 34111353Ssam argv = margv; 34211353Ssam } 34311353Ssam if (argc < 2) { 344*11650Ssam printf("%s remote-files\n", argv[0]); 34511353Ssam return; 34611353Ssam } 347*11650Ssam while ((cp = remglob(argc, argv)) != NULL) 348*11650Ssam if (confirm(argv[0], cp)) 349*11650Ssam recvrequest("RETR", cp, cp, "w"); 350*11650Ssam } 351*11650Ssam 352*11650Ssam char * 353*11650Ssam remglob(argc, argv) 354*11650Ssam char *argv[]; 355*11650Ssam { 356*11650Ssam char temp[16], *cp; 357*11650Ssam static char buf[MAXPATHLEN]; 358*11650Ssam static FILE *ftemp = NULL; 359*11650Ssam static char **args; 360*11650Ssam int oldverbose; 361*11650Ssam 362*11650Ssam if (!doglob) { 363*11650Ssam if (argc == NULL) 364*11650Ssam args = argv; 365*11650Ssam if ((cp = *++args) == NULL) 366*11650Ssam args = NULL; 367*11650Ssam return (cp); 36811353Ssam } 369*11650Ssam if (ftemp == NULL) { 370*11650Ssam strcpy(temp, "/tmp/ftpXXXXXX"); 371*11650Ssam mktemp(temp); 372*11650Ssam oldverbose = verbose, verbose = 0; 373*11650Ssam recvrequest("NLST", temp, argv[1], "w"); 374*11650Ssam verbose = oldverbose; 375*11650Ssam ftemp = fopen(temp, "r"); 376*11650Ssam unlink(temp); 377*11650Ssam if (ftemp == NULL) { 378*11650Ssam printf("can't find list of remote files, oops\n"); 37911353Ssam return; 38011353Ssam } 38111353Ssam } 382*11650Ssam if (fgets(buf, sizeof (buf), ftemp) == NULL) { 383*11650Ssam fclose(ftemp), ftemp = NULL; 384*11650Ssam return (NULL); 38511353Ssam } 386*11650Ssam if ((cp = index(buf, '\n')) != NULL) 387*11650Ssam *cp = '\0'; 388*11650Ssam return (buf); 38911353Ssam } 39011353Ssam 39110294Ssam char * 39210294Ssam onoff(bool) 39310294Ssam int bool; 39410294Ssam { 39510294Ssam 39610294Ssam return (bool ? "on" : "off"); 39710294Ssam } 39810294Ssam 39910294Ssam /* 40010294Ssam * Show status. 40110294Ssam */ 40210294Ssam status(argc, argv) 40310294Ssam char *argv[]; 40410294Ssam { 40510294Ssam 40610294Ssam if (connected) 40710294Ssam printf("Connected to %s.\n", hostname); 40810294Ssam else 40910294Ssam printf("Not connected.\n"); 41010294Ssam printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 41110294Ssam modename, typename, formname, structname); 41211353Ssam printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 41311353Ssam onoff(verbose), onoff(bell), onoff(interactive), 41411353Ssam onoff(doglob)); 415*11650Ssam printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 416*11650Ssam onoff(hash), onoff(sendport)); 41710294Ssam } 41810294Ssam 41910294Ssam /* 42010294Ssam * Set beep on cmd completed mode. 42110294Ssam */ 42210294Ssam /*VARARGS*/ 42310294Ssam setbell() 42410294Ssam { 42510294Ssam 42610294Ssam bell = !bell; 42710294Ssam printf("Bell mode %s.\n", onoff(bell)); 42810294Ssam } 42910294Ssam 43010294Ssam /* 43110294Ssam * Turn on packet tracing. 43210294Ssam */ 43310294Ssam /*VARARGS*/ 43410294Ssam settrace() 43510294Ssam { 43610294Ssam 43710294Ssam trace = !trace; 43810294Ssam printf("Packet tracing %s.\n", onoff(trace)); 43910294Ssam } 44010294Ssam 44110294Ssam /* 442*11650Ssam * Toggle hash mark printing during transfers. 443*11650Ssam */ 444*11650Ssam /*VARARGS*/ 445*11650Ssam sethash() 446*11650Ssam { 447*11650Ssam 448*11650Ssam hash = !hash; 449*11650Ssam printf("Hash mark printing %s", onoff(hash)); 450*11650Ssam if (hash) 451*11650Ssam printf(" (%d bytes/hash mark)", BUFSIZ); 452*11650Ssam printf(".\n"); 453*11650Ssam } 454*11650Ssam 455*11650Ssam /* 45610294Ssam * Turn on printing of server echo's. 45710294Ssam */ 45810294Ssam /*VARARGS*/ 45910294Ssam setverbose() 46010294Ssam { 46110294Ssam 46210294Ssam verbose = !verbose; 46310294Ssam printf("Verbose mode %s.\n", onoff(verbose)); 46410294Ssam } 46510294Ssam 46610294Ssam /* 467*11650Ssam * Toggle PORT cmd use before each data connection. 468*11650Ssam */ 469*11650Ssam /*VARARGS*/ 470*11650Ssam setport() 471*11650Ssam { 472*11650Ssam 473*11650Ssam sendport = !sendport; 474*11650Ssam printf("Use of PORT cmds %s.\n", onoff(sendport)); 475*11650Ssam } 476*11650Ssam 477*11650Ssam /* 47810294Ssam * Turn on interactive prompting 47910294Ssam * during mget, mput, and mdelete. 48010294Ssam */ 48110294Ssam /*VARARGS*/ 48210294Ssam setprompt() 48310294Ssam { 48410294Ssam 48510294Ssam interactive = !interactive; 48610294Ssam printf("Interactive mode %s.\n", onoff(interactive)); 48710294Ssam } 48810294Ssam 48910294Ssam /* 49011353Ssam * Toggle metacharacter interpretation 49111353Ssam * on local file names. 49211353Ssam */ 49311353Ssam /*VARARGS*/ 49411353Ssam setglob() 49511353Ssam { 49611353Ssam 49711353Ssam doglob = !doglob; 49811353Ssam printf("Globbing %s.\n", onoff(doglob)); 49911353Ssam } 50011353Ssam 50111353Ssam /* 50210294Ssam * Set debugging mode on/off and/or 50310294Ssam * set level of debugging. 50410294Ssam */ 50510294Ssam setdebug(argc, argv) 50610294Ssam char *argv[]; 50710294Ssam { 50810294Ssam int val; 50910294Ssam 51010294Ssam if (argc > 1) { 51110294Ssam val = atoi(argv[1]); 51210294Ssam if (val < 0) { 51310294Ssam printf("%s: bad debugging value.\n", argv[1]); 51410294Ssam return; 51510294Ssam } 51610294Ssam } else 51710294Ssam val = !debug; 51810294Ssam debug = val; 51910294Ssam if (debug) 52010294Ssam options |= SO_DEBUG; 52110294Ssam else 52210294Ssam options &= ~SO_DEBUG; 52310294Ssam printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 52410294Ssam } 52510294Ssam 52610294Ssam /* 52710294Ssam * Set current working directory 52810294Ssam * on remote machine. 52910294Ssam */ 53010294Ssam cd(argc, argv) 53110294Ssam char *argv[]; 53210294Ssam { 53310294Ssam 53410294Ssam if (!connected) { 53510294Ssam printf("Not connected.\n"); 53610294Ssam return; 53710294Ssam } 53810294Ssam if (argc < 2) { 53910294Ssam strcat(line, " "); 54010294Ssam printf("(remote-directory) "); 54110294Ssam gets(&line[strlen(line)]); 54210294Ssam makeargv(); 54310294Ssam argc = margc; 54410294Ssam argv = margv; 54510294Ssam } 54610294Ssam if (argc < 2) { 54710294Ssam printf("%s remote-directory\n", argv[0]); 54810294Ssam return; 54910294Ssam } 55010294Ssam (void) command("CWD %s", argv[1]); 55110294Ssam } 55210294Ssam 55310294Ssam /* 55410294Ssam * Set current working directory 55510294Ssam * on local machine. 55610294Ssam */ 55710294Ssam lcd(argc, argv) 55810294Ssam char *argv[]; 55910294Ssam { 56011353Ssam char buf[MAXPATHLEN]; 56111353Ssam extern char *home; 56210294Ssam 56311353Ssam if (argc < 2) 56411353Ssam argc++, argv[1] = home; 56510294Ssam if (argc != 2) { 56610294Ssam printf("%s local-directory\n", argv[0]); 56710294Ssam return; 56810294Ssam } 56911353Ssam if (!globulize(&argv[1])) 57011353Ssam return; 57111353Ssam if (chdir(argv[1]) < 0) { 57210294Ssam perror(argv[1]); 57311353Ssam return; 57411353Ssam } 57511353Ssam printf("Local directory now %s\n", getwd(buf)); 57610294Ssam } 57710294Ssam 57810294Ssam /* 57910294Ssam * Delete a single file. 58010294Ssam */ 58110294Ssam delete(argc, argv) 58210294Ssam char *argv[]; 58310294Ssam { 58410294Ssam 58510294Ssam if (argc < 2) { 58610294Ssam strcat(line, " "); 58710294Ssam printf("(remote-file) "); 58810294Ssam gets(&line[strlen(line)]); 58910294Ssam makeargv(); 59010294Ssam argc = margc; 59110294Ssam argv = margv; 59210294Ssam } 59310294Ssam if (argc < 2) { 59410294Ssam printf("%s remote-file\n", argv[0]); 59510294Ssam return; 59610294Ssam } 59710294Ssam (void) command("DELE %s", argv[1]); 59810294Ssam } 59910294Ssam 60010294Ssam /* 601*11650Ssam * Delete multiple files. 602*11650Ssam */ 603*11650Ssam mdelete(argc, argv) 604*11650Ssam char *argv[]; 605*11650Ssam { 606*11650Ssam char *cp; 607*11650Ssam 608*11650Ssam if (argc < 2) { 609*11650Ssam strcat(line, " "); 610*11650Ssam printf("(remote-files) "); 611*11650Ssam gets(&line[strlen(line)]); 612*11650Ssam makeargv(); 613*11650Ssam argc = margc; 614*11650Ssam argv = margv; 615*11650Ssam } 616*11650Ssam if (argc < 2) { 617*11650Ssam printf("%s remote-files\n", argv[0]); 618*11650Ssam return; 619*11650Ssam } 620*11650Ssam while ((cp = remglob(argc, argv)) != NULL) 621*11650Ssam if (confirm(argv[0], cp)) 622*11650Ssam (void) command("DELE %s", cp); 623*11650Ssam } 624*11650Ssam /* 62510294Ssam * Rename a remote file. 62610294Ssam */ 62710294Ssam renamefile(argc, argv) 62810294Ssam char *argv[]; 62910294Ssam { 63010294Ssam 63110294Ssam if (argc < 2) { 63210294Ssam strcat(line, " "); 63310294Ssam printf("(from-name) "); 63410294Ssam gets(&line[strlen(line)]); 63510294Ssam makeargv(); 63610294Ssam argc = margc; 63710294Ssam argv = margv; 63810294Ssam } 63910294Ssam if (argc < 2) { 64010294Ssam usage: 64110294Ssam printf("%s from-name to-name\n", argv[0]); 64210294Ssam return; 64310294Ssam } 64410294Ssam if (argc < 3) { 64510294Ssam strcat(line, " "); 64610294Ssam printf("(to-name) "); 64710294Ssam gets(&line[strlen(line)]); 64810294Ssam makeargv(); 64910294Ssam argc = margc; 65010294Ssam argv = margv; 65110294Ssam } 65210294Ssam if (argc < 3) 65310294Ssam goto usage; 65410294Ssam if (command("RNFR %s", argv[1]) == CONTINUE) 65510294Ssam (void) command("RNTO %s", argv[2]); 65610294Ssam } 65710294Ssam 65810294Ssam /* 65910294Ssam * Get a directory listing 66010294Ssam * of remote files. 66110294Ssam */ 66210294Ssam ls(argc, argv) 66310294Ssam char *argv[]; 66410294Ssam { 665*11650Ssam char *cmd, *mode; 666*11650Ssam int i; 66710294Ssam 66810294Ssam if (argc < 2) 66910294Ssam argc++, argv[1] = NULL; 67010294Ssam if (argc < 3) 67110294Ssam argc++, argv[2] = "-"; 67210294Ssam cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; 67311353Ssam if (strcmp(argv[2], "-") && !globulize(&argv[2])) 67411353Ssam return; 675*11650Ssam mode = argc > 3 ? "a" : "w"; 676*11650Ssam for (i = 1; i < argc - 1; i++) 677*11650Ssam recvrequest(cmd, argv[argc - 1], argv[i], mode); 67810294Ssam } 67910294Ssam 68010294Ssam /* 68110294Ssam * Do a shell escape 68210294Ssam */ 68310294Ssam shell(argc, argv) 68410294Ssam char *argv[]; 68510294Ssam { 68610294Ssam 68710294Ssam printf("Sorry, this function is unimplemented.\n"); 68810294Ssam } 68910294Ssam 69010294Ssam /* 69110294Ssam * Send new user information (re-login) 69210294Ssam */ 69310294Ssam user(argc, argv) 69410294Ssam int argc; 69510294Ssam char **argv; 69610294Ssam { 69710294Ssam char acct[80], *getpass(); 69810294Ssam int n; 69910294Ssam 70010294Ssam if (argc < 2) { 70110294Ssam strcat(line, " "); 70210294Ssam printf("(username) "); 70310294Ssam gets(&line[strlen(line)]); 70410294Ssam makeargv(); 70510294Ssam argc = margc; 70610294Ssam argv = margv; 70710294Ssam } 70810294Ssam if (argc > 4) { 70910294Ssam printf("usage: %s username [password] [account]\n", argv[0]); 71010294Ssam return; 71110294Ssam } 71210294Ssam n = command("USER %s", argv[1]); 71310294Ssam if (n == CONTINUE) { 71410294Ssam if (argc < 3 ) 71510294Ssam argv[2] = getpass("Password: "), argc++; 71610294Ssam n = command("PASS %s", argv[2]); 71710294Ssam } 71810294Ssam if (n == CONTINUE) { 71910294Ssam if (argc < 4) { 72010294Ssam printf("Account: "); (void) fflush(stdout); 72110294Ssam (void) fgets(acct, sizeof(acct) - 1, stdin); 72210294Ssam acct[strlen(acct) - 1] = '\0'; 72310294Ssam argv[3] = acct; argc++; 72410294Ssam } 72510294Ssam n = command("ACCT %s", acct); 72610294Ssam } 72710294Ssam if (n != COMPLETE) { 72810294Ssam fprintf(stderr, "Login failed.\n"); 72910294Ssam return (0); 73010294Ssam } 73110294Ssam return (1); 73210294Ssam } 73310294Ssam 73410294Ssam /* 73510294Ssam * Print working directory. 73610294Ssam */ 73710294Ssam /*VARARGS*/ 73810294Ssam pwd() 73910294Ssam { 74010294Ssam if (!connected) { 74110294Ssam printf("Not connected.\n"); 74210294Ssam return; 74310294Ssam } 74410294Ssam (void) command("XPWD"); 74510294Ssam } 74610294Ssam 74710294Ssam /* 74810294Ssam * Make a directory. 74910294Ssam */ 75010294Ssam makedir(argc, argv) 75110294Ssam char *argv[]; 75210294Ssam { 75310294Ssam 75410294Ssam if (argc < 2) { 75510294Ssam strcat(line, " "); 75610294Ssam printf("(directory-name) "); 75710294Ssam gets(&line[strlen(line)]); 75810294Ssam makeargv(); 75910294Ssam argc = margc; 76010294Ssam argv = margv; 76110294Ssam } 76210294Ssam if (argc < 2) { 76310294Ssam printf("%s directory-name\n", argv[0]); 76410294Ssam return; 76510294Ssam } 76610294Ssam (void) command("XMKD %s", argv[1]); 76710294Ssam } 76810294Ssam 76910294Ssam /* 77010294Ssam * Remove a directory. 77110294Ssam */ 77210294Ssam removedir(argc, argv) 77310294Ssam char *argv[]; 77410294Ssam { 77510294Ssam 77610294Ssam if (argc < 2) { 77710294Ssam strcat(line, " "); 77810294Ssam printf("(directory-name) "); 77910294Ssam gets(&line[strlen(line)]); 78010294Ssam makeargv(); 78110294Ssam argc = margc; 78210294Ssam argv = margv; 78310294Ssam } 78410294Ssam if (argc < 2) { 78510294Ssam printf("%s directory-name\n", argv[0]); 78610294Ssam return; 78710294Ssam } 78810294Ssam (void) command("XRMD %s", argv[1]); 78910294Ssam } 79010294Ssam 79110294Ssam /* 79210294Ssam * Send a line, verbatim, to the remote machine. 79310294Ssam */ 79410294Ssam quote(argc, argv) 79510294Ssam char *argv[]; 79610294Ssam { 79710294Ssam int i; 79810294Ssam char buf[BUFSIZ]; 79910294Ssam 80010294Ssam if (argc < 2) { 80110294Ssam strcat(line, " "); 80210294Ssam printf("(command line to send) "); 80310294Ssam gets(&line[strlen(line)]); 80410294Ssam makeargv(); 80510294Ssam argc = margc; 80610294Ssam argv = margv; 80710294Ssam } 80810294Ssam if (argc < 2) { 80910294Ssam printf("usage: %s line-to-send\n", argv[0]); 81010294Ssam return; 81110294Ssam } 81210294Ssam strcpy(buf, argv[1]); 81310294Ssam for (i = 2; i < argc; i++) { 81410294Ssam strcat(buf, " "); 81510294Ssam strcat(buf, argv[i]); 81610294Ssam } 81710294Ssam (void) command(buf); 81810294Ssam } 81910294Ssam 82010294Ssam /* 82110294Ssam * Ask the other side for help. 82210294Ssam */ 82310294Ssam rmthelp(argc, argv) 82410294Ssam char *argv[]; 82510294Ssam { 82610294Ssam int oldverbose = verbose; 82710294Ssam 82810294Ssam verbose = 1; 82910294Ssam (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 83010294Ssam verbose = oldverbose; 83110294Ssam } 83210294Ssam 83310294Ssam /* 83410294Ssam * Terminate session and exit. 83510294Ssam */ 83610294Ssam /*VARARGS*/ 83710294Ssam quit() 83810294Ssam { 83910294Ssam 84010294Ssam disconnect(); 84110294Ssam exit(0); 84210294Ssam } 84310294Ssam 84410294Ssam /* 84510294Ssam * Terminate session, but don't exit. 84610294Ssam */ 84710294Ssam disconnect() 84810294Ssam { 84910294Ssam extern FILE *cout; 85010294Ssam extern int data; 85110294Ssam 85210294Ssam if (!connected) 85310294Ssam return; 85410294Ssam (void) command("QUIT"); 85510294Ssam (void) fclose(cout); 85610294Ssam cout = NULL; 85710294Ssam connected = 0; 85810294Ssam data = -1; 85910294Ssam } 86011353Ssam 861*11650Ssam confirm(cmd, file) 86211353Ssam char *cmd, *file; 86311353Ssam { 86411353Ssam char line[BUFSIZ]; 86511353Ssam 86611353Ssam if (!interactive) 867*11650Ssam return (1); 86811353Ssam printf("%s %s? ", cmd, file); 86911353Ssam fflush(stdout); 87011353Ssam gets(line); 871*11650Ssam return (*line != 'n' && *line != 'N'); 87211353Ssam } 87311353Ssam 87411353Ssam fatal(msg) 87511353Ssam char *msg; 87611353Ssam { 87711353Ssam 87811353Ssam fprintf(stderr, "ftp: %s\n"); 87911353Ssam exit(1); 88011353Ssam } 88111353Ssam 88211353Ssam /* 88311353Ssam * Glob a local file name specification with 88411353Ssam * the expectation of a single return value. 88511353Ssam * Can't control multiple values being expanded 88611353Ssam * from the expression, we return only the first. 88711353Ssam */ 88811353Ssam globulize(cpp) 88911353Ssam char **cpp; 89011353Ssam { 89111353Ssam char **globbed; 89211353Ssam 89311353Ssam if (!doglob) 89411353Ssam return (1); 89511353Ssam globbed = glob(*cpp); 89611353Ssam if (globerr != NULL) { 89711353Ssam printf("%s: %s\n", *cpp, globerr); 89811353Ssam if (globbed) 89911353Ssam blkfree(globbed); 90011353Ssam return (0); 90111353Ssam } 90211353Ssam if (globbed) { 90311353Ssam *cpp = *globbed++; 90411353Ssam /* don't waste too much memory */ 90511353Ssam if (*globbed) 90611353Ssam blkfree(globbed); 90711353Ssam } 90811353Ssam return (1); 90911353Ssam } 910