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.

455 lines
14 KiB

  1. /*
  2. * h t t p u t i l. c p p
  3. *
  4. * Author: Greg Friedman
  5. *
  6. * Purpose: Utility functions used to implement http mail.
  7. *
  8. * Copyright (C) Microsoft Corp. 1998.
  9. */
  10. #include "pch.hxx"
  11. #include "httputil.h"
  12. #include "xpcomm.h"
  13. #include "iso8601.h"
  14. #include "storutil.h"
  15. #include "flagconv.h"
  16. #include "demand.h"
  17. //----------------------------------------------------------------------
  18. // Http_FreeTargetList
  19. //----------------------------------------------------------------------
  20. void Http_FreeTargetList(LPHTTPTARGETLIST pTargets)
  21. {
  22. if (pTargets)
  23. {
  24. if (pTargets->prgTarget)
  25. {
  26. for (DWORD dw = 0; dw < pTargets->cTarget; dw++)
  27. {
  28. if (pTargets->prgTarget[dw])
  29. MemFree(const_cast<char *>(pTargets->prgTarget[dw]));
  30. }
  31. MemFree(pTargets->prgTarget);
  32. }
  33. MemFree(pTargets);
  34. }
  35. }
  36. //----------------------------------------------------------------------
  37. // Http_NameFromUrl
  38. //----------------------------------------------------------------------
  39. HRESULT Http_NameFromUrl(LPCSTR pszUrl, LPSTR pszBuffer, DWORD *pdwBufferLen)
  40. {
  41. HRESULT hr = S_OK;
  42. char szLocalBuf[MAX_PATH];
  43. URL_COMPONENTS urlComponents;
  44. DWORD dw = 0;
  45. ZeroMemory(&urlComponents, sizeof(URL_COMPONENTS));
  46. // use wininet to break the path out and to decode the url while
  47. // we're at it.
  48. urlComponents.dwStructSize = sizeof(URL_COMPONENTS);
  49. urlComponents.lpszUrlPath = szLocalBuf;
  50. urlComponents.dwUrlPathLength = MAX_PATH;
  51. if (!InternetCrackUrl(pszUrl, lstrlen(pszUrl), NOFLAGS /* ICU_DECODE */, &urlComponents))
  52. {
  53. hr = GetLastError();
  54. goto exit;
  55. }
  56. // subtract one to start at the char before the last one. this skips
  57. // the last char in the case of a folder that ends in '/'
  58. dw = urlComponents.dwUrlPathLength - 1;
  59. while (dw && ('/' != szLocalBuf[dw - 1]))
  60. dw--;
  61. // dw represents the count of chars that are NOT in the
  62. // name. reverse it.
  63. dw = urlComponents.dwUrlPathLength - dw;
  64. if (dw >= *pdwBufferLen)
  65. {
  66. hr = E_OUTOFMEMORY;
  67. goto exit;
  68. }
  69. CopyMemory(pszBuffer, &szLocalBuf[urlComponents.dwUrlPathLength - dw], dw + 1);
  70. *pdwBufferLen = dw;
  71. exit:
  72. return hr;
  73. }
  74. //----------------------------------------------------------------------
  75. // Http_AddMessageToFolder
  76. //----------------------------------------------------------------------
  77. HRESULT Http_AddMessageToFolder(IMessageFolder *pFolder,
  78. LPSTR pszAcctId,
  79. LPHTTPMEMBERINFO pmi,
  80. MESSAGEFLAGS dwFlags,
  81. LPSTR pszUrl,
  82. LPMESSAGEID pidMessage)
  83. {
  84. HRESULT hr = S_OK;
  85. MESSAGEINFO mi;
  86. FILETIME ft;
  87. DWORD dwTimeFlags = NOFLAGS;
  88. LPSTR pszFreeFrom = NULL;
  89. LPSTR pszFreeTo = NULL;
  90. ADDRESSLIST addrList;
  91. char szUrlComponent[MAX_PATH];
  92. DWORD dwUrlComponentLen = MAX_PATH;
  93. PROPVARIANT rDecodedSubj;
  94. PROPVARIANT rDecodedFrom;
  95. PROPVARIANT rDecodedTo;
  96. LPSTR pszSubject = NULL;
  97. if (NULL == pszUrl)
  98. return E_INVALIDARG;
  99. ZeroMemory(&mi, sizeof(MESSAGEINFO));
  100. rDecodedSubj.vt = rDecodedFrom.vt = rDecodedTo.vt = VT_LPSTR;
  101. rDecodedSubj.pszVal = rDecodedFrom.pszVal = rDecodedTo.pszVal = NULL;
  102. // build a message info and pump the header into the store
  103. mi.pszAcctId = pszAcctId;
  104. // get the store to generate an id
  105. if (FAILED(hr = pFolder->GenerateId((DWORD *)&mi.idMessage)))
  106. goto exit;
  107. if (NULL != pidMessage)
  108. *pidMessage = mi.idMessage;
  109. if (FAILED(hr = Http_NameFromUrl(pszUrl, szUrlComponent, &dwUrlComponentLen)))
  110. goto exit;
  111. mi.dwFlags |= dwFlags;
  112. // if a message info was passed in, use its data
  113. if (NULL != pmi)
  114. {
  115. mi.cbMessage = pmi->dwContentLength;
  116. if (pmi->fRead)
  117. mi.dwFlags = ARF_READ;
  118. if (pmi->fHasAttachment)
  119. mi.dwFlags |= ARF_HASATTACH;
  120. if (NULL != pmi->pszSubject)
  121. {
  122. if (SUCCEEDED(MimeOleDecodeHeader(NULL, pmi->pszSubject, &rDecodedSubj, NULL)))
  123. pszSubject = rDecodedSubj.pszVal;
  124. else
  125. pszSubject = pmi->pszSubject;
  126. mi.pszSubject = pszSubject;
  127. mi.pszNormalSubj = SzNormalizeSubject(pszSubject);
  128. if (NULL == mi.pszNormalSubj)
  129. mi.pszNormalSubj = pszSubject;
  130. }
  131. if (pmi->pszFrom && S_OK == MimeOleParseRfc822Address(IAT_FROM, IET_ENCODED, pmi->pszFrom, &addrList))
  132. {
  133. if (addrList.cAdrs > 0)
  134. {
  135. pszFreeFrom = addrList.prgAdr[0].pszFriendly;
  136. addrList.prgAdr[0].pszFriendly = NULL;
  137. // only use the parsed address if it is at least three chars long
  138. if (pszFreeFrom && lstrlen(pszFreeFrom) >= 3)
  139. mi.pszDisplayFrom = pszFreeFrom;
  140. }
  141. g_pMoleAlloc->FreeAddressList(&addrList);
  142. }
  143. if (NULL == mi.pszDisplayFrom && NULL != pmi->pszFrom)
  144. {
  145. if (SUCCEEDED(MimeOleDecodeHeader(NULL, pmi->pszFrom, &rDecodedFrom, NULL)))
  146. mi.pszDisplayFrom = rDecodedFrom.pszVal;
  147. else
  148. mi.pszDisplayFrom = pmi->pszFrom;
  149. }
  150. if (SUCCEEDED(iso8601::toFileTime(pmi->pszDate, &ft, &dwTimeFlags)))
  151. {
  152. if (!(dwTimeFlags & ISO8601_ST_HOUR))
  153. mi.dwFlags |= ARF_PARTIAL_RECVTIME;
  154. mi.ftReceived = ft;
  155. }
  156. if (pmi->pszTo && S_OK == MimeOleParseRfc822Address(IAT_TO, IET_ENCODED, pmi->pszTo, &addrList))
  157. {
  158. if (addrList.cAdrs > 0)
  159. {
  160. pszFreeTo = addrList.prgAdr[0].pszFriendly;
  161. addrList.prgAdr[0].pszFriendly = NULL;
  162. // only use the parsed address if it is at least three chars long
  163. if (pszFreeTo && lstrlen(pszFreeTo) >= 3)
  164. mi.pszDisplayTo = pszFreeTo;
  165. }
  166. g_pMoleAlloc->FreeAddressList(&addrList);
  167. }
  168. if (NULL == mi.pszDisplayTo && NULL != pmi->pszTo)
  169. {
  170. if (SUCCEEDED(MimeOleDecodeHeader(NULL, pmi->pszTo, &rDecodedTo, NULL)))
  171. mi.pszDisplayTo = rDecodedTo.pszVal;
  172. else
  173. mi.pszDisplayTo = pmi->pszTo;
  174. }
  175. }
  176. mi.pszUrlComponent = szUrlComponent;
  177. // Add it to the database
  178. IF_FAILEXIT(hr = pFolder->InsertRecord(&mi));
  179. // normalize the response
  180. hr = S_OK;
  181. exit:
  182. SafeMimeOleFree(rDecodedSubj.pszVal);
  183. SafeMimeOleFree(rDecodedFrom.pszVal);
  184. SafeMimeOleFree(rDecodedTo.pszVal);
  185. SafeMemFree(pszFreeFrom);
  186. SafeMemFree(pszFreeTo);
  187. return hr;
  188. }
  189. //----------------------------------------------------------------------
  190. // Http_SetMessageStream
  191. //----------------------------------------------------------------------
  192. HRESULT Http_SetMessageStream(IMessageFolder *pFolder,
  193. MESSAGEID idMessage,
  194. IStream *pStream,
  195. LPFILEADDRESS pfa,
  196. BOOL fSetDisplayProps)
  197. {
  198. HRESULT hr = S_OK;
  199. IMimeMessage *pMimeMsg = NULL;
  200. IMimePropertySet *pPropertySet = NULL;
  201. DWORD dwFlags = 0;
  202. MESSAGEINFO mi = {0};
  203. LPMESSAGEINFO pmiFree = NULL;
  204. FILETIME ftCurrent;
  205. PROPVARIANT rVariant;
  206. IMimeAddressTable *pAdrTable = NULL;
  207. ADDRESSPROPS rAddress = {0};
  208. LPSTR pszDisplayFrom = NULL;
  209. LPSTR pszEmailFrom = NULL;
  210. LPSTR pszDisplayTo = NULL;
  211. LPSTR pszEmailTo = NULL;
  212. LPSTR pszMessageId = NULL;
  213. LPSTR pszXref = NULL;
  214. LPSTR pszReferences = NULL;
  215. LPSTR pszSubject = NULL;
  216. LPSTR pszNormalSubj = NULL;
  217. LPSTR pszAcctId = NULL;
  218. LPSTR pszAcctName = NULL;
  219. LPSTR pszServer = NULL;
  220. LPSTR pszForwardTo = NULL;
  221. LPSTR pszMSOESRec = NULL;
  222. // Default Sent and Received Times...
  223. GetSystemTimeAsFileTime(&ftCurrent);
  224. // Create a Message. We can't use the folder's OpenMessage
  225. // method, because the folder's stream will be locked for write
  226. // access.
  227. IF_FAILEXIT(hr = MimeOleCreateMessage(NULL, &pMimeMsg));
  228. IF_FAILEXIT(hr = HrRewindStream(pStream));
  229. IF_FAILEXIT(hr = pMimeMsg->Load(pStream));
  230. // Get the Root Property Set from the Message
  231. IF_FAILEXIT(hr = pMimeMsg->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pPropertySet));
  232. // find the message in the store
  233. IF_FAILEXIT(hr = GetMessageInfo(pFolder, idMessage, &mi));
  234. pmiFree = &mi;
  235. // update the fields of the message info
  236. if (SUCCEEDED(pMimeMsg->GetFlags(&dwFlags)))
  237. mi.dwFlags |= ConvertIMFFlagsToARF(dwFlags);
  238. // unset the download flag
  239. mi.dwFlags &= ~ARF_DOWNLOAD;
  240. // Set Variant tyStore
  241. rVariant.vt = VT_UI4;
  242. // Priority
  243. if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_PRIORITY), 0, &rVariant)))
  244. mi.wPriority = (WORD)rVariant.ulVal;
  245. // Init Variant
  246. rVariant.vt = VT_FILETIME;
  247. if (0 == mi.ftSent.dwLowDateTime && 0 == mi.ftSent.dwHighDateTime)
  248. {
  249. if (SUCCEEDED(pMimeMsg->GetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &rVariant)))
  250. mi.ftSent = rVariant.filetime;
  251. else
  252. mi.ftSent = ftCurrent;
  253. }
  254. if (0 == mi.ftReceived.dwLowDateTime && 0 == mi.ftReceived.dwHighDateTime)
  255. {
  256. if (SUCCEEDED(pMimeMsg->GetProp(PIDTOSTR(PID_ATT_RECVTIME), 0, &rVariant)))
  257. mi.ftReceived = rVariant.filetime;
  258. else
  259. mi.ftReceived = ftCurrent;
  260. }
  261. // Get Address Table
  262. IF_FAILEXIT(hr = pPropertySet->BindToObject(IID_IMimeAddressTable, (LPVOID *)&pAdrTable));
  263. // Display From
  264. if (fSetDisplayProps && NULL == mi.pszDisplayFrom)
  265. {
  266. pAdrTable->GetFormat(IAT_FROM, AFT_DISPLAY_FRIENDLY, &pszDisplayFrom);
  267. mi.pszDisplayFrom = pszDisplayFrom;
  268. }
  269. // Email From
  270. rAddress.dwProps = IAP_EMAIL;
  271. if (NULL == mi.pszEmailFrom && SUCCEEDED(pAdrTable->GetSender(&rAddress)))
  272. {
  273. pszEmailFrom = rAddress.pszEmail;
  274. mi.pszEmailFrom = pszEmailFrom;
  275. }
  276. // Display to
  277. if (fSetDisplayProps && NULL == mi.pszDisplayTo)
  278. {
  279. pAdrTable->GetFormat(IAT_TO, AFT_DISPLAY_FRIENDLY, &pszDisplayTo);
  280. mi.pszDisplayTo = pszDisplayTo;
  281. }
  282. // Email To
  283. if (NULL == mi.pszEmailTo)
  284. {
  285. pAdrTable->GetFormat(IAT_TO, AFT_DISPLAY_EMAIL, &pszEmailTo);
  286. mi.pszEmailTo = pszEmailTo;
  287. }
  288. // String properties
  289. rVariant.vt = VT_LPSTR;
  290. // pszMessageId
  291. if (NULL == mi.pszMessageId && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, &rVariant)))
  292. {
  293. pszMessageId = rVariant.pszVal;
  294. mi.pszMessageId = pszMessageId;
  295. }
  296. // pszXref
  297. if (NULL == mi.pszXref && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_XREF), NOFLAGS, &rVariant)))
  298. {
  299. pszXref = rVariant.pszVal;
  300. mi.pszXref = pszXref;
  301. }
  302. // pszReferences
  303. if (NULL == mi.pszReferences && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(STR_HDR_REFS), NOFLAGS, &rVariant)))
  304. {
  305. pszReferences = rVariant.pszVal;
  306. mi.pszReferences = pszReferences;
  307. }
  308. // pszSubject
  309. if (NULL == mi.pszSubject && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &rVariant)))
  310. {
  311. pszSubject = rVariant.pszVal;
  312. mi.pszSubject = pszSubject;
  313. }
  314. // pszNormalSubj
  315. if (fSetDisplayProps && NULL == mi.pszNormalSubj && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_NORMSUBJ), NOFLAGS, &rVariant)))
  316. {
  317. pszNormalSubj = rVariant.pszVal;
  318. mi.pszNormalSubj = pszNormalSubj;
  319. }
  320. // pszAcctId
  321. if (NULL == mi.pszAcctId && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &rVariant)))
  322. {
  323. pszAcctId = rVariant.pszVal;
  324. mi.pszAcctId = pszAcctId;
  325. }
  326. // pszAcctName
  327. if (NULL == mi.pszAcctName && SUCCEEDED(pPropertySet->GetProp(STR_ATT_ACCOUNTNAME, NOFLAGS, &rVariant)))
  328. {
  329. pszAcctName = rVariant.pszVal;
  330. mi.pszAcctName = pszAcctName;
  331. }
  332. // pszServer
  333. if (NULL == mi.pszServer && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_SERVER), NOFLAGS, &rVariant)))
  334. {
  335. pszServer = rVariant.pszVal;
  336. mi.pszServer = pszServer;
  337. }
  338. // ForwardTo
  339. if (NULL == mi.pszForwardTo && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_FORWARDTO), NOFLAGS, &rVariant)))
  340. {
  341. pszForwardTo = rVariant.pszVal;
  342. mi.pszForwardTo = pszForwardTo;
  343. }
  344. if (NULL == mi.pszMSOESRec && SUCCEEDED(pPropertySet->GetProp(STR_HDR_XMSOESREC, NOFLAGS, &rVariant)))
  345. {
  346. pszMSOESRec = rVariant.pszVal;
  347. mi.pszMSOESRec = pszMSOESRec;
  348. }
  349. IF_FAILEXIT(hr = pFolder->UpdateRecord(&mi));
  350. // if everything succeeded, commit the message to the store
  351. IF_FAILEXIT(hr = pFolder->SetMessageStream(idMessage, pStream));
  352. // the stream has now been used. null out the file address
  353. if (NULL != pfa)
  354. *pfa = NULL;
  355. exit:
  356. MemFree(pszDisplayFrom);
  357. MemFree(pszEmailFrom);
  358. MemFree(pszDisplayTo);
  359. MemFree(pszEmailTo);
  360. MemFree(pszMessageId);
  361. MemFree(pszXref);
  362. MemFree(pszReferences);
  363. MemFree(pszSubject);
  364. MemFree(pszNormalSubj);
  365. MemFree(pszAcctId);
  366. MemFree(pszAcctName);
  367. MemFree(pszServer);
  368. MemFree(pszForwardTo);
  369. MemFree(pszMSOESRec);
  370. SafeRelease(pMimeMsg);
  371. SafeRelease(pPropertySet);
  372. if (pmiFree)
  373. pFolder->FreeRecord(pmiFree);
  374. SafeRelease(pAdrTable);
  375. return hr;
  376. }