110294Ssam #ifndef lint 2*11353Ssam static char sccsid[] = "@(#)cmds.c 4.3 (Berkeley) 03/01/83"; 310294Ssam #endif 410294Ssam 510294Ssam /* 610294Ssam * FTP User Program -- Command Routines. 710294Ssam */ 8*11353Ssam #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> 15*11353Ssam #include <stat.h> 1610294Ssam 1710294Ssam #include "ftp.h" 1810294Ssam #include "ftp_var.h" 1910294Ssam 20*11353Ssam extern char *globerr; 21*11353Ssam extern char **glob(); 22*11353Ssam 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 */ 20010294Ssam put(argc, argv) 20110294Ssam char *argv[]; 20210294Ssam { 20310294Ssam 20410294Ssam if (!connected) { 20510294Ssam printf("Not connected.\n"); 20610294Ssam return; 20710294Ssam } 20810294Ssam if (argc == 2) 20910294Ssam argc++, argv[2] = argv[1]; 21010294Ssam if (argc < 2) { 21110294Ssam strcat(line, " "); 21210294Ssam printf("(local-file) "); 21310294Ssam gets(&line[strlen(line)]); 21410294Ssam makeargv(); 21510294Ssam argc = margc; 21610294Ssam argv = margv; 21710294Ssam } 21810294Ssam if (argc < 2) { 21910294Ssam usage: 22010294Ssam printf("%s local-file remote-file\n", argv[0]); 22110294Ssam return; 22210294Ssam } 22310294Ssam if (argc < 3) { 22410294Ssam strcat(line, " "); 22510294Ssam printf("(remote-file) "); 22610294Ssam gets(&line[strlen(line)]); 22710294Ssam makeargv(); 22810294Ssam argc = margc; 22910294Ssam argv = margv; 23010294Ssam } 23110294Ssam if (argc < 3) 23210294Ssam goto usage; 233*11353Ssam if (!globulize(&argv[1])) 234*11353Ssam return; 23510294Ssam sendrequest("STOR", argv[1], argv[2]); 23610294Ssam } 23710294Ssam 23810294Ssam /* 239*11353Ssam * Send one or more files. 24010294Ssam */ 241*11353Ssam mput(argc, argv) 242*11353Ssam char *argv[]; 243*11353Ssam { 244*11353Ssam char **cpp, *dst; 245*11353Ssam int i; 246*11353Ssam 247*11353Ssam if (!connected) { 248*11353Ssam printf("Not connected.\n"); 249*11353Ssam return; 250*11353Ssam } 251*11353Ssam if (argc < 2) { 252*11353Ssam printf("%s local-file remote-file, or\n", argv[0]); 253*11353Ssam printf("%s local-files\n", argv[0]); 254*11353Ssam return; 255*11353Ssam } 256*11353Ssam if (argc == 3) { 257*11353Ssam if (!globulize(&argv[1])) 258*11353Ssam return; 259*11353Ssam sendrequest("STOR", argv[1], argv[2]); 260*11353Ssam return; 261*11353Ssam } 262*11353Ssam /* 263*11353Ssam * Check for shell metacharacters which we might 264*11353Ssam * want to expand into a list of file names. 265*11353Ssam */ 266*11353Ssam for (i = 1; i < argc; i++) { 267*11353Ssam if (!doglob) { 268*11353Ssam if (!skip(argv[0], argv[i])) 269*11353Ssam sendrequest("STOR", argv[i], argv[i]); 270*11353Ssam continue; 271*11353Ssam } 272*11353Ssam cpp = glob(argv[i]); 273*11353Ssam if (globerr != NULL) { 274*11353Ssam printf("%s: %s\n", argv[i], globerr); 275*11353Ssam if (cpp) 276*11353Ssam blkfree(cpp); 277*11353Ssam continue; 278*11353Ssam } 279*11353Ssam if (cpp == NULL) { 280*11353Ssam printf("%s: no match\n", argv[i]); 281*11353Ssam continue; 282*11353Ssam } 283*11353Ssam while (*cpp != NULL) { 284*11353Ssam if (!skip(argv[0], *cpp)) 285*11353Ssam sendrequest("STOR", *cpp, *cpp); 286*11353Ssam free(*cpp), cpp++; 287*11353Ssam } 288*11353Ssam } 289*11353Ssam } 290*11353Ssam 291*11353Ssam /* 292*11353Ssam * Receive one file. 293*11353Ssam */ 29410294Ssam get(argc, argv) 29510294Ssam char *argv[]; 29610294Ssam { 29710294Ssam 29810294Ssam if (!connected) { 29910294Ssam printf("Not connected.\n"); 30010294Ssam return; 30110294Ssam } 30210294Ssam if (argc == 2) 30310294Ssam argc++, argv[2] = argv[1]; 30410294Ssam if (argc < 2) { 30510294Ssam strcat(line, " "); 30610294Ssam printf("(remote-file) "); 30710294Ssam gets(&line[strlen(line)]); 30810294Ssam makeargv(); 30910294Ssam argc = margc; 31010294Ssam argv = margv; 31110294Ssam } 31210294Ssam if (argc < 2) { 31310294Ssam usage: 314*11353Ssam printf("%s remote-file [ local-file ]\n", argv[0]); 31510294Ssam return; 31610294Ssam } 31710294Ssam if (argc < 3) { 31810294Ssam strcat(line, " "); 31910294Ssam printf("(local-file) "); 32010294Ssam gets(&line[strlen(line)]); 32110294Ssam makeargv(); 32210294Ssam argc = margc; 32310294Ssam argv = margv; 32410294Ssam } 32510294Ssam if (argc < 3) 32610294Ssam goto usage; 327*11353Ssam if (!globulize(&argv[2])) 328*11353Ssam return; 32910294Ssam recvrequest("RETR", argv[2], argv[1]); 33010294Ssam } 33110294Ssam 332*11353Ssam /* 333*11353Ssam * Get multiple files. 334*11353Ssam */ 335*11353Ssam mget(argc, argv) 336*11353Ssam char *argv[]; 337*11353Ssam { 338*11353Ssam char temp[16], *dst, dstpath[MAXPATHLEN], buf[MAXPATHLEN]; 339*11353Ssam FILE *ftemp; 340*11353Ssam int madedir = 0, oldverbose; 341*11353Ssam struct stat stb; 342*11353Ssam 343*11353Ssam if (!connected) { 344*11353Ssam printf("Not connected.\n"); 345*11353Ssam return; 346*11353Ssam } 347*11353Ssam if (argc == 2) 348*11353Ssam argc++, argv[2] = argv[1]; 349*11353Ssam if (argc < 2) { 350*11353Ssam strcat(line, " "); 351*11353Ssam printf("(remote-directory) "); 352*11353Ssam gets(&line[strlen(line)]); 353*11353Ssam makeargv(); 354*11353Ssam argc = margc; 355*11353Ssam argv = margv; 356*11353Ssam } 357*11353Ssam if (argc < 2) { 358*11353Ssam usage: 359*11353Ssam printf("%s remote-directory [ local-directory ], or\n", 360*11353Ssam argv[0]); 361*11353Ssam printf("%s remote-files local-directory\n", argv[0]); 362*11353Ssam return; 363*11353Ssam } 364*11353Ssam if (argc < 3) { 365*11353Ssam strcat(line, " "); 366*11353Ssam printf("(local-directory) "); 367*11353Ssam gets(&line[strlen(line)]); 368*11353Ssam makeargv(); 369*11353Ssam argc = margc; 370*11353Ssam argv = margv; 371*11353Ssam } 372*11353Ssam if (argc < 3) 373*11353Ssam goto usage; 374*11353Ssam dst = argv[argc - 1]; 375*11353Ssam if (!globulize(&dst)) 376*11353Ssam return; 377*11353Ssam /* 378*11353Ssam * If destination doesn't exist, 379*11353Ssam * try and create it. 380*11353Ssam */ 381*11353Ssam if (stat(dst, &stb) < 0) { 382*11353Ssam if (mkdir(dst, 0777) < 0) { 383*11353Ssam perror(dst); 384*11353Ssam return; 385*11353Ssam } 386*11353Ssam madedir++; 387*11353Ssam } else { 388*11353Ssam if ((stb.st_mode & S_IFMT) != S_IFDIR) { 389*11353Ssam printf("%s: not a directory\n", dst); 390*11353Ssam return; 391*11353Ssam } 392*11353Ssam } 393*11353Ssam /* 394*11353Ssam * Multiple files, just get each one without an nlst. 395*11353Ssam */ 396*11353Ssam if (argc > 3) { 397*11353Ssam int i; 398*11353Ssam 399*11353Ssam for (i = 1; i < argc - 1; i++) 400*11353Ssam recvrequest("RETR", 401*11353Ssam sprintf(dstpath, "%s/%s", dst, argv[i]), argv[i]); 402*11353Ssam return; 403*11353Ssam } 404*11353Ssam /* 405*11353Ssam * Get a directory full of files. Perform an 406*11353Ssam * nlst to find the file names, then retrieve 407*11353Ssam * each individually. If prompting is on, ask 408*11353Ssam * before grabbing each file. 409*11353Ssam */ 410*11353Ssam strcpy(temp, "/tmp/ftpXXXXXX"); 411*11353Ssam mktemp(temp); 412*11353Ssam oldverbose = verbose, verbose = 0; 413*11353Ssam recvrequest("NLST", temp, argv[1]); 414*11353Ssam verbose = oldverbose; 415*11353Ssam ftemp = fopen(temp, "r"); 416*11353Ssam unlink(temp); 417*11353Ssam if (ftemp == NULL) { 418*11353Ssam printf("can't find list of remote files, oops\n"); 419*11353Ssam if (madedir) 420*11353Ssam (void) rmdir(dst); 421*11353Ssam return; 422*11353Ssam } 423*11353Ssam while (fgets(buf, sizeof (buf), ftemp) != NULL) { 424*11353Ssam char *cp = index(buf, '\n'); 425*11353Ssam 426*11353Ssam if (cp) 427*11353Ssam *cp = '\0'; 428*11353Ssam if (skip(argv[0], buf)) 429*11353Ssam continue; 430*11353Ssam recvrequest("RETR", sprintf(dstpath, "%s/%s", dst, buf), buf); 431*11353Ssam } 432*11353Ssam fclose(ftemp); 433*11353Ssam } 434*11353Ssam 43510294Ssam char * 43610294Ssam onoff(bool) 43710294Ssam int bool; 43810294Ssam { 43910294Ssam 44010294Ssam return (bool ? "on" : "off"); 44110294Ssam } 44210294Ssam 44310294Ssam /* 44410294Ssam * Show status. 44510294Ssam */ 44610294Ssam status(argc, argv) 44710294Ssam char *argv[]; 44810294Ssam { 44910294Ssam 45010294Ssam if (connected) 45110294Ssam printf("Connected to %s.\n", hostname); 45210294Ssam else 45310294Ssam printf("Not connected.\n"); 45410294Ssam printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 45510294Ssam modename, typename, formname, structname); 456*11353Ssam printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 457*11353Ssam onoff(verbose), onoff(bell), onoff(interactive), 458*11353Ssam onoff(doglob)); 45910294Ssam } 46010294Ssam 46110294Ssam /* 46210294Ssam * Set beep on cmd completed mode. 46310294Ssam */ 46410294Ssam /*VARARGS*/ 46510294Ssam setbell() 46610294Ssam { 46710294Ssam 46810294Ssam bell = !bell; 46910294Ssam printf("Bell mode %s.\n", onoff(bell)); 47010294Ssam } 47110294Ssam 47210294Ssam /* 47310294Ssam * Turn on packet tracing. 47410294Ssam */ 47510294Ssam /*VARARGS*/ 47610294Ssam settrace() 47710294Ssam { 47810294Ssam 47910294Ssam trace = !trace; 48010294Ssam printf("Packet tracing %s.\n", onoff(trace)); 48110294Ssam } 48210294Ssam 48310294Ssam /* 48410294Ssam * Turn on printing of server echo's. 48510294Ssam */ 48610294Ssam /*VARARGS*/ 48710294Ssam setverbose() 48810294Ssam { 48910294Ssam 49010294Ssam verbose = !verbose; 49110294Ssam printf("Verbose mode %s.\n", onoff(verbose)); 49210294Ssam } 49310294Ssam 49410294Ssam /* 49510294Ssam * Turn on interactive prompting 49610294Ssam * during mget, mput, and mdelete. 49710294Ssam */ 49810294Ssam /*VARARGS*/ 49910294Ssam setprompt() 50010294Ssam { 50110294Ssam 50210294Ssam interactive = !interactive; 50310294Ssam printf("Interactive mode %s.\n", onoff(interactive)); 50410294Ssam } 50510294Ssam 50610294Ssam /* 507*11353Ssam * Toggle metacharacter interpretation 508*11353Ssam * on local file names. 509*11353Ssam */ 510*11353Ssam /*VARARGS*/ 511*11353Ssam setglob() 512*11353Ssam { 513*11353Ssam 514*11353Ssam doglob = !doglob; 515*11353Ssam printf("Globbing %s.\n", onoff(doglob)); 516*11353Ssam } 517*11353Ssam 518*11353Ssam /* 51910294Ssam * Set debugging mode on/off and/or 52010294Ssam * set level of debugging. 52110294Ssam */ 52210294Ssam setdebug(argc, argv) 52310294Ssam char *argv[]; 52410294Ssam { 52510294Ssam int val; 52610294Ssam 52710294Ssam if (argc > 1) { 52810294Ssam val = atoi(argv[1]); 52910294Ssam if (val < 0) { 53010294Ssam printf("%s: bad debugging value.\n", argv[1]); 53110294Ssam return; 53210294Ssam } 53310294Ssam } else 53410294Ssam val = !debug; 53510294Ssam debug = val; 53610294Ssam if (debug) 53710294Ssam options |= SO_DEBUG; 53810294Ssam else 53910294Ssam options &= ~SO_DEBUG; 54010294Ssam printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 54110294Ssam } 54210294Ssam 54310294Ssam /* 54410294Ssam * Set current working directory 54510294Ssam * on remote machine. 54610294Ssam */ 54710294Ssam cd(argc, argv) 54810294Ssam char *argv[]; 54910294Ssam { 55010294Ssam 55110294Ssam if (!connected) { 55210294Ssam printf("Not connected.\n"); 55310294Ssam return; 55410294Ssam } 55510294Ssam if (argc < 2) { 55610294Ssam strcat(line, " "); 55710294Ssam printf("(remote-directory) "); 55810294Ssam gets(&line[strlen(line)]); 55910294Ssam makeargv(); 56010294Ssam argc = margc; 56110294Ssam argv = margv; 56210294Ssam } 56310294Ssam if (argc < 2) { 56410294Ssam printf("%s remote-directory\n", argv[0]); 56510294Ssam return; 56610294Ssam } 56710294Ssam (void) command("CWD %s", argv[1]); 56810294Ssam } 56910294Ssam 57010294Ssam /* 57110294Ssam * Set current working directory 57210294Ssam * on local machine. 57310294Ssam */ 57410294Ssam lcd(argc, argv) 57510294Ssam char *argv[]; 57610294Ssam { 577*11353Ssam char buf[MAXPATHLEN]; 578*11353Ssam extern char *home; 57910294Ssam 580*11353Ssam if (argc < 2) 581*11353Ssam argc++, argv[1] = home; 58210294Ssam if (argc != 2) { 58310294Ssam printf("%s local-directory\n", argv[0]); 58410294Ssam return; 58510294Ssam } 586*11353Ssam if (!globulize(&argv[1])) 587*11353Ssam return; 588*11353Ssam if (chdir(argv[1]) < 0) { 58910294Ssam perror(argv[1]); 590*11353Ssam return; 591*11353Ssam } 592*11353Ssam printf("Local directory now %s\n", getwd(buf)); 59310294Ssam } 59410294Ssam 59510294Ssam /* 59610294Ssam * Delete a single file. 59710294Ssam */ 59810294Ssam delete(argc, argv) 59910294Ssam char *argv[]; 60010294Ssam { 60110294Ssam 60210294Ssam if (argc < 2) { 60310294Ssam strcat(line, " "); 60410294Ssam printf("(remote-file) "); 60510294Ssam gets(&line[strlen(line)]); 60610294Ssam makeargv(); 60710294Ssam argc = margc; 60810294Ssam argv = margv; 60910294Ssam } 61010294Ssam if (argc < 2) { 61110294Ssam printf("%s remote-file\n", argv[0]); 61210294Ssam return; 61310294Ssam } 61410294Ssam (void) command("DELE %s", argv[1]); 61510294Ssam } 61610294Ssam 61710294Ssam /* 61810294Ssam * Rename a remote file. 61910294Ssam */ 62010294Ssam renamefile(argc, argv) 62110294Ssam char *argv[]; 62210294Ssam { 62310294Ssam 62410294Ssam if (argc < 2) { 62510294Ssam strcat(line, " "); 62610294Ssam printf("(from-name) "); 62710294Ssam gets(&line[strlen(line)]); 62810294Ssam makeargv(); 62910294Ssam argc = margc; 63010294Ssam argv = margv; 63110294Ssam } 63210294Ssam if (argc < 2) { 63310294Ssam usage: 63410294Ssam printf("%s from-name to-name\n", argv[0]); 63510294Ssam return; 63610294Ssam } 63710294Ssam if (argc < 3) { 63810294Ssam strcat(line, " "); 63910294Ssam printf("(to-name) "); 64010294Ssam gets(&line[strlen(line)]); 64110294Ssam makeargv(); 64210294Ssam argc = margc; 64310294Ssam argv = margv; 64410294Ssam } 64510294Ssam if (argc < 3) 64610294Ssam goto usage; 64710294Ssam if (command("RNFR %s", argv[1]) == CONTINUE) 64810294Ssam (void) command("RNTO %s", argv[2]); 64910294Ssam } 65010294Ssam 65110294Ssam /* 65210294Ssam * Get a directory listing 65310294Ssam * of remote files. 65410294Ssam */ 65510294Ssam ls(argc, argv) 65610294Ssam char *argv[]; 65710294Ssam { 65810294Ssam char *cmd; 65910294Ssam 66010294Ssam if (argc < 2) 66110294Ssam argc++, argv[1] = NULL; 66210294Ssam if (argc < 3) 66310294Ssam argc++, argv[2] = "-"; 66410294Ssam if (argc > 3) { 66510294Ssam printf("usage: %s remote-directory local-file\n", argv[0]); 66610294Ssam return; 66710294Ssam } 66810294Ssam cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; 669*11353Ssam if (strcmp(argv[2], "-") && !globulize(&argv[2])) 670*11353Ssam return; 67110294Ssam recvrequest(cmd, argv[2], argv[1]); 67210294Ssam } 67310294Ssam 67410294Ssam /* 67510294Ssam * Do a shell escape 67610294Ssam */ 67710294Ssam shell(argc, argv) 67810294Ssam char *argv[]; 67910294Ssam { 68010294Ssam 68110294Ssam printf("Sorry, this function is unimplemented.\n"); 68210294Ssam } 68310294Ssam 68410294Ssam /* 68510294Ssam * Send new user information (re-login) 68610294Ssam */ 68710294Ssam user(argc, argv) 68810294Ssam int argc; 68910294Ssam char **argv; 69010294Ssam { 69110294Ssam char acct[80], *getpass(); 69210294Ssam int n; 69310294Ssam 69410294Ssam if (argc < 2) { 69510294Ssam strcat(line, " "); 69610294Ssam printf("(username) "); 69710294Ssam gets(&line[strlen(line)]); 69810294Ssam makeargv(); 69910294Ssam argc = margc; 70010294Ssam argv = margv; 70110294Ssam } 70210294Ssam if (argc > 4) { 70310294Ssam printf("usage: %s username [password] [account]\n", argv[0]); 70410294Ssam return; 70510294Ssam } 70610294Ssam n = command("USER %s", argv[1]); 70710294Ssam if (n == CONTINUE) { 70810294Ssam if (argc < 3 ) 70910294Ssam argv[2] = getpass("Password: "), argc++; 71010294Ssam n = command("PASS %s", argv[2]); 71110294Ssam } 71210294Ssam if (n == CONTINUE) { 71310294Ssam if (argc < 4) { 71410294Ssam printf("Account: "); (void) fflush(stdout); 71510294Ssam (void) fgets(acct, sizeof(acct) - 1, stdin); 71610294Ssam acct[strlen(acct) - 1] = '\0'; 71710294Ssam argv[3] = acct; argc++; 71810294Ssam } 71910294Ssam n = command("ACCT %s", acct); 72010294Ssam } 72110294Ssam if (n != COMPLETE) { 72210294Ssam fprintf(stderr, "Login failed.\n"); 72310294Ssam return (0); 72410294Ssam } 72510294Ssam return (1); 72610294Ssam } 72710294Ssam 72810294Ssam /* 72910294Ssam * Print working directory. 73010294Ssam */ 73110294Ssam /*VARARGS*/ 73210294Ssam pwd() 73310294Ssam { 73410294Ssam if (!connected) { 73510294Ssam printf("Not connected.\n"); 73610294Ssam return; 73710294Ssam } 73810294Ssam (void) command("XPWD"); 73910294Ssam } 74010294Ssam 74110294Ssam /* 74210294Ssam * Make a directory. 74310294Ssam */ 74410294Ssam makedir(argc, argv) 74510294Ssam char *argv[]; 74610294Ssam { 74710294Ssam 74810294Ssam if (argc < 2) { 74910294Ssam strcat(line, " "); 75010294Ssam printf("(directory-name) "); 75110294Ssam gets(&line[strlen(line)]); 75210294Ssam makeargv(); 75310294Ssam argc = margc; 75410294Ssam argv = margv; 75510294Ssam } 75610294Ssam if (argc < 2) { 75710294Ssam printf("%s directory-name\n", argv[0]); 75810294Ssam return; 75910294Ssam } 76010294Ssam (void) command("XMKD %s", argv[1]); 76110294Ssam } 76210294Ssam 76310294Ssam /* 76410294Ssam * Remove a directory. 76510294Ssam */ 76610294Ssam removedir(argc, argv) 76710294Ssam char *argv[]; 76810294Ssam { 76910294Ssam 77010294Ssam if (argc < 2) { 77110294Ssam strcat(line, " "); 77210294Ssam printf("(directory-name) "); 77310294Ssam gets(&line[strlen(line)]); 77410294Ssam makeargv(); 77510294Ssam argc = margc; 77610294Ssam argv = margv; 77710294Ssam } 77810294Ssam if (argc < 2) { 77910294Ssam printf("%s directory-name\n", argv[0]); 78010294Ssam return; 78110294Ssam } 78210294Ssam (void) command("XRMD %s", argv[1]); 78310294Ssam } 78410294Ssam 78510294Ssam /* 78610294Ssam * Send a line, verbatim, to the remote machine. 78710294Ssam */ 78810294Ssam quote(argc, argv) 78910294Ssam char *argv[]; 79010294Ssam { 79110294Ssam int i; 79210294Ssam char buf[BUFSIZ]; 79310294Ssam 79410294Ssam if (argc < 2) { 79510294Ssam strcat(line, " "); 79610294Ssam printf("(command line to send) "); 79710294Ssam gets(&line[strlen(line)]); 79810294Ssam makeargv(); 79910294Ssam argc = margc; 80010294Ssam argv = margv; 80110294Ssam } 80210294Ssam if (argc < 2) { 80310294Ssam printf("usage: %s line-to-send\n", argv[0]); 80410294Ssam return; 80510294Ssam } 80610294Ssam strcpy(buf, argv[1]); 80710294Ssam for (i = 2; i < argc; i++) { 80810294Ssam strcat(buf, " "); 80910294Ssam strcat(buf, argv[i]); 81010294Ssam } 81110294Ssam (void) command(buf); 81210294Ssam } 81310294Ssam 81410294Ssam /* 81510294Ssam * Ask the other side for help. 81610294Ssam */ 81710294Ssam rmthelp(argc, argv) 81810294Ssam char *argv[]; 81910294Ssam { 82010294Ssam int oldverbose = verbose; 82110294Ssam 82210294Ssam verbose = 1; 82310294Ssam (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 82410294Ssam verbose = oldverbose; 82510294Ssam } 82610294Ssam 82710294Ssam /* 82810294Ssam * Terminate session and exit. 82910294Ssam */ 83010294Ssam /*VARARGS*/ 83110294Ssam quit() 83210294Ssam { 83310294Ssam 83410294Ssam disconnect(); 83510294Ssam exit(0); 83610294Ssam } 83710294Ssam 83810294Ssam /* 83910294Ssam * Terminate session, but don't exit. 84010294Ssam */ 84110294Ssam disconnect() 84210294Ssam { 84310294Ssam extern FILE *cout; 84410294Ssam extern int data; 84510294Ssam 84610294Ssam if (!connected) 84710294Ssam return; 84810294Ssam (void) command("QUIT"); 84910294Ssam (void) fclose(cout); 85010294Ssam cout = NULL; 85110294Ssam connected = 0; 85210294Ssam data = -1; 85310294Ssam } 854*11353Ssam 855*11353Ssam skip(cmd, file) 856*11353Ssam char *cmd, *file; 857*11353Ssam { 858*11353Ssam char line[BUFSIZ]; 859*11353Ssam 860*11353Ssam if (!interactive) 861*11353Ssam return (0); 862*11353Ssam printf("%s %s? ", cmd, file); 863*11353Ssam fflush(stdout); 864*11353Ssam gets(line); 865*11353Ssam return (*line == 'y'); 866*11353Ssam } 867*11353Ssam 868*11353Ssam fatal(msg) 869*11353Ssam char *msg; 870*11353Ssam { 871*11353Ssam 872*11353Ssam fprintf(stderr, "ftp: %s\n"); 873*11353Ssam exit(1); 874*11353Ssam } 875*11353Ssam 876*11353Ssam /* 877*11353Ssam * Glob a local file name specification with 878*11353Ssam * the expectation of a single return value. 879*11353Ssam * Can't control multiple values being expanded 880*11353Ssam * from the expression, we return only the first. 881*11353Ssam */ 882*11353Ssam globulize(cpp) 883*11353Ssam char **cpp; 884*11353Ssam { 885*11353Ssam char **globbed; 886*11353Ssam 887*11353Ssam if (!doglob) 888*11353Ssam return (1); 889*11353Ssam globbed = glob(*cpp); 890*11353Ssam if (globerr != NULL) { 891*11353Ssam printf("%s: %s\n", *cpp, globerr); 892*11353Ssam if (globbed) 893*11353Ssam blkfree(globbed); 894*11353Ssam return (0); 895*11353Ssam } 896*11353Ssam if (globbed) { 897*11353Ssam *cpp = *globbed++; 898*11353Ssam /* don't waste too much memory */ 899*11353Ssam if (*globbed) 900*11353Ssam blkfree(globbed); 901*11353Ssam } 902*11353Ssam return (1); 903*11353Ssam } 904