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.

564 lines
18 KiB

  1. // --------------------------------------------------------------------------------
  2. // Inetdate.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #ifndef MAC
  8. #include <shlwapi.h>
  9. #endif // !MAC
  10. #include "demand.h"
  11. #include "strconst.h"
  12. #include "dllmain.h"
  13. // ------------------------------------------------------------------------------------------
  14. // Prototypes
  15. // ------------------------------------------------------------------------------------------
  16. BOOL FFindMonth(LPCSTR pszMonth, LPSYSTEMTIME pst);
  17. BOOL FFindDayOfWeek(LPCSTR pszDayOfWeek, LPSYSTEMTIME pst);
  18. void ProcessTimeZoneInfo(LPCSTR pszTimeZone, ULONG cchTimeZone, LONG *pcHoursToAdd, LONG *pcMinutesToAdd);
  19. // ------------------------------------------------------------------------------------------
  20. // Date Conversion Data
  21. // ------------------------------------------------------------------------------------------
  22. #define CCHMIN_INTERNET_DATE 5
  23. // ------------------------------------------------------------------------------------------
  24. // Date Conversion States
  25. // ------------------------------------------------------------------------------------------
  26. #define IDF_MONTH FLAG01
  27. #define IDF_DAYOFWEEK FLAG02
  28. #define IDF_TIME FLAG03
  29. #define IDF_TIMEZONE FLAG04
  30. #define IDF_MACTIME FLAG05
  31. #define IDF_DAYOFMONTH FLAG06
  32. #define IDF_YEAR FLAG07
  33. static const char c_szTZ[] = "TZ";
  34. // ------------------------------------------------------------------------------------------
  35. // MimeOleInetDateToFileTime - Tue, 21 Jan 1997 18:25:40 GMT
  36. // ------------------------------------------------------------------------------------------
  37. MIMEOLEAPI MimeOleInetDateToFileTime(LPCSTR pszDate, LPFILETIME pft)
  38. {
  39. // Locals
  40. HRESULT hr=S_OK;
  41. SYSTEMTIME st={0};
  42. ULONG cchToken;
  43. LPCSTR pszToken;
  44. LONG cHoursToAdd=0, cMinutesToAdd=0;
  45. DWORD dwState=0;
  46. LONG lUnitsToAdd = 0;
  47. CStringParser cString;
  48. LARGE_INTEGER liTime;
  49. BOOL fRemovedDash = FALSE;
  50. LONGLONG liHoursToAdd = 1i64, liMinutesToAdd = 1i64;
  51. // Check Params
  52. if (NULL == pszDate || NULL == pft)
  53. return TrapError(E_INVALIDARG);
  54. // Init the String Parser
  55. cString.Init(pszDate, lstrlen(pszDate), PSF_NOTRAILWS | PSF_NOFRONTWS | PSF_NOCOMMENTS | PSF_ESCAPED);
  56. // Init systime
  57. st.wMonth = st.wDay = 1;
  58. // SetTokens
  59. cString.SetTokens(c_szCommaSpaceDash);
  60. // While we have characters to process
  61. while(1)
  62. {
  63. // IMAP has non-standard date format that uses "-" delimiter instead of " ".
  64. // When we're pretty sure we don't need "-" anymore, jettison from token list
  65. // otherwise we will mess up timezone parsing (which can start with a "-")
  66. // NOTE that we assume that we NEVER have to stuff the dash back in. We only need
  67. // the dash for IMAP dates, and IMAP dates should ALWAYS come before the time.
  68. if (FALSE == fRemovedDash &&
  69. ((dwState & IDF_YEAR) || ((dwState & (IDF_TIME | IDF_TIMEZONE)) == IDF_TIME))) // In case NO DATE or time BEFORE date
  70. {
  71. cString.SetTokens(c_szCommaSpace); // Remove dash from token list
  72. fRemovedDash = TRUE;
  73. }
  74. // Scan to ", " or "-" in IMAP case
  75. cString.ChParse();
  76. // Get parsed Token
  77. cchToken = cString.CchValue();
  78. pszToken = cString.PszValue();
  79. // Done
  80. if (0 == cchToken)
  81. break;
  82. // If the Word is not a digit
  83. if (IsDigit((LPSTR)pszToken) == FALSE)
  84. {
  85. // We haven't found the month
  86. if (!(IDF_MONTH & dwState))
  87. {
  88. // Lookup the Month
  89. if (FFindMonth(pszToken, &st) == TRUE)
  90. {
  91. dwState |= IDF_MONTH;
  92. continue;
  93. }
  94. }
  95. // We haven't found the day of the week
  96. if (!(IDF_DAYOFWEEK & dwState))
  97. {
  98. // Lookup the Month
  99. if (FFindDayOfWeek(pszToken, &st) == TRUE)
  100. {
  101. dwState |= IDF_DAYOFWEEK;
  102. continue;
  103. }
  104. }
  105. // Time Zone
  106. if ((IDF_TIME & dwState) && !(IDF_TIMEZONE & dwState))
  107. {
  108. dwState |= IDF_TIMEZONE;
  109. ProcessTimeZoneInfo(pszToken, cchToken, &cHoursToAdd, &cMinutesToAdd);
  110. }
  111. // Support "AM" and "PM" from Mac Mail Gateway
  112. if (IDF_MACTIME & dwState)
  113. {
  114. // Token Length
  115. if (2 == cchToken)
  116. {
  117. if (lstrcmpi("PM", pszToken) == 0)
  118. {
  119. if (st.wHour < 12)
  120. st.wHour += 12;
  121. }
  122. else if (lstrcmpi("AM", pszToken) == 0)
  123. {
  124. if (st.wHour == 12)
  125. st.wHour = 0;
  126. }
  127. }
  128. }
  129. }
  130. else
  131. {
  132. // Does string have a colon in it
  133. LPSTR pszColon = PszScanToCharA((LPSTR)pszToken, ':');
  134. // Found colon and time has not been found
  135. if (!(IDF_TIME & dwState) && '\0' != *pszColon)
  136. {
  137. // Its a time stamp - TBD - DBCS this part - AWN 28 Mar 94
  138. if (7 == cchToken || 8 == cchToken)
  139. {
  140. // Locals
  141. CHAR szTemp[CCHMAX_INTERNET_DATE];
  142. // Prefix with zero to make eight
  143. if (cchToken == 7)
  144. wnsprintfA(szTemp, ARRAYSIZE(szTemp), "0%s", pszToken);
  145. else
  146. StrCpyNA(szTemp, pszToken, ARRAYSIZE(szTemp));
  147. // convert the time into system time
  148. st.wHour = (WORD) StrToInt(szTemp);
  149. st.wMinute = (WORD) StrToInt(szTemp + 3);
  150. st.wSecond = (WORD) StrToInt(szTemp + 6);
  151. // Adjustments if needed
  152. if (st.wHour < 0 || st.wHour > 24)
  153. st.wHour = 0;
  154. if (st.wMinute < 0 || st.wMinute > 59)
  155. st.wMinute = 0;
  156. if (st.wSecond < 0 || st.wSecond > 59)
  157. st.wSecond = 0;
  158. // We found the time
  159. dwState |= IDF_TIME;
  160. }
  161. // This if process times of the time 12:01 AM or 01:45 PM
  162. else if (cchToken < 6 && lstrlen(pszColon) <= 3)
  163. {
  164. // rgchWord is pointing to hour.
  165. st.wHour = (WORD) StrToInt(pszToken);
  166. // Step over colon
  167. Assert(':' == *pszColon);
  168. pszColon++;
  169. // Get Minute
  170. st.wMinute = (WORD) StrToInt(pszColon);
  171. st.wSecond = 0;
  172. // It should never happen, but do bounds check anyway.
  173. if (st.wHour < 0 || st.wHour > 24)
  174. st.wHour = 0;
  175. if (st.wMinute < 0 || st.wMinute > 59)
  176. st.wMinute = 0;
  177. // Mac Time
  178. dwState |= IDF_TIME;
  179. dwState |= IDF_MACTIME;
  180. }
  181. }
  182. else
  183. {
  184. // Convert to int
  185. ULONG ulValue = StrToInt(pszToken);
  186. // Day of month
  187. if (!(IDF_DAYOFMONTH & dwState) && ulValue < 32)
  188. {
  189. // Set Day of Month
  190. st.wDay = (WORD)ulValue;
  191. // Adjust
  192. if (st.wDay < 1 || st.wDay > 31)
  193. st.wDay = 1;
  194. // Set State
  195. dwState |= IDF_DAYOFMONTH;
  196. }
  197. // Year
  198. else if (!(IDF_YEAR & dwState))
  199. {
  200. // 2-digit year
  201. if (ulValue < 100) // 2-digit year
  202. {
  203. // Compute Current Year
  204. ulValue += (((ulValue > g_ulY2kThreshold) ? g_ulUpperCentury - 1 : g_ulUpperCentury) * 100);
  205. }
  206. // Set Year
  207. st.wYear = (WORD)ulValue;
  208. // Set State
  209. dwState |= IDF_YEAR;
  210. }
  211. }
  212. }
  213. }
  214. // Convert sys time to file time
  215. if (SystemTimeToFileTime(&st, pft) == FALSE)
  216. {
  217. hr = TrapError(MIME_E_INVALID_INET_DATE);
  218. goto exit;
  219. }
  220. // No time zone was found ?
  221. if (!ISFLAGSET(dwState, IDF_TIMEZONE))
  222. {
  223. // Get default time zone
  224. ProcessTimeZoneInfo(c_szTZ, lstrlen(c_szTZ), &cHoursToAdd, &cMinutesToAdd);
  225. }
  226. // Init
  227. liTime.LowPart = pft->dwLowDateTime;
  228. liTime.HighPart = pft->dwHighDateTime;
  229. // Adjust the hour
  230. if (cHoursToAdd != 0)
  231. {
  232. lUnitsToAdd = cHoursToAdd * 3600;
  233. liHoursToAdd *= lUnitsToAdd;
  234. liHoursToAdd *= 10000000i64;
  235. liTime.QuadPart += liHoursToAdd;
  236. }
  237. // Adjust the minutes
  238. if (cMinutesToAdd != 0)
  239. {
  240. lUnitsToAdd = cMinutesToAdd * 60;
  241. liMinutesToAdd *= lUnitsToAdd;
  242. liMinutesToAdd *= 10000000i64;
  243. liTime.QuadPart += liMinutesToAdd;
  244. }
  245. // Assign the result to FILETIME
  246. pft->dwLowDateTime = liTime.LowPart;
  247. pft->dwHighDateTime = liTime.HighPart;
  248. exit:
  249. // Failure Defaults to current time...
  250. if (FAILED(hr))
  251. {
  252. GetSystemTime(&st);
  253. SystemTimeToFileTime(&st, pft);
  254. }
  255. // Done
  256. return hr;
  257. }
  258. // ------------------------------------------------------------------------------------------
  259. // FFindMonth
  260. // ------------------------------------------------------------------------------------------
  261. BOOL FFindMonth(LPCSTR pszMonth, LPSYSTEMTIME pst)
  262. {
  263. // Locals
  264. ULONG ulIndex;
  265. // Index of Month, one-based
  266. if (FAILED(HrIndexOfMonth(pszMonth, &ulIndex)))
  267. return FALSE;
  268. // Set It
  269. pst->wMonth = (WORD)ulIndex;
  270. // Found It
  271. return TRUE;
  272. }
  273. // ------------------------------------------------------------------------------------------
  274. // FFindDayOfWeek
  275. // ------------------------------------------------------------------------------------------
  276. BOOL FFindDayOfWeek(LPCSTR pszDayOfWeek, LPSYSTEMTIME pst)
  277. {
  278. // Locals
  279. ULONG ulIndex;
  280. // Index of Day, 0 based
  281. if (FAILED(HrIndexOfWeek(pszDayOfWeek, &ulIndex)))
  282. return FALSE;
  283. // Set It
  284. pst->wDayOfWeek = (WORD)ulIndex;
  285. // Failure
  286. return TRUE;
  287. }
  288. // ------------------------------------------------------------------------------------------
  289. // ProcessTimeZoneInfo
  290. // ------------------------------------------------------------------------------------------
  291. void ProcessTimeZoneInfo(LPCSTR pszTimeZone, ULONG cchTimeZone, LONG *pcHoursToAdd, LONG *pcMinutesToAdd)
  292. {
  293. // Locals
  294. CHAR szTimeZone[CCHMAX_INTERNET_DATE];
  295. // Invalid Arg
  296. Assert(pszTimeZone && pcHoursToAdd && pcMinutesToAdd && cchTimeZone <= sizeof(szTimeZone));
  297. // Copy buffer so we can but nulls into it...
  298. CopyMemory(szTimeZone, pszTimeZone, (sizeof(szTimeZone) < cchTimeZone + 1)?sizeof(szTimeZone):cchTimeZone + 1);
  299. // Init
  300. *pcHoursToAdd = *pcMinutesToAdd = 0;
  301. // +hhmm or -hhmm
  302. if (('-' == *szTimeZone || '+' == *szTimeZone) && cchTimeZone <= 5)
  303. {
  304. // Take off
  305. cchTimeZone -= 1;
  306. // determine the hour/minute offset
  307. if (cchTimeZone == 4)
  308. {
  309. *pcMinutesToAdd = StrToInt(szTimeZone + 3);
  310. *(szTimeZone + 3) = 0x00;
  311. *pcHoursToAdd = StrToInt(szTimeZone + 1);
  312. }
  313. // 3
  314. else if (cchTimeZone == 3)
  315. {
  316. *pcMinutesToAdd = StrToInt(szTimeZone + 2);
  317. *(szTimeZone + 2) = 0x00;
  318. *pcHoursToAdd = StrToInt(szTimeZone + 1);
  319. }
  320. // 2
  321. else if (cchTimeZone == 2 || cchTimeZone == 1)
  322. {
  323. *pcMinutesToAdd = 0;
  324. *pcHoursToAdd = StrToInt(szTimeZone + 1);
  325. }
  326. if ('+' == *szTimeZone)
  327. {
  328. *pcHoursToAdd = -(*pcHoursToAdd);
  329. *pcMinutesToAdd = -(*pcMinutesToAdd);
  330. }
  331. }
  332. // Xenix conversion: TZ = current time zone or other unknown tz types.
  333. else if (lstrcmpi(szTimeZone, "TZ") == 0 || lstrcmpi(szTimeZone, "LOCAL") == 0 || lstrcmpi(szTimeZone, "UNDEFINED") == 0)
  334. {
  335. // Locals
  336. TIME_ZONE_INFORMATION tzi ;
  337. DWORD dwResult;
  338. LONG cMinuteBias;
  339. // Get Current System Timezone Information
  340. dwResult = GetTimeZoneInformation (&tzi);
  341. AssertSz(dwResult != 0xFFFFFFFF, "GetTimeZoneInformation Failed.");
  342. // If that didn't fail
  343. if (dwResult != 0xFFFFFFFF)
  344. {
  345. // Locals
  346. cMinuteBias = tzi.Bias;
  347. // Modify Minute Bias
  348. if (dwResult == TIME_ZONE_ID_STANDARD)
  349. cMinuteBias += tzi.StandardBias;
  350. else if (dwResult == TIME_ZONE_ID_DAYLIGHT)
  351. cMinuteBias += tzi.DaylightBias ;
  352. // Adjust ToAdd Returs
  353. *pcHoursToAdd = cMinuteBias / 60;
  354. *pcMinutesToAdd = cMinuteBias % 60;
  355. }
  356. }
  357. // Loop through known time zone standards
  358. else
  359. {
  360. // Locals
  361. INETTIMEZONE rTimeZone;
  362. // Find time zone info
  363. if (FAILED(HrFindInetTimeZone(szTimeZone, &rTimeZone)))
  364. DebugTrace("Unrecognized zone info: [%s]\n", szTimeZone);
  365. else
  366. {
  367. *pcHoursToAdd = rTimeZone.cHourOffset;
  368. *pcMinutesToAdd = rTimeZone.cMinuteOffset;
  369. }
  370. }
  371. }
  372. // ------------------------------------------------------------------------------------------
  373. // MimeOleFileTimeToInetDate
  374. // ------------------------------------------------------------------------------------------
  375. MIMEOLEAPI MimeOleFileTimeToInetDate(LPFILETIME pft, LPSTR pszDate, ULONG cchMax)
  376. {
  377. // Locals
  378. SYSTEMTIME st;
  379. DWORD dwTimeZoneId=TIME_ZONE_ID_UNKNOWN;
  380. CHAR cDiff;
  381. LONG ltzBias=0;
  382. LONG ltzHour;
  383. LONG ltzMinute;
  384. TIME_ZONE_INFORMATION tzi;
  385. // Invalid Arg
  386. if (NULL == pszDate)
  387. return TrapError(E_INVALIDARG);
  388. if (cchMax < CCHMAX_INTERNET_DATE)
  389. return TrapError(MIME_E_BUFFER_TOO_SMALL);
  390. // Verify lpst is set
  391. if (pft == NULL || (pft->dwLowDateTime == 0 && pft->dwHighDateTime == 0))
  392. {
  393. GetLocalTime(&st);
  394. }
  395. else
  396. {
  397. FILETIME ftLocal;
  398. FileTimeToLocalFileTime(pft, &ftLocal);
  399. FileTimeToSystemTime(&ftLocal, &st);
  400. }
  401. // Gets TIME_ZONE_INFORMATION
  402. dwTimeZoneId = GetTimeZoneInformation (&tzi);
  403. switch (dwTimeZoneId)
  404. {
  405. case TIME_ZONE_ID_STANDARD:
  406. ltzBias = tzi.Bias + tzi.StandardBias;
  407. break;
  408. case TIME_ZONE_ID_DAYLIGHT:
  409. ltzBias = tzi.Bias + tzi.DaylightBias;
  410. break;
  411. case TIME_ZONE_ID_UNKNOWN:
  412. default:
  413. ltzBias = tzi.Bias;
  414. break;
  415. }
  416. // Set Hour Minutes and time zone dif
  417. ltzHour = ltzBias / 60;
  418. ltzMinute = ltzBias % 60;
  419. cDiff = (ltzHour < 0) ? '+' : '-';
  420. // Constructs RFC 822 format: "ddd, dd mmm yyyy hh:mm:ss +/- hhmm\0"
  421. Assert(st.wMonth);
  422. wnsprintfA(pszDate, cchMax, "%3s, %d %3s %4d %02d:%02d:%02d %c%02d%02d",
  423. PszDayFromIndex(st.wDayOfWeek), // "ddd"
  424. st.wDay, // "dd"
  425. PszMonthFromIndex(st.wMonth), // "mmm"
  426. st.wYear, // "yyyy"
  427. st.wHour, // "hh"
  428. st.wMinute, // "mm"
  429. st.wSecond, // "ss"
  430. cDiff, // "+" / "-"
  431. abs (ltzHour), // "hh"
  432. abs (ltzMinute)); // "mm"
  433. // Done
  434. return S_OK;
  435. }
  436. #ifdef WININET_DATE
  437. // ------------------------------------------------------------------------------------------
  438. // MimeOleInetDateToFileTime
  439. // ------------------------------------------------------------------------------------------
  440. MIMEOLEAPI MimeOleInetDateToFileTime(LPCSTR pszDate, LPFILETIME pft)
  441. {
  442. // Locals
  443. SYSTEMTIME st;
  444. // Check Params
  445. if (NULL == pszDate || NULL == pft)
  446. return TrapError(E_INVALIDARG);
  447. // Use wininet to convert date...
  448. if (InternetTimeToSystemTime(pszDate, &st, 0) == 0)
  449. return TrapError(E_FAIL);
  450. // Convert to file time
  451. SystemTimeToFileTime(&st, pft);
  452. // Done
  453. return S_OK;
  454. }
  455. // ------------------------------------------------------------------------------------------
  456. // MimeOleFileTimeToInetDate
  457. // ------------------------------------------------------------------------------------------
  458. MIMEOLEAPI MimeOleFileTimeToInetDate(LPFILETIME pft, LPSTR pszDate, ULONG cchMax)
  459. {
  460. // Locals
  461. SYSTEMTIME st;
  462. // Invalid Arg
  463. if (NULL == pszDate)
  464. return TrapError(E_INVALIDARG);
  465. if (cchMax < CCHMAX_INTERNET_TIME)
  466. return TrapError(MIME_E_BUFFER_TOO_SMALL);
  467. // Verify lpst is set
  468. if (pft == NULL || (pft->dwLowDateTime == 0 && pft->dwHighDateTime == 0))
  469. GetLocalTime(&st);
  470. else
  471. FileTimeToSystemTime(pft, &st);
  472. // Use wininet to convert date...
  473. if (InternetTimeFromSystemTime(&st, INTERNET_RFC1123_FORMAT, pszDate, cchMax) == 0)
  474. return TrapError(E_FAIL);
  475. // Done
  476. return S_OK;
  477. }
  478. #endif