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.

527 lines
12 KiB

  1. #include <windows.h>
  2. #include "download.h"
  3. #include "util.h"
  4. #define BUFFERSIZE 4096
  5. char g_szBuffer[BUFFERSIZE];
  6. #define TIMEOUT_PERIOD 120
  7. CDownloader::CDownloader()
  8. {
  9. _pBnd = NULL;
  10. _cRef = 1;
  11. _pStm = NULL;
  12. _hDL = CreateEvent(NULL, TRUE, FALSE, NULL);
  13. _hFile = INVALID_HANDLE_VALUE;
  14. }
  15. CDownloader::~CDownloader()
  16. {
  17. if(_hDL)
  18. CloseHandle(_hDL);
  19. }
  20. STDMETHODIMP CDownloader::QueryInterface(const GUID &riid,void **ppv )
  21. {
  22. *ppv = NULL ;
  23. if( IsEqualGUID(riid,IID_IUnknown) )
  24. {
  25. *ppv = (IUnknown *) (IBindStatusCallback *)this;
  26. }
  27. else if (IsEqualGUID(riid,IID_IBindStatusCallback) )
  28. {
  29. *ppv = (IBindStatusCallback *) this;
  30. }
  31. else if (IsEqualGUID(riid, IID_IAuthenticate))
  32. {
  33. *ppv = (IAuthenticate *) this;
  34. }
  35. else if (IsEqualGUID(riid,IID_IHttpNegotiate))
  36. {
  37. *ppv = (IHttpNegotiate*) this;
  38. }
  39. if (*ppv)
  40. {
  41. // increment our reference count before we hand out our interface
  42. ((LPUNKNOWN)*ppv)->AddRef();
  43. return(NOERROR);
  44. }
  45. return( E_NOINTERFACE );
  46. }
  47. STDMETHODIMP_(ULONG) CDownloader::AddRef()
  48. {
  49. return(++_cRef);
  50. }
  51. STDMETHODIMP_(ULONG) CDownloader::Release()
  52. {
  53. if(!--_cRef)
  54. {
  55. delete this;
  56. return(0);
  57. }
  58. return( _cRef );
  59. }
  60. STDMETHODIMP CDownloader::GetBindInfo( DWORD *grfBINDF, BINDINFO *pbindInfo)
  61. {
  62. // clear BINDINFO but keep its size
  63. DWORD cbSize = pbindInfo->cbSize;
  64. ZeroMemory( pbindInfo, cbSize );
  65. pbindInfo->cbSize = cbSize;
  66. *grfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_RESYNCHRONIZE;
  67. pbindInfo->dwBindVerb = BINDVERB_GET;
  68. return(NOERROR);
  69. }
  70. STDMETHODIMP CDownloader::OnStartBinding(DWORD /*grfBSCOption*/,IBinding *p)
  71. {
  72. _pBnd = p;
  73. _pBnd->AddRef();
  74. return(NOERROR);
  75. }
  76. STDMETHODIMP CDownloader::GetPriority(LONG *pnPriority)
  77. {
  78. return(E_NOTIMPL);
  79. }
  80. STDMETHODIMP CDownloader::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR pwzStatusText)
  81. {
  82. return NOERROR;
  83. }
  84. STDMETHODIMP CDownloader::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pFmtetc, STGMEDIUM *pstgmed)
  85. {
  86. // bring in major changes here
  87. HRESULT hr = NOERROR;
  88. DWORD dwRead = 0;
  89. DWORD dwReadThisCall = 0;
  90. DWORD dwWritten = 0;
  91. if(!_pStm)
  92. {
  93. _pStm = pstgmed->pstm;
  94. _pStm->AddRef();
  95. }
  96. // should ignore WAIT_TIMEOUT while getting bytes from urlmon
  97. _fTimeoutValid = FALSE;
  98. do
  99. {
  100. hr = _pStm->Read(g_szBuffer, BUFFERSIZE, &dwRead);
  101. if( SUCCEEDED(hr) || ( (hr == E_PENDING) && (dwRead > 0) ) )
  102. {
  103. if(_hFile)
  104. if(!WriteFile(_hFile, g_szBuffer, dwRead, &dwWritten, NULL))
  105. {
  106. hr = E_FAIL;
  107. Abort();
  108. }
  109. }
  110. } while (hr == NOERROR);
  111. _uTickCount = 0;
  112. _fTimeoutValid = TRUE; // should increment dwTickCount if WAIT_TIMEOUT occurs now
  113. return NOERROR;
  114. }
  115. STDMETHODIMP CDownloader::OnObjectAvailable(REFIID riid, IUnknown *punk)
  116. {
  117. return(E_NOTIMPL);
  118. }
  119. STDMETHODIMP CDownloader::OnLowResource(DWORD reserved)
  120. {
  121. _pBnd->Abort();
  122. return(S_OK);
  123. }
  124. STDMETHODIMP CDownloader::OnStopBinding(HRESULT hrError, LPCWSTR szError)
  125. {
  126. _fTimeoutValid = FALSE;
  127. if((hrError == E_ABORT) && _fTimeout)
  128. {
  129. // This is the timeout case
  130. _hDLResult = INET_E_CONNECTION_TIMEOUT;
  131. }
  132. else
  133. {
  134. // this is all other cases
  135. _hDLResult = hrError;
  136. }
  137. SetEvent(_hDL);
  138. return(NOERROR);
  139. }
  140. /* IAuthenticate::Authenticate
  141. */
  142. STDMETHODIMP CDownloader::Authenticate(HWND *phwnd,
  143. LPWSTR *pszUserName, LPWSTR *pszPassword)
  144. {
  145. if (!phwnd || !pszUserName || !pszPassword)
  146. return E_POINTER;
  147. *pszUserName = NULL;
  148. *pszPassword = NULL;
  149. *phwnd = GetDesktopWindow() ;
  150. return S_OK;
  151. }
  152. HRESULT GetAMoniker( LPOLESTR url, IMoniker ** ppmkr )
  153. {
  154. HRESULT hr = CreateURLMoniker(0,url,ppmkr);
  155. return( hr );
  156. }
  157. HRESULT CDownloader::DoDownload(LPCSTR pszUrl, LPCSTR lpszFilename)
  158. {
  159. HRESULT hr = NOERROR;
  160. BOOL fQuit = FALSE;
  161. DWORD dwRet;
  162. if(!pszUrl) return E_INVALIDARG;
  163. WCHAR wszUrl[INTERNET_MAX_URL_LENGTH];
  164. MultiByteToWideChar(CP_ACP, 0, pszUrl, -1,wszUrl, sizeof(wszUrl)/sizeof(wszUrl[0]));
  165. IMoniker *ptmpmkr;
  166. hr = GetAMoniker(wszUrl, &ptmpmkr );
  167. IBindCtx * pBindCtx = 0;
  168. if( SUCCEEDED(hr) )
  169. {
  170. if(SUCCEEDED(::CreateBindCtx(0,&pBindCtx)))
  171. hr = ::RegisterBindStatusCallback(pBindCtx, (IBindStatusCallback *) this, 0, 0) ;
  172. }
  173. _fTimeout = FALSE;
  174. _fTimeoutValid = TRUE;
  175. _uTickCount = 0;
  176. if(lpszFilename)
  177. {
  178. // Create the file
  179. _hFile = CreateFile(lpszFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
  180. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  181. if(_hFile == INVALID_HANDLE_VALUE)
  182. hr = E_FAIL;
  183. }
  184. if( SUCCEEDED(hr) )
  185. hr = ptmpmkr->BindToStorage(pBindCtx, 0, IID_IStream, (void**)&_pStm );
  186. // we need this here because it synchronus *FAIL* case,
  187. // we Set the event in onstopbinding, but we skip the loop below so it
  188. // never gets reset.
  189. // If BindToStorage fails without even sending onstopbinding, we are resetting
  190. // an unsignalled event, which is OK.
  191. if(FAILED(hr))
  192. ResetEvent(_hDL);
  193. // here we wait for Bind to complete
  194. //Wait for download event or abort
  195. while(SUCCEEDED(hr) && !fQuit)
  196. {
  197. dwRet = MsgWaitForMultipleObjects(1, &_hDL, FALSE, 1000, QS_ALLINPUT);
  198. if(dwRet == WAIT_OBJECT_0)
  199. {
  200. // Download is finished
  201. hr = _hDLResult;
  202. ResetEvent(_hDL);
  203. break;
  204. }
  205. else if(dwRet == WAIT_TIMEOUT) // our wait has expired
  206. {
  207. if(_fTimeoutValid)
  208. _uTickCount++;
  209. // if our tick count is past threshold, abort the download
  210. // BUGBUG: What about synch. case? We can't time out
  211. if(_uTickCount >= TIMEOUT_PERIOD)
  212. {
  213. _fTimeout = TRUE;
  214. Abort();
  215. }
  216. }
  217. else
  218. {
  219. MSG msg;
  220. // read all of the messages in this next loop
  221. // removing each message as we read it
  222. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  223. {
  224. // if it's a quit message we're out of here
  225. if (msg.message == WM_QUIT)
  226. fQuit = TRUE;
  227. else
  228. {
  229. // otherwise dispatch it
  230. DispatchMessage(&msg);
  231. } // end of PeekMessage while loop
  232. }
  233. }
  234. }
  235. // clean up all our stuff
  236. if(_hFile != INVALID_HANDLE_VALUE)
  237. CloseHandle(_hFile);
  238. _hFile = INVALID_HANDLE_VALUE;
  239. if(_pBnd)
  240. {
  241. _pBnd->Release();
  242. _pBnd = 0;
  243. }
  244. if(_pStm)
  245. {
  246. _pStm->Release();
  247. _pStm = 0;
  248. }
  249. return hr;
  250. }
  251. HRESULT CDownloader::Abort()
  252. {
  253. if(_pBnd)
  254. {
  255. _pBnd->Abort();
  256. }
  257. return NOERROR;
  258. }
  259. STDMETHODIMP CDownloader::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved,
  260. LPWSTR * pszAdditionalHeaders)
  261. {
  262. return S_OK;
  263. }
  264. STDMETHODIMP CDownloader:: OnResponse(DWORD dwResponseCode, LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
  265. LPWSTR * pszAdditionalResquestHeaders)
  266. {
  267. WriteToLog("\nResponse Header\n\n");
  268. char sz[1024];
  269. WideCharToMultiByte(CP_ACP, 0, szResponseHeaders, -1, sz, sizeof(sz), NULL, NULL);
  270. WriteToLog(sz);
  271. return S_OK;
  272. }
  273. CSiteMgr::CSiteMgr()
  274. {
  275. m_pSites = NULL;
  276. m_pCurrentSite = NULL;
  277. }
  278. CSiteMgr::~CSiteMgr()
  279. {
  280. while(m_pSites)
  281. {
  282. SITEINFO* pTemp = m_pSites;
  283. m_pSites = m_pSites->pNextSite;
  284. ResizeBuffer(pTemp->lpszUrl, 0, 0);
  285. ResizeBuffer(pTemp->lpszSiteName, 0, 0);
  286. ResizeBuffer(pTemp, 0, 0);
  287. }
  288. }
  289. BOOL CSiteMgr::GetNextSite(LPTSTR* lpszUrl, LPTSTR* lpszName)
  290. {
  291. if(!m_pSites)
  292. return FALSE;
  293. if(!m_pCurrentSite)
  294. {
  295. m_pCurrentSite = m_pSites;
  296. }
  297. *lpszUrl = m_pCurrentSite->lpszUrl;
  298. *lpszName = m_pCurrentSite->lpszSiteName;
  299. m_pCurrentSite = m_pCurrentSite->pNextSite;
  300. return TRUE;
  301. }
  302. HRESULT CSiteMgr::Initialize(LPCTSTR lpszUrl)
  303. {
  304. CDownloader cdwn;
  305. TCHAR szFileName[MAX_PATH], szTempPath[MAX_PATH];
  306. if(!GetTempPath(sizeof(szTempPath), szTempPath))
  307. {
  308. return HRESULT_FROM_WIN32(GetLastError());
  309. }
  310. GetLanguageString(m_szLang);
  311. LPTSTR lpszDatUrl = (LPTSTR)ResizeBuffer(NULL, lstrlen(lpszUrl) + 3 + sizeof("PatchSites.dat"), FALSE);
  312. wsprintf(lpszDatUrl, "%s/PatchSites.dat", lpszUrl);
  313. CombinePaths(szTempPath, "PatchSites.dat", szFileName);
  314. WriteToLog("Downloading %1\n", lpszDatUrl);
  315. HRESULT hr = cdwn.DoDownload(lpszDatUrl, szFileName);
  316. if(FAILED(hr))
  317. {
  318. WriteToLog("Downloading %1 failed with error code:%2!lx!\n", lpszDatUrl, hr);
  319. DeleteFile(szFileName);
  320. ResizeBuffer(lpszDatUrl, 0, 0);
  321. return hr;
  322. }
  323. BOOL flag = TRUE;
  324. hr = ParseSitesFile(szFileName);
  325. if(hr == E_UNEXPECTED && !m_pSites && flag)
  326. {
  327. flag = FALSE;
  328. lstrcpy(m_szLang, "EN");
  329. hr = ParseSitesFile(szFileName);
  330. }
  331. DeleteFile(szFileName);
  332. ResizeBuffer(lpszDatUrl, 0, 0);
  333. return hr;
  334. }
  335. HRESULT CSiteMgr::ParseSitesFile(LPTSTR pszPath)
  336. {
  337. DWORD dwSize;
  338. LPSTR pBuf, pCurrent, pEnd;
  339. HANDLE hfile = CreateFile(pszPath, GENERIC_READ, 0, NULL,
  340. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  341. if(hfile == INVALID_HANDLE_VALUE)
  342. return E_FAIL;
  343. dwSize = GetFileSize(hfile, NULL);
  344. pBuf = (LPSTR)ResizeBuffer(NULL, dwSize + 1, FALSE);
  345. if(!pBuf)
  346. {
  347. CloseHandle(hfile);
  348. return E_OUTOFMEMORY;
  349. }
  350. // Copy contents of file to our buffer
  351. ReadFile(hfile, pBuf, dwSize, &dwSize, NULL);
  352. pCurrent = pBuf;
  353. pEnd = pBuf + dwSize;
  354. *pEnd = 0;
  355. // One pass thru replacing \n or \r with \0
  356. while(pCurrent <= pEnd)
  357. {
  358. if(*pCurrent == '\r' || *pCurrent == '\n')
  359. *pCurrent = 0;
  360. pCurrent++;
  361. }
  362. pCurrent = pBuf;
  363. while(1)
  364. {
  365. while(pCurrent <= pEnd && *pCurrent == 0)
  366. pCurrent++;
  367. // we are now pointing at begginning of line or pCurrent > pBuf
  368. if(pCurrent > pEnd)
  369. break;
  370. ParseAndAllocateDownloadSite(pCurrent);
  371. pCurrent += lstrlen(pCurrent);
  372. }
  373. ResizeBuffer(pBuf, 0, 0);
  374. CloseHandle(hfile);
  375. if(!m_pSites)
  376. return E_UNEXPECTED;
  377. else
  378. return NOERROR;
  379. }
  380. BOOL CSiteMgr::ParseAndAllocateDownloadSite(LPTSTR psz)
  381. {
  382. char szUrl[1024];
  383. char szName[256];
  384. char szlang[256];
  385. char szregion[256];
  386. BOOL bQueryTrue = TRUE;
  387. GetStringField(psz, 0, szUrl, sizeof(szUrl));
  388. GetStringField(psz,1, szName, sizeof(szName));
  389. GetStringField(psz, 2, szlang, sizeof(szlang));
  390. GetStringField(psz, 3, szregion, sizeof(szregion));
  391. if(szUrl[0] == 0 || szName[0] == 0 || szlang[0] == 0 || szregion[0] == 0)
  392. return NULL;
  393. if(lstrcmpi(szlang, m_szLang))
  394. {
  395. return FALSE;
  396. }
  397. SITEINFO* pNewSite = (SITEINFO*) ResizeBuffer(NULL, sizeof(SITEINFO), FALSE);
  398. pNewSite->lpszSiteName = (LPTSTR) ResizeBuffer(NULL, lstrlen(szName) + 1, FALSE);
  399. lstrcpy(pNewSite->lpszSiteName, szName);
  400. pNewSite->lpszUrl = (LPTSTR) ResizeBuffer(NULL, lstrlen(szUrl) + 1, FALSE);
  401. lstrcpy(pNewSite->lpszUrl, szUrl);
  402. pNewSite->pNextSite = m_pSites;
  403. m_pSites = pNewSite;
  404. return TRUE;
  405. }