From 9eb484b21b0bb1153c9a900ea56c994b7e717958 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 18 Jul 2024 16:10:10 +0200 Subject: [PATCH 1/3] [winpr,timezone] implement EnumDynamicTimeZoneInformation --- winpr/libwinpr/timezone/CMakeLists.txt | 2 +- winpr/libwinpr/timezone/timezone.c | 94 +++++++++++++++++++++++--- 2 files changed, 86 insertions(+), 10 deletions(-) diff --git a/winpr/libwinpr/timezone/CMakeLists.txt b/winpr/libwinpr/timezone/CMakeLists.txt index a60c2e8df..c877e1890 100644 --- a/winpr/libwinpr/timezone/CMakeLists.txt +++ b/winpr/libwinpr/timezone/CMakeLists.txt @@ -19,12 +19,12 @@ set(SRCS TimeZoneNameMap.c TimeZoneNameMap.h TimeZoneNameMapUtils.c + timezone.c ) if (NOT WIN32) list(APPEND SRCS TimeZoneIanaAbbrevMap.c TimeZoneIanaAbbrevMap.h - timezone.c ) endif() diff --git a/winpr/libwinpr/timezone/timezone.c b/winpr/libwinpr/timezone/timezone.c index d22358bb5..4b013445d 100644 --- a/winpr/libwinpr/timezone/timezone.c +++ b/winpr/libwinpr/timezone/timezone.c @@ -38,7 +38,9 @@ #include "TimeZoneNameMap.h" #include "TimeZoneIanaAbbrevMap.h" -#ifndef _WIN32 +#ifdef _WIN32 +#pragma comment(lib, "advapi32") +#else #include #include @@ -710,6 +712,34 @@ BOOL TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformati (defined(_WIN32) && (defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0600 || \ !defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0501)) /* Windows Vista */ +typedef enum +{ + HAVE_TRANSITION_DATES = 0, + HAVE_NO_STANDARD_TRANSITION_DATE = 1, + HAVE_NO_DAYLIGHT_TRANSITION_DATE = 2 +} dyn_transition_result; + +static int dynamic_time_zone_from_localtime(const struct tm* local_time, + PDYNAMIC_TIME_ZONE_INFORMATION tz) +{ + WINPR_ASSERT(local_time); + WINPR_ASSERT(tz); + int rc = HAVE_TRANSITION_DATES; + + tz->Bias = get_bias(local_time, FALSE); + if (local_time->tm_isdst >= 0) + { + /* DST bias is the difference between standard time and DST in minutes */ + const LONG d = get_bias(local_time, TRUE); + tz->DaylightBias = -1 * labs(tz->Bias - d); + if (!get_transition_date(local_time, FALSE, &tz->StandardDate)) + rc |= HAVE_NO_STANDARD_TRANSITION_DATE; + if (!get_transition_date(local_time, TRUE, &tz->DaylightDate)) + rc |= HAVE_NO_DAYLIGHT_TRANSITION_DATE; + } + return rc; +} + DWORD GetDynamicTimeZoneInformation(PDYNAMIC_TIME_ZONE_INFORMATION tz) { BOOL doesNotHaveStandardDate = FALSE; @@ -734,12 +764,10 @@ DWORD GetDynamicTimeZoneInformation(PDYNAMIC_TIME_ZONE_INFORMATION tz) tz->Bias = get_bias(local_time, FALSE); if (local_time->tm_isdst >= 0) { - /* DST bias is the difference between standard time and DST in minutes */ - const LONG d = get_bias(local_time, TRUE); - tz->DaylightBias = -1 * labs(tz->Bias - d); - if (!get_transition_date(local_time, FALSE, &tz->StandardDate)) + const int rc = dynamic_time_zone_from_localtime(local_time, tz); + if (rc & HAVE_NO_STANDARD_TRANSITION_DATE) doesNotHaveStandardDate = TRUE; - if (!get_transition_date(local_time, TRUE, &tz->DaylightDate)) + if (rc & HAVE_NO_DAYLIGHT_TRANSITION_DATE) doesNotHaveDaylightDate = TRUE; } @@ -822,9 +850,57 @@ BOOL TzSpecificLocalTimeToSystemTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION* lpTi DWORD EnumDynamicTimeZoneInformation(const DWORD dwIndex, PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation) { - WINPR_UNUSED(dwIndex); - WINPR_UNUSED(lpTimeZoneInformation); - return 0; + if (!lpTimeZoneInformation) + return ERROR_INVALID_PARAMETER; + const DYNAMIC_TIME_ZONE_INFORMATION empty = { 0 }; + *lpTimeZoneInformation = empty; + + if (dwIndex >= TimeZoneNameMapSize) + return ERROR_NO_MORE_ITEMS; + + const TimeZoneNameMapEntry* entry = &TimeZoneNameMap[dwIndex]; + if (entry->DaylightName) + ConvertUtf8ToWChar(entry->DaylightName, lpTimeZoneInformation->DaylightName, + ARRAYSIZE(lpTimeZoneInformation->DaylightName)); + if (entry->StandardName) + ConvertUtf8ToWChar(entry->StandardName, lpTimeZoneInformation->StandardName, + ARRAYSIZE(lpTimeZoneInformation->StandardName)); + if (entry->Id) + ConvertUtf8ToWChar(entry->Id, lpTimeZoneInformation->TimeZoneKeyName, + ARRAYSIZE(lpTimeZoneInformation->TimeZoneKeyName)); + + const time_t t = time(NULL); + struct tm tres = { 0 }; + + const char* tz = getenv("TZ"); + char* tzcopy = NULL; + if (tz) + { + size_t tzianalen = 0; + winpr_asprintf(&tzcopy, &tzianalen, "TZ=%s", tz); + } + + char* tziana = NULL; + { + size_t tzianalen = 0; + winpr_asprintf(&tziana, &tzianalen, "TZ=%s", entry->Iana); + } + if (tziana) + putenv(tziana); + + tzset(); + struct tm* local_time = localtime_r(&t, &tres); + free(tziana); + if (tzcopy) + putenv(tzcopy); + else + unsetenv("TZ"); + free(tzcopy); + + if (local_time) + dynamic_time_zone_from_localtime(local_time, lpTimeZoneInformation); + + return ERROR_SUCCESS; } DWORD GetDynamicTimeZoneInformationEffectiveYears( From 6c682c84180bedb229133789ee316b86a30540e6 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 23 Apr 2024 15:40:04 +0200 Subject: [PATCH 2/3] [client,common] add option to set timezone * /timezone now allows setting the timezone used from a windows timezone key name * /list:timezones now lists all available windows timezone key names --- client/common/cmdline.c | 57 ++++++++++++++++++++++++++++-- client/common/cmdline.h | 5 ++- winpr/include/winpr/timezone.h | 2 ++ winpr/libwinpr/timezone/timezone.c | 25 ++++++++++--- 4 files changed, 81 insertions(+), 8 deletions(-) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index e17c40dc3..f5ac643b1 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -1666,11 +1667,24 @@ static void freerdp_client_print_keyboard_list(void) RDP_KEYBOARD_LAYOUT_TYPE_IME); } +static void freerdp_client_print_timezone_list(void) +{ + DWORD index = 0; + DYNAMIC_TIME_ZONE_INFORMATION info = { 0 }; + while (EnumDynamicTimeZoneInformation(index++, &info) != ERROR_NO_MORE_ITEMS) + { + char TimeZoneKeyName[ARRAYSIZE(info.TimeZoneKeyName) + 1] = { 0 }; + + ConvertWCharNToUtf8(info.TimeZoneKeyName, ARRAYSIZE(info.TimeZoneKeyName), TimeZoneKeyName, + ARRAYSIZE(TimeZoneKeyName)); + printf("%" PRIu32 ": '%s'\n", index, TimeZoneKeyName); + } +} + static void freerdp_client_print_tune_list(const rdpSettings* settings) { SSIZE_T type = 0; - printf("%s\t%50s\t%s\t%s", "", "", "", "\n"); for (size_t x = 0; x < FreeRDP_Settings_StableAPI_MAX; x++) { const char* name = freerdp_settings_get_name_for_key(x); @@ -1755,7 +1769,9 @@ int freerdp_client_settings_command_line_status_print_ex(rdpSettings* settings, if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT) { - if (option_equals("tune", arg->Value)) + if (option_equals("timezones", arg->Value)) + freerdp_client_print_timezone_list(); + else if (option_equals("tune", arg->Value)) freerdp_client_print_tune_list(settings); else if (option_equals("kbd", arg->Value)) freerdp_client_print_keyboard_list(); @@ -4718,6 +4734,43 @@ static int freerdp_client_settings_parse_command_line_arguments_int( if (!freerdp_settings_set_uint32(settings, FreeRDP_TcpAckTimeout, (UINT32)val)) return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE); } + CommandLineSwitchCase(arg, "timezone") + { + BOOL found = FALSE; + DWORD index = 0; + DYNAMIC_TIME_ZONE_INFORMATION info = { 0 }; + char TimeZoneKeyName[ARRAYSIZE(info.TimeZoneKeyName) + 1] = { 0 }; + while (EnumDynamicTimeZoneInformation(index++, &info) != ERROR_NO_MORE_ITEMS) + { + ConvertWCharNToUtf8(info.TimeZoneKeyName, ARRAYSIZE(info.TimeZoneKeyName), + TimeZoneKeyName, ARRAYSIZE(TimeZoneKeyName)); + + if (strncmp(TimeZoneKeyName, arg->Value, ARRAYSIZE(TimeZoneKeyName)) == 0) + { + found = TRUE; + break; + } + } + if (!found) + return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE); + + if (!freerdp_settings_set_string(settings, FreeRDP_DynamicDSTTimeZoneKeyName, + TimeZoneKeyName)) + return fail_at(arg, COMMAND_LINE_ERROR); + + TIME_ZONE_INFORMATION* tz = + freerdp_settings_get_pointer_writable(settings, FreeRDP_ClientTimeZone); + if (!tz) + return fail_at(arg, COMMAND_LINE_ERROR_MEMORY); + + tz->Bias = info.Bias; + tz->DaylightBias = info.DaylightBias; + tz->DaylightDate = info.DaylightDate; + memcpy(tz->DaylightName, info.DaylightName, sizeof(tz->DaylightName)); + tz->StandardBias = info.StandardBias; + tz->StandardDate = info.StandardDate; + memcpy(tz->StandardName, info.StandardName, sizeof(tz->StandardName)); + } CommandLineSwitchCase(arg, "aero") { if (!freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, enable)) diff --git a/client/common/cmdline.h b/client/common/cmdline.h index fe116202e..a4232052c 100644 --- a/client/common/cmdline.h +++ b/client/common/cmdline.h @@ -297,7 +297,7 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = { { "list", COMMAND_LINE_VALUE_REQUIRED | COMMAND_LINE_PRINT, "[kbd|kbd-scancode|kbd-lang[:]|smartcard[:[pkinit-anchors:][,pkcs11-module:<" "name>]]|" - "monitor|tune]", + "monitor|tune|timezones]", "List available options for subcommand", NULL, -1, NULL, "List available options for subcommand" }, { "log-filters", COMMAND_LINE_VALUE_REQUIRED, ":[,:[,...]]", NULL, NULL, @@ -453,6 +453,9 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = { { "timeout", COMMAND_LINE_VALUE_REQUIRED, "