[NET] Fix the timezone issue in the logon hours parser and display code of the USER...
[reactos.git] / base / applications / network / net / cmdUser.c
index f697d45..dc75278 100644 (file)
@@ -12,6 +12,8 @@
 
 #define SECONDS_PER_DAY (60 * 60 * 24)
 #define SECONDS_PER_HOUR (60 * 60)
+#define HOURS_PER_DAY 24
+#define DAYS_PER_WEEK 7
 
 typedef struct _COUNTY_TABLE
 {
@@ -48,6 +50,8 @@ static COUNTRY_TABLE CountryTable[] =
   {785, 5103},   // Arabic
   {972, 5104} }; // Hebrew
 
+//static PWSTR DaysArray[] = {L"So", L"Mo", L"Di", L"Mi", L"Do", L"Fr", L"Sa"};
+static PWSTR DaysArray[] = {L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat"};
 
 static
 int
@@ -226,14 +230,27 @@ GetCountryFromCountryCode(
 
 static
 BOOL
-BitValue(
-    PBYTE pLogonHours,
+GetBitValue(
+    PBYTE pBitmap,
+    DWORD dwBitNumber)
+{
+    DWORD dwIndex = dwBitNumber / 8;
+    BYTE Mask = 1 << (dwBitNumber & 7);
+
+    return ((pBitmap[dwIndex] & Mask) != 0);
+}
+
+
+static
+VOID
+SetBitValue(
+    PBYTE pBitmap,
     DWORD dwBitNumber)
 {
     DWORD dwIndex = dwBitNumber / 8;
     BYTE Mask = 1 << (dwBitNumber & 7);
 
-    return ((pLogonHours[dwIndex] & Mask) != 0);
+    pBitmap[dwIndex] |= Mask;
 }
 
 
@@ -245,8 +262,12 @@ PrintLogonHours(
     INT nPaddedLength)
 {
     DWORD dwUnitsPerDay, dwBitNumber, dwSecondsPerUnit;
-    DWORD dwStartTime, dwEndTime, dwStartDay, dwEndDay;
+    DWORD dwStartTime, dwEndTime, dwStartDay, dwEndDay, dwBias;
     BOOL bBitValue, bFirst = TRUE;
+    TIME_ZONE_INFORMATION TimeZoneInformation;
+
+    GetTimeZoneInformation(&TimeZoneInformation);
+    dwBias = (TimeZoneInformation.Bias / 60) * SECONDS_PER_HOUR;
 
     if ((dwUnitsPerWeek == 0) ||
         ((dwUnitsPerWeek %7) != 0))
@@ -262,7 +283,7 @@ PrintLogonHours(
 
     for (dwBitNumber = 0; dwBitNumber < dwUnitsPerWeek; dwBitNumber++)
     {
-        bBitValue = BitValue(pLogonHours, dwBitNumber);
+        bBitValue = GetBitValue(pLogonHours, dwBitNumber);
         if (bBitValue)
         {
             dwStartTime = dwSecondsPerUnit * dwBitNumber;
@@ -271,7 +292,7 @@ PrintLogonHours(
             {
                 dwBitNumber++;
                 if (dwBitNumber < dwUnitsPerWeek)
-                    bBitValue = BitValue(pLogonHours, dwBitNumber);
+                    bBitValue = GetBitValue(pLogonHours, dwBitNumber);
             }
 
             dwEndTime = dwSecondsPerUnit * dwBitNumber;
@@ -291,7 +312,9 @@ PrintLogonHours(
 
                 PrintMessageString(4307 + dwStartDay);
                 ConPuts(StdOut, L" ");
-                PrintLocalTime((dwStartTime % SECONDS_PER_DAY) + SECONDS_PER_HOUR);
+
+                /* Convert from GMT to local timezone */
+                PrintLocalTime((dwStartTime % SECONDS_PER_DAY) - dwBias);
 
                 ConPrintf(StdOut, L" - ");
                 if (dwStartDay != dwEndDay)
@@ -300,13 +323,21 @@ PrintLogonHours(
                     ConPuts(StdOut, L" ");
                 }
 
-                PrintLocalTime((dwEndTime % SECONDS_PER_DAY) + SECONDS_PER_HOUR);
+                /* Convert from GMT to local timezone */
+                PrintLocalTime((dwEndTime % SECONDS_PER_DAY) - dwBias);
                 ConPuts(StdOut, L"\n");
             }
 
             bFirst = FALSE;
         }
     }
+
+    if (bFirst)
+    {
+        /* No logon hours */
+        PrintMessageString(4434);
+        ConPuts(StdOut, L"\n");
+    }
 }
 
 
@@ -802,6 +833,273 @@ ParseDate(
 }
 
 
+static
+BOOL
+ParseHour(
+    PWSTR pszString,
+    PLONG plHour)
+{
+    PWCHAR pChar;
+    LONG lHour = 0;
+
+    if (!iswdigit(pszString[0]))
+        return FALSE;
+
+    pChar = pszString;
+    while (iswdigit(*pChar))
+    {
+        lHour = lHour * 10 + *pChar - L'0';
+        pChar++;
+    }
+
+    if (lHour > 24)
+        return FALSE;
+
+    if (lHour == 24)
+        lHour = 0;
+
+    if ((*pChar != UNICODE_NULL) &&
+        (lHour >= 1) &&
+        (lHour <= 12))
+    {
+        if ((_wcsicmp(pChar, L"am") == 0) ||
+            (_wcsicmp(pChar, L"a.m.") == 0))
+        {
+            if (lHour == 12)
+                lHour = 0;
+        }
+        else if ((_wcsicmp(pChar, L"pm") == 0) ||
+                 (_wcsicmp(pChar, L"p.m.") == 0))
+        {
+            if (lHour != 12)
+                lHour += 12;
+        }
+        else
+        {
+            return FALSE;
+        }
+    }
+
+    *plHour = lHour;
+
+    return TRUE;
+}
+
+
+static
+BOOL
+ParseDay(
+    PWSTR pszString,
+    PDWORD pdwDay)
+{
+    DWORD i;
+
+    for (i = 0; i < ARRAYSIZE(DaysArray); i++)
+    {
+        if (_wcsicmp(pszString, DaysArray[i]) == 0)
+        {
+            *pdwDay = i;
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+
+static
+DWORD
+ParseLogonHours(
+    PWSTR pszParams,
+    PBYTE *ppLogonBitmap,
+    PDWORD pdwUnitsPerWeek)
+{
+    TIME_ZONE_INFORMATION TimeZoneInformation;
+    PBYTE pLogonBitmap = NULL;
+    DWORD dwError = ERROR_SUCCESS;
+    WCHAR szBuffer[32];
+    PWSTR ptr1, ptr2;
+    WCHAR prevSep, nextSep;
+    DWORD dwStartDay, dwEndDay, i, j;
+    LONG lStartHour, lEndHour, lBias;
+    BYTE DayBitmap;
+    BYTE HourBitmap[6];
+
+    GetTimeZoneInformation(&TimeZoneInformation);
+    lBias = TimeZoneInformation.Bias / 60;
+
+    pLogonBitmap = HeapAlloc(GetProcessHeap(),
+                             HEAP_ZERO_MEMORY,
+                             UNITS_PER_WEEK / 8);
+    if (pLogonBitmap == NULL)
+        return ERROR_OUTOFMEMORY;
+
+    if (*pszParams == UNICODE_NULL)
+    {
+        goto done;
+    }
+
+    if (wcsicmp(pszParams, L"all") == 0)
+    {
+        FillMemory(pLogonBitmap, UNITS_PER_WEEK / 8, 0xFF);
+        goto done;
+    }
+
+    ZeroMemory(&DayBitmap, sizeof(DayBitmap));
+    ZeroMemory(HourBitmap, sizeof(HourBitmap));
+
+    ZeroMemory(szBuffer, sizeof(szBuffer));
+    ptr1 = pszParams;
+    ptr2 = szBuffer;
+    prevSep = UNICODE_NULL;
+    nextSep = UNICODE_NULL;
+    for (;;)
+    {
+        if (*ptr1 != L'-' && *ptr1 != L',' && *ptr1 != L';' && *ptr1 != UNICODE_NULL)
+        {
+            *ptr2 = *ptr1;
+            ptr2++;
+        }
+        else
+        {
+            prevSep = nextSep;
+            nextSep = *ptr1;
+
+            if (prevSep != L'-')
+            {
+                /* Set first value */
+                if (iswdigit(szBuffer[0]))
+                {
+                    /* Parse hour */
+                    if (!ParseHour(szBuffer, &lStartHour))
+                    {
+                        dwError = 3769;
+                        break;
+                    }
+
+                    /* Convert from local timezone to GMT */
+                    lStartHour += lBias;
+                    if (lStartHour < 0)
+                        lStartHour += UNITS_PER_WEEK;
+                    else if (lStartHour > UNITS_PER_WEEK)
+                        lStartHour -= UNITS_PER_WEEK;
+
+                    SetBitValue(HourBitmap, (DWORD)lStartHour);
+                }
+                else
+                {
+                    /* Parse day */
+                    if (!ParseDay(szBuffer, &dwStartDay))
+                    {
+                        dwError = 3768;
+                        break;
+                    }
+
+                    SetBitValue(&DayBitmap, dwStartDay);
+                }
+            }
+            else
+            {
+                /* Set second value */
+                if (iswdigit(szBuffer[0]))
+                {
+                    /* Parse hour */
+                    if (!ParseHour(szBuffer, &lEndHour))
+                    {
+                        dwError = 3769;
+                        break;
+                    }
+
+                    if (lEndHour < lStartHour)
+                        lEndHour += HOURS_PER_DAY;
+                    else if (lEndHour == lStartHour)
+                        lEndHour = lStartHour + HOURS_PER_DAY;
+
+                    /* Convert from local timezone to GMT */
+                    lEndHour += lBias;
+                    if (lEndHour < 0)
+                        lEndHour += UNITS_PER_WEEK;
+                    else if (lEndHour > UNITS_PER_WEEK)
+                        lEndHour -= UNITS_PER_WEEK;
+
+                    for (i = (DWORD)lStartHour; i < (DWORD)lEndHour; i++)
+                        SetBitValue(HourBitmap, i);
+                }
+                else
+                {
+                    /* Parse day */
+                    if (!ParseDay(szBuffer, &dwEndDay))
+                    {
+                        dwError = 3768;
+                        break;
+                    }
+
+                    if (dwEndDay <= dwStartDay)
+                        dwEndDay += DAYS_PER_WEEK;
+
+                    for (i = dwStartDay; i <= dwEndDay; i++)
+                        SetBitValue(&DayBitmap, i % DAYS_PER_WEEK);
+                }
+            }
+
+            if (*ptr1 == L';' || *ptr1 == UNICODE_NULL)
+            {
+                /* Fill the logon hour bitmap */
+                for (i = 0; i < DAYS_PER_WEEK; i++)
+                {
+                    if (GetBitValue(&DayBitmap, i))
+                    {
+                        for (j = 0; j < 48; j++)
+                        {
+                            if (GetBitValue(HourBitmap, j))
+                                SetBitValue(pLogonBitmap, ((i * HOURS_PER_DAY) + j) % UNITS_PER_WEEK);
+                        }
+                    }
+                }
+
+                /* Reset the Bitmaps */
+                ZeroMemory(&DayBitmap, sizeof(DayBitmap));
+                ZeroMemory(HourBitmap, sizeof(HourBitmap));
+            }
+
+            if (*ptr1 == UNICODE_NULL)
+                break;
+
+            ZeroMemory(szBuffer, sizeof(szBuffer));
+            ptr2 = szBuffer;
+        }
+
+        ptr1++;
+    }
+
+#if 0
+    printf("LogonBitmap:\n");
+    for (i = 0; i < DAYS_PER_WEEK; i++)
+    {
+        j = i * 3;
+        printf("%lu: %02x%02x%02x\n", i, pLogonHours[j + 2], pLogonHours[j + 1], pLogonHours[j + 0]);
+    }
+    printf("\n");
+#endif
+
+done:
+    if (dwError == ERROR_SUCCESS)
+    {
+        *ppLogonBitmap = pLogonBitmap;
+        *pdwUnitsPerWeek = UNITS_PER_WEEK;
+    }
+    else
+    {
+        if (pLogonBitmap != NULL)
+            HeapFree(GetProcessHeap(), 0, pLogonBitmap);
+        *ppLogonBitmap = NULL;
+        *pdwUnitsPerWeek = 0;
+    }
+
+    return dwError;
+}
+
+
 INT
 cmdUser(
     INT argc,
@@ -824,6 +1122,8 @@ cmdUser(
     LPWSTR endptr;
     DWORD value;
     BOOL bPasswordAllocated = FALSE;
+    PBYTE pLogonHours = NULL;
+    DWORD dwUnitsPerWeek;
     NET_API_STATUS Status;
 
     i = 2;
@@ -877,7 +1177,7 @@ cmdUser(
         ConPrintf(StdOut, L"Status: %lu\n", Status);
         return 0;
     }
-    else if (lpUserName != NULL && lpPassword == NULL)
+    else if (lpUserName != NULL && lpPassword == NULL && argc == 3)
     {
         Status = DisplayUser(lpUserName);
         ConPrintf(StdOut, L"Status: %lu\n", Status);
@@ -1032,8 +1332,19 @@ cmdUser(
         }
         else if (_wcsnicmp(argv[j], L"/times:", 7) == 0)
         {
-            /* FIXME */
-            ConPuts(StdErr, L"The /TIMES option is not supported yet.\n");
+            Status = ParseLogonHours(&argv[j][7],
+                                     &pLogonHours,
+                                     &dwUnitsPerWeek);
+            if (Status == ERROR_SUCCESS)
+            {
+                pUserInfo->usri4_logon_hours = pLogonHours;
+                pUserInfo->usri4_units_per_week = dwUnitsPerWeek;
+            }
+            else
+            {
+                PrintMessageString(Status);
+                goto done;
+            }
         }
         else if (_wcsnicmp(argv[j], L"/usercomment:", 13) == 0)
         {
@@ -1098,6 +1409,9 @@ cmdUser(
     }
 
 done:
+    if (pLogonHours != NULL)
+        HeapFree(GetProcessHeap(), 0, pLogonHours);
+
     if (pWorkstations != NULL)
         HeapFree(GetProcessHeap(), 0, pWorkstations);