|
|
/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
cmds.c
Abstract:
FTP commands
Author:
Richard L Firth (rfirth) 03-Nov-1995
Revision History:
03-Nov-1995 rfirth Created
--*/
#include "ftpcatp.h"
//
// manifests
//
#define MAX_ARGV 20
#define COMMAND_WHITESPACE TEXT(" ,\r\n")
//
// external functions
//
extern BOOL Prompt( IN LPCTSTR pszPrompt, OUT LPTSTR* ppszCommand );
//
// prototypes
//
BOOL dbgbreak(HINTERNET, int, PTCHAR *); BOOL chdir(HINTERNET, int, PTCHAR *); BOOL del(HINTERNET, int, PTCHAR *); BOOL dir(HINTERNET, int, PTCHAR *); BOOL get(HINTERNET, int, PTCHAR *); BOOL help(HINTERNET, int, PTCHAR *); BOOL lcd(HINTERNET, int, char**); BOOL mkdir(HINTERNET, int, PTCHAR *); BOOL put(HINTERNET, int, PTCHAR *); BOOL pwd(HINTERNET, int, PTCHAR *); BOOL quit(HINTERNET, int, PTCHAR *); BOOL rb(HINTERNET, int, char**); BOOL rename_file(HINTERNET, int, PTCHAR *); BOOL rmdir(HINTERNET, int, PTCHAR *); BOOL wb(HINTERNET, int, char**); BOOL toggle_verbose(HINTERNET, int, PTCHAR *); BOOL set_type(HINTERNET, int, PTCHAR *); BOOL open_file(HINTERNET, int, PTCHAR *); BOOL close_file(HINTERNET, int, PTCHAR *); BOOL read_file(HINTERNET, int, PTCHAR *); BOOL write_file(HINTERNET, int, PTCHAR *); BOOL DispatchCommand(LPTSTR, HINTERNET);
#if DBG
BOOL CheckHandles(HINTERNET, int, PTCHAR*);
#endif
//
// external data
//
extern DWORD Verbose; extern INTERNET_STATUS_CALLBACK PreviousCallback; extern HINTERNET hCancel; extern BOOL AsyncMode; extern HANDLE AsyncEvent; extern DWORD AsyncResult; extern DWORD AsyncError; extern BOOL UseQueryData;
//
// data
//
typedef struct { LPCSTR pszCommand; LPCSTR HelpText; BOOL (*fn)(HINTERNET, int, PTCHAR []); } COMMAND_ENTRY;
COMMAND_ENTRY Commands[] = {
#if DBG
{"b", "Break into debugger", dbgbreak}, #endif
{"!", "Shell escape", NULL}, {"?", "This list", help}, {"cd", "Change to a remote directory", chdir}, {"close", "Close an open file handle", close_file}, {"dir", "List a directory", dir}, {"del", "Delete a remote file", del}, {"get", "Copy a file from the server", get},
#if DBG
{"hndl", "Get current handle count", CheckHandles}, #endif
{"lcd", "Change local directory", lcd}, {"md", "Create a remote directory", mkdir}, {"open", "Open a file for read or write", open_file}, {"put", "Copy a file to the server", put}, {"pwd", "Display the current directory", pwd}, {"quit", "Terminate this program", quit}, {"rb", "Get/set Read buffer size", rb}, {"rd", "Remove a remote directory", rmdir}, {"read", "Read data from a file", read_file}, {"ren", "Rename a remote file", rename_file}, {"type", "Set transfer type", set_type}, {"verbose", "Toggle verbose mode", toggle_verbose}, {"wb", "Get/set Write buffer size", wb}, {"write", "Write data to a file", write_file}, {NULL, NULL, NULL} };
BOOL fQuit = FALSE; DWORD CacheFlags = 0; HINTERNET FileHandle = NULL;
//
// functions
//
void get_response(HINTERNET hFtp) {
DWORD buflen; char buffer[2048]; DWORD category;
buflen = sizeof(buffer); if (InternetGetLastResponseInfo(&category, buffer, &buflen)) { if (hFtp && (Verbose >= 2)) {
DWORD len = sizeof(DWORD); DWORD dwFlags;
if (InternetQueryOption(hFtp, INTERNET_OPTION_REQUEST_FLAGS, &dwFlags, &len)) { if (dwFlags & INTERNET_REQFLAG_FROM_CACHE) { fprintf(stderr, "****** Got from the cache ***** \n"); } else { fprintf(stderr, "****** From the wire ***** \n"); } } } if (buflen || (Verbose >= 2)) { print_response(buffer, buflen, TRUE); } } else {
DWORD error;
error = GetLastError(); if (Verbose || (error != ERROR_INSUFFICIENT_BUFFER)) {
LPSTR errString;
errString = (error == ERROR_INSUFFICIENT_BUFFER) ? "InternetGetLastResponseInfo() returns error %d (buflen = %d)\n" : "InternetGetLastResponseInfo() returns error %d\n" ; printf(errString, error, buflen); } if (error = ERROR_INSUFFICIENT_BUFFER) {
LPSTR errbuf;
if ((errbuf = malloc(buflen)) == NULL) { printf("error: get_response: malloc(%d) failed\n", buflen); return; } if (InternetGetLastResponseInfo(&category, errbuf, &buflen)) { if (buflen || (Verbose >= 2)) { print_response(errbuf, buflen, TRUE); } } else { printf("error: get_response: InternetGetLastResponseInfo() returns error %d (buflen = %d)\n", GetLastError(), buflen ); } free(errbuf); } } }
BOOL quit( IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[] ) { fQuit = TRUE;
return TRUE; }
BOOL get( IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[] ) { LPTSTR pszFilename; LPTSTR pszLocalfile; BOOL ok;
if (argc < 2) { if (!Prompt(TEXT("remote-name: "), &pszFilename)) { return FALSE; } } else { pszFilename = argv[1]; }
if (argc >= 3) { pszLocalfile = argv[2]; } else { pszLocalfile = pszFilename; }
ok = FtpGetFile(hFtpSession, pszFilename, pszLocalfile, FALSE, FILE_ATTRIBUTE_NORMAL, CacheFlags | FTP_TRANSFER_TYPE_BINARY, FTPCAT_GET_CONTEXT );
if (AsyncMode && !ok) { if (GetLastError() != ERROR_IO_PENDING) { print_error("get", "FtpGetFile()"); } else { if (Verbose) { printf("waiting for async FtpGetFile()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; } }
if (!ok) { if (AsyncMode) { SetLastError(AsyncError); } print_error("get", "%sFtpGetFile()", AsyncMode ? "async " : ""); } else { get_response(hFtpSession); }
return ok; }
BOOL put( IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[] ) { LPTSTR pszFilename; LPTSTR pszLocalfile; BOOL ok;
if (argc < 2) { if (!Prompt(TEXT("remote-name: "), &pszFilename)) { return FALSE; } } else { pszFilename = argv[1]; }
if (argc >= 3) { pszLocalfile = argv[2]; } else { pszLocalfile = pszFilename; }
ok = FtpPutFile(hFtpSession, pszLocalfile, pszFilename, FTP_TRANSFER_TYPE_BINARY, FTPCAT_PUT_CONTEXT ); if (AsyncMode && !ok) { if (GetLastError() != ERROR_IO_PENDING) { print_error("put", "FtpPutFile()"); } else { if (Verbose) { printf("waiting for async FtpPutFile()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; } }
if (!ok) { if (AsyncMode) { SetLastError(AsyncError); } print_error("put", "%sFtpPutFile()", AsyncMode ? "async " : ""); } else { get_response(hFtpSession); }
return ok; }
BOOL rename_file( IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[] ) { LPTSTR pszTemp; LPTSTR pszOldFilename; LPTSTR pszNewFilename; BOOL ok;
if (argc < 2) { if (!Prompt(TEXT("Old name: "), &pszTemp)) { return FALSE; }
pszOldFilename = lstrdup(pszTemp);
if (pszOldFilename == NULL) { return FALSE; } } else { pszOldFilename = argv[1]; }
if (argc < 3) { if (!Prompt(TEXT("New name: "), &pszNewFilename)) { return FALSE; } } else { pszNewFilename = argv[2]; }
ok = FtpRenameFile(hFtpSession, pszOldFilename, pszNewFilename );
if (AsyncMode && !ok) { if (GetLastError() != ERROR_IO_PENDING) { print_error("rename_file", "FtpRenameFile()"); } else { if (Verbose) { printf("waiting for async FtpRenameFile()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; } }
if (!ok) { if (AsyncMode) { SetLastError(AsyncError); } print_error("rename_file", "%sFtpRenameFile()", AsyncMode ? "async " : ""); } else { get_response(hFtpSession); }
if (argc < 2) { LocalFree(pszOldFilename); }
return ok; }
BOOL del( IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[] ) { LPTSTR pszFilename; BOOL ok;
if (argc < 2) { if (!Prompt(TEXT("File name: "), &pszFilename)) { return FALSE; } } else { pszFilename = argv[1]; }
ok = FtpDeleteFile(hFtpSession, pszFilename);
if (AsyncMode && !ok) { if (GetLastError() != ERROR_IO_PENDING) { print_error("del", "FtpDeleteFile()"); } else { if (Verbose) { printf("waiting for async FtpDeleteFile()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; } }
if (!ok) { if (AsyncMode) { SetLastError(AsyncError); } print_error("del", "%sFtpDeleteFile()", AsyncMode ? "async " : "" ); } else { get_response(hFtpSession); }
return ok; }
BOOL mkdir( IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[] ) { LPTSTR pszDirname; BOOL ok;
if (argc < 2) { if (!Prompt(TEXT("Directory name: "), &pszDirname)) { return FALSE; } } else { pszDirname = argv[1]; }
ok = FtpCreateDirectory(hFtpSession, pszDirname );
if (AsyncMode && !ok) { if (GetLastError() != ERROR_IO_PENDING) { print_error("mkdir", "FtpCreateDirectory()"); } else { if (Verbose) { printf("waiting for async FtpCreateDirectory()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; } }
if (!ok) { if (AsyncMode) { SetLastError(AsyncError); } print_error("mkdir", "%sFtpCreateDirectory()", AsyncMode ? "async " : ""); } else { get_response(hFtpSession); }
return ok; }
BOOL chdir( IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[] ) { LPTSTR pszDirname; BOOL ok;
if (argc < 2) { if (!Prompt(TEXT("Directory name: "), &pszDirname)) { return FALSE; } } else { pszDirname = argv[1]; }
ok = FtpSetCurrentDirectory(hFtpSession, pszDirname );
if (AsyncMode && !ok) { if (GetLastError() != ERROR_IO_PENDING) { print_error("chdir", "FtpSetCurrentDirectory()"); } else { if (Verbose) { printf("waiting for async FtpSetCurrentDirectory()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; } }
if (!ok) { if (AsyncMode) { SetLastError(AsyncError); } print_error("chdir", "%sFtpSetCurrentDirectory()", AsyncMode ? "async " : ""); } else { get_response(hFtpSession); }
return ok; }
BOOL rmdir( IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[] ) { LPTSTR pszDirname; BOOL ok;
if (argc < 2) { if (!Prompt(TEXT("Directory name: "), &pszDirname)) { return FALSE; } } else { pszDirname = argv[1]; }
ok = FtpRemoveDirectory(hFtpSession, pszDirname );
if (AsyncMode && !ok) { if (GetLastError() != ERROR_IO_PENDING) { print_error("rmdir", "FtpRemoveDirectory()"); } else { if (Verbose) { printf("waiting for async FtpRemoveDirectory()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; } }
if (!ok) { if (AsyncMode) { SetLastError(AsyncError); } print_error("rmdir", "%sFtpRemoveDirectory()", AsyncMode ? "async " : ""); } else { get_response(hFtpSession); }
return ok; }
BOOL dir( IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[] ) { BOOL ok; WIN32_FIND_DATA ffd; SYSTEMTIME st; LPTSTR pszFileSpec; TCHAR EmptyExpression[] = ""; HINTERNET hFind; HINTERNET hPrevious; static LPSTR month[] = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
if (argc < 2) { pszFileSpec = EmptyExpression; } else { pszFileSpec = argv[1]; }
hFind = FtpFindFirstFileA(hFtpSession, pszFileSpec, &ffd, CacheFlags, // dwFlags
FTPCAT_FIND_CONTEXT );
if (AsyncMode && (hFind == NULL)) { if (GetLastError() == ERROR_IO_PENDING) { if (Verbose) { printf("waiting for async FtpFindFirstFile()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); hFind = (HINTERNET)AsyncResult; if (hFind == NULL) { SetLastError(AsyncError); } } }
if (hFind == NULL) { print_error("dir", "%sFtpFindFirstFile()", AsyncMode ? "async " : ""); return FALSE; }
hPrevious = hCancel; hCancel = hFind;
get_response(hFind); putchar('\n');
ok = TRUE; while (ok) { if (!FileTimeToSystemTime(&ffd.ftLastWriteTime, &st)) { printf("| ftLastWriteTime = ERROR\n"); }
printf("%02d-%s-%04d %02d:%02d:%02d %15d bytes %-s%-s%-s%-s%-s%-s %s\n", st.wDay, month[st.wMonth], st.wYear, st.wHour, st.wMinute, st.wSecond, ffd.nFileSizeLow, (ffd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? "Archive " : "", (ffd.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ? "Normal " : "", (ffd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? "System " : "", (ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? "Hidden " : "", (ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? "ReadOnly " : "", (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? "Directory " : "", ffd.cFileName );
if (UseQueryData) {
DWORD error; DWORD avail;
ok = InternetQueryDataAvailable(hFind, &avail, 0, 0); if (!ok) { error = GetLastError(); if (error == ERROR_IO_PENDING) { if (Verbose) { printf("waiting for async InternetQueryDataAvailable()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; SetLastError(AsyncError); } } if (!ok) { print_error("dir", "%sSYNC InternetQueryDataAvailable()", AsyncMode ? "A" : ""); break; }
if (Verbose) { printf("InternetQueryDataAvailable() returns %d available\n", avail); }
if (avail == 0) { break; } }
ok = InternetFindNextFile(hFind, &ffd);
if (!ok && AsyncMode) { if (GetLastError() == ERROR_IO_PENDING) { if (Verbose) { printf("waiting for async InternetFindNextFile()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; if (!ok) { SetLastError(AsyncError); } } }
if (!ok) { if (GetLastError() != ERROR_NO_MORE_FILES) { print_error("dir", "%sInternetFindNextFile()", AsyncMode ? "async " : ""); break; } } }
putchar('\n');
close_handle(hFind);
hCancel = hPrevious;
return ok; }
BOOL pwd( IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[] ) { BOOL ok; char* buf; DWORD len;
len = 0; ok = FtpGetCurrentDirectory(hFtpSession, NULL, &len);
if (AsyncMode && !ok) { if (GetLastError() != ERROR_IO_PENDING) { print_error("pwd", "async FtpGetCurrentDirectory()"); } else { if (Verbose) { printf("waiting for async FtpGetCurrentDirectory()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; SetLastError(AsyncError); } }
if (ok) { printf("error: FtpGetCurrentDirectory() w/ no buffer returns ok\n"); return FALSE; } else if (Verbose) { printf("FtpGetCurrentDirectory() returns %d, %d bytes in cur dir\n", GetLastError(), len ); }
buf = (char*)malloc(len);
ok = FtpGetCurrentDirectory(hFtpSession, buf, &len);
if (AsyncMode && !ok) { if (GetLastError() != ERROR_IO_PENDING) { print_error("pwd", "async FtpGetCurrentDirectory()"); } else { if (Verbose) { printf("waiting for async FtpGetCurrentDirectory()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); ok = (BOOL)AsyncResult; SetLastError(AsyncError); } }
if (!ok) { print_error("pwd", "%sFtpGetCurrentDirectory()", AsyncMode ? "async " : ""); } else { get_response(hFtpSession); lprintf(TEXT("Current directory: %s\n"), buf); }
free(buf);
return ok; }
BOOL help(IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[]) {
int i;
for (i = 0; Commands[i].pszCommand != NULL; ++i) { lprintf(TEXT("\t%s\t%s\n"), Commands[i].pszCommand, Commands[i].HelpText ); }
return TRUE; }
#if DBG
BOOL CheckHandles(HINTERNET hFtpSession, int argc, PTCHAR argv[]) { printf("handle count = %d\n", GetProcessHandleCount()); return TRUE; }
#endif
BOOL lcd(HINTERNET hInternet, int argc, char** argv) {
char curDir[MAX_PATH + 1]; DWORD curDirLen;
if (argc == 2) { if (!SetCurrentDirectory(argv[1])) { print_error("lcd", "SetCurrentDirectory()"); return FALSE; } } else if (argc != 1) { printf("error: lcd: incorrect number of arguments\n"); return FALSE; }
curDirLen = sizeof(curDir); if (GetCurrentDirectory(curDirLen, curDir)) { printf("Current directory is %s\n", curDir); return TRUE; } else { print_error("lcd", "GetCurrentDirectory()"); return FALSE; } }
BOOL rb(HINTERNET hInternet, int argc, char** argv) {
DWORD value; DWORD valueLength;
if (argc > 1) { value = atoi(argv[1]); if (!InternetSetOption(hInternet, INTERNET_OPTION_READ_BUFFER_SIZE, (LPVOID)&value, sizeof(DWORD) )) { print_error("rb", "InternetSetOption()"); return FALSE; } } valueLength = sizeof(value); if (InternetQueryOption(hInternet, INTERNET_OPTION_READ_BUFFER_SIZE, (LPVOID)&value, &valueLength )) { printf("Read buffer size = %d bytes\n", value); return TRUE; } else { print_error("rb", "InternetQueryOption()"); return FALSE; } }
BOOL wb(HINTERNET hInternet, int argc, char** argv) {
DWORD value; DWORD valueLength;
if (argc > 1) { value = atoi(argv[1]); if (!InternetSetOption(hInternet, INTERNET_OPTION_WRITE_BUFFER_SIZE, (LPVOID)&value, sizeof(DWORD) )) { print_error("wb", "InternetSetOption()"); return FALSE; } } valueLength = sizeof(value); if (InternetQueryOption(hInternet, INTERNET_OPTION_WRITE_BUFFER_SIZE, (LPVOID)&value, &valueLength )) { printf("Write buffer size = %d bytes\n", value); return TRUE; } else { print_error("wb", "InternetQueryOption()"); return FALSE; } }
BOOL toggle_verbose(HINTERNET hInternet, int argc, PTCHAR * argv) {
static DWORD PreviousVerbose = 0;
if (Verbose) { PreviousVerbose = Verbose; Verbose = 0; } else { Verbose = PreviousVerbose; if (Verbose == 0) { Verbose = 1; } } printf("Verbose mode is o%s\n", Verbose ? "n" : "ff"); return TRUE; }
BOOL toggle_callback(HINTERNET hInternet, int argc, PTCHAR * argv) {
INTERNET_STATUS_CALLBACK callback;
if (PreviousCallback != NULL && PreviousCallback != my_callback) { printf("error: PreviousCallback %x not recognized\n", PreviousCallback); } else { PreviousCallback = InternetSetStatusCallback(hInternet, PreviousCallback); if (PreviousCallback == INTERNET_INVALID_STATUS_CALLBACK) { print_error("toggle_callback", "InternetSetStatusCallback()"); } else if (PreviousCallback != NULL && PreviousCallback != my_callback) { printf("error: PreviousCallback %x not recognized\n", PreviousCallback); } else if (Verbose) { printf("callback toggled Ok\n"); } }
printf("Verbose mode is o%s\n", Verbose ? "n" : "ff"); return TRUE; }
BOOL dbgbreak(HINTERNET hInternet, int argc, PTCHAR * argv) { DebugBreak(); return TRUE; }
BOOL set_type(HINTERNET hInternet, int argc, PTCHAR * argv) { return TRUE; }
BOOL open_file(HINTERNET hInternet, int argc, PTCHAR * argv) {
HINTERNET hFile; BOOL bOk;
if (argc < 2) { printf("error: required filename missing\n"); return FALSE; } hFile = FtpOpenFile(hInternet, argv[1], GENERIC_READ, 0, AsyncMode ? FTPCAT_OPEN_CONTEXT : 0 ); if (AsyncMode && !hFile) { if (GetLastError() != ERROR_IO_PENDING) { print_error("open_file", "async FtpOpenFile()"); return FALSE; } if (Verbose) { printf("waiting for async FtpOpenFile()...\n"); } WaitForSingleObject(AsyncEvent, INFINITE); hFile = (HINTERNET)AsyncResult; SetLastError(AsyncError); } if (!hFile) { print_error("open_file", "%sFtpOpenFile()", AsyncMode ? "async " : ""); } else { get_response(hInternet); printf("returned handle is %#x\n", hFile); } return hFile != NULL; }
BOOL close_file(HINTERNET hInternet, int argc, PTCHAR * argv) {
HINTERNET hFile; BOOL bOk;
if (argc < 2) { printf("error: required handle missing\n"); return FALSE; } hFile = (HINTERNET)strtol(argv[1], NULL, 0); bOk = InternetCloseHandle(hFile); if (!bOk) { print_error("close_file", "InternetCloseHandle()"); } else if (Verbose) { printf("handle %#x closed OK\n", hFile); } return bOk; }
BOOL read_file(HINTERNET hInternet, int argc, PTCHAR * argv) { return TRUE; }
BOOL write_file(HINTERNET hInternet, int argc, PTCHAR * argv) { return TRUE; }
BOOL DispatchCommand( IN LPTSTR pszCommand, IN HINTERNET hFtpSession ) { COMMAND_ENTRY *pce; PTCHAR ArgV[MAX_ARGV]; int index; int state;
if (*pszCommand == TEXT('!')) {
LPSTR shellPath;
shellPath = getenv("COMSPEC"); if (shellPath == NULL) { printf("error: COMSPEC environment variable not set\n"); return FALSE; }
++pszCommand; while (isspace(*pszCommand)) { ++pszCommand; }
if (*pszCommand != TEXT('\0')) { _spawnlp(_P_WAIT, shellPath, "/C", pszCommand, NULL); } else { printf("\nSpawning command interpreter. Type \"exit\" to return to FTP\n\n"); _spawnlp(_P_WAIT, shellPath, "/K", NULL); putchar('\n'); } return TRUE; }
state = 0; index = 0;
while (*pszCommand) { switch (state) { case 0: if (!isspace(*pszCommand)) { if (*pszCommand == '"') { state = 2; } else { state = 1; } ArgV[index++] = (state == 2) ? (pszCommand + 1) : pszCommand; } break;
case 1: if (isspace(*pszCommand)) { *pszCommand = '\0'; state = 0; } break;
case 2: if (*pszCommand == '"') { *pszCommand = '\0'; state = 0; } break; } ++pszCommand; }
if (index == 0) { return FALSE; }
for (pce = Commands; pce->pszCommand != NULL; pce++) { if (lstrcmpi(pce->pszCommand, ArgV[0]) == 0) { return pce->fn(hFtpSession, index, ArgV); } }
if (!lstrcmpi(ArgV[0], "q")) { return quit(hFtpSession, index, ArgV); }
printf("error: unrecognized command: \"%s\"\n", ArgV[0]);
return FALSE; }
|