Skip to content

Commit

Permalink
[client,common] add timezone parameter
Browse files Browse the repository at this point in the history
* Add GetTimeZoneInformationFromTZ to allow setting a timezone from an
  IANA zone
* Add /timezone:<zone> command line to set timezone from command line
* Move initialization of settings::ClientTimeZone from
  rdp_write_client_time_zone to freerdp_settings_new
  • Loading branch information
akallabeth committed Apr 22, 2024
1 parent 1687a64 commit 24a161b
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 54 deletions.
9 changes: 9 additions & 0 deletions client/common/cmdline.c
Original file line number Diff line number Diff line change
Expand Up @@ -4601,6 +4601,15 @@ static int freerdp_client_settings_parse_command_line_arguments_int(
if (!freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, !enable))
return COMMAND_LINE_ERROR;
}
#ifndef _WIN32
CommandLineSwitchCase(arg, "timezone")
{
TIME_ZONE_INFORMATION tz = { 0 };
GetTimeZoneInformationFromTZ(&tz, arg->Value);
if (!freerdp_settings_set_pointer_array(settings, FreeRDP_ClientTimeZone, 0, &tz))
return COMMAND_LINE_ERROR;
}
#endif
CommandLineSwitchCase(arg, "timeout")
{
ULONGLONG val = 0;
Expand Down
4 changes: 4 additions & 0 deletions client/common/cmdline.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,10 @@ 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" },
#ifndef _WIN32
{ "timezone", COMMAND_LINE_VALUE_REQUIRED, "<IANA value>", NULL, NULL, -1, NULL,
"IANA timezone to use" },
#endif
{ "tls", COMMAND_LINE_VALUE_REQUIRED, "[ciphers|seclevel|secrets-file|enforce]", NULL, NULL, -1,
NULL,
"TLS configuration options:"
Expand Down
3 changes: 3 additions & 0 deletions libfreerdp/core/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,9 @@ rdpSettings* freerdp_settings_new(DWORD flags)
if (!settings->ClientTimeZone)
goto out_fail;

if (!settings->ServerMode)
GetTimeZoneInformation(settings->ClientTimeZone);

if (!freerdp_settings_set_bool(settings, FreeRDP_TcpKeepAlive, TRUE) ||
!freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveRetries, 3) ||
!freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveDelay, 5) ||
Expand Down
1 change: 0 additions & 1 deletion libfreerdp/core/timezone.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ BOOL rdp_write_client_time_zone(wStream* s, rdpSettings* settings)
if (!tz)
return FALSE;

GetTimeZoneInformation(tz);
if (!Stream_EnsureRemainingCapacity(s, 4ull + sizeof(tz->StandardName)))
return FALSE;

Expand Down
3 changes: 3 additions & 0 deletions winpr/include/winpr/timezone.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ extern "C"
*LPDYNAMIC_TIME_ZONE_INFORMATION;

WINPR_API DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation);
WINPR_API DWORD GetTimeZoneInformationFromTZ(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,
const char* tzstr);

WINPR_API BOOL SetTimeZoneInformation(const TIME_ZONE_INFORMATION* lpTimeZoneInformation);
WINPR_API BOOL SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime, LPFILETIME lpFileTime);
WINPR_API BOOL FileTimeToSystemTime(const FILETIME* lpFileTime, LPSYSTEMTIME lpSystemTime);
Expand Down
155 changes: 102 additions & 53 deletions winpr/libwinpr/timezone/timezone.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,59 +294,10 @@ static BOOL winpr_match_unix_timezone_identifier_with_list(const char* tzid, con
return FALSE;
}

static TIME_ZONE_ENTRY* winpr_detect_windows_time_zone(void)
static TIME_ZONE_ENTRY* winpr_unix_to_windows_time_zone(const char* tzid)
{
char* tzid = NULL;
char* ntzid = NULL;
LPCSTR tz = "TZ";

DWORD nSize = GetEnvironmentVariableA(tz, NULL, 0);
if (nSize)
{
tzid = (char*)malloc(nSize);
if (!GetEnvironmentVariableA(tz, tzid, nSize))
{
free(tzid);
tzid = NULL;
}
else if (tzid[0] == ':')
{
/* Remove leading colon, see tzset(3) */
memmove(tzid, tzid + 1, nSize - sizeof(char));
}
}

if (tzid == NULL)
tzid = winpr_get_unix_timezone_identifier_from_file();

if (tzid == NULL)
{
tzid = winpr_get_timezone_from_link(NULL, 0);
}
else
{
const char* zipath = "/usr/share/zoneinfo/";
char buf[1024] = { 0 };
const char* links[] = { buf };

if (tzid[0] == '/')
{
/* Full path given in TZ */
links[0] = tzid;
}
else
snprintf(buf, ARRAYSIZE(buf), "%s%s", zipath, tzid);

ntzid = winpr_get_timezone_from_link(links, 1);
if (ntzid != NULL)
{
free(tzid);
tzid = ntzid;
}
}

if (tzid == NULL)
return NULL;
goto end;

WLog_INFO(TAG, "tzid: %s", tzid);

Expand All @@ -364,7 +315,6 @@ static TIME_ZONE_ENTRY* winpr_detect_windows_time_zone(void)
if (winpr_match_unix_timezone_identifier_with_list(tzid, wzid->tzid))
{
TIME_ZONE_ENTRY* ctimezone = (TIME_ZONE_ENTRY*)malloc(sizeof(TIME_ZONE_ENTRY));
free(tzid);

if (!ctimezone)
return NULL;
Expand All @@ -375,11 +325,104 @@ static TIME_ZONE_ENTRY* winpr_detect_windows_time_zone(void)
}
}

end:
WLog_ERR(TAG, "Unable to find a match for unix timezone: %s", tzid);
return NULL;
}

static char* winpr_time_zone_from_env(void)
{
LPCSTR tz = "TZ";
char* tzid = NULL;

DWORD nSize = GetEnvironmentVariableA(tz, NULL, 0);
if (nSize > 0)
{
tzid = (char*)calloc(nSize, sizeof(char));
if (!tzid)
goto fail;
if (!GetEnvironmentVariableA(tz, tzid, nSize))
goto fail;
else if (tzid[0] == ':')
{
/* Remove leading colon, see tzset(3) */
memmove(tzid, tzid + 1, nSize - sizeof(char));
}
}

return tzid;

fail:
free(tzid);
return NULL;
}

static char* winpr_translate_time_zone(const char* tzid)
{
const char* zipath = "/usr/share/zoneinfo/";
char* buf = NULL;
const char* links[] = { buf };

if (!tzid)
return NULL;

if (tzid[0] == '/')
{
/* Full path given in TZ */
links[0] = tzid;
}
else
{
size_t bsize = 0;
winpr_asprintf(&buf, &bsize, "%s%s", zipath, tzid);
links[0] = buf;
}

char* ntzid = winpr_get_timezone_from_link(links, 1);
free(buf);
return ntzid;
}

static char* winpr_guess_time_zone(void)
{
char* tzid = winpr_time_zone_from_env();
if (tzid)
goto end;
tzid = winpr_get_unix_timezone_identifier_from_file();
if (tzid)
goto end;
tzid = winpr_get_timezone_from_link(NULL, 0);
if (tzid)
goto end;

end:
{
char* ntzid = winpr_translate_time_zone(tzid);
if (ntzid)
{
free(tzid);
return ntzid;
}
return tzid;
}
}

static TIME_ZONE_ENTRY* winpr_detect_windows_time_zone(const char* tzstr)
{
char* tzid = NULL;

if (tzstr)
tzid = _strdup(tzstr);
else
tzid = winpr_guess_time_zone();
if (!tzid)
return NULL;

TIME_ZONE_ENTRY* ctimezone = winpr_unix_to_windows_time_zone(tzid);
free(tzid);
return ctimezone;
}

static const TIME_ZONE_RULE_ENTRY*
winpr_get_current_time_zone_rule(const TIME_ZONE_RULE_ENTRY* rules, UINT32 count)
{
Expand All @@ -402,6 +445,12 @@ winpr_get_current_time_zone_rule(const TIME_ZONE_RULE_ENTRY* rules, UINT32 count

DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation)
{
return GetTimeZoneInformationFromTZ(lpTimeZoneInformation, NULL);
}

DWORD GetTimeZoneInformationFromTZ(LPTIME_ZONE_INFORMATION lpTimeZoneInformation, const char* tzstr)
{

time_t t = 0;
struct tm tres = { 0 };
TIME_ZONE_ENTRY* dtz = NULL;
Expand All @@ -427,7 +476,7 @@ DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation)
tz->Bias = (LONG)bias;
}
#endif
dtz = winpr_detect_windows_time_zone();
dtz = winpr_detect_windows_time_zone(tzstr);

if (dtz != NULL)
{
Expand Down

0 comments on commit 24a161b

Please sign in to comment.