Leaked source code of windows server 2003
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

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. cmds.c
  5. Abstract:
  6. FTP commands
  7. Author:
  8. Richard L Firth (rfirth) 03-Nov-1995
  9. Revision History:
  10. 03-Nov-1995 rfirth
  11. Created
  12. --*/
  13. #include "ftpcatp.h"
  14. //
  15. // manifests
  16. //
  17. #define MAX_ARGV 20
  18. #define COMMAND_WHITESPACE TEXT(" ,\r\n")
  19. //
  20. // external functions
  21. //
  22. extern
  23. BOOL
  24. Prompt(
  25. IN LPCTSTR pszPrompt,
  26. OUT LPTSTR* ppszCommand
  27. );
  28. //
  29. // prototypes
  30. //
  31. BOOL dbgbreak(HINTERNET, int, PTCHAR *);
  32. BOOL chdir(HINTERNET, int, PTCHAR *);
  33. BOOL del(HINTERNET, int, PTCHAR *);
  34. BOOL dir(HINTERNET, int, PTCHAR *);
  35. BOOL get(HINTERNET, int, PTCHAR *);
  36. BOOL help(HINTERNET, int, PTCHAR *);
  37. BOOL lcd(HINTERNET, int, char**);
  38. BOOL mkdir(HINTERNET, int, PTCHAR *);
  39. BOOL put(HINTERNET, int, PTCHAR *);
  40. BOOL pwd(HINTERNET, int, PTCHAR *);
  41. BOOL quit(HINTERNET, int, PTCHAR *);
  42. BOOL rb(HINTERNET, int, char**);
  43. BOOL rename_file(HINTERNET, int, PTCHAR *);
  44. BOOL rmdir(HINTERNET, int, PTCHAR *);
  45. BOOL wb(HINTERNET, int, char**);
  46. BOOL toggle_verbose(HINTERNET, int, PTCHAR *);
  47. BOOL set_type(HINTERNET, int, PTCHAR *);
  48. BOOL open_file(HINTERNET, int, PTCHAR *);
  49. BOOL close_file(HINTERNET, int, PTCHAR *);
  50. BOOL read_file(HINTERNET, int, PTCHAR *);
  51. BOOL write_file(HINTERNET, int, PTCHAR *);
  52. BOOL DispatchCommand(LPTSTR, HINTERNET);
  53. #if DBG
  54. BOOL CheckHandles(HINTERNET, int, PTCHAR*);
  55. #endif
  56. //
  57. // external data
  58. //
  59. extern DWORD Verbose;
  60. extern INTERNET_STATUS_CALLBACK PreviousCallback;
  61. extern HINTERNET hCancel;
  62. extern BOOL AsyncMode;
  63. extern HANDLE AsyncEvent;
  64. extern DWORD AsyncResult;
  65. extern DWORD AsyncError;
  66. extern BOOL UseQueryData;
  67. //
  68. // data
  69. //
  70. typedef struct {
  71. LPCSTR pszCommand;
  72. LPCSTR HelpText;
  73. BOOL (*fn)(HINTERNET, int, PTCHAR []);
  74. } COMMAND_ENTRY;
  75. COMMAND_ENTRY Commands[] = {
  76. #if DBG
  77. {"b", "Break into debugger", dbgbreak},
  78. #endif
  79. {"!", "Shell escape", NULL},
  80. {"?", "This list", help},
  81. {"cd", "Change to a remote directory", chdir},
  82. {"close", "Close an open file handle", close_file},
  83. {"dir", "List a directory", dir},
  84. {"del", "Delete a remote file", del},
  85. {"get", "Copy a file from the server", get},
  86. #if DBG
  87. {"hndl", "Get current handle count", CheckHandles},
  88. #endif
  89. {"lcd", "Change local directory", lcd},
  90. {"md", "Create a remote directory", mkdir},
  91. {"open", "Open a file for read or write", open_file},
  92. {"put", "Copy a file to the server", put},
  93. {"pwd", "Display the current directory", pwd},
  94. {"quit", "Terminate this program", quit},
  95. {"rb", "Get/set Read buffer size", rb},
  96. {"rd", "Remove a remote directory", rmdir},
  97. {"read", "Read data from a file", read_file},
  98. {"ren", "Rename a remote file", rename_file},
  99. {"type", "Set transfer type", set_type},
  100. {"verbose", "Toggle verbose mode", toggle_verbose},
  101. {"wb", "Get/set Write buffer size", wb},
  102. {"write", "Write data to a file", write_file},
  103. {NULL, NULL, NULL}
  104. };
  105. BOOL fQuit = FALSE;
  106. DWORD CacheFlags = 0;
  107. HINTERNET FileHandle = NULL;
  108. //
  109. // functions
  110. //
  111. void get_response(HINTERNET hFtp) {
  112. DWORD buflen;
  113. char buffer[2048];
  114. DWORD category;
  115. buflen = sizeof(buffer);
  116. if (InternetGetLastResponseInfo(&category, buffer, &buflen)) {
  117. if (hFtp && (Verbose >= 2)) {
  118. DWORD len = sizeof(DWORD);
  119. DWORD dwFlags;
  120. if (InternetQueryOption(hFtp,
  121. INTERNET_OPTION_REQUEST_FLAGS,
  122. &dwFlags,
  123. &len)) {
  124. if (dwFlags & INTERNET_REQFLAG_FROM_CACHE) {
  125. fprintf(stderr, "****** Got from the cache ***** \n");
  126. } else {
  127. fprintf(stderr, "****** From the wire ***** \n");
  128. }
  129. }
  130. }
  131. if (buflen || (Verbose >= 2)) {
  132. print_response(buffer, buflen, TRUE);
  133. }
  134. } else {
  135. DWORD error;
  136. error = GetLastError();
  137. if (Verbose || (error != ERROR_INSUFFICIENT_BUFFER)) {
  138. LPSTR errString;
  139. errString = (error == ERROR_INSUFFICIENT_BUFFER)
  140. ? "InternetGetLastResponseInfo() returns error %d (buflen = %d)\n"
  141. : "InternetGetLastResponseInfo() returns error %d\n"
  142. ;
  143. printf(errString, error, buflen);
  144. }
  145. if (error = ERROR_INSUFFICIENT_BUFFER) {
  146. LPSTR errbuf;
  147. if ((errbuf = malloc(buflen)) == NULL) {
  148. printf("error: get_response: malloc(%d) failed\n", buflen);
  149. return;
  150. }
  151. if (InternetGetLastResponseInfo(&category, errbuf, &buflen)) {
  152. if (buflen || (Verbose >= 2)) {
  153. print_response(errbuf, buflen, TRUE);
  154. }
  155. } else {
  156. printf("error: get_response: InternetGetLastResponseInfo() returns error %d (buflen = %d)\n",
  157. GetLastError(),
  158. buflen
  159. );
  160. }
  161. free(errbuf);
  162. }
  163. }
  164. }
  165. BOOL
  166. quit(
  167. IN HINTERNET hFtpSession,
  168. IN int argc,
  169. IN PTCHAR argv[]
  170. )
  171. {
  172. fQuit = TRUE;
  173. return TRUE;
  174. }
  175. BOOL
  176. get(
  177. IN HINTERNET hFtpSession,
  178. IN int argc,
  179. IN PTCHAR argv[]
  180. )
  181. {
  182. LPTSTR pszFilename;
  183. LPTSTR pszLocalfile;
  184. BOOL ok;
  185. if (argc < 2) {
  186. if (!Prompt(TEXT("remote-name: "), &pszFilename)) {
  187. return FALSE;
  188. }
  189. } else {
  190. pszFilename = argv[1];
  191. }
  192. if (argc >= 3) {
  193. pszLocalfile = argv[2];
  194. } else {
  195. pszLocalfile = pszFilename;
  196. }
  197. ok = FtpGetFile(hFtpSession,
  198. pszFilename,
  199. pszLocalfile,
  200. FALSE,
  201. FILE_ATTRIBUTE_NORMAL,
  202. CacheFlags
  203. | FTP_TRANSFER_TYPE_BINARY,
  204. FTPCAT_GET_CONTEXT
  205. );
  206. if (AsyncMode && !ok) {
  207. if (GetLastError() != ERROR_IO_PENDING) {
  208. print_error("get", "FtpGetFile()");
  209. } else {
  210. if (Verbose) {
  211. printf("waiting for async FtpGetFile()...\n");
  212. }
  213. WaitForSingleObject(AsyncEvent, INFINITE);
  214. ok = (BOOL)AsyncResult;
  215. }
  216. }
  217. if (!ok) {
  218. if (AsyncMode) {
  219. SetLastError(AsyncError);
  220. }
  221. print_error("get", "%sFtpGetFile()", AsyncMode ? "async " : "");
  222. } else {
  223. get_response(hFtpSession);
  224. }
  225. return ok;
  226. }
  227. BOOL
  228. put(
  229. IN HINTERNET hFtpSession,
  230. IN int argc,
  231. IN PTCHAR argv[]
  232. )
  233. {
  234. LPTSTR pszFilename;
  235. LPTSTR pszLocalfile;
  236. BOOL ok;
  237. if (argc < 2) {
  238. if (!Prompt(TEXT("remote-name: "), &pszFilename)) {
  239. return FALSE;
  240. }
  241. } else {
  242. pszFilename = argv[1];
  243. }
  244. if (argc >= 3) {
  245. pszLocalfile = argv[2];
  246. } else {
  247. pszLocalfile = pszFilename;
  248. }
  249. ok = FtpPutFile(hFtpSession,
  250. pszLocalfile,
  251. pszFilename,
  252. FTP_TRANSFER_TYPE_BINARY,
  253. FTPCAT_PUT_CONTEXT
  254. );
  255. if (AsyncMode && !ok) {
  256. if (GetLastError() != ERROR_IO_PENDING) {
  257. print_error("put", "FtpPutFile()");
  258. } else {
  259. if (Verbose) {
  260. printf("waiting for async FtpPutFile()...\n");
  261. }
  262. WaitForSingleObject(AsyncEvent, INFINITE);
  263. ok = (BOOL)AsyncResult;
  264. }
  265. }
  266. if (!ok) {
  267. if (AsyncMode) {
  268. SetLastError(AsyncError);
  269. }
  270. print_error("put", "%sFtpPutFile()", AsyncMode ? "async " : "");
  271. } else {
  272. get_response(hFtpSession);
  273. }
  274. return ok;
  275. }
  276. BOOL
  277. rename_file(
  278. IN HINTERNET hFtpSession,
  279. IN int argc,
  280. IN PTCHAR argv[]
  281. )
  282. {
  283. LPTSTR pszTemp;
  284. LPTSTR pszOldFilename;
  285. LPTSTR pszNewFilename;
  286. BOOL ok;
  287. if (argc < 2) {
  288. if (!Prompt(TEXT("Old name: "), &pszTemp)) {
  289. return FALSE;
  290. }
  291. pszOldFilename = lstrdup(pszTemp);
  292. if (pszOldFilename == NULL) {
  293. return FALSE;
  294. }
  295. } else {
  296. pszOldFilename = argv[1];
  297. }
  298. if (argc < 3) {
  299. if (!Prompt(TEXT("New name: "), &pszNewFilename)) {
  300. return FALSE;
  301. }
  302. } else {
  303. pszNewFilename = argv[2];
  304. }
  305. ok = FtpRenameFile(hFtpSession,
  306. pszOldFilename,
  307. pszNewFilename
  308. );
  309. if (AsyncMode && !ok) {
  310. if (GetLastError() != ERROR_IO_PENDING) {
  311. print_error("rename_file", "FtpRenameFile()");
  312. } else {
  313. if (Verbose) {
  314. printf("waiting for async FtpRenameFile()...\n");
  315. }
  316. WaitForSingleObject(AsyncEvent, INFINITE);
  317. ok = (BOOL)AsyncResult;
  318. }
  319. }
  320. if (!ok) {
  321. if (AsyncMode) {
  322. SetLastError(AsyncError);
  323. }
  324. print_error("rename_file", "%sFtpRenameFile()", AsyncMode ? "async " : "");
  325. } else {
  326. get_response(hFtpSession);
  327. }
  328. if (argc < 2) {
  329. LocalFree(pszOldFilename);
  330. }
  331. return ok;
  332. }
  333. BOOL
  334. del(
  335. IN HINTERNET hFtpSession,
  336. IN int argc,
  337. IN PTCHAR argv[]
  338. )
  339. {
  340. LPTSTR pszFilename;
  341. BOOL ok;
  342. if (argc < 2) {
  343. if (!Prompt(TEXT("File name: "), &pszFilename)) {
  344. return FALSE;
  345. }
  346. } else {
  347. pszFilename = argv[1];
  348. }
  349. ok = FtpDeleteFile(hFtpSession, pszFilename);
  350. if (AsyncMode && !ok) {
  351. if (GetLastError() != ERROR_IO_PENDING) {
  352. print_error("del", "FtpDeleteFile()");
  353. } else {
  354. if (Verbose) {
  355. printf("waiting for async FtpDeleteFile()...\n");
  356. }
  357. WaitForSingleObject(AsyncEvent, INFINITE);
  358. ok = (BOOL)AsyncResult;
  359. }
  360. }
  361. if (!ok) {
  362. if (AsyncMode) {
  363. SetLastError(AsyncError);
  364. }
  365. print_error("del",
  366. "%sFtpDeleteFile()",
  367. AsyncMode ? "async " : ""
  368. );
  369. } else {
  370. get_response(hFtpSession);
  371. }
  372. return ok;
  373. }
  374. BOOL
  375. mkdir(
  376. IN HINTERNET hFtpSession,
  377. IN int argc,
  378. IN PTCHAR argv[]
  379. )
  380. {
  381. LPTSTR pszDirname;
  382. BOOL ok;
  383. if (argc < 2) {
  384. if (!Prompt(TEXT("Directory name: "), &pszDirname)) {
  385. return FALSE;
  386. }
  387. } else {
  388. pszDirname = argv[1];
  389. }
  390. ok = FtpCreateDirectory(hFtpSession,
  391. pszDirname
  392. );
  393. if (AsyncMode && !ok) {
  394. if (GetLastError() != ERROR_IO_PENDING) {
  395. print_error("mkdir", "FtpCreateDirectory()");
  396. } else {
  397. if (Verbose) {
  398. printf("waiting for async FtpCreateDirectory()...\n");
  399. }
  400. WaitForSingleObject(AsyncEvent, INFINITE);
  401. ok = (BOOL)AsyncResult;
  402. }
  403. }
  404. if (!ok) {
  405. if (AsyncMode) {
  406. SetLastError(AsyncError);
  407. }
  408. print_error("mkdir", "%sFtpCreateDirectory()", AsyncMode ? "async " : "");
  409. } else {
  410. get_response(hFtpSession);
  411. }
  412. return ok;
  413. }
  414. BOOL
  415. chdir(
  416. IN HINTERNET hFtpSession,
  417. IN int argc,
  418. IN PTCHAR argv[]
  419. )
  420. {
  421. LPTSTR pszDirname;
  422. BOOL ok;
  423. if (argc < 2) {
  424. if (!Prompt(TEXT("Directory name: "), &pszDirname)) {
  425. return FALSE;
  426. }
  427. } else {
  428. pszDirname = argv[1];
  429. }
  430. ok = FtpSetCurrentDirectory(hFtpSession,
  431. pszDirname
  432. );
  433. if (AsyncMode && !ok) {
  434. if (GetLastError() != ERROR_IO_PENDING) {
  435. print_error("chdir", "FtpSetCurrentDirectory()");
  436. } else {
  437. if (Verbose) {
  438. printf("waiting for async FtpSetCurrentDirectory()...\n");
  439. }
  440. WaitForSingleObject(AsyncEvent, INFINITE);
  441. ok = (BOOL)AsyncResult;
  442. }
  443. }
  444. if (!ok) {
  445. if (AsyncMode) {
  446. SetLastError(AsyncError);
  447. }
  448. print_error("chdir", "%sFtpSetCurrentDirectory()", AsyncMode ? "async " : "");
  449. } else {
  450. get_response(hFtpSession);
  451. }
  452. return ok;
  453. }
  454. BOOL
  455. rmdir(
  456. IN HINTERNET hFtpSession,
  457. IN int argc,
  458. IN PTCHAR argv[]
  459. )
  460. {
  461. LPTSTR pszDirname;
  462. BOOL ok;
  463. if (argc < 2) {
  464. if (!Prompt(TEXT("Directory name: "), &pszDirname)) {
  465. return FALSE;
  466. }
  467. } else {
  468. pszDirname = argv[1];
  469. }
  470. ok = FtpRemoveDirectory(hFtpSession,
  471. pszDirname
  472. );
  473. if (AsyncMode && !ok) {
  474. if (GetLastError() != ERROR_IO_PENDING) {
  475. print_error("rmdir", "FtpRemoveDirectory()");
  476. } else {
  477. if (Verbose) {
  478. printf("waiting for async FtpRemoveDirectory()...\n");
  479. }
  480. WaitForSingleObject(AsyncEvent, INFINITE);
  481. ok = (BOOL)AsyncResult;
  482. }
  483. }
  484. if (!ok) {
  485. if (AsyncMode) {
  486. SetLastError(AsyncError);
  487. }
  488. print_error("rmdir", "%sFtpRemoveDirectory()", AsyncMode ? "async " : "");
  489. } else {
  490. get_response(hFtpSession);
  491. }
  492. return ok;
  493. }
  494. BOOL
  495. dir(
  496. IN HINTERNET hFtpSession,
  497. IN int argc,
  498. IN PTCHAR argv[]
  499. )
  500. {
  501. BOOL ok;
  502. WIN32_FIND_DATA ffd;
  503. SYSTEMTIME st;
  504. LPTSTR pszFileSpec;
  505. TCHAR EmptyExpression[] = "";
  506. HINTERNET hFind;
  507. HINTERNET hPrevious;
  508. static LPSTR month[] = {
  509. "",
  510. "Jan",
  511. "Feb",
  512. "Mar",
  513. "Apr",
  514. "May",
  515. "Jun",
  516. "Jul",
  517. "Aug",
  518. "Sep",
  519. "Oct",
  520. "Nov",
  521. "Dec"
  522. };
  523. if (argc < 2) {
  524. pszFileSpec = EmptyExpression;
  525. } else {
  526. pszFileSpec = argv[1];
  527. }
  528. hFind = FtpFindFirstFileA(hFtpSession,
  529. pszFileSpec,
  530. &ffd,
  531. CacheFlags, // dwFlags
  532. FTPCAT_FIND_CONTEXT
  533. );
  534. if (AsyncMode && (hFind == NULL)) {
  535. if (GetLastError() == ERROR_IO_PENDING) {
  536. if (Verbose) {
  537. printf("waiting for async FtpFindFirstFile()...\n");
  538. }
  539. WaitForSingleObject(AsyncEvent, INFINITE);
  540. hFind = (HINTERNET)AsyncResult;
  541. if (hFind == NULL) {
  542. SetLastError(AsyncError);
  543. }
  544. }
  545. }
  546. if (hFind == NULL) {
  547. print_error("dir", "%sFtpFindFirstFile()", AsyncMode ? "async " : "");
  548. return FALSE;
  549. }
  550. hPrevious = hCancel;
  551. hCancel = hFind;
  552. get_response(hFind);
  553. putchar('\n');
  554. ok = TRUE;
  555. while (ok) {
  556. if (!FileTimeToSystemTime(&ffd.ftLastWriteTime, &st)) {
  557. printf("| ftLastWriteTime = ERROR\n");
  558. }
  559. printf("%02d-%s-%04d %02d:%02d:%02d %15d bytes %-s%-s%-s%-s%-s%-s %s\n",
  560. st.wDay,
  561. month[st.wMonth],
  562. st.wYear,
  563. st.wHour,
  564. st.wMinute,
  565. st.wSecond,
  566. ffd.nFileSizeLow,
  567. (ffd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? "Archive " : "",
  568. (ffd.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ? "Normal " : "",
  569. (ffd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? "System " : "",
  570. (ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? "Hidden " : "",
  571. (ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? "ReadOnly " : "",
  572. (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? "Directory " : "",
  573. ffd.cFileName
  574. );
  575. if (UseQueryData) {
  576. DWORD error;
  577. DWORD avail;
  578. ok = InternetQueryDataAvailable(hFind, &avail, 0, 0);
  579. if (!ok) {
  580. error = GetLastError();
  581. if (error == ERROR_IO_PENDING) {
  582. if (Verbose) {
  583. printf("waiting for async InternetQueryDataAvailable()...\n");
  584. }
  585. WaitForSingleObject(AsyncEvent, INFINITE);
  586. ok = (BOOL)AsyncResult;
  587. SetLastError(AsyncError);
  588. }
  589. }
  590. if (!ok) {
  591. print_error("dir", "%sSYNC InternetQueryDataAvailable()", AsyncMode ? "A" : "");
  592. break;
  593. }
  594. if (Verbose) {
  595. printf("InternetQueryDataAvailable() returns %d available\n", avail);
  596. }
  597. if (avail == 0) {
  598. break;
  599. }
  600. }
  601. ok = InternetFindNextFile(hFind, &ffd);
  602. if (!ok && AsyncMode) {
  603. if (GetLastError() == ERROR_IO_PENDING) {
  604. if (Verbose) {
  605. printf("waiting for async InternetFindNextFile()...\n");
  606. }
  607. WaitForSingleObject(AsyncEvent, INFINITE);
  608. ok = (BOOL)AsyncResult;
  609. if (!ok) {
  610. SetLastError(AsyncError);
  611. }
  612. }
  613. }
  614. if (!ok) {
  615. if (GetLastError() != ERROR_NO_MORE_FILES) {
  616. print_error("dir", "%sInternetFindNextFile()", AsyncMode ? "async " : "");
  617. break;
  618. }
  619. }
  620. }
  621. putchar('\n');
  622. close_handle(hFind);
  623. hCancel = hPrevious;
  624. return ok;
  625. }
  626. BOOL
  627. pwd(
  628. IN HINTERNET hFtpSession,
  629. IN int argc,
  630. IN PTCHAR argv[]
  631. )
  632. {
  633. BOOL ok;
  634. char* buf;
  635. DWORD len;
  636. len = 0;
  637. ok = FtpGetCurrentDirectory(hFtpSession, NULL, &len);
  638. if (AsyncMode && !ok) {
  639. if (GetLastError() != ERROR_IO_PENDING) {
  640. print_error("pwd", "async FtpGetCurrentDirectory()");
  641. } else {
  642. if (Verbose) {
  643. printf("waiting for async FtpGetCurrentDirectory()...\n");
  644. }
  645. WaitForSingleObject(AsyncEvent, INFINITE);
  646. ok = (BOOL)AsyncResult;
  647. SetLastError(AsyncError);
  648. }
  649. }
  650. if (ok) {
  651. printf("error: FtpGetCurrentDirectory() w/ no buffer returns ok\n");
  652. return FALSE;
  653. } else if (Verbose) {
  654. printf("FtpGetCurrentDirectory() returns %d, %d bytes in cur dir\n",
  655. GetLastError(),
  656. len
  657. );
  658. }
  659. buf = (char*)malloc(len);
  660. ok = FtpGetCurrentDirectory(hFtpSession, buf, &len);
  661. if (AsyncMode && !ok) {
  662. if (GetLastError() != ERROR_IO_PENDING) {
  663. print_error("pwd", "async FtpGetCurrentDirectory()");
  664. } else {
  665. if (Verbose) {
  666. printf("waiting for async FtpGetCurrentDirectory()...\n");
  667. }
  668. WaitForSingleObject(AsyncEvent, INFINITE);
  669. ok = (BOOL)AsyncResult;
  670. SetLastError(AsyncError);
  671. }
  672. }
  673. if (!ok) {
  674. print_error("pwd", "%sFtpGetCurrentDirectory()", AsyncMode ? "async " : "");
  675. } else {
  676. get_response(hFtpSession);
  677. lprintf(TEXT("Current directory: %s\n"), buf);
  678. }
  679. free(buf);
  680. return ok;
  681. }
  682. BOOL help(IN HINTERNET hFtpSession, IN int argc, IN PTCHAR argv[]) {
  683. int i;
  684. for (i = 0; Commands[i].pszCommand != NULL; ++i) {
  685. lprintf(TEXT("\t%s\t%s\n"),
  686. Commands[i].pszCommand,
  687. Commands[i].HelpText
  688. );
  689. }
  690. return TRUE;
  691. }
  692. #if DBG
  693. BOOL CheckHandles(HINTERNET hFtpSession, int argc, PTCHAR argv[]) {
  694. printf("handle count = %d\n", GetProcessHandleCount());
  695. return TRUE;
  696. }
  697. #endif
  698. BOOL lcd(HINTERNET hInternet, int argc, char** argv) {
  699. char curDir[MAX_PATH + 1];
  700. DWORD curDirLen;
  701. if (argc == 2) {
  702. if (!SetCurrentDirectory(argv[1])) {
  703. print_error("lcd", "SetCurrentDirectory()");
  704. return FALSE;
  705. }
  706. } else if (argc != 1) {
  707. printf("error: lcd: incorrect number of arguments\n");
  708. return FALSE;
  709. }
  710. curDirLen = sizeof(curDir);
  711. if (GetCurrentDirectory(curDirLen, curDir)) {
  712. printf("Current directory is %s\n", curDir);
  713. return TRUE;
  714. } else {
  715. print_error("lcd", "GetCurrentDirectory()");
  716. return FALSE;
  717. }
  718. }
  719. BOOL rb(HINTERNET hInternet, int argc, char** argv) {
  720. DWORD value;
  721. DWORD valueLength;
  722. if (argc > 1) {
  723. value = atoi(argv[1]);
  724. if (!InternetSetOption(hInternet,
  725. INTERNET_OPTION_READ_BUFFER_SIZE,
  726. (LPVOID)&value,
  727. sizeof(DWORD)
  728. )) {
  729. print_error("rb", "InternetSetOption()");
  730. return FALSE;
  731. }
  732. }
  733. valueLength = sizeof(value);
  734. if (InternetQueryOption(hInternet,
  735. INTERNET_OPTION_READ_BUFFER_SIZE,
  736. (LPVOID)&value,
  737. &valueLength
  738. )) {
  739. printf("Read buffer size = %d bytes\n", value);
  740. return TRUE;
  741. } else {
  742. print_error("rb", "InternetQueryOption()");
  743. return FALSE;
  744. }
  745. }
  746. BOOL wb(HINTERNET hInternet, int argc, char** argv) {
  747. DWORD value;
  748. DWORD valueLength;
  749. if (argc > 1) {
  750. value = atoi(argv[1]);
  751. if (!InternetSetOption(hInternet,
  752. INTERNET_OPTION_WRITE_BUFFER_SIZE,
  753. (LPVOID)&value,
  754. sizeof(DWORD)
  755. )) {
  756. print_error("wb", "InternetSetOption()");
  757. return FALSE;
  758. }
  759. }
  760. valueLength = sizeof(value);
  761. if (InternetQueryOption(hInternet,
  762. INTERNET_OPTION_WRITE_BUFFER_SIZE,
  763. (LPVOID)&value,
  764. &valueLength
  765. )) {
  766. printf("Write buffer size = %d bytes\n", value);
  767. return TRUE;
  768. } else {
  769. print_error("wb", "InternetQueryOption()");
  770. return FALSE;
  771. }
  772. }
  773. BOOL toggle_verbose(HINTERNET hInternet, int argc, PTCHAR * argv) {
  774. static DWORD PreviousVerbose = 0;
  775. if (Verbose) {
  776. PreviousVerbose = Verbose;
  777. Verbose = 0;
  778. } else {
  779. Verbose = PreviousVerbose;
  780. if (Verbose == 0) {
  781. Verbose = 1;
  782. }
  783. }
  784. printf("Verbose mode is o%s\n", Verbose ? "n" : "ff");
  785. return TRUE;
  786. }
  787. BOOL toggle_callback(HINTERNET hInternet, int argc, PTCHAR * argv) {
  788. INTERNET_STATUS_CALLBACK callback;
  789. if (PreviousCallback != NULL && PreviousCallback != my_callback) {
  790. printf("error: PreviousCallback %x not recognized\n", PreviousCallback);
  791. } else {
  792. PreviousCallback = InternetSetStatusCallback(hInternet, PreviousCallback);
  793. if (PreviousCallback == INTERNET_INVALID_STATUS_CALLBACK) {
  794. print_error("toggle_callback", "InternetSetStatusCallback()");
  795. } else if (PreviousCallback != NULL && PreviousCallback != my_callback) {
  796. printf("error: PreviousCallback %x not recognized\n", PreviousCallback);
  797. } else if (Verbose) {
  798. printf("callback toggled Ok\n");
  799. }
  800. }
  801. printf("Verbose mode is o%s\n", Verbose ? "n" : "ff");
  802. return TRUE;
  803. }
  804. BOOL dbgbreak(HINTERNET hInternet, int argc, PTCHAR * argv) {
  805. DebugBreak();
  806. return TRUE;
  807. }
  808. BOOL set_type(HINTERNET hInternet, int argc, PTCHAR * argv) {
  809. return TRUE;
  810. }
  811. BOOL open_file(HINTERNET hInternet, int argc, PTCHAR * argv) {
  812. HINTERNET hFile;
  813. BOOL bOk;
  814. if (argc < 2) {
  815. printf("error: required filename missing\n");
  816. return FALSE;
  817. }
  818. hFile = FtpOpenFile(hInternet,
  819. argv[1],
  820. GENERIC_READ,
  821. 0,
  822. AsyncMode ? FTPCAT_OPEN_CONTEXT : 0
  823. );
  824. if (AsyncMode && !hFile) {
  825. if (GetLastError() != ERROR_IO_PENDING) {
  826. print_error("open_file", "async FtpOpenFile()");
  827. return FALSE;
  828. }
  829. if (Verbose) {
  830. printf("waiting for async FtpOpenFile()...\n");
  831. }
  832. WaitForSingleObject(AsyncEvent, INFINITE);
  833. hFile = (HINTERNET)AsyncResult;
  834. SetLastError(AsyncError);
  835. }
  836. if (!hFile) {
  837. print_error("open_file", "%sFtpOpenFile()", AsyncMode ? "async " : "");
  838. } else {
  839. get_response(hInternet);
  840. printf("returned handle is %#x\n", hFile);
  841. }
  842. return hFile != NULL;
  843. }
  844. BOOL close_file(HINTERNET hInternet, int argc, PTCHAR * argv) {
  845. HINTERNET hFile;
  846. BOOL bOk;
  847. if (argc < 2) {
  848. printf("error: required handle missing\n");
  849. return FALSE;
  850. }
  851. hFile = (HINTERNET)strtol(argv[1], NULL, 0);
  852. bOk = InternetCloseHandle(hFile);
  853. if (!bOk) {
  854. print_error("close_file", "InternetCloseHandle()");
  855. } else if (Verbose) {
  856. printf("handle %#x closed OK\n", hFile);
  857. }
  858. return bOk;
  859. }
  860. BOOL read_file(HINTERNET hInternet, int argc, PTCHAR * argv) {
  861. return TRUE;
  862. }
  863. BOOL write_file(HINTERNET hInternet, int argc, PTCHAR * argv) {
  864. return TRUE;
  865. }
  866. BOOL
  867. DispatchCommand(
  868. IN LPTSTR pszCommand,
  869. IN HINTERNET hFtpSession
  870. )
  871. {
  872. COMMAND_ENTRY *pce;
  873. PTCHAR ArgV[MAX_ARGV];
  874. int index;
  875. int state;
  876. if (*pszCommand == TEXT('!')) {
  877. LPSTR shellPath;
  878. shellPath = getenv("COMSPEC");
  879. if (shellPath == NULL) {
  880. printf("error: COMSPEC environment variable not set\n");
  881. return FALSE;
  882. }
  883. ++pszCommand;
  884. while (isspace(*pszCommand)) {
  885. ++pszCommand;
  886. }
  887. if (*pszCommand != TEXT('\0')) {
  888. _spawnlp(_P_WAIT, shellPath, "/C", pszCommand, NULL);
  889. } else {
  890. printf("\nSpawning command interpreter. Type \"exit\" to return to FTP\n\n");
  891. _spawnlp(_P_WAIT, shellPath, "/K", NULL);
  892. putchar('\n');
  893. }
  894. return TRUE;
  895. }
  896. state = 0;
  897. index = 0;
  898. while (*pszCommand) {
  899. switch (state) {
  900. case 0:
  901. if (!isspace(*pszCommand)) {
  902. if (*pszCommand == '"') {
  903. state = 2;
  904. } else {
  905. state = 1;
  906. }
  907. ArgV[index++] = (state == 2) ? (pszCommand + 1) : pszCommand;
  908. }
  909. break;
  910. case 1:
  911. if (isspace(*pszCommand)) {
  912. *pszCommand = '\0';
  913. state = 0;
  914. }
  915. break;
  916. case 2:
  917. if (*pszCommand == '"') {
  918. *pszCommand = '\0';
  919. state = 0;
  920. }
  921. break;
  922. }
  923. ++pszCommand;
  924. }
  925. if (index == 0) {
  926. return FALSE;
  927. }
  928. for (pce = Commands; pce->pszCommand != NULL; pce++) {
  929. if (lstrcmpi(pce->pszCommand, ArgV[0]) == 0) {
  930. return pce->fn(hFtpSession, index, ArgV);
  931. }
  932. }
  933. if (!lstrcmpi(ArgV[0], "q")) {
  934. return quit(hFtpSession, index, ArgV);
  935. }
  936. printf("error: unrecognized command: \"%s\"\n", ArgV[0]);
  937. return FALSE;
  938. }