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.

602 lines
14 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. ftpcat.c
  5. Abstract:
  6. Windows Internet API FTP test program
  7. Provides the same functionality as a cut-down version of the venerable
  8. (console-mode) ftp program
  9. Author:
  10. Richard L Firth (rfirth) 05-Jun-1995
  11. Environment:
  12. Win32 user-mode console app
  13. Revision History:
  14. 05-Jun-1995 rfirth
  15. Created
  16. --*/
  17. #include "ftpcatp.h"
  18. #undef tolower
  19. //
  20. // macros
  21. //
  22. #define IS_ARG(c) (((c) == '-') || ((c) == '/'))
  23. //
  24. // manifests
  25. //
  26. #define MAX_COMMAND_LENGTH 100
  27. //
  28. // external data
  29. //
  30. extern BOOL fQuit;
  31. extern DWORD CacheFlags;
  32. //
  33. // data
  34. //
  35. DWORD Verbose = 0;
  36. INTERNET_STATUS_CALLBACK PreviousCallback;
  37. HINTERNET hCancel = NULL;
  38. BOOL AsyncMode = FALSE;
  39. BOOL fOffline = FALSE;
  40. DWORD Context = 0;
  41. DWORD AsyncResult = 0;
  42. DWORD AsyncError = 0;
  43. HANDLE AsyncEvent = NULL;
  44. BOOL UseQueryData = FALSE;
  45. #if DBG
  46. BOOL CheckHandleLeak = FALSE;
  47. #endif
  48. //
  49. // external functions
  50. //
  51. extern BOOL DispatchCommand(LPCTSTR, HANDLE);
  52. //
  53. // prototypes
  54. //
  55. void __cdecl main(int, char**);
  56. void __cdecl control_c_handler(int);
  57. void usage(void);
  58. BOOL Prompt(LPCTSTR, LPTSTR*);
  59. //
  60. // functions
  61. //
  62. void __cdecl main(int argc, char** argv) {
  63. LPTSTR ptszSite = NULL;
  64. LPTSTR ptszUser = NULL;
  65. LPTSTR ptszPass = NULL;
  66. HINTERNET hInternet;
  67. HINTERNET hFtpSession;
  68. DWORD dwLocalAccessFlags;
  69. LPTSTR lpszCmd;
  70. DWORD lastError;
  71. DWORD bufLen;
  72. BOOL enableCallbacks = FALSE;
  73. DWORD flags = 0;
  74. DWORD accessMethod = INTERNET_OPEN_TYPE_PRECONFIG;
  75. BOOL expectingProxy = FALSE;
  76. LPSTR proxyServer = NULL;
  77. for (--argc, ++argv; argc; --argc, ++argv) {
  78. if (IS_ARG(**argv)) {
  79. switch (*++*argv) {
  80. case '?':
  81. usage();
  82. break;
  83. case 'a':
  84. ++*argv;
  85. if ((**argv == 'l') || (**argv == 'd')) {
  86. accessMethod = INTERNET_OPEN_TYPE_DIRECT;
  87. } else if (**argv == 'p') {
  88. accessMethod = INTERNET_OPEN_TYPE_PROXY;
  89. if (*++*argv) {
  90. proxyServer = *argv;
  91. } else {
  92. expectingProxy = TRUE;
  93. }
  94. } else {
  95. printf("error: unrecognised access type: '%c'\n", **argv);
  96. usage();
  97. }
  98. break;
  99. case 'c':
  100. enableCallbacks = TRUE;
  101. break;
  102. #if DBG
  103. case 'l':
  104. CheckHandleLeak = TRUE;
  105. break;
  106. #endif
  107. case 'n':
  108. CacheFlags |= INTERNET_FLAG_DONT_CACHE;
  109. break;
  110. case 'p':
  111. flags |= INTERNET_FLAG_PASSIVE;
  112. break;
  113. case 'q':
  114. UseQueryData = TRUE;
  115. break;
  116. case 'v':
  117. if (*++*argv == '\0') {
  118. Verbose = 1;
  119. } else {
  120. Verbose = atoi(*argv);
  121. }
  122. break;
  123. case 'x':
  124. Context = (DWORD)atoi(++*argv);
  125. break;
  126. case 'y':
  127. AsyncMode = TRUE;
  128. break;
  129. case 'o':
  130. fOffline = TRUE;
  131. break;
  132. default:
  133. printf("error: unrecognized command line flag: '%c'\n", **argv);
  134. usage();
  135. }
  136. } else if (expectingProxy) {
  137. proxyServer = *argv;
  138. expectingProxy = FALSE;
  139. } else if (ptszSite == NULL) {
  140. ptszSite = *argv;
  141. } else if (ptszUser == NULL) {
  142. ptszUser = *argv;
  143. } else if (ptszPass == NULL) {
  144. ptszPass = *argv;
  145. } else {
  146. printf("error: unrecognized command line argument: \"%s\"\n", *argv);
  147. usage();
  148. }
  149. }
  150. if (ptszSite == NULL) {
  151. printf("error: required server name argument missing\n");
  152. exit(1);
  153. }
  154. if (AsyncMode) {
  155. //
  156. // create auto-reset, initially unsignalled event
  157. //
  158. AsyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  159. if (AsyncEvent == NULL) {
  160. print_error("ftpcat", "CreateEvent()");
  161. exit(1);
  162. }
  163. }
  164. //
  165. // add a control-c handler
  166. //
  167. signal(SIGINT, control_c_handler);
  168. #if DBG
  169. if (CheckHandleLeak) {
  170. printf("initial handle count = %d\n", GetProcessHandleCount());
  171. }
  172. #endif
  173. #if DBG
  174. if (CheckHandleLeak && Verbose) {
  175. printf("Initial handle count = %d\n", GetProcessHandleCount());
  176. }
  177. #endif
  178. if (Verbose) {
  179. printf("calling InternetOpen()...\n");
  180. }
  181. hInternet = InternetOpen("ftpcat",
  182. accessMethod,
  183. proxyServer,
  184. NULL,
  185. AsyncMode ? INTERNET_FLAG_ASYNC : 0
  186. | (fOffline ? INTERNET_FLAG_OFFLINE : 0)
  187. );
  188. if (hInternet == NULL) {
  189. print_error("ftpcat", "InternetOpen()");
  190. exit(1);
  191. } else if (Verbose) {
  192. printf("Internet handle = %x\n", hInternet);
  193. hCancel = hInternet;
  194. }
  195. #if DBG
  196. if (CheckHandleLeak) {
  197. printf("after InternetOpen(): handle count = %d\n", GetProcessHandleCount());
  198. }
  199. #endif
  200. if (enableCallbacks) {
  201. //
  202. // let's have a status callback
  203. //
  204. // Note that callbacks can be set even before we have opened a handle
  205. // to the internet/gateway
  206. //
  207. PreviousCallback = InternetSetStatusCallback(hInternet, my_callback);
  208. if (PreviousCallback == INTERNET_INVALID_STATUS_CALLBACK) {
  209. print_error("ftpcat", "InternetSetStatusCallback()");
  210. } else if (Verbose) {
  211. printf("previous Internet callback = %x\n", PreviousCallback);
  212. }
  213. }
  214. if (Verbose) {
  215. printf("calling InternetConnect()...\n");
  216. }
  217. hFtpSession = InternetConnect(hInternet,
  218. ptszSite,
  219. 0,
  220. ptszUser,
  221. ptszPass,
  222. INTERNET_SERVICE_FTP,
  223. flags,
  224. FTPCAT_CONNECT_CONTEXT
  225. );
  226. if ((hFtpSession == NULL) && AsyncMode) {
  227. if (Verbose) {
  228. printf("waiting for async InternetConnect()...\n");
  229. }
  230. WaitForSingleObject(AsyncEvent, INFINITE);
  231. hFtpSession = (HINTERNET)AsyncResult;
  232. SetLastError(AsyncError);
  233. }
  234. if (hFtpSession == NULL) {
  235. if (AsyncMode) {
  236. SetLastError(AsyncError);
  237. }
  238. print_error("ftpcat",
  239. "%sInternetConnect()",
  240. AsyncMode ? "async " : ""
  241. );
  242. get_response(hFtpSession);
  243. close_handle(hInternet);
  244. exit(1);
  245. } else if (Verbose) {
  246. printf("FTP session handle = %x\n", hFtpSession);
  247. }
  248. #if DBG
  249. if (CheckHandleLeak) {
  250. printf("after InternetConnect(): handle count = %d\n", GetProcessHandleCount());
  251. }
  252. #endif
  253. printf("Connected to %s.\n", ptszSite);
  254. get_response(hFtpSession);
  255. #if DBG
  256. if (CheckHandleLeak) {
  257. printf("after InternetGetLastResponseInfo(): handle count = %d\n", GetProcessHandleCount());
  258. }
  259. #endif
  260. //
  261. // set the (top level) cancellable handle
  262. //
  263. hCancel = hFtpSession;
  264. while (!fQuit) {
  265. if (Prompt(TEXT("ftp> "), &lpszCmd)) {
  266. DispatchCommand(lpszCmd, hFtpSession);
  267. }
  268. }
  269. if (Verbose) {
  270. printf("Closing %x\n", hFtpSession);
  271. }
  272. close_handle(hFtpSession);
  273. #if DBG
  274. if (CheckHandleLeak) {
  275. printf("after InternetCloseHandle(): handle count = %d\n", GetProcessHandleCount());
  276. }
  277. #endif
  278. get_response(hFtpSession);
  279. #if DBG
  280. if (CheckHandleLeak) {
  281. printf("after InternetGetLastResponseInfo(): handle count = %d\n", GetProcessHandleCount());
  282. }
  283. #endif
  284. close_handle(hInternet);
  285. #if DBG
  286. if (CheckHandleLeak) {
  287. printf("after InternetCloseHandle(): handle count = %d\n", GetProcessHandleCount());
  288. }
  289. if (CheckHandleLeak && Verbose) {
  290. printf("Final handle count = %d\n", GetProcessHandleCount());
  291. }
  292. #endif
  293. exit(0);
  294. }
  295. void __cdecl control_c_handler(int sig) {
  296. //
  297. // disable signals
  298. //
  299. signal(SIGINT, SIG_IGN);
  300. //
  301. // cancel the current operation
  302. //
  303. if (Verbose) {
  304. printf("control-c handler\n");
  305. }
  306. if (hCancel == NULL) {
  307. if (Verbose) {
  308. printf("control-c handler: no Internet operation in progress\n");
  309. }
  310. } else {
  311. close_handle(hCancel);
  312. }
  313. //
  314. // re-enable this signal handler
  315. //
  316. signal(SIGINT, control_c_handler);
  317. }
  318. void usage() {
  319. printf("\n"
  320. "usage: ftpcat [-a{g{[ ]server}|l|d|p}] [-c] [-d] [-n] [-p] [-v] [-x#] [-y]\n"
  321. " {servername} [username] [password]\n"
  322. "\n"
  323. "where: -a = access type. Default is pre-configured:\n"
  324. " g = gateway access via <gateway server>\n"
  325. " l = local internet access\n"
  326. " d = local internet access\n"
  327. " p = CERN proxy access\n"
  328. " -c = Enable callbacks\n"
  329. " -n = Don't cache\n"
  330. " -p = Use Passive transfer mode\n"
  331. " -v = Verbose mode. Default is off\n"
  332. " -x = Set context value\n"
  333. " -y = Asynchronous APIs\n"
  334. );
  335. exit(1);
  336. }
  337. BOOL
  338. Prompt(
  339. IN LPCTSTR pszPrompt,
  340. OUT LPTSTR* ppszCommand
  341. )
  342. {
  343. static CHAR Command[MAX_COMMAND_LENGTH + sizeof(TEXT('\0'))];
  344. #ifdef UNICODE
  345. static WCHAR wchBuf[MAX_COMMAND_LENGTH + sizeof(L'\0')];
  346. #endif
  347. DWORD dwBytesRead;
  348. PTCHAR pch;
  349. lprintf(TEXT("%s"), pszPrompt);
  350. if (!ReadFile(GetStdHandle(STD_INPUT_HANDLE),
  351. Command,
  352. MAX_COMMAND_LENGTH * sizeof(CHAR),
  353. &dwBytesRead,
  354. NULL)) {
  355. return FALSE;
  356. }
  357. Command[dwBytesRead] = '\0';
  358. #ifdef UNICODE
  359. wsprintf(wchBuf, L"%S", Command);
  360. *ppszCommand = wchBuf;
  361. #else
  362. *ppszCommand = Command;
  363. #endif
  364. pch = lstrchr(*ppszCommand, TEXT('\r'));
  365. if (pch) {
  366. *pch = TEXT('\0');
  367. }
  368. return TRUE;
  369. }
  370. VOID
  371. my_callback(
  372. HINTERNET Handle,
  373. DWORD Context,
  374. DWORD Status,
  375. LPVOID Info,
  376. DWORD Length
  377. )
  378. {
  379. char* type$;
  380. switch (Status) {
  381. case INTERNET_STATUS_RESOLVING_NAME:
  382. type$ = "RESOLVING NAME";
  383. break;
  384. case INTERNET_STATUS_NAME_RESOLVED:
  385. type$ = "NAME RESOLVED";
  386. break;
  387. case INTERNET_STATUS_CONNECTING_TO_SERVER:
  388. type$ = "CONNECTING TO SERVER";
  389. break;
  390. case INTERNET_STATUS_CONNECTED_TO_SERVER:
  391. type$ = "CONNECTED TO SERVER";
  392. break;
  393. case INTERNET_STATUS_SENDING_REQUEST:
  394. type$ = "SENDING REQUEST";
  395. break;
  396. case INTERNET_STATUS_REQUEST_SENT:
  397. type$ = "REQUEST SENT";
  398. break;
  399. case INTERNET_STATUS_RECEIVING_RESPONSE:
  400. type$ = "RECEIVING RESPONSE";
  401. break;
  402. case INTERNET_STATUS_RESPONSE_RECEIVED:
  403. type$ = "RESPONSE RECEIVED";
  404. break;
  405. case INTERNET_STATUS_CLOSING_CONNECTION:
  406. type$ = "CLOSING CONNECTION";
  407. break;
  408. case INTERNET_STATUS_CONNECTION_CLOSED:
  409. type$ = "CONNECTION CLOSED";
  410. break;
  411. case INTERNET_STATUS_HANDLE_CREATED:
  412. type$ = "HANDLE CREATED";
  413. hCancel = *(LPHINTERNET)Info;
  414. break;
  415. case INTERNET_STATUS_HANDLE_CLOSING:
  416. type$ = "HANDLE CLOSING";
  417. break;
  418. case INTERNET_STATUS_REQUEST_COMPLETE:
  419. type$ = "REQUEST COMPLETE";
  420. AsyncResult = ((LPINTERNET_ASYNC_RESULT)Info)->dwResult;
  421. AsyncError = ((LPINTERNET_ASYNC_RESULT)Info)->dwError;
  422. break;
  423. default:
  424. type$ = "???";
  425. break;
  426. }
  427. if (Verbose) {
  428. printf("callback: handle %x [context %x [%s]] %s ",
  429. Handle,
  430. Context,
  431. (Context == FTPCAT_CONNECT_CONTEXT) ? "Connect"
  432. : (Context == FTPCAT_FIND_CONTEXT) ? "Find"
  433. : (Context == FTPCAT_FILE_CONTEXT) ? "File"
  434. : (Context == FTPCAT_GET_CONTEXT) ? "Get"
  435. : (Context == FTPCAT_PUT_CONTEXT) ? "Put"
  436. : (Context == FTPCAT_COMMAND_CONTEXT) ? "Command"
  437. : (Context == FTPCAT_OPEN_CONTEXT) ? "Open"
  438. : "???",
  439. type$
  440. );
  441. if (Info) {
  442. if ((Status == INTERNET_STATUS_HANDLE_CREATED)
  443. || (Status == INTERNET_STATUS_HANDLE_CLOSING)) {
  444. printf("%x", *(LPHINTERNET)Info);
  445. } else if (Length == sizeof(DWORD)) {
  446. printf("%d", *(LPDWORD)Info);
  447. } else {
  448. printf(Info);
  449. }
  450. }
  451. putchar('\n');
  452. }
  453. if (Status == INTERNET_STATUS_REQUEST_COMPLETE) {
  454. get_response(Handle);
  455. if (AsyncMode) {
  456. SetEvent(AsyncEvent);
  457. } else {
  458. printf("error: INTERNET_STATUS_REQUEST_COMPLETE returned. Not async\n");
  459. }
  460. }
  461. }
  462. void close_handle(HINTERNET handle) {
  463. if (Verbose) {
  464. printf("closing handle %#x\n", handle);
  465. }
  466. if (!InternetCloseHandle(handle)) {
  467. print_error("close_handle", "InternetCloseHandle(%x)", handle);
  468. }
  469. }
  470. #if DBG
  471. DWORD GetProcessHandleCount() {
  472. DWORD error;
  473. DWORD count;
  474. DWORD countSize;
  475. countSize = sizeof(count);
  476. if (!InternetQueryOption(NULL,
  477. INTERNET_OPTION_GET_HANDLE_COUNT,
  478. &count,
  479. &countSize
  480. )) {
  481. print_error("GetProcessHandleCount", "InternetQueryOption()");
  482. return 0;
  483. }
  484. return count;
  485. }
  486. #endif