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.

989 lines
29 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. gc.c
  5. Abstract:
  6. Gopher client test program
  7. Basically a real console-mode (win32) gopher client that uses the gopher
  8. client APIs
  9. Contents:
  10. Author:
  11. Richard L Firth (rfirth) 08-Nov-1994
  12. Environment:
  13. Win32 console mode user executable
  14. Revision History:
  15. 08-Nov-1994 rfirth
  16. Created
  17. --*/
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <windows.h>
  21. #include <wininet.h>
  22. #include <wininetd.h>
  23. #include <string.h>
  24. #include <malloc.h>
  25. #include <ctype.h>
  26. #include <fcntl.h>
  27. #include <io.h>
  28. #include <catlib.h>
  29. #ifndef _CRTAPI1
  30. #define _CRTAPI1
  31. #endif
  32. #define IS_ARG(c) (((c) == '-') || ((c) == '/'))
  33. //
  34. // manifests
  35. //
  36. #define HOME -1
  37. #define GC_CONNECT_CONTEXT 0x47474747
  38. #define GC_FIND_CONTEXT 0x47474644
  39. #define GC_FILE_CONTEXT 0x47474645
  40. //
  41. // prototypes
  42. //
  43. void _CRTAPI1 main(int, char**);
  44. void usage(void);
  45. void _CRTAPI1 my_cleanup(void);
  46. void gopher(LPSTR, WORD, CHAR, LPSTR);
  47. BOOL get_dir(LPSTR, LPSTR);
  48. void get_file(LPSTR);
  49. int get_user_request(LPSTR);
  50. void clear_items(void);
  51. void my_callback(HINTERNET, DWORD, DWORD, LPVOID, DWORD);
  52. void print_error(char*, char*, ...);
  53. char hex_to_char(char);
  54. char* decontrol(char*, char*);
  55. void toodle_pip(void);
  56. //
  57. // global data
  58. //
  59. BOOL Verbose = FALSE;
  60. BOOL MakeRequestGopherPlus = FALSE;
  61. HINTERNET InetHandle = NULL;
  62. HINTERNET hGopherSession = NULL;
  63. BOOL NewHome = FALSE;
  64. INTERNET_STATUS_CALLBACK PreviousCallback;
  65. BOOL AsyncMode = FALSE;
  66. HANDLE AsyncEvent = NULL;
  67. DWORD AsyncResult;
  68. DWORD AsyncError;
  69. DWORD CacheFlags = 0;
  70. BOOL UseQueryData = FALSE;
  71. DWORD UserContext = 0;
  72. BOOL UseUserContext = FALSE;
  73. //
  74. // functions
  75. //
  76. void _CRTAPI1 main(int argc, char** argv) {
  77. LPSTR server = NULL;
  78. LPSTR selector = NULL;
  79. WORD port = 70;
  80. BOOL fCallback = FALSE;
  81. char selectorType = '1';
  82. DWORD accessMethod = PRE_CONFIG_INTERNET_ACCESS;
  83. BOOL expectingProxy = FALSE;
  84. LPSTR proxyServer = NULL;
  85. for (--argc, ++argv; argc; --argc, ++argv) {
  86. if (IS_ARG(**argv)) {
  87. switch (*++*argv) {
  88. case '?':
  89. usage();
  90. break;
  91. case '+':
  92. MakeRequestGopherPlus = TRUE;
  93. break;
  94. case 'a':
  95. ++*argv;
  96. if (**argv == 'l') {
  97. accessMethod = INTERNET_OPEN_TYPE_DIRECT;
  98. } else if (**argv == 'p') {
  99. accessMethod = INTERNET_OPEN_TYPE_PROXY;
  100. if (*++*argv) {
  101. proxyServer = *argv;
  102. } else {
  103. expectingProxy = TRUE;
  104. }
  105. } else {
  106. printf("error: unrecognised access type: '%c'\n", **argv);
  107. usage();
  108. }
  109. break;
  110. case 'c':
  111. fCallback = TRUE;
  112. break;
  113. case 'n':
  114. CacheFlags |= INTERNET_FLAG_DONT_CACHE;
  115. break;
  116. case 'p':
  117. port = atoi(++*argv);
  118. break;
  119. case 'q':
  120. UseQueryData = TRUE;
  121. break;
  122. case 't':
  123. selectorType = *++*argv;
  124. break;
  125. case 'v':
  126. Verbose = TRUE;
  127. break;
  128. case 'x':
  129. UseUserContext = TRUE;
  130. if (*++*argv) {
  131. UserContext = (DWORD)strtoul(*argv, NULL, 0);
  132. }
  133. break;
  134. case 'y':
  135. AsyncMode = TRUE;
  136. break;
  137. default:
  138. printf("unknown command line flag: '%c'\n", **argv);
  139. usage();
  140. }
  141. } else if (expectingProxy) {
  142. proxyServer = *argv;
  143. expectingProxy = FALSE;
  144. } else if (!server) {
  145. server = *argv;
  146. } else if (!selector) {
  147. selector = *argv;
  148. } else {
  149. printf("unknown command line argument: \"%s\"\n", *argv);
  150. usage();
  151. }
  152. }
  153. if (!server) {
  154. usage();
  155. }
  156. //
  157. // exit function
  158. //
  159. atexit(my_cleanup);
  160. if (AsyncMode) {
  161. //
  162. // create an auto-reset, initially unsignalled event
  163. //
  164. AsyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  165. if (!AsyncEvent) {
  166. print_error("gc", "CreateEvent()");
  167. exit(1);
  168. }
  169. }
  170. //
  171. // open gateway
  172. //
  173. InetHandle = InternetOpen("gc",
  174. accessMethod,
  175. proxyServer,
  176. NULL,
  177. AsyncMode ? INTERNET_FLAG_ASYNC : 0
  178. );
  179. if (InetHandle == NULL) {
  180. print_error("gc", "InternetOpen()");
  181. exit(1);
  182. }
  183. if (fCallback) {
  184. //
  185. // let's have a status callback
  186. //
  187. PreviousCallback = InternetSetStatusCallback(InetHandle, my_callback);
  188. if (Verbose) {
  189. printf("previous Internet callback = %x\n", PreviousCallback);
  190. }
  191. }
  192. hGopherSession = InternetConnect(InetHandle,
  193. server,
  194. 0,
  195. NULL,
  196. NULL,
  197. INTERNET_SERVICE_GOPHER,
  198. 0,
  199. UseUserContext ? UserContext : GC_CONNECT_CONTEXT
  200. );
  201. if (AsyncMode && (hGopherSession == NULL)) {
  202. if (GetLastError() != ERROR_IO_PENDING) {
  203. print_error("gc", "InternetConnect()");
  204. exit(1);
  205. } else {
  206. if (Verbose) {
  207. printf("Waiting for async InternetConnect()\n");
  208. }
  209. WaitForSingleObject(AsyncEvent, INFINITE);
  210. hGopherSession = (HINTERNET)AsyncResult;
  211. SetLastError(AsyncError);
  212. }
  213. }
  214. if (hGopherSession == NULL) {
  215. print_error("gc", "InternetConnect()");
  216. exit(1);
  217. }
  218. gopher(server, port, selectorType, selector);
  219. if (Verbose) {
  220. printf("closing InternetConnect handle %x\n", hGopherSession);
  221. }
  222. if (!InternetCloseHandle(hGopherSession)) {
  223. print_error("gc", "InternetCloseHandle(%#x)", hGopherSession);
  224. } else {
  225. hGopherSession = NULL;
  226. }
  227. if (Verbose) {
  228. printf("closing InternetOpen handle %x\n", InetHandle);
  229. }
  230. if (!InternetCloseHandle(InetHandle)) {
  231. print_error("gc", "InternetCloseHandle(%#x)", InetHandle);
  232. } else {
  233. InetHandle = NULL;
  234. }
  235. toodle_pip();
  236. exit(0);
  237. }
  238. void toodle_pip() {
  239. static LPSTR intl[] = {
  240. "Goodbye",
  241. "Au revoir",
  242. "Auf wiederzehen",
  243. "Cheers",
  244. "Ciao"
  245. };
  246. srand(GetTickCount());
  247. printf("%s.\n", intl[rand() % (sizeof(intl) / sizeof(intl[0]))]);
  248. }
  249. void usage() {
  250. printf("\n"
  251. "usage: gc [-+] [-a{l|p[ ]proxy}] [-c] [-p#] [-n] [-v] [-y] [-q] [-t<char>]\n"
  252. " [-x#] [selector] <server>\n"
  253. "\n"
  254. "where: -+ = First request is gopher+\n"
  255. " -a = Access type. Default is pre-configured:\n"
  256. " l = direct internet access\n"
  257. " p = proxy access\n"
  258. " -c = Enable status callbacks\n"
  259. " -n = Don't cache\n"
  260. " -p = Port number to connect to at <server>. Default is 70\n"
  261. " -q = use InternetQueryDataAvailable\n"
  262. " -t = Selector type character, e.g. -t9 for binary file. Default is dir\n"
  263. " -v = Verbose mode\n"
  264. " -x = Context value. # is number to use as context\n"
  265. " -y = Asynchronous APIs\n"
  266. );
  267. exit(1);
  268. }
  269. void _CRTAPI1 my_cleanup() {
  270. if (hGopherSession != NULL) {
  271. printf("closing InternetConnect handle %x\n", hGopherSession);
  272. if (!InternetCloseHandle(hGopherSession)) {
  273. print_error("my_cleanup", "InternetCloseHandle(%#x)", hGopherSession);
  274. }
  275. }
  276. if (InetHandle != NULL) {
  277. printf("closing InternetOpen handle %x\n", InetHandle);
  278. if (!InternetCloseHandle(InetHandle)) {
  279. print_error("my_cleanup", "InternetCloseHandle(%#x)", InetHandle);
  280. }
  281. }
  282. }
  283. char HomeLocator[MAX_GOPHER_SELECTOR_TEXT];
  284. typedef struct {
  285. LPSTR display_string;
  286. LPSTR locator;
  287. } GINFO;
  288. GINFO items[4096];
  289. int nitems = 0;
  290. void gopher(LPSTR server, WORD port, CHAR selectorType, LPSTR selector) {
  291. LPSTR request = "";
  292. char locator[MAX_GOPHER_SELECTOR_TEXT];
  293. DWORD len;
  294. BOOL done = FALSE;
  295. HINTERNET h;
  296. BOOL unknownType;
  297. DWORD gopherType;
  298. //
  299. // if the user supplied a gopher type character then create a default
  300. // text locator, then change the type (evil!). Otherwise, the default
  301. // is directory
  302. //
  303. gopherType = selector ? GOPHER_TYPE_TEXT_FILE : GOPHER_TYPE_DIRECTORY;
  304. if (MakeRequestGopherPlus) {
  305. gopherType |= GOPHER_TYPE_GOPHER_PLUS;
  306. }
  307. len = sizeof(HomeLocator);
  308. if (!GopherCreateLocator(server,
  309. port,
  310. NULL,
  311. selector,
  312. gopherType,
  313. locator,
  314. &len
  315. )) {
  316. print_error("gopher", "GopherCreateLocator()");
  317. return;
  318. }
  319. if (selector) {
  320. *locator = selectorType;
  321. }
  322. NewHome = TRUE;
  323. while (!done) {
  324. DWORD gopherType;
  325. unknownType = FALSE;
  326. if (!GopherGetLocatorType(locator, &gopherType)) {
  327. print_error("gopher", "GopherGetLocatorType()");
  328. exit(1);
  329. }
  330. if (gopherType & GOPHER_TYPE_DIRECTORY) {
  331. if (get_dir(locator, NULL)) {
  332. if (NewHome) {
  333. strcpy(HomeLocator, locator);
  334. NewHome = FALSE;
  335. }
  336. }
  337. } else if (gopherType & GOPHER_TYPE_FILE_MASK) {
  338. get_file(locator);
  339. } else {
  340. if (gopherType & GOPHER_TYPE_INDEX_SERVER) {
  341. char searchBuf[256];
  342. printf("\nEnter Text To Search For: ");
  343. gets(searchBuf);
  344. get_dir(locator, searchBuf);
  345. } else {
  346. unknownType = TRUE;
  347. }
  348. }
  349. if (unknownType) {
  350. char dcbuf[1024];
  351. printf("error: gopher: locator %s is unknown type\n",
  352. decontrol(locator, dcbuf)
  353. );
  354. return;
  355. }
  356. done = get_user_request(locator) == 0;
  357. }
  358. }
  359. char CurrentDirLocator[256];
  360. BOOL get_dir(LPSTR locator, LPSTR search) {
  361. HINTERNET h;
  362. GOPHER_FIND_DATA data;
  363. DWORD error;
  364. h = GopherFindFirstFile(hGopherSession,
  365. locator,
  366. search,
  367. &data,
  368. CacheFlags, // dwFlags
  369. UseUserContext ? UserContext : GC_FIND_CONTEXT
  370. );
  371. if (AsyncMode && (h == NULL)) {
  372. error = GetLastError();
  373. if (error == ERROR_IO_PENDING) {
  374. if (Verbose) {
  375. printf("waiting for async GopherFindFirstFile()...\n");
  376. }
  377. WaitForSingleObject(AsyncEvent, INFINITE);
  378. h = (HINTERNET)AsyncResult;
  379. error = AsyncError;
  380. }
  381. if (h == NULL) {
  382. SetLastError(error);
  383. }
  384. }
  385. if (h != NULL) {
  386. LPGOPHER_FIND_DATA p = (LPGOPHER_FIND_DATA)&data;
  387. SYSTEMTIME systemTime;
  388. int i = 0;
  389. char timeBuf[9];
  390. char sizeBuf[32];
  391. BOOL ok;
  392. clear_items();
  393. strcpy(CurrentDirLocator, locator);
  394. do {
  395. items[i].display_string = _strdup(p->DisplayString);
  396. items[i].locator = _strdup(p->Locator);
  397. ++i;
  398. if ((p->LastModificationTime.dwLowDateTime != 0)
  399. && (p->LastModificationTime.dwHighDateTime != 0)) {
  400. FileTimeToSystemTime(&p->LastModificationTime, &systemTime);
  401. sprintf(timeBuf,
  402. "%02d-%02d-%02d",
  403. systemTime.wMonth,
  404. systemTime.wDay,
  405. systemTime.wYear % 100
  406. );
  407. sprintf(sizeBuf, "%d", p->SizeLow);
  408. } else {
  409. timeBuf[0] = '\0';
  410. sizeBuf[0] = '\0';
  411. }
  412. printf("%5d %c %7s %10s %8s %s\n",
  413. i,
  414. (p->GopherType & GOPHER_TYPE_GOPHER_PLUS) ? '+' : ' ',
  415. (p->GopherType & GOPHER_TYPE_TEXT_FILE) ? "Text"
  416. : (p->GopherType & GOPHER_TYPE_DIRECTORY) ? "Dir"
  417. : (p->GopherType & GOPHER_TYPE_CSO) ? "Phone"
  418. : (p->GopherType & GOPHER_TYPE_ERROR) ? "Error"
  419. : (p->GopherType & GOPHER_TYPE_MAC_BINHEX) ? "MAC"
  420. : (p->GopherType & GOPHER_TYPE_DOS_ARCHIVE) ? "Archive"
  421. : (p->GopherType & GOPHER_TYPE_UNIX_UUENCODED) ? "UNIX"
  422. : (p->GopherType & GOPHER_TYPE_INDEX_SERVER) ? "Index"
  423. : (p->GopherType & GOPHER_TYPE_TELNET) ? "Telnet"
  424. : (p->GopherType & GOPHER_TYPE_BINARY) ? "Binary"
  425. : (p->GopherType & GOPHER_TYPE_REDUNDANT) ? "Backup"
  426. : (p->GopherType & GOPHER_TYPE_TN3270) ? "TN3270"
  427. : (p->GopherType & GOPHER_TYPE_GIF) ? "GIF"
  428. : (p->GopherType & GOPHER_TYPE_IMAGE) ? "Image"
  429. : (p->GopherType & GOPHER_TYPE_BITMAP) ? "Bitmap"
  430. : (p->GopherType & GOPHER_TYPE_MOVIE) ? "Movie"
  431. : (p->GopherType & GOPHER_TYPE_SOUND) ? "Sound"
  432. : (p->GopherType & GOPHER_TYPE_HTML) ? "HTML"
  433. : (p->GopherType & GOPHER_TYPE_PDF) ? "PDF"
  434. : (p->GopherType & GOPHER_TYPE_CALENDAR) ? "Cal"
  435. : (p->GopherType & GOPHER_TYPE_INLINE) ? "Inline"
  436. : (p->GopherType & GOPHER_TYPE_UNKNOWN) ? "Unknown"
  437. : "\a????",
  438. sizeBuf,
  439. timeBuf,
  440. p->DisplayString
  441. );
  442. if (UseQueryData) {
  443. DWORD avail;
  444. ok = InternetQueryDataAvailable(h, &avail, 0, 0);
  445. if (!ok) {
  446. error = GetLastError();
  447. if (error == ERROR_IO_PENDING) {
  448. if (Verbose) {
  449. printf("waiting for async InternetQueryDataAvailable()...\n");
  450. }
  451. WaitForSingleObject(AsyncEvent, INFINITE);
  452. ok = (BOOL)AsyncResult;
  453. SetLastError(AsyncError);
  454. }
  455. }
  456. if (ok) {
  457. if (Verbose) {
  458. printf("%sSYNC IQDA(): %d available\n", AsyncMode ? "A" : "", avail);
  459. }
  460. } else {
  461. print_error("get_dir()", "InternetQueryDataAvailable()");
  462. break;
  463. }
  464. }
  465. ok = InternetFindNextFile(h, (LPGOPHER_FIND_DATA)&data);
  466. if (AsyncMode && !ok) {
  467. error = GetLastError();
  468. if (error == ERROR_IO_PENDING) {
  469. if (Verbose) {
  470. printf("waiting for async InternetFindNextFile()...\n");
  471. }
  472. WaitForSingleObject(AsyncEvent, INFINITE);
  473. ok = (BOOL)AsyncResult;
  474. error = AsyncError;
  475. }
  476. SetLastError(error);
  477. }
  478. } while (ok);
  479. if (GetLastError() != ERROR_NO_MORE_FILES) {
  480. print_error("get_dir", "InternetFindNextFile()");
  481. }
  482. nitems = i;
  483. if (Verbose) {
  484. printf("closing Find handle %x\n", h);
  485. }
  486. if (!InternetCloseHandle(h)) {
  487. print_error("get_dir", "InternetCloseHandle(%#x)", h);
  488. }
  489. return TRUE;
  490. } else {
  491. print_error("get_dir", "GopherFindFirstFile()");
  492. return FALSE;
  493. }
  494. }
  495. void get_file(LPSTR locator) {
  496. HINTERNET h;
  497. char buf[4096];
  498. DWORD error;
  499. h = GopherOpenFile(hGopherSession,
  500. locator,
  501. NULL,
  502. CacheFlags,
  503. UseUserContext ? UserContext : GC_FILE_CONTEXT
  504. );
  505. if (AsyncMode && (h == NULL)) {
  506. error = GetLastError();
  507. if (error == ERROR_IO_PENDING) {
  508. if (Verbose) {
  509. printf("waiting for async GopherOpenFile()...\n");
  510. }
  511. WaitForSingleObject(AsyncEvent, INFINITE);
  512. h = (HINTERNET)AsyncResult;
  513. error = AsyncError;
  514. }
  515. SetLastError(error);
  516. }
  517. if (h == NULL) {
  518. print_error("get_file", "GopherOpenFile()");
  519. } else {
  520. DWORD nread;
  521. BOOL ok;
  522. DWORD avail;
  523. do {
  524. if (UseQueryData) {
  525. ok = InternetQueryDataAvailable(h, &avail, 0, 0);
  526. if (!ok) {
  527. error = GetLastError();
  528. if (error == ERROR_IO_PENDING) {
  529. if (Verbose) {
  530. printf("waiting for async InternetQueryDataAvailable()...\n");
  531. }
  532. WaitForSingleObject(AsyncEvent, INFINITE);
  533. ok = (BOOL)AsyncResult;
  534. SetLastError(AsyncError);
  535. }
  536. }
  537. if (ok) {
  538. if (Verbose) {
  539. printf("%sSYNC IQDA(): %d available\n", AsyncMode ? "A" : "", avail);
  540. }
  541. } else {
  542. print_error("get_dir()", "InternetQueryDataAvailable()");
  543. break;
  544. }
  545. } else {
  546. avail = sizeof(buf);
  547. }
  548. avail = min(avail, sizeof(buf));
  549. if (avail == 0) {
  550. break;
  551. }
  552. ok = InternetReadFile(h, buf, avail, &nread);
  553. if (!ok && AsyncMode) {
  554. error = GetLastError();
  555. if (error == ERROR_IO_PENDING) {
  556. if (Verbose) {
  557. printf("waiting for async InternetReadFile()...\n");
  558. }
  559. WaitForSingleObject(AsyncEvent, INFINITE);
  560. ok = (BOOL)AsyncResult;
  561. error = AsyncError;
  562. }
  563. SetLastError(error);
  564. }
  565. if (ok) {
  566. if (!nread) {
  567. printf("=== end of file ===\n");
  568. break;
  569. } else {
  570. _setmode(1, _O_BINARY);
  571. _write(1, buf, nread);
  572. }
  573. }
  574. } while (ok);
  575. if (!ok) {
  576. error = GetLastError();
  577. if (error != ERROR_SUCCESS) {
  578. print_error("get_file", "InternetReadFile()");
  579. }
  580. }
  581. if (Verbose) {
  582. printf("closing File handle %x\n", h);
  583. }
  584. if (!InternetCloseHandle(h)) {
  585. print_error("get_file", "InternetCloseHandle(%#x)", h);
  586. }
  587. }
  588. }
  589. int get_user_request(LPSTR locator) {
  590. int n;
  591. char buf[80];
  592. BOOL got = FALSE;
  593. char newLocator[256];
  594. char serverBuf[80];
  595. char portBuf[32];
  596. DWORD len = sizeof(newLocator);
  597. int i;
  598. BOOL ok;
  599. DWORD handles;
  600. DWORD size_handles;
  601. while (!got) {
  602. printf("\nEnter selection: ");
  603. gets(buf);
  604. if (isdigit(buf[0])) {
  605. n = atoi(buf);
  606. if (n >= 1 && n <= nitems) {
  607. strcpy(locator, items[n - 1].locator);
  608. got = TRUE;
  609. } else {
  610. printf("\n"
  611. "error: must enter number in the range 1 to %d\n", nitems);
  612. }
  613. } else {
  614. switch (buf[0]) {
  615. case '+':
  616. printf("NYI\n");
  617. break;
  618. case '.':
  619. strcpy(locator, CurrentDirLocator);
  620. got = TRUE;
  621. break;
  622. case 'g':
  623. for (i = 1; buf[i] && isspace(buf[i]); ) {
  624. ++i;
  625. }
  626. if (buf[i]) {
  627. int j = 0;
  628. while (buf[i] && !isspace(buf[i])) {
  629. serverBuf[j++] = buf[i++];
  630. }
  631. serverBuf[j] = 0;
  632. while (buf[i] && isspace(buf[i])) {
  633. ++i;
  634. }
  635. } else {
  636. printf("server: ");
  637. gets(serverBuf);
  638. }
  639. if (buf[i]) {
  640. int j = 0;
  641. while (buf[i] && !isspace(buf[i])) {
  642. portBuf[j++] = buf[i++];
  643. }
  644. portBuf[j] = 0;
  645. } else {
  646. printf("port: ");
  647. gets(portBuf);
  648. }
  649. if (!GopherCreateLocator(serverBuf,
  650. (WORD)atoi(portBuf),
  651. NULL,
  652. NULL,
  653. GOPHER_TYPE_DIRECTORY,
  654. newLocator,
  655. &len
  656. )) {
  657. print_error("get_user_request", "GopherCreateLocator()");
  658. } else {
  659. strcpy(locator, newLocator);
  660. got = TRUE;
  661. }
  662. NewHome = TRUE;
  663. break;
  664. case 'h':
  665. n = HOME;
  666. strcpy(locator, HomeLocator);
  667. got = TRUE;
  668. break;
  669. case 'l':
  670. size_handles = sizeof(handles);
  671. ok = InternetQueryOption(NULL,
  672. INTERNET_OPTION_GET_HANDLE_COUNT,
  673. (LPVOID)&handles,
  674. &size_handles
  675. );
  676. if (!ok) {
  677. print_error("get_user_request", "InternetQueryOption(handle count)");
  678. } else {
  679. printf("current handle count = %d\n", handles);
  680. }
  681. break;
  682. case 'q':
  683. toodle_pip();
  684. exit(0);
  685. case 's':
  686. PreviousCallback = InternetSetStatusCallback(InetHandle,
  687. PreviousCallback
  688. );
  689. if (Verbose) {
  690. printf("previous Internet callback = %x\n", PreviousCallback);
  691. }
  692. if ((PreviousCallback != NULL) && (PreviousCallback != my_callback)) {
  693. printf("error: get_gopher_request: previous callback not recognised\n");
  694. }
  695. got = TRUE;
  696. break;
  697. case 'v':
  698. Verbose = !Verbose;
  699. printf("verbose mode %s\n", Verbose ? "on" : "off");
  700. break;
  701. default:
  702. printf("\n"
  703. "enter the number of your selection or one of the following:\n"
  704. "\n"
  705. "\t+ = toggle gopher+\n"
  706. "\t. = list current directory\n"
  707. "\tg = go to new server\n"
  708. "\th = list home directory\n"
  709. "\t1 = display handle usage\n"
  710. "\tq = quit\n"
  711. "\ts = toggle status callback\n"
  712. "\tv = toggle verbose mode\n"
  713. );
  714. }
  715. }
  716. }
  717. putchar('\n');
  718. return n;
  719. }
  720. void clear_items() {
  721. while (nitems) {
  722. --nitems;
  723. free(items[nitems].display_string);
  724. free(items[nitems].locator);
  725. }
  726. }
  727. VOID
  728. my_callback(
  729. HINTERNET Handle,
  730. DWORD Context,
  731. DWORD Status,
  732. LPVOID Info,
  733. DWORD Length
  734. )
  735. {
  736. char* type$;
  737. switch (Status) {
  738. case INTERNET_STATUS_RESOLVING_NAME:
  739. type$ = "RESOLVING NAME";
  740. break;
  741. case INTERNET_STATUS_NAME_RESOLVED:
  742. type$ = "NAME RESOLVED";
  743. break;
  744. case INTERNET_STATUS_CONNECTING_TO_SERVER:
  745. type$ = "CONNECTING TO SERVER";
  746. break;
  747. case INTERNET_STATUS_CONNECTED_TO_SERVER:
  748. type$ = "CONNECTED TO SERVER";
  749. break;
  750. case INTERNET_STATUS_SENDING_REQUEST:
  751. type$ = "SENDING REQUEST";
  752. break;
  753. case INTERNET_STATUS_REQUEST_SENT:
  754. type$ = "REQUEST SENT";
  755. break;
  756. case INTERNET_STATUS_RECEIVING_RESPONSE:
  757. type$ = "RECEIVING RESPONSE";
  758. break;
  759. case INTERNET_STATUS_RESPONSE_RECEIVED:
  760. type$ = "RESPONSE RECEIVED";
  761. break;
  762. case INTERNET_STATUS_CLOSING_CONNECTION:
  763. type$ = "CLOSING CONNECTION";
  764. break;
  765. case INTERNET_STATUS_CONNECTION_CLOSED:
  766. type$ = "CONNECTION CLOSED";
  767. break;
  768. case INTERNET_STATUS_HANDLE_CREATED:
  769. type$ = "HANDLE CREATED";
  770. break;
  771. case INTERNET_STATUS_HANDLE_CLOSING:
  772. type$ = "HANDLE CLOSING";
  773. break;
  774. case INTERNET_STATUS_REQUEST_COMPLETE:
  775. type$ = "REQUEST COMPLETE";
  776. AsyncResult = ((LPINTERNET_ASYNC_RESULT)Info)->dwResult;
  777. AsyncError = ((LPINTERNET_ASYNC_RESULT)Info)->dwError;
  778. break;
  779. default:
  780. type$ = "???";
  781. break;
  782. }
  783. if (Verbose) {
  784. printf("callback: handle %x [context %x [%s]] %s ",
  785. Handle,
  786. Context,
  787. (Context == GC_CONNECT_CONTEXT) ? "Connect"
  788. : (Context == GC_FIND_CONTEXT) ? "Find"
  789. : (Context == GC_FILE_CONTEXT) ? "File"
  790. : "???",
  791. type$
  792. );
  793. if (Info) {
  794. if ((Status == INTERNET_STATUS_HANDLE_CREATED)
  795. || (Status == INTERNET_STATUS_HANDLE_CLOSING)) {
  796. printf("%x", *(LPHINTERNET)Info);
  797. } else if (Length == sizeof(DWORD)) {
  798. printf("%d", *(LPDWORD)Info);
  799. } else if (Status != INTERNET_STATUS_REQUEST_COMPLETE) {
  800. printf(Info);
  801. }
  802. }
  803. putchar('\n');
  804. }
  805. if (Status == INTERNET_STATUS_REQUEST_COMPLETE) {
  806. if (AsyncMode) {
  807. SetEvent(AsyncEvent);
  808. } else {
  809. printf("error: INTERNET_STATUS_REQUEST_COMPLETE received when not async\n");
  810. }
  811. }
  812. }
  813. char hex_to_char(char b) {
  814. return (b <= 9) ? (b + '0') : ((b - 10) + 'a');
  815. }
  816. char* decontrol(char* instr, char* outstr) {
  817. char* outp;
  818. for (outp = outstr; *instr; ++instr) {
  819. if (*instr < 0x20) {
  820. *outp++ = '\\';
  821. switch (*instr) {
  822. case '\t':
  823. *outp++ = 't';
  824. break;
  825. case '\r':
  826. *outp++ = 'r';
  827. break;
  828. case '\n':
  829. *outp++ = 'n';
  830. break;
  831. default:
  832. *outp++ = 'x';
  833. *outp++ = hex_to_char((char)(*instr >> 4));
  834. *outp++ = hex_to_char((char)(*instr & 15));
  835. }
  836. } else {
  837. *outp++ = *instr;
  838. }
  839. }
  840. *outp = 0;
  841. return outstr;
  842. }