You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1109 lines
28 KiB
1109 lines
28 KiB
/*++
|
|
|
|
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;
|
|
}
|