|
|
// --------------------------------------------------------------------------------
// Inetdate.cpp
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
// Steven J. Bailey
// --------------------------------------------------------------------------------
#include "pch.hxx"
#ifndef MAC
#include <shlwapi.h>
#endif // !MAC
#include "demand.h"
#include "strconst.h"
#include "dllmain.h"
// ------------------------------------------------------------------------------------------
// Prototypes
// ------------------------------------------------------------------------------------------
BOOL FFindMonth(LPCSTR pszMonth, LPSYSTEMTIME pst); BOOL FFindDayOfWeek(LPCSTR pszDayOfWeek, LPSYSTEMTIME pst); void ProcessTimeZoneInfo(LPCSTR pszTimeZone, ULONG cchTimeZone, LONG *pcHoursToAdd, LONG *pcMinutesToAdd);
// ------------------------------------------------------------------------------------------
// Date Conversion Data
// ------------------------------------------------------------------------------------------
#define CCHMIN_INTERNET_DATE 5
// ------------------------------------------------------------------------------------------
// Date Conversion States
// ------------------------------------------------------------------------------------------
#define IDF_MONTH FLAG01
#define IDF_DAYOFWEEK FLAG02
#define IDF_TIME FLAG03
#define IDF_TIMEZONE FLAG04
#define IDF_MACTIME FLAG05
#define IDF_DAYOFMONTH FLAG06
#define IDF_YEAR FLAG07
static const char c_szTZ[] = "TZ";
// ------------------------------------------------------------------------------------------
// MimeOleInetDateToFileTime - Tue, 21 Jan 1997 18:25:40 GMT
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleInetDateToFileTime(LPCSTR pszDate, LPFILETIME pft) { // Locals
HRESULT hr=S_OK; SYSTEMTIME st={0}; ULONG cchToken; LPCSTR pszToken; LONG cHoursToAdd=0, cMinutesToAdd=0; DWORD dwState=0; LONG lUnitsToAdd = 0; CStringParser cString; LARGE_INTEGER liTime; BOOL fRemovedDash = FALSE; LONGLONG liHoursToAdd = 1i64, liMinutesToAdd = 1i64;
// Check Params
if (NULL == pszDate || NULL == pft) return TrapError(E_INVALIDARG);
// Init the String Parser
cString.Init(pszDate, lstrlen(pszDate), PSF_NOTRAILWS | PSF_NOFRONTWS | PSF_NOCOMMENTS | PSF_ESCAPED);
// Init systime
st.wMonth = st.wDay = 1;
// SetTokens
cString.SetTokens(c_szCommaSpaceDash);
// While we have characters to process
while(1) { // IMAP has non-standard date format that uses "-" delimiter instead of " ".
// When we're pretty sure we don't need "-" anymore, jettison from token list
// otherwise we will mess up timezone parsing (which can start with a "-")
// NOTE that we assume that we NEVER have to stuff the dash back in. We only need
// the dash for IMAP dates, and IMAP dates should ALWAYS come before the time.
if (FALSE == fRemovedDash && ((dwState & IDF_YEAR) || ((dwState & (IDF_TIME | IDF_TIMEZONE)) == IDF_TIME))) // In case NO DATE or time BEFORE date
{ cString.SetTokens(c_szCommaSpace); // Remove dash from token list
fRemovedDash = TRUE; }
// Scan to ", " or "-" in IMAP case
cString.ChParse();
// Get parsed Token
cchToken = cString.CchValue(); pszToken = cString.PszValue();
// Done
if (0 == cchToken) break;
// If the Word is not a digit
if (IsDigit((LPSTR)pszToken) == FALSE) { // We haven't found the month
if (!(IDF_MONTH & dwState)) { // Lookup the Month
if (FFindMonth(pszToken, &st) == TRUE) { dwState |= IDF_MONTH; continue; } }
// We haven't found the day of the week
if (!(IDF_DAYOFWEEK & dwState)) { // Lookup the Month
if (FFindDayOfWeek(pszToken, &st) == TRUE) { dwState |= IDF_DAYOFWEEK; continue; } }
// Time Zone
if ((IDF_TIME & dwState) && !(IDF_TIMEZONE & dwState)) { dwState |= IDF_TIMEZONE; ProcessTimeZoneInfo(pszToken, cchToken, &cHoursToAdd, &cMinutesToAdd); }
// Support "AM" and "PM" from Mac Mail Gateway
if (IDF_MACTIME & dwState) { // Token Length
if (2 == cchToken) { if (lstrcmpi("PM", pszToken) == 0) { if (st.wHour < 12) st.wHour += 12; } else if (lstrcmpi("AM", pszToken) == 0) { if (st.wHour == 12) st.wHour = 0; } } } }
else { // Does string have a colon in it
LPSTR pszColon = PszScanToCharA((LPSTR)pszToken, ':');
// Found colon and time has not been found
if (!(IDF_TIME & dwState) && '\0' != *pszColon) { // Its a time stamp - TBD - DBCS this part - AWN 28 Mar 94
if (7 == cchToken || 8 == cchToken) { // Locals
CHAR szTemp[CCHMAX_INTERNET_DATE];
// Prefix with zero to make eight
if (cchToken == 7) wnsprintfA(szTemp, ARRAYSIZE(szTemp), "0%s", pszToken); else StrCpyNA(szTemp, pszToken, ARRAYSIZE(szTemp));
// convert the time into system time
st.wHour = (WORD) StrToInt(szTemp); st.wMinute = (WORD) StrToInt(szTemp + 3); st.wSecond = (WORD) StrToInt(szTemp + 6);
// Adjustments if needed
if (st.wHour < 0 || st.wHour > 24) st.wHour = 0; if (st.wMinute < 0 || st.wMinute > 59) st.wMinute = 0; if (st.wSecond < 0 || st.wSecond > 59) st.wSecond = 0;
// We found the time
dwState |= IDF_TIME; }
// This if process times of the time 12:01 AM or 01:45 PM
else if (cchToken < 6 && lstrlen(pszColon) <= 3) { // rgchWord is pointing to hour.
st.wHour = (WORD) StrToInt(pszToken);
// Step over colon
Assert(':' == *pszColon); pszColon++;
// Get Minute
st.wMinute = (WORD) StrToInt(pszColon); st.wSecond = 0;
// It should never happen, but do bounds check anyway.
if (st.wHour < 0 || st.wHour > 24) st.wHour = 0; if (st.wMinute < 0 || st.wMinute > 59) st.wMinute = 0;
// Mac Time
dwState |= IDF_TIME; dwState |= IDF_MACTIME; } } else { // Convert to int
ULONG ulValue = StrToInt(pszToken);
// Day of month
if (!(IDF_DAYOFMONTH & dwState) && ulValue < 32) { // Set Day of Month
st.wDay = (WORD)ulValue;
// Adjust
if (st.wDay < 1 || st.wDay > 31) st.wDay = 1;
// Set State
dwState |= IDF_DAYOFMONTH; }
// Year
else if (!(IDF_YEAR & dwState)) { // 2-digit year
if (ulValue < 100) // 2-digit year
{ // Compute Current Year
ulValue += (((ulValue > g_ulY2kThreshold) ? g_ulUpperCentury - 1 : g_ulUpperCentury) * 100); }
// Set Year
st.wYear = (WORD)ulValue;
// Set State
dwState |= IDF_YEAR; } } } }
// Convert sys time to file time
if (SystemTimeToFileTime(&st, pft) == FALSE) { hr = TrapError(MIME_E_INVALID_INET_DATE); goto exit; }
// No time zone was found ?
if (!ISFLAGSET(dwState, IDF_TIMEZONE)) { // Get default time zone
ProcessTimeZoneInfo(c_szTZ, lstrlen(c_szTZ), &cHoursToAdd, &cMinutesToAdd); }
// Init
liTime.LowPart = pft->dwLowDateTime; liTime.HighPart = pft->dwHighDateTime;
// Adjust the hour
if (cHoursToAdd != 0) { lUnitsToAdd = cHoursToAdd * 3600; liHoursToAdd *= lUnitsToAdd; liHoursToAdd *= 10000000i64; liTime.QuadPart += liHoursToAdd; }
// Adjust the minutes
if (cMinutesToAdd != 0) { lUnitsToAdd = cMinutesToAdd * 60; liMinutesToAdd *= lUnitsToAdd; liMinutesToAdd *= 10000000i64; liTime.QuadPart += liMinutesToAdd; }
// Assign the result to FILETIME
pft->dwLowDateTime = liTime.LowPart; pft->dwHighDateTime = liTime.HighPart;
exit: // Failure Defaults to current time...
if (FAILED(hr)) { GetSystemTime(&st); SystemTimeToFileTime(&st, pft); }
// Done
return hr; }
// ------------------------------------------------------------------------------------------
// FFindMonth
// ------------------------------------------------------------------------------------------
BOOL FFindMonth(LPCSTR pszMonth, LPSYSTEMTIME pst) { // Locals
ULONG ulIndex;
// Index of Month, one-based
if (FAILED(HrIndexOfMonth(pszMonth, &ulIndex))) return FALSE;
// Set It
pst->wMonth = (WORD)ulIndex;
// Found It
return TRUE; }
// ------------------------------------------------------------------------------------------
// FFindDayOfWeek
// ------------------------------------------------------------------------------------------
BOOL FFindDayOfWeek(LPCSTR pszDayOfWeek, LPSYSTEMTIME pst) { // Locals
ULONG ulIndex;
// Index of Day, 0 based
if (FAILED(HrIndexOfWeek(pszDayOfWeek, &ulIndex))) return FALSE;
// Set It
pst->wDayOfWeek = (WORD)ulIndex;
// Failure
return TRUE; }
// ------------------------------------------------------------------------------------------
// ProcessTimeZoneInfo
// ------------------------------------------------------------------------------------------
void ProcessTimeZoneInfo(LPCSTR pszTimeZone, ULONG cchTimeZone, LONG *pcHoursToAdd, LONG *pcMinutesToAdd) { // Locals
CHAR szTimeZone[CCHMAX_INTERNET_DATE];
// Invalid Arg
Assert(pszTimeZone && pcHoursToAdd && pcMinutesToAdd && cchTimeZone <= sizeof(szTimeZone));
// Copy buffer so we can but nulls into it...
CopyMemory(szTimeZone, pszTimeZone, (sizeof(szTimeZone) < cchTimeZone + 1)?sizeof(szTimeZone):cchTimeZone + 1);
// Init
*pcHoursToAdd = *pcMinutesToAdd = 0;
// +hhmm or -hhmm
if (('-' == *szTimeZone || '+' == *szTimeZone) && cchTimeZone <= 5) { // Take off
cchTimeZone -= 1;
// determine the hour/minute offset
if (cchTimeZone == 4) { *pcMinutesToAdd = StrToInt(szTimeZone + 3); *(szTimeZone + 3) = 0x00; *pcHoursToAdd = StrToInt(szTimeZone + 1); }
// 3
else if (cchTimeZone == 3) { *pcMinutesToAdd = StrToInt(szTimeZone + 2); *(szTimeZone + 2) = 0x00; *pcHoursToAdd = StrToInt(szTimeZone + 1); }
// 2
else if (cchTimeZone == 2 || cchTimeZone == 1) { *pcMinutesToAdd = 0; *pcHoursToAdd = StrToInt(szTimeZone + 1); }
if ('+' == *szTimeZone) { *pcHoursToAdd = -(*pcHoursToAdd); *pcMinutesToAdd = -(*pcMinutesToAdd); } }
// Xenix conversion: TZ = current time zone or other unknown tz types.
else if (lstrcmpi(szTimeZone, "TZ") == 0 || lstrcmpi(szTimeZone, "LOCAL") == 0 || lstrcmpi(szTimeZone, "UNDEFINED") == 0) { // Locals
TIME_ZONE_INFORMATION tzi ; DWORD dwResult; LONG cMinuteBias;
// Get Current System Timezone Information
dwResult = GetTimeZoneInformation (&tzi); AssertSz(dwResult != 0xFFFFFFFF, "GetTimeZoneInformation Failed.");
// If that didn't fail
if (dwResult != 0xFFFFFFFF) { // Locals
cMinuteBias = tzi.Bias;
// Modify Minute Bias
if (dwResult == TIME_ZONE_ID_STANDARD) cMinuteBias += tzi.StandardBias; else if (dwResult == TIME_ZONE_ID_DAYLIGHT) cMinuteBias += tzi.DaylightBias ;
// Adjust ToAdd Returs
*pcHoursToAdd = cMinuteBias / 60; *pcMinutesToAdd = cMinuteBias % 60; } }
// Loop through known time zone standards
else { // Locals
INETTIMEZONE rTimeZone;
// Find time zone info
if (FAILED(HrFindInetTimeZone(szTimeZone, &rTimeZone))) DebugTrace("Unrecognized zone info: [%s]\n", szTimeZone); else { *pcHoursToAdd = rTimeZone.cHourOffset; *pcMinutesToAdd = rTimeZone.cMinuteOffset; } } }
// ------------------------------------------------------------------------------------------
// MimeOleFileTimeToInetDate
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleFileTimeToInetDate(LPFILETIME pft, LPSTR pszDate, ULONG cchMax) { // Locals
SYSTEMTIME st; DWORD dwTimeZoneId=TIME_ZONE_ID_UNKNOWN; CHAR cDiff; LONG ltzBias=0; LONG ltzHour; LONG ltzMinute; TIME_ZONE_INFORMATION tzi;
// Invalid Arg
if (NULL == pszDate) return TrapError(E_INVALIDARG); if (cchMax < CCHMAX_INTERNET_DATE) return TrapError(MIME_E_BUFFER_TOO_SMALL);
// Verify lpst is set
if (pft == NULL || (pft->dwLowDateTime == 0 && pft->dwHighDateTime == 0)) { GetLocalTime(&st); } else { FILETIME ftLocal; FileTimeToLocalFileTime(pft, &ftLocal); FileTimeToSystemTime(&ftLocal, &st); }
// Gets TIME_ZONE_INFORMATION
dwTimeZoneId = GetTimeZoneInformation (&tzi); switch (dwTimeZoneId) { case TIME_ZONE_ID_STANDARD: ltzBias = tzi.Bias + tzi.StandardBias; break;
case TIME_ZONE_ID_DAYLIGHT: ltzBias = tzi.Bias + tzi.DaylightBias; break;
case TIME_ZONE_ID_UNKNOWN: default: ltzBias = tzi.Bias; break; }
// Set Hour Minutes and time zone dif
ltzHour = ltzBias / 60; ltzMinute = ltzBias % 60; cDiff = (ltzHour < 0) ? '+' : '-';
// Constructs RFC 822 format: "ddd, dd mmm yyyy hh:mm:ss +/- hhmm\0"
Assert(st.wMonth); wnsprintfA(pszDate, cchMax, "%3s, %d %3s %4d %02d:%02d:%02d %c%02d%02d", PszDayFromIndex(st.wDayOfWeek), // "ddd"
st.wDay, // "dd"
PszMonthFromIndex(st.wMonth), // "mmm"
st.wYear, // "yyyy"
st.wHour, // "hh"
st.wMinute, // "mm"
st.wSecond, // "ss"
cDiff, // "+" / "-"
abs (ltzHour), // "hh"
abs (ltzMinute)); // "mm"
// Done
return S_OK; }
#ifdef WININET_DATE
// ------------------------------------------------------------------------------------------
// MimeOleInetDateToFileTime
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleInetDateToFileTime(LPCSTR pszDate, LPFILETIME pft) { // Locals
SYSTEMTIME st;
// Check Params
if (NULL == pszDate || NULL == pft) return TrapError(E_INVALIDARG);
// Use wininet to convert date...
if (InternetTimeToSystemTime(pszDate, &st, 0) == 0) return TrapError(E_FAIL);
// Convert to file time
SystemTimeToFileTime(&st, pft);
// Done
return S_OK; }
// ------------------------------------------------------------------------------------------
// MimeOleFileTimeToInetDate
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleFileTimeToInetDate(LPFILETIME pft, LPSTR pszDate, ULONG cchMax) { // Locals
SYSTEMTIME st;
// Invalid Arg
if (NULL == pszDate) return TrapError(E_INVALIDARG); if (cchMax < CCHMAX_INTERNET_TIME) return TrapError(MIME_E_BUFFER_TOO_SMALL);
// Verify lpst is set
if (pft == NULL || (pft->dwLowDateTime == 0 && pft->dwHighDateTime == 0)) GetLocalTime(&st); else FileTimeToSystemTime(pft, &st);
// Use wininet to convert date...
if (InternetTimeFromSystemTime(&st, INTERNET_RFC1123_FORMAT, pszDate, cchMax) == 0) return TrapError(E_FAIL);
// Done
return S_OK; } #endif
|