Merge pull request #10391 from akallabeth/timezone_impro
Timezone improved
This commit is contained in:
commit
1fe61c9432
@ -30,6 +30,7 @@
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/ncrypt.h>
|
||||
#include <winpr/environment.h>
|
||||
#include <winpr/timezone.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/addin.h>
|
||||
@ -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", "<index>", "<key>", "<type>", "<default value>\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))
|
||||
|
@ -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[:<value>]|smartcard[:[pkinit-anchors:<path>][,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, "<tag>:<level>[,<tag>:<level>[,...]]", NULL, NULL,
|
||||
@ -453,6 +453,9 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
|
||||
{ "timeout", COMMAND_LINE_VALUE_REQUIRED, "<time in ms>", "9000", NULL, -1, "timeout",
|
||||
"Advanced setting for high latency links: Adjust connection timeout, use if you encounter "
|
||||
"timeout failures with your connection" },
|
||||
{ "timezone", COMMAND_LINE_VALUE_REQUIRED, "<windows timezone>", NULL, NULL, -1, NULL,
|
||||
"Use supplied windows timezone for connection (requires server support), see /list:timezones "
|
||||
"for allowed values" },
|
||||
{ "tls", COMMAND_LINE_VALUE_REQUIRED, "[ciphers|seclevel|secrets-file|enforce]", NULL, NULL, -1,
|
||||
NULL,
|
||||
"TLS configuration options:"
|
||||
|
@ -110,6 +110,8 @@ extern "C"
|
||||
const PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation, LPDWORD FirstYear,
|
||||
LPDWORD LastYear);
|
||||
|
||||
#else
|
||||
#pragma comment(lib, "advapi32")
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -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()
|
||||
|
||||
|
@ -41,9 +41,7 @@ typedef struct
|
||||
const char* Iana;
|
||||
} TimeZoneNameMapEntry;
|
||||
|
||||
extern const TimeZoneNameMapEntry TimeZoneNameMap[];
|
||||
extern const size_t TimeZoneNameMapSize;
|
||||
|
||||
const TimeZoneNameMapEntry* TimeZoneGetAt(size_t index);
|
||||
const char* TimeZoneIanaToWindows(const char* iana, TimeZoneNameType type);
|
||||
|
||||
#endif
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <winpr/config.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/string.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -31,6 +32,36 @@
|
||||
|
||||
#include "TimeZoneNameMap.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t count;
|
||||
TimeZoneNameMapEntry* entries;
|
||||
} TimeZoneNameMapContext;
|
||||
|
||||
static BOOL CALLBACK load_timezones(PINIT_ONCE once, PVOID param, PVOID* pvcontext)
|
||||
{
|
||||
// Do not expose these, only used internally.
|
||||
extern const TimeZoneNameMapEntry TimeZoneNameMap[];
|
||||
extern const size_t TimeZoneNameMapSize;
|
||||
|
||||
TimeZoneNameMapContext* context = pvcontext;
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
context->count = TimeZoneNameMapSize;
|
||||
context->entries = TimeZoneNameMap;
|
||||
}
|
||||
|
||||
const TimeZoneNameMapEntry* TimeZoneGetAt(size_t index)
|
||||
{
|
||||
static INIT_ONCE init_guard = INIT_ONCE_STATIC_INIT;
|
||||
static TimeZoneNameMapContext context = { 0 };
|
||||
|
||||
InitOnceExecuteOnce(&init_guard, load_timezones, NULL, &context);
|
||||
if (index >= context.count)
|
||||
return NULL;
|
||||
return &context.entries[index];
|
||||
}
|
||||
|
||||
static const char* return_type(const TimeZoneNameMapEntry* entry, TimeZoneNameType type)
|
||||
{
|
||||
WINPR_ASSERT(entry);
|
||||
@ -51,6 +82,37 @@ static const char* return_type(const TimeZoneNameMapEntry* entry, TimeZoneNameTy
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL iana_cmp(const TimeZoneNameMapEntry* entry, const char* iana)
|
||||
{
|
||||
if (!entry || !iana || !entry->Iana)
|
||||
return FALSE;
|
||||
return strcmp(iana, entry->Iana) == 0;
|
||||
}
|
||||
|
||||
static BOOL id_cmp(const TimeZoneNameMapEntry* entry, const char* id)
|
||||
{
|
||||
if (!entry || !id || !entry->Id)
|
||||
return FALSE;
|
||||
return strcmp(id, entry->Id) == 0;
|
||||
}
|
||||
|
||||
static const char* get_for_type(const char* val, TimeZoneNameType type,
|
||||
BOOL (*cmp)(const TimeZoneNameMapEntry*, const char*))
|
||||
{
|
||||
WINPR_ASSERT(val);
|
||||
WINPR_ASSERT(cmp);
|
||||
|
||||
size_t index = 0;
|
||||
while (TRUE)
|
||||
{
|
||||
const TimeZoneNameMapEntry* entry = TimeZoneGetAt(index++);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
if (cmp(entry, val))
|
||||
return return_type(entry, type);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WITH_TIMEZONE_ICU)
|
||||
static char* get_wzid_icu(const UChar* utzid, size_t utzid_len)
|
||||
{
|
||||
@ -88,21 +150,11 @@ static char* get(const char* iana)
|
||||
|
||||
static const char* map_fallback(const char* iana, TimeZoneNameType type)
|
||||
{
|
||||
const char* res = NULL;
|
||||
char* wzid = get(iana);
|
||||
if (!wzid)
|
||||
return NULL;
|
||||
|
||||
for (size_t x = 0; x < TimeZoneNameMapSize; x++)
|
||||
{
|
||||
const TimeZoneNameMapEntry* entry = &TimeZoneNameMap[x];
|
||||
if (strcmp(wzid, entry->Id) == 0)
|
||||
{
|
||||
res = return_type(entry, type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char* res = get_for_type(wzid, type, id_cmp);
|
||||
free(wzid);
|
||||
return res;
|
||||
}
|
||||
@ -149,22 +201,13 @@ const char* TimeZoneIanaToWindows(const char* iana, TimeZoneNameType type)
|
||||
if (!iana)
|
||||
return NULL;
|
||||
|
||||
for (size_t x = 0; x < TimeZoneNameMapSize; x++)
|
||||
{
|
||||
const TimeZoneNameMapEntry* entry = &TimeZoneNameMap[x];
|
||||
if (strcmp(iana, entry->Iana) == 0)
|
||||
return return_type(entry, type);
|
||||
}
|
||||
const char* val = get_for_type(iana, type, iana_cmp);
|
||||
if (val)
|
||||
return val;
|
||||
|
||||
const char* wzid = map_fallback(iana, type);
|
||||
if (!wzid)
|
||||
return NULL;
|
||||
|
||||
for (size_t x = 0; x < TimeZoneNameMapSize; x++)
|
||||
{
|
||||
const TimeZoneNameMapEntry* entry = &TimeZoneNameMap[x];
|
||||
if (strcmp(wzid, entry->Id) == 0)
|
||||
return return_type(entry, type);
|
||||
}
|
||||
return NULL;
|
||||
return get_for_type(wzid, type, id_cmp);
|
||||
}
|
||||
|
@ -710,6 +710,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 +762,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;
|
||||
}
|
||||
|
||||
@ -817,14 +843,62 @@ BOOL TzSpecificLocalTimeToSystemTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION* lpTi
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0602)) /* Windows 8 */
|
||||
#if !defined(_WIN32)
|
||||
|
||||
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;
|
||||
|
||||
const TimeZoneNameMapEntry* entry = TimeZoneGetAt(dwIndex);
|
||||
if (!entry)
|
||||
return ERROR_NO_MORE_ITEMS;
|
||||
|
||||
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(
|
||||
@ -833,7 +907,24 @@ DWORD GetDynamicTimeZoneInformationEffectiveYears(
|
||||
WINPR_UNUSED(lpTimeZoneInformation);
|
||||
WINPR_UNUSED(FirstYear);
|
||||
WINPR_UNUSED(LastYear);
|
||||
return 0;
|
||||
return ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
#elif _WIN32_WINNT < 0x0602 /* Windows 8 */
|
||||
DWORD EnumDynamicTimeZoneInformation(const DWORD dwIndex,
|
||||
PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation)
|
||||
{
|
||||
WINPR_UNUSED(dwIndex);
|
||||
WINPR_UNUSED(lpTimeZoneInformation);
|
||||
return ERROR_NO_MORE_ITEMS;
|
||||
}
|
||||
|
||||
DWORD GetDynamicTimeZoneInformationEffectiveYears(
|
||||
const PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation, LPDWORD FirstYear, LPDWORD LastYear)
|
||||
{
|
||||
WINPR_UNUSED(lpTimeZoneInformation);
|
||||
WINPR_UNUSED(FirstYear);
|
||||
WINPR_UNUSED(LastYear);
|
||||
return ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user