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.

1013 lines
23 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. TODO: cmntool.c
  5. Abstract:
  6. <TODO: fill in abstract>
  7. Author:
  8. TODO: <full name> (<alias>) <date>
  9. Revision History:
  10. <full name> (<alias>) <date> <comments>
  11. --*/
  12. #include "pch.h"
  13. #include "resource.h"
  14. #include <wininet.h>
  15. typedef enum {
  16. DOWNLOAD_CONNECTING,
  17. DOWNLOAD_GETTING_FILE,
  18. DOWNLOAD_DISCONNECTING
  19. } DOWNLOADSTATE;
  20. typedef HINTERNET (WINAPI * INTERNETOPEN) (
  21. IN LPCSTR lpszAgent,
  22. IN DWORD dwAccessType,
  23. IN LPCSTR lpszProxyName,
  24. IN LPCSTR lpszProxyBypass,
  25. IN DWORD dwFlags
  26. );
  27. typedef BOOL (WINAPI * INTERNETCLOSEHANDLE) (
  28. IN HINTERNET Handle
  29. );
  30. typedef HINTERNET (WINAPI * INTERNETOPENURL) (
  31. IN HINTERNET hInternetSession,
  32. IN LPCSTR lpszUrl,
  33. IN LPCSTR lpszHeaders,
  34. IN DWORD dwHeadersLength,
  35. IN DWORD dwFlags,
  36. IN DWORD dwContext
  37. );
  38. typedef BOOL (WINAPI * INTERNETREADFILE) (
  39. IN HINTERNET hFile,
  40. IN LPVOID lpBuffer,
  41. IN DWORD dwNumberOfBytesToRead,
  42. OUT LPDWORD lpNumberOfBytesRead
  43. );
  44. typedef BOOL (WINAPI * INTERNETCANONICALIZEURLA) (
  45. IN LPCSTR lpszUrl,
  46. OUT LPSTR lpszBuffer,
  47. IN OUT LPDWORD lpdwBufferLength,
  48. IN DWORD dwFlags
  49. );
  50. typedef DWORD (WINAPI * INTERNETSETFILEPOINTER) (
  51. IN HINTERNET hFile,
  52. IN LONG lDistanceToMove,
  53. IN PVOID pReserved,
  54. IN DWORD dwMoveMethod,
  55. IN DWORD dwContext
  56. );
  57. typedef BOOL (WINAPI * INTERNETHANGUP) (
  58. IN DWORD dwConnection,
  59. IN DWORD dwReserved
  60. );
  61. typedef DWORD (WINAPI * INTERNETDIALA) (
  62. IN HWND hwndParent,
  63. IN PCSTR lpszConnectoid,
  64. IN DWORD dwFlags,
  65. OUT LPDWORD lpdwConnection,
  66. IN DWORD dwReserved
  67. );
  68. static HINSTANCE g_Lib;
  69. static INTERNETOPEN g_InternetOpenA;
  70. static INTERNETCLOSEHANDLE g_InternetCloseHandle;
  71. static INTERNETOPENURL g_InternetOpenUrlA;
  72. static INTERNETREADFILE g_InternetReadFile;
  73. static INTERNETCANONICALIZEURLA g_InternetCanonicalizeUrlA;
  74. static INTERNETSETFILEPOINTER g_InternetSetFilePointer;
  75. static INTERNETDIALA g_InternetDialA;
  76. static INTERNETHANGUP g_InternetHangUp;
  77. static BOOL g_Dialed;
  78. static DWORD g_Cxn;
  79. HANDLE g_hHeap;
  80. HINSTANCE g_hInst;
  81. BOOL WINAPI MigUtil_Entry (HINSTANCE, DWORD, PVOID);
  82. PCSTR g_AppName = TEXT("FTP Download Engine");
  83. //PCSTR g_DirFile = TEXT("ftp://jimschm-dev/upgdir.inf");
  84. PCSTR g_DirFile = TEXT("file://popcorn/public/jimschm/upgdir.inf");
  85. BOOL
  86. DownloadUpdates (
  87. HANDLE CancelEvent, OPTIONAL
  88. HANDLE WantToRetryEvent, OPTIONAL
  89. HANDLE OkToRetryEvent, OPTIONAL
  90. PCSTR *Url OPTIONAL
  91. );
  92. BOOL
  93. pDownloadUpdatesWithUi (
  94. VOID
  95. );
  96. BOOL
  97. pCallEntryPoints (
  98. DWORD Reason
  99. )
  100. {
  101. HINSTANCE Instance;
  102. //
  103. // Simulate DllMain
  104. //
  105. Instance = g_hInst;
  106. //
  107. // Initialize the common libs
  108. //
  109. if (!MigUtil_Entry (Instance, Reason, NULL)) {
  110. return FALSE;
  111. }
  112. //
  113. // TODO: Add others here if needed (don't forget to prototype above)
  114. //
  115. return TRUE;
  116. }
  117. BOOL
  118. Init (
  119. VOID
  120. )
  121. {
  122. g_hHeap = GetProcessHeap();
  123. g_hInst = GetModuleHandle (NULL);
  124. return pCallEntryPoints (DLL_PROCESS_ATTACH);
  125. }
  126. VOID
  127. Terminate (
  128. VOID
  129. )
  130. {
  131. pCallEntryPoints (DLL_PROCESS_DETACH);
  132. }
  133. VOID
  134. HelpAndExit (
  135. VOID
  136. )
  137. {
  138. //
  139. // This routine is called whenever command line args are wrong
  140. //
  141. _ftprintf (
  142. stderr,
  143. TEXT("Command Line Syntax:\n\n")
  144. //
  145. // TODO: Describe command line syntax(es), indent 2 spaces
  146. //
  147. TEXT(" cmntool [/F:file]\n")
  148. TEXT("\nDescription:\n\n")
  149. //
  150. // TODO: Describe tool, indent 2 spaces
  151. //
  152. TEXT(" cmntool is a stub!\n")
  153. TEXT("\nArguments:\n\n")
  154. //
  155. // TODO: Describe args, indent 2 spaces, say optional if necessary
  156. //
  157. TEXT(" /F Specifies optional file name\n")
  158. );
  159. exit (1);
  160. }
  161. INT
  162. __cdecl
  163. _tmain (
  164. INT argc,
  165. PCTSTR argv[]
  166. )
  167. {
  168. INT i;
  169. PCTSTR FileArg;
  170. //
  171. // TODO: Parse command line here
  172. //
  173. for (i = 1 ; i < argc ; i++) {
  174. if (argv[i][0] == TEXT('/') || argv[i][0] == TEXT('-')) {
  175. switch (_totlower (_tcsnextc (&argv[i][1]))) {
  176. case TEXT('f'):
  177. //
  178. // Sample option - /f:file
  179. //
  180. if (argv[i][2] == TEXT(':')) {
  181. FileArg = &argv[i][3];
  182. } else if (i + 1 < argc) {
  183. FileArg = argv[++i];
  184. } else {
  185. HelpAndExit();
  186. }
  187. break;
  188. default:
  189. HelpAndExit();
  190. }
  191. } else {
  192. //
  193. // Parse other args that don't require / or -
  194. //
  195. // None
  196. HelpAndExit();
  197. }
  198. }
  199. //
  200. // Begin processing
  201. //
  202. if (!Init()) {
  203. return 0;
  204. }
  205. //
  206. // TODO: Do work here
  207. //
  208. pDownloadUpdatesWithUi();
  209. //
  210. // End of processing
  211. //
  212. Terminate();
  213. return 0;
  214. }
  215. typedef struct {
  216. HANDLE CancelEvent;
  217. HANDLE WantToRetryEvent;
  218. HANDLE OkToRetryEvent;
  219. HANDLE CloseEvent;
  220. PCSTR Url;
  221. } EVENTSTRUCT, *PEVENTSTRUCT;
  222. BOOL
  223. CALLBACK
  224. pUiDlgProc (
  225. HWND hdlg,
  226. UINT msg,
  227. WPARAM wParam,
  228. LPARAM lParam
  229. )
  230. {
  231. static PEVENTSTRUCT eventStruct;
  232. static UINT retries;
  233. DWORD rc;
  234. CHAR lastUrl[256];
  235. CHAR text[256];
  236. switch (msg) {
  237. case WM_INITDIALOG:
  238. eventStruct = (PEVENTSTRUCT) lParam;
  239. retries = 0;
  240. lastUrl[0] = 0;
  241. SetTimer (hdlg, 1, 100, NULL);
  242. break;
  243. case WM_COMMAND:
  244. switch (LOWORD(wParam)) {
  245. case IDCANCEL:
  246. ShowWindow (GetDlgItem (hdlg, IDC_MSG2), SW_HIDE);
  247. ShowWindow (GetDlgItem (hdlg, IDC_URL), SW_HIDE);
  248. ShowWindow (GetDlgItem (hdlg, IDC_RETRIES), SW_HIDE);
  249. SetDlgItemTextA (hdlg, IDC_MSG1, "Stopping download...");
  250. SetFocus (GetDlgItem (hdlg, IDC_MSG1));
  251. EnableWindow (GetDlgItem (hdlg, IDCANCEL), FALSE);
  252. SetEvent (eventStruct->CancelEvent);
  253. break;
  254. }
  255. break;
  256. case WM_TIMER:
  257. //
  258. // Check the events
  259. //
  260. rc = WaitForSingleObject (eventStruct->WantToRetryEvent, 0);
  261. if (rc == WAIT_OBJECT_0) {
  262. //
  263. // A download failed. Try again?
  264. //
  265. if (StringCompareA (lastUrl, eventStruct->Url)) {
  266. retries = 0;
  267. }
  268. StackStringCopy (lastUrl, eventStruct->Url);
  269. retries++;
  270. if (retries > 5) {
  271. //
  272. // Too many retries -- give up!
  273. //
  274. SetEvent (eventStruct->CancelEvent);
  275. } else {
  276. //
  277. // Retry
  278. //
  279. wsprintfA (text, "on attempt %u. Retrying.", retries);
  280. SetDlgItemText (hdlg, IDC_RETRIES, text);
  281. if (eventStruct->Url) {
  282. SetDlgItemText (hdlg, IDC_URL, eventStruct->Url);
  283. }
  284. ShowWindow (GetDlgItem (hdlg, IDC_MSG2), SW_SHOW);
  285. ShowWindow (GetDlgItem (hdlg, IDC_URL), SW_SHOW);
  286. ShowWindow (GetDlgItem (hdlg, IDC_RETRIES), SW_SHOW);
  287. SetEvent (eventStruct->OkToRetryEvent);
  288. }
  289. }
  290. rc = WaitForSingleObject (eventStruct->CloseEvent, 0);
  291. if (rc == WAIT_OBJECT_0) {
  292. EndDialog (hdlg, IDCANCEL);
  293. }
  294. return TRUE;
  295. case WM_DESTROY:
  296. KillTimer (hdlg, 1);
  297. break;
  298. }
  299. return FALSE;
  300. }
  301. DWORD
  302. WINAPI
  303. pUiThread (
  304. PVOID Arg
  305. )
  306. {
  307. DialogBoxParam (
  308. g_hInst,
  309. (PCTSTR) IDD_STATUS,
  310. NULL,
  311. pUiDlgProc,
  312. (LPARAM) Arg
  313. );
  314. return 0;
  315. }
  316. HANDLE
  317. pCreateUiThread (
  318. PEVENTSTRUCT EventStruct
  319. )
  320. {
  321. HANDLE h;
  322. DWORD threadId;
  323. h = CreateThread (NULL, 0, pUiThread, EventStruct, 0, &threadId);
  324. return h;
  325. }
  326. BOOL
  327. pDownloadUpdatesWithUi (
  328. VOID
  329. )
  330. {
  331. EVENTSTRUCT es;
  332. BOOL b = FALSE;
  333. HANDLE h;
  334. //
  335. // Create the events
  336. //
  337. es.CancelEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
  338. es.WantToRetryEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
  339. es.OkToRetryEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
  340. es.CloseEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
  341. es.Url = NULL;
  342. if (!es.CancelEvent || !es.WantToRetryEvent ||
  343. !es.OkToRetryEvent || !es.CloseEvent
  344. ) {
  345. DEBUGMSG ((DBG_ERROR, "Can't create events"));
  346. return FALSE;
  347. }
  348. //
  349. // Start the UI
  350. //
  351. h = pCreateUiThread (&es);
  352. if (!h) {
  353. DEBUGMSG ((DBG_ERROR, "Can't create UI thread"));
  354. } else {
  355. //
  356. // Perform the download
  357. //
  358. b = DownloadUpdates (
  359. es.CancelEvent,
  360. es.WantToRetryEvent,
  361. es.OkToRetryEvent,
  362. &es.Url
  363. );
  364. //
  365. // End the UI
  366. //
  367. SetEvent (es.CloseEvent);
  368. WaitForSingleObject (h, INFINITE);
  369. }
  370. //
  371. // Cleanup & exit
  372. //
  373. CloseHandle (es.CancelEvent);
  374. CloseHandle (es.WantToRetryEvent);
  375. CloseHandle (es.OkToRetryEvent);
  376. CloseHandle (es.CloseEvent);
  377. return b;
  378. }
  379. BOOL
  380. pOpenWinInetSupport (
  381. VOID
  382. )
  383. {
  384. g_Lib = LoadLibrary (TEXT("wininet.dll"));
  385. if (!g_Lib) {
  386. return FALSE;
  387. }
  388. (FARPROC) g_InternetOpenA = GetProcAddress (g_Lib, "InternetOpenA");
  389. (FARPROC) g_InternetCloseHandle = GetProcAddress (g_Lib, "InternetCloseHandle");
  390. (FARPROC) g_InternetOpenUrlA = GetProcAddress (g_Lib, "InternetOpenUrlA");
  391. (FARPROC) g_InternetReadFile = GetProcAddress (g_Lib, "InternetReadFile");
  392. (FARPROC) g_InternetCanonicalizeUrlA = GetProcAddress (g_Lib, "InternetCanonicalizeUrlA");
  393. (FARPROC) g_InternetSetFilePointer = GetProcAddress (g_Lib, "InternetSetFilePointer");
  394. (FARPROC) g_InternetHangUp = GetProcAddress (g_Lib, "InternetHangUp");
  395. (FARPROC) g_InternetDialA = GetProcAddress (g_Lib, "InternetDialA");
  396. if (!g_InternetOpenA || !g_InternetOpenUrlA || !g_InternetReadFile ||
  397. !g_InternetCloseHandle || !g_InternetCanonicalizeUrlA ||
  398. !g_InternetSetFilePointer || !g_InternetDialA || !g_InternetHangUp
  399. ) {
  400. return FALSE;
  401. }
  402. return TRUE;
  403. }
  404. VOID
  405. pCloseWinInetSupport (
  406. VOID
  407. )
  408. {
  409. FreeLibrary (g_Lib);
  410. g_Lib = NULL;
  411. g_InternetOpenA = NULL;
  412. g_InternetOpenUrlA = NULL;
  413. g_InternetReadFile = NULL;
  414. g_InternetCloseHandle = NULL;
  415. g_InternetCanonicalizeUrlA = NULL;
  416. g_InternetSetFilePointer = NULL;
  417. g_InternetDialA = NULL;
  418. g_InternetHangUp = NULL;
  419. }
  420. BOOL
  421. pDownloadFile (
  422. HINTERNET Session,
  423. PCSTR RemoteFileUrl,
  424. PCSTR LocalFile,
  425. HANDLE CancelEvent
  426. )
  427. {
  428. HINTERNET connection;
  429. PBYTE buffer = NULL;
  430. UINT size = 65536;
  431. DWORD bytesRead;
  432. DWORD dontCare;
  433. HANDLE file = INVALID_HANDLE_VALUE;
  434. BOOL b = FALSE;
  435. //
  436. // Establish connection to the file
  437. //
  438. connection = g_InternetOpenUrlA (
  439. Session,
  440. RemoteFileUrl,
  441. NULL,
  442. 0,
  443. INTERNET_FLAG_RELOAD, //INTERNET_FLAG_NO_UI
  444. 0
  445. );
  446. if (!connection) {
  447. DEBUGMSGA ((DBG_ERROR "Can't connect to %s", RemoteFileUrl));
  448. return FALSE;
  449. }
  450. __try {
  451. //
  452. // Create the local file
  453. //
  454. file = CreateFileA (
  455. LocalFile,
  456. GENERIC_WRITE,
  457. 0,
  458. NULL,
  459. CREATE_ALWAYS,
  460. FILE_ATTRIBUTE_NORMAL,
  461. NULL
  462. );
  463. if (file == INVALID_HANDLE_VALUE) {
  464. DEBUGMSGA ((DBG_ERROR, "Can't create %s", LocalFile));
  465. __leave;
  466. }
  467. //
  468. // Allocate a big buffer for downloading
  469. //
  470. buffer = MemAlloc (g_hHeap, 0, size);
  471. if (!buffer) {
  472. __leave;
  473. }
  474. //
  475. // Download the file
  476. //
  477. for (;;) {
  478. if (WAIT_OBJECT_0 == WaitForSingleObject (CancelEvent, 0)) {
  479. DEBUGMSG ((DBG_VERBOSE, "User cancellation detected"));
  480. __leave;
  481. }
  482. if (!g_InternetReadFile (connection, buffer, size, &bytesRead)) {
  483. DEBUGMSGA ((DBG_ERROR, "Error downloading %s", RemoteFileUrl));
  484. __leave;
  485. }
  486. if (!bytesRead) {
  487. break;
  488. }
  489. if (!WriteFile (file, buffer, bytesRead, &dontCare, NULL)) {
  490. DEBUGMSGA ((DBG_ERROR, "Error writing to %s", LocalFile));
  491. __leave;
  492. }
  493. }
  494. b = TRUE;
  495. }
  496. __finally {
  497. g_InternetCloseHandle (connection);
  498. CloseHandle (file);
  499. if (!b) {
  500. DeleteFileA (LocalFile);
  501. }
  502. if (buffer) {
  503. MemFree (g_hHeap, 0, buffer);
  504. }
  505. }
  506. return b;
  507. }
  508. BOOL
  509. pDownloadFileWithRetry (
  510. IN HINTERNET Session,
  511. IN PCSTR Url,
  512. IN PCSTR DestFile,
  513. IN HANDLE CancelEvent, OPTIONAL
  514. IN HANDLE WantToRetryEvent, OPTIONAL
  515. IN HANDLE OkToRetryEvent OPTIONAL
  516. )
  517. /*++
  518. Routine Description:
  519. pDownloadFileWithRetry downloads a URL to a local file, as specified by the
  520. caller. If CancelEvent is specified, then the caller can stop the download
  521. by setting the event.
  522. This function implements a retry mechanism via events. If the caller
  523. specifies WantToRetryEvent and OkToRetryEvent, then this routine will allow
  524. the caller an opportunity to retry a failed download.
  525. The retry protocol is as follows:
  526. - Caller establishes a wait on WantToRetryEvent, then calls DownloadUpdates
  527. - Error occurs downloading one of the files
  528. - WantToRetryEvent is set by this routine
  529. - Caller's wait wakes up
  530. - Caller asks user if they want to retry
  531. - Caller sets CancelEvent or OkToRetryEvent, depending on user choice
  532. - This routine wakes up and either retries or aborts
  533. The caller must create all three events as auto-reset events in the
  534. non-signaled state.
  535. Arguments:
  536. Session - Specifies the handle to an open internet session.
  537. Url - Specifies the URL to download.
  538. DestFile - Specifies the local path to download the file to.
  539. CancelEvent - Specifies the handle to a caller-owned event. When this
  540. event is set, the function will return FALSE and
  541. GetLastError will return ERROR_CANCELLED.
  542. WantToRetryEvent - Specifies the caller-owned event that is set when a
  543. download error occurs. The caller should be waiting on
  544. this event before calling DownloadUpdates.
  545. OkToRetry - Specifies the caller-owned event that will be set in
  546. response to a user's request to retry.
  547. Return Value:
  548. TRUE if the file was downloaded, FALSE if the user decides to cancel the
  549. download.
  550. --*/
  551. {
  552. BOOL fail;
  553. HANDLE waitArray[2];
  554. DWORD rc;
  555. //
  556. // Loop until success, user decides to cancel, or user decides
  557. // not to retry on error
  558. //
  559. for (;;) {
  560. fail = FALSE;
  561. if (!pDownloadFile (Session, Url, DestFile, CancelEvent)) {
  562. fail = TRUE;
  563. if (GetLastError() != ERROR_CANCELLED &&
  564. CancelEvent && WantToRetryEvent && OkToRetryEvent
  565. ) {
  566. //
  567. // We set the WantToRetryEvent. The UI thread should
  568. // be waiting on this. The UI thread will then ask
  569. // the user if they want to retry or cancel. If the
  570. // user wants to retry, the UI thread will set the
  571. // OkToRetryEvent. If the user wants to cancel, the
  572. // UI thread will set the CancelEvent.
  573. //
  574. SetEvent (WantToRetryEvent);
  575. waitArray[0] = CancelEvent;
  576. waitArray[1] = OkToRetryEvent;
  577. rc = WaitForMultipleObjects (2, waitArray, FALSE, INFINITE);
  578. if (rc == WAIT_OBJECT_0 + 1) {
  579. continue;
  580. }
  581. //
  582. // We fail
  583. //
  584. SetLastError (ERROR_CANCELLED);
  585. }
  586. }
  587. break;
  588. }
  589. return !fail;
  590. }
  591. VOID
  592. pGoOffline (
  593. VOID
  594. )
  595. {
  596. if (g_Dialed) {
  597. g_Dialed = FALSE;
  598. g_InternetHangUp (g_Cxn, 0);
  599. }
  600. }
  601. BOOL
  602. pGoOnline (
  603. HINTERNET Session
  604. )
  605. {
  606. HINTERNET connection;
  607. if (g_Dialed) {
  608. pGoOffline();
  609. }
  610. //
  611. // Check if we are online
  612. //
  613. connection = g_InternetOpenUrlA (
  614. Session,
  615. "http://www.microsoft.com/",
  616. NULL,
  617. 0,
  618. INTERNET_FLAG_RELOAD,
  619. 0
  620. );
  621. if (connection) {
  622. DEBUGMSG ((DBG_VERBOSE, "Able to connect to www.microsoft.com"));
  623. g_InternetCloseHandle (connection);
  624. return TRUE;
  625. }
  626. //
  627. // Unable to contact www.microsoft.com. Possibilities:
  628. //
  629. // - net cable unplugged
  630. // - firewall without a proxy
  631. // - no online connection (i.e., need to dial ISP)
  632. // - www.microsoft.com or some part of the Internet is down
  633. // - user has no Internet access at all
  634. //
  635. // Try RAS, then try connection again.
  636. //
  637. g_InternetDialA (NULL, NULL, INTERNET_AUTODIAL_FORCE_ONLINE, &g_Cxn, 0);
  638. g_Dialed = TRUE;
  639. connection = g_InternetOpenUrlA (
  640. Session,
  641. "http://www.microsoft.com/",
  642. NULL,
  643. 0,
  644. INTERNET_FLAG_RELOAD,
  645. 0
  646. );
  647. if (connection) {
  648. DEBUGMSG ((DBG_VERBOSE, "Able to connect to www.microsoft.com via RAS"));
  649. g_InternetCloseHandle (connection);
  650. return TRUE;
  651. }
  652. pGoOffline();
  653. return FALSE;
  654. }
  655. BOOL
  656. DownloadUpdates (
  657. HANDLE CancelEvent, OPTIONAL
  658. HANDLE WantToRetryEvent, OPTIONAL
  659. HANDLE OkToRetryEvent, OPTIONAL
  660. PCSTR *StatusUrl OPTIONAL
  661. )
  662. {
  663. HINTERNET session;
  664. CHAR url[MAX_PATH];
  665. DWORD size;
  666. BOOL b = FALSE;
  667. CHAR tempPath[MAX_TCHAR_PATH];
  668. CHAR dirFile[MAX_TCHAR_PATH];
  669. HINF inf;
  670. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  671. PCSTR p;
  672. PCSTR q;
  673. if (!pOpenWinInetSupport()) {
  674. DEBUGMSG ((DBG_ERROR, "Can't open wininet.dll"));
  675. return FALSE;
  676. }
  677. __try {
  678. session = g_InternetOpenA (
  679. g_AppName,
  680. INTERNET_OPEN_TYPE_PRECONFIG,
  681. NULL,
  682. NULL,
  683. 0
  684. );
  685. if (!session) {
  686. DEBUGMSG ((DBG_ERROR, "InternetOpen returned NULL"));
  687. SetLastError (ERROR_NOT_CONNECTED);
  688. __leave;
  689. }
  690. if (!pGoOnline (session)) {
  691. DEBUGMSG ((DBG_ERROR, "Can't go online"));
  692. SetLastError (ERROR_NOT_CONNECTED);
  693. __leave;
  694. }
  695. size = ARRAYSIZE(url);
  696. if (!g_InternetCanonicalizeUrlA (g_DirFile, url, &size, 0)) {
  697. DEBUGMSGA ((DBG_ERROR, "Can't canonicalize %s", g_DirFile));
  698. SetLastError (ERROR_CONNECTION_ABORTED);
  699. __leave;
  700. }
  701. GetTempPathA (ARRAYSIZE(tempPath), tempPath);
  702. GetTempFileNameA (tempPath, "ftp", 0, dirFile);
  703. if (StatusUrl) {
  704. *StatusUrl = url;
  705. }
  706. if (!pDownloadFileWithRetry (
  707. session,
  708. url,
  709. dirFile,
  710. CancelEvent,
  711. WantToRetryEvent,
  712. OkToRetryEvent
  713. )) {
  714. DEBUGMSGA ((DBG_ERROR, "Can't download %s", url));
  715. // last error set to a valid return condition
  716. __leave;
  717. }
  718. inf = InfOpenInfFileA (dirFile);
  719. if (inf == INVALID_HANDLE_VALUE) {
  720. DEBUGMSGA ((DBG_ERROR, "Can't open %s", dirFile));
  721. // last error set to the reason of the INF failure
  722. __leave;
  723. }
  724. __try {
  725. if (InfFindFirstLineA (inf, "Win9xUpg", NULL, &is)) {
  726. do {
  727. p = InfGetStringFieldA (&is, 1);
  728. q = InfGetStringFieldA (&is, 2);
  729. if (!p || !q) {
  730. continue;
  731. }
  732. q = ExpandEnvironmentTextA (q);
  733. size = ARRAYSIZE(url);
  734. if (!g_InternetCanonicalizeUrlA (p, url, &size, 0)) {
  735. DEBUGMSGA ((DBG_ERROR, "Can't canonicalize INF-specified URL: %s", p));
  736. SetLastError (ERROR_CONNECTION_ABORTED);
  737. __leave;
  738. }
  739. if (!pDownloadFileWithRetry (
  740. session,
  741. url,
  742. q,
  743. CancelEvent,
  744. WantToRetryEvent,
  745. OkToRetryEvent
  746. )) {
  747. FreeTextA (q);
  748. DEBUGMSGA ((DBG_ERROR, "Can't download INF-specified URL: %s", url));
  749. // last error set to a valid return code
  750. __leave;
  751. }
  752. FreeTextA (q);
  753. } while (InfFindNextLine (&is));
  754. }
  755. }
  756. __finally {
  757. InfCloseInfFile (inf);
  758. }
  759. }
  760. __finally {
  761. if (session) {
  762. g_InternetCloseHandle (session);
  763. }
  764. InfCleanUpInfStruct (&is);
  765. DeleteFileA (dirFile);
  766. pGoOffline();
  767. pCloseWinInetSupport();
  768. }
  769. return b;
  770. }