📄 minincftp.c
字号:
/* minincftp.c * * Example of a command-line shell interface to FTP using the library. */#define VERSION "3.1.0"#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <ncftp.h> /* Library header. */#include <Strn.h> /* Library header. */#define kKilobyte 1024#define kMegabyte (kKilobyte * 1024)#define kGigabyte ((long) kMegabyte * 1024L)#define kTerabyte ((double) kGigabyte * 1024.0)#if defined(WIN32) || defined(_WINDOWS)# define sleep WinSleep#endifFTPLibraryInfo li;FTPConnectionInfo fi;static voidUsage(void){ fprintf(stderr, "MiniNcFTP, copyright 1995 by Mike Gleason, NcFTP Software.\n"); fprintf(stderr, "Usage: minincftp [-P port] [-u user] [-p password] hostname\n"); fprintf(stderr, "Library version: %s.\n", gLibNcFTPVersion + 5);#ifdef UNAME fprintf(stderr, "System: %s.\n", UNAME);#endif DisposeWinsock(); exit(2);} /* Usage */static voidAbort(int sigNum){ signal(sigNum, Abort); /* Hopefully the I/O operation in progress * will complete, and we'll abort before * it starts a new block. */ fi.cancelXfer++; /* If the user appears to be getting impatient, * restore the default signal handler so the * next ^C abends the program. */ if (fi.cancelXfer >= 2) signal(sigNum, SIG_DFL);} /* Abort *//* This will abbreviate a string so that it fits into max characters. * It will use ellipses as appropriate. Make sure the string has * at least max + 1 characters allocated for it. */static voidAbbrevStr(char *dst, const char *src, size_t max, int mode){ int len; len = (int) strlen(src); if (len > (int) max) { if (mode == 0) { /* ...Put ellipses at left */ (void) strcpy(dst, "..."); (void) Strncat(dst, src + len - (int) max + 3, max + 1); } else { /* Put ellipses at right... */ (void) Strncpy(dst, src, max + 1); (void) strcpy(dst + max - 3, "..."); } } else { (void) Strncpy(dst, src, max + 1); }} /* AbbrevStr */static doubleFileSize(double size, const char **uStr0, double *uMult0){ double uMult, uTotal; const char *uStr; /* The comparisons below may look odd, but the reason * for them is that we only want a maximum of 3 digits * before the decimal point. (I.e., we don't want to * see "1017.2 kB", instead we want "0.99 MB". */ if (size > (999.5 * kGigabyte)) { uStr = "TB"; uMult = kTerabyte; } else if (size > (999.5 * kMegabyte)) { uStr = "GB"; uMult = kGigabyte; } else if (size > (999.5 * kKilobyte)) { uStr = "MB"; uMult = kMegabyte; } else if (size > 999.5) { uStr = "kB"; uMult = 1024; } else { uStr = "B"; uMult = 1; } if (uStr0 != NULL) *uStr0 = uStr; if (uMult0 != NULL) *uMult0 = uMult; uTotal = size / ((double) uMult); if (uTotal < 0.0) uTotal = 0.0; return (uTotal);} /* FileSize */static voidPrSizeAndRateMeter(const FTPCIPtr cip, int mode){ double rate; const char *rStr; char localName[32]; char line[128]; size_t i; switch (mode) { case kPrInitMsg: if (cip->lname == NULL) { localName[0] = '\0'; } else { AbbrevStr(localName, cip->lname, sizeof(localName) - 2, 0); (void) STRNCAT(localName, ":"); } (void) fprintf(stderr, "%-32s", localName); break; case kPrUpdateMsg: rate = FileSize(cip->kBytesPerSec * 1024.0, &rStr, NULL); if (cip->lname == NULL) { localName[0] = '\0'; } else { AbbrevStr(localName, cip->lname, sizeof(localName) - 2, 0); (void) STRNCAT(localName, ":"); }#ifdef PRINTF_LONG_LONG_LLD (void) sprintf(line, "%-32s %10lld bytes %6.2f %s/s", localName, (longest_int) (cip->bytesTransferred + cip->startPoint), rate, rStr );#elif defined(PRINTF_LONG_LONG_QD) (void) sprintf(line, "%-32s %10qd bytes %6.2f %s/s", localName, (longest_int) (cip->bytesTransferred + cip->startPoint), rate, rStr );#else (void) sprintf(line, "%-32s %10ld bytes %6.2f %s/s", localName, (long) (cip->bytesTransferred + cip->startPoint), rate, rStr );#endif /* Pad the rest of the line with spaces, to erase any * stuff that might have been left over from the last * update. */ for (i=strlen(line); i < 80 - 2; i++) line[i] = ' '; line[i] = '\0'; /* Print the updated information. */ (void) fprintf(stderr, "\r%s", line); break; case kPrEndMsg: (void) fprintf(stderr, "\n\r"); break; }} /* PrSizeAndRateMeter */static intLs(const FTPCIPtr cip, char *cmdstr, char *lsflag){ int cmd; int result; cmd = (cmdstr[0] == 'd') ? 1 : 0; fflush(stdout); result = FTPList(cip, STDOUT_FILENO, cmd, lsflag); return result;} /* Ls */static voidShell(const FTPCIPtr cip){ char line[256]; char argv[10][80], *cp, *token; char s1[256]; int i, c1, code; int argc; time_t mdtm; longest_int size; if (fi.dataPortMode != kPassiveMode) { printf("Using PORT (non-passive) mode for data connections.\n"); } else { printf("Using PASV (passive) mode for data connections.\n"); } printf("Type \"passive\" to toggle between PORT and PASV.\n"); printf("\n"); for (;;) {nextcmd: code = kNoErr; printf("MiniNcFTP> "); memset(line, 0, sizeof(line)); memset(argv, 0, sizeof(argv)); if (fgets(line, sizeof(line), stdin) == NULL) break; cp = line; for (argc=0; argc<10; argc++) { argv[argc][0] = '\0'; token = strtok(cp, " \n\t\r"); if (token == NULL) break; STRNCPY(argv[argc], token); if (argv[argc][sizeof(argv[0]) - 1] != '\0') { fprintf(stderr, "parameter too long\n"); goto nextcmd; } cp = NULL; } printf("\n"); c1 = argv[0][0]; cip->errNo = 0;#define USAGECHECK(a,n) if ((argc - 1) < n) { fprintf(stderr, "Error: \"%s\" requires %d parameter%s.\n", #a, n, "s"); goto nextcmd; }#define USAGECHECK1(a) if ((argc - 1) < 1) { fprintf(stderr, "Error: \"%s\" requires %d parameter%s.\n", #a, 1, ""); goto nextcmd; } switch (c1) { case 'c': if (strcasecmp(argv[0], "cd") == 0) { /* chdir, cd */ USAGECHECK1(cd) code = FTPChdir(cip, argv[1]); } else if (strcasecmp(argv[0], "chmod") == 0) { USAGECHECK(chmod, 2) code = FTPChmod(cip, argv[2], argv[1], kGlobYes); } else goto bad; break; case 'd': if (strcasecmp(argv[0], "dir") == 0) { code = Ls(cip, argv[0], argv[1]); /* dir */ } else if (strcasecmp(argv[0], "delete") == 0) { USAGECHECK1(delete) code = FTPDelete(cip, argv[1], kRecursiveNo, kGlobYes); } else goto bad; break; case 'g': if (strcasecmp(argv[0], "get1") == 0) { USAGECHECK(get1, 2) (void) signal(SIGINT, Abort); code = FTPGetOneFile3(cip, argv[1], argv[2], kTypeBinary, (-1), kResumeYes, kAppendNo, kDeleteNo, kNoFTPConfirmResumeDownloadProc, 0); (void) signal(SIGINT, SIG_DFL); if (cip->bytesTransferred > 0L) printf("%lu bytes transferred, %.2f kB/sec.\n", (unsigned long) cip->bytesTransferred, cip->kBytesPerSec); } else if (strcasecmp(argv[0], "get") == 0) { USAGECHECK1(get) (void) signal(SIGINT, Abort); code = FTPGetFiles3(cip, argv[1], argv[2], kRecursiveNo, kGlobYes, kTypeBinary, kResumeYes, kAppendNo, kDeleteNo, kTarNo, kNoFTPConfirmResumeDownloadProc, 0); (void) signal(SIGINT, SIG_DFL); if (cip->bytesTransferred > 0L) printf("%lu bytes transferred, %.2f kB/sec.\n", (unsigned long) cip->bytesTransferred, cip->kBytesPerSec); } else goto bad; break; case 'l': if (strcasecmp(argv[0], "ls") == 0) { (void) signal(SIGINT, Abort); code = Ls(cip, argv[0], argv[1]); (void) signal(SIGINT, SIG_DFL); if (cip->bytesTransferred > 0L) printf("%lu bytes transferred, %.2f kB/sec.\n", (unsigned long) cip->bytesTransferred, cip->kBytesPerSec); } else if (strcasecmp(argv[0], "lcd") == 0) { USAGECHECK1(lcd) if (chdir(argv[1]) < 0) { perror(argv[1]); } else { if (FTPGetLocalCWD(line, sizeof(line)) != NULL) { printf("Current local directory is: %s\n", line); } } } else goto bad; break; case 'm': if (strcasecmp(argv[0], "mkdir") == 0) { USAGECHECK1(mkdir) code = FTPMkdir(cip, argv[1], kRecursiveYes); } else if (strcasecmp(argv[0], "modtime") == 0) { USAGECHECK1(modtime) code = FTPFileModificationTime(cip, argv[1], &mdtm); printf("%s modtime = %lu.\n", argv[1], (unsigned long) mdtm); } else goto bad; break; case 'p': if (strcasecmp(argv[0], "passive") == 0) { if (fi.dataPortMode == kPassiveMode) { fi.dataPortMode = kSendPortMode; printf("Using PORT (non-passive) mode for data connections.\n"); } else { fi.dataPortMode = kPassiveMode; printf("Using PASV (passive) mode for data connections.\n"); } } else if (strcasecmp(argv[0], "pwd") == 0) { code = FTPGetCWD(cip, s1, sizeof(s1)); /* pwd */ printf("cwd = [%s]\n", s1); } else if (strcasecmp(argv[0], "put1") == 0) { USAGECHECK(put1, 2) (void) signal(SIGINT, Abort); code = FTPPutOneFile(cip, argv[1], argv[2]); (void) signal(SIGINT, SIG_DFL); if (cip->bytesTransferred > 0L) printf("%lu bytes transferred, %.2f kB/sec.\n", (unsigned long) cip->bytesTransferred, cip->kBytesPerSec); } else if (strcasecmp(argv[0], "put") == 0) { USAGECHECK1(put) (void) signal(SIGINT, Abort); code = FTPPutFiles(cip, argv[1], argv[2], kRecursiveNo, kGlobYes); (void) signal(SIGINT, SIG_DFL); if (cip->bytesTransferred > 0L) printf("%lu bytes transferred, %.2f kB/sec.\n", (unsigned long) cip->bytesTransferred, cip->kBytesPerSec); } else goto bad; break; case 'q': case 'Q': if (strcasecmp(argv[0], "quote") == 0) { USAGECHECK1(quote) STRNCPY(s1, argv[1]); for (i=2; i<10; i++) { if (argv[i][0] == '\0') break; STRNCAT(s1, " "); STRNCAT(s1, argv[i]); } FTPCmd(cip, "%s", s1); } else if (strcasecmp(argv[0], "quit") == 0) { return; } else goto bad; break; case 'r': if (strcasecmp(argv[0], "rename") == 0) { USAGECHECK(rename, 2) code = FTPRename(cip, argv[1], argv[2]); } else if (strcasecmp(argv[0], "rmdir") == 0) { USAGECHECK1(rmdir) code = FTPRmdir(cip, argv[1], kRecursiveNo, kGlobYes); } else goto bad; break; case 's': if (strcasecmp(argv[0], "size") == 0) { USAGECHECK1(size)#ifdef PRINTF_LONG_LONG code = FTPFileSize(cip, argv[1], &size, 'I'); printf("%s size = " PRINTF_LONG_LONG ".\n", argv[1], size);#else code = FTPFileSize(cip, argv[1], &size, 'I'); printf("%s size = %lu.\n", argv[1], (unsigned long) size);#endif } else goto bad; break; case 'u': if (strcasecmp(argv[0], "umask") == 0) { USAGECHECK1(umask) code = FTPUmask(cip, argv[1]); } else goto bad; break; case 'X': case 'x': return; case '\0': break; default: bad: printf("Commands are: cd dir ls passive quit rmdir\n"); printf(" chmod get mkdir put quote size\n"); printf(" delete lcd modtime pwd rename umask\n"); } if (code != kNoErr) { fprintf(stderr, "Return code for %s was %d (%s).\n", argv[0], code, FTPStrError(code)); } }} /* Shell */main_void_return_tmain(int argc, char **argv){ int result, c; GetoptInfo opt; InitWinsock(); result = FTPInitLibrary(&li); if (result < 0) { fprintf(stderr, "Init library error %d.\n", result); DisposeWinsock(); exit(1); } result = FTPInitConnectionInfo(&li, &fi, kDefaultFTPBufSize); if (result < 0) { fprintf(stderr, "Init connection info error %d.\n", result); DisposeWinsock(); exit(1); } fi.debugLog = stdout; fi.errLog = stderr; fi.progress = PrSizeAndRateMeter; fi.dataPortMode = kSendPortMode; STRNCPY(fi.user, "anonymous"); GetoptReset(&opt); while ((c = Getopt(&opt, argc, argv, "d:e:P:p:u:F")) > 0) switch(c) { case 'P': fi.port = atoi(opt.arg); break; case 'u': STRNCPY(fi.user, opt.arg); break; case 'p': STRNCPY(fi.pass, opt.arg); /* Don't recommend doing this! */ break; case 'e': fi.errLog = fopen(opt.arg, "a"); break; case 'd': fi.debugLog = fopen(opt.arg, "a"); break; case 'F': if (fi.dataPortMode == kPassiveMode) fi.dataPortMode = kSendPortMode; else fi.dataPortMode = kPassiveMode; break; default: Usage(); } if (opt.ind > argc - 1) Usage(); if ((strcmp(fi.user, "anonymous") != 0) && (strcmp(fi.user, "ftp") != 0) && (fi.pass[0] == '\0')) (void) GetPass("Password: ", fi.pass, sizeof(fi.pass)); STRNCPY(fi.host, argv[opt.ind]); if ((result = FTPOpenHost(&fi)) < 0) { fprintf(stderr, "Cannot open host: %s.\n", FTPStrError(result)); DisposeWinsock(); exit(1); } Shell(&fi); FTPCloseHost(&fi); DisposeWinsock(); exit(0);} /* main */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -