FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
libfreerdp/core/timezone.c
1
20#include <freerdp/config.h>
21
22#include <winpr/crt.h>
23#include <winpr/assert.h>
24#include <winpr/timezone.h>
25
26#include "settings.h"
27#include "timezone.h"
28
29#include <freerdp/log.h>
30#define TAG FREERDP_TAG("core.timezone")
31
32#if !defined(WITH_DEBUG_TIMEZONE)
33#define log_timezone(tzif, result)
34#else
35#define log_timezone(tzif, result) log_timezone_((tzif), (result), __FILE__, __func__, __LINE__)
36static const char* weekday2str(WORD wDayOfWeek)
37{
38 switch (wDayOfWeek)
39 {
40 case 0:
41 return "SUNDAY";
42 case 1:
43 return "MONDAY";
44 case 2:
45 return "TUESDAY";
46 case 3:
47 return "WEDNESDAY";
48 case 4:
49 return "THURSDAY";
50 case 5:
51 return "FRIDAY";
52 case 6:
53 return "SATURDAY";
54 default:
55 return "DAY-OF-MAGIC";
56 }
57}
58
59static char* systemtime2str(const SYSTEMTIME* t, char* buffer, size_t len)
60{
61 const SYSTEMTIME empty = { 0 };
62
63 if (memcmp(t, &empty, sizeof(SYSTEMTIME)) == 0)
64 (void)_snprintf(buffer, len, "{ not set }");
65 else
66 {
67 (void)_snprintf(buffer, len,
68 "{ %" PRIu16 "-%" PRIu16 "-%" PRIu16 " [%s] %" PRIu16 ":%" PRIu16
69 ":%" PRIu16 ".%" PRIu16 "}",
70 t->wYear, t->wMonth, t->wDay, weekday2str(t->wDayOfWeek), t->wHour,
71 t->wMinute, t->wSecond, t->wMilliseconds);
72 }
73 return buffer;
74}
75
76static void log_print(wLog* log, DWORD level, const char* file, const char* fkt, size_t line, ...)
77{
78 if (!WLog_IsLevelActive(log, level))
79 return;
80
81 va_list ap = { 0 };
82 va_start(ap, line);
83 WLog_PrintMessageVA(log, WLOG_MESSAGE_TEXT, level, line, file, fkt, ap);
84 va_end(ap);
85}
86
87static void log_timezone_(const TIME_ZONE_INFORMATION* tzif, DWORD result, const char* file,
88 const char* fkt, size_t line)
89{
90 WINPR_ASSERT(tzif);
91
92 char buffer[64] = { 0 };
93 DWORD level = WLOG_TRACE;
94 wLog* log = WLog_Get(TIMEZONE_TAG);
95 log_print(log, level, file, fkt, line, "TIME_ZONE_INFORMATION {");
96 log_print(log, level, file, fkt, line, " Bias=%" PRId32, tzif->Bias);
97 (void)ConvertWCharNToUtf8(tzif->StandardName, ARRAYSIZE(tzif->StandardName), buffer,
98 ARRAYSIZE(buffer));
99 log_print(log, level, file, fkt, line, " StandardName=%s", buffer);
100 log_print(log, level, file, fkt, line, " StandardDate=%s",
101 systemtime2str(&tzif->StandardDate, buffer, sizeof(buffer)));
102 log_print(log, level, file, fkt, line, " StandardBias=%" PRId32, tzif->StandardBias);
103
104 (void)ConvertWCharNToUtf8(tzif->DaylightName, ARRAYSIZE(tzif->DaylightName), buffer,
105 ARRAYSIZE(buffer));
106 log_print(log, level, file, fkt, line, " DaylightName=%s", buffer);
107 log_print(log, level, file, fkt, line, " DaylightDate=%s",
108 systemtime2str(&tzif->DaylightDate, buffer, sizeof(buffer)));
109 log_print(log, level, file, fkt, line, " DaylightBias=%" PRId32, tzif->DaylightBias);
110
111 switch (result)
112 {
113 case TIME_ZONE_ID_DAYLIGHT:
114 log_print(log, level, file, fkt, line, " DaylightDate in use");
115 break;
116 case TIME_ZONE_ID_STANDARD:
117 log_print(log, level, file, fkt, line, " StandardDate in use");
118 break;
119 default:
120 log_print(log, level, file, fkt, line, " UnknownDate in use");
121 break;
122 }
123 log_print(log, level, file, fkt, line, "}");
124}
125#endif
126
127static BOOL rdp_read_system_time(wStream* s, SYSTEMTIME* system_time);
128static BOOL rdp_write_system_time(wStream* s, const SYSTEMTIME* system_time);
129
137BOOL rdp_read_system_time(wStream* s, SYSTEMTIME* system_time)
138{
139 WINPR_ASSERT(system_time);
140
141 if (!Stream_CheckAndLogRequiredLength(TAG, s, 16ull))
142 return FALSE;
143
144 Stream_Read_UINT16(s, system_time->wYear); /* wYear, must be set to 0 */
145 Stream_Read_UINT16(s, system_time->wMonth); /* wMonth */
146 Stream_Read_UINT16(s, system_time->wDayOfWeek); /* wDayOfWeek */
147 Stream_Read_UINT16(s, system_time->wDay); /* wDay */
148 Stream_Read_UINT16(s, system_time->wHour); /* wHour */
149 Stream_Read_UINT16(s, system_time->wMinute); /* wMinute */
150 Stream_Read_UINT16(s, system_time->wSecond); /* wSecond */
151 Stream_Read_UINT16(s, system_time->wMilliseconds); /* wMilliseconds */
152 return TRUE;
153}
154
162BOOL rdp_write_system_time(wStream* s, const SYSTEMTIME* system_time)
163{
164 WINPR_ASSERT(system_time);
165 if (!Stream_EnsureRemainingCapacity(s, 16ull))
166 return FALSE;
167
168 Stream_Write_UINT16(s, system_time->wYear); /* wYear, must be set to 0 */
169 Stream_Write_UINT16(s, system_time->wMonth); /* wMonth */
170 Stream_Write_UINT16(s, system_time->wDayOfWeek); /* wDayOfWeek */
171 Stream_Write_UINT16(s, system_time->wDay); /* wDay */
172 Stream_Write_UINT16(s, system_time->wHour); /* wHour */
173 Stream_Write_UINT16(s, system_time->wMinute); /* wMinute */
174 Stream_Write_UINT16(s, system_time->wSecond); /* wSecond */
175 Stream_Write_UINT16(s, system_time->wMilliseconds); /* wMilliseconds */
176 return TRUE;
177}
178
188BOOL rdp_read_client_time_zone(wStream* s, rdpSettings* settings)
189{
190 LPTIME_ZONE_INFORMATION tz = { 0 };
191
192 if (!s || !settings)
193 return FALSE;
194
195 if (!Stream_CheckAndLogRequiredLength(TAG, s, 172))
196 return FALSE;
197
198 tz = settings->ClientTimeZone;
199
200 if (!tz)
201 return FALSE;
202
203 Stream_Read_INT32(s, tz->Bias); /* Bias */
204 /* standardName (64 bytes) */
205 Stream_Read(s, tz->StandardName, sizeof(tz->StandardName));
206 if (!rdp_read_system_time(s, &tz->StandardDate)) /* StandardDate */
207 return FALSE;
208 Stream_Read_INT32(s, tz->StandardBias); /* StandardBias */
209 /* daylightName (64 bytes) */
210 Stream_Read(s, tz->DaylightName, sizeof(tz->DaylightName));
211 if (!rdp_read_system_time(s, &tz->DaylightDate)) /* DaylightDate */
212 return FALSE;
213 Stream_Read_INT32(s, tz->DaylightBias); /* DaylightBias */
214 log_timezone(tz, 0);
215 return TRUE;
216}
217
227BOOL rdp_write_client_time_zone(wStream* s, rdpSettings* settings)
228{
229 WINPR_ASSERT(settings);
230 const LPTIME_ZONE_INFORMATION tz = settings->ClientTimeZone;
231
232 if (!tz)
233 return FALSE;
234
235 log_timezone(tz, 0);
236 if (!Stream_EnsureRemainingCapacity(s, 4ull + sizeof(tz->StandardName)))
237 return FALSE;
238
239 /* Bias defined in windows headers as LONG
240 * but [MS-RDPBCGR] 2.2.1.11.1.1.1.1 Time Zone Information (TS_TIME_ZONE_INFORMATION) defines it
241 * as unsigned.... assume the spec is buggy as an unsigned value only works on half of the
242 * world.
243 */
244 Stream_Write_INT32(s, tz->Bias);
245 /* standardName (64 bytes) */
246 Stream_Write(s, tz->StandardName, sizeof(tz->StandardName));
247 /* StandardDate */
248 if (!rdp_write_system_time(s, &tz->StandardDate))
249 return FALSE;
250
251 /* Note that StandardBias is ignored if no valid standardDate is provided. */
252 /* StandardBias */
253 if (!Stream_EnsureRemainingCapacity(s, 4ull + sizeof(tz->DaylightName)))
254 return FALSE;
255
256 /* StandardBias defined in windows headers as LONG
257 * but [MS-RDPBCGR] 2.2.1.11.1.1.1.1 Time Zone Information (TS_TIME_ZONE_INFORMATION) defines it
258 * as unsigned.... assume the spec is buggy as an unsigned value only works on half of the
259 * world.
260 */
261 Stream_Write_INT32(s, tz->StandardBias);
262
263 /* daylightName (64 bytes) */
264 Stream_Write(s, tz->DaylightName, sizeof(tz->DaylightName));
265 /* DaylightDate */
266 if (!rdp_write_system_time(s, &tz->DaylightDate))
267 return FALSE;
268 /* Note that DaylightBias is ignored if no valid daylightDate is provided. */
269 /* DaylightBias */
270 if (!Stream_EnsureRemainingCapacity(s, 4ull))
271 return FALSE;
272
273 /* DaylightBias defined in windows headers as LONG
274 * but [MS-RDPBCGR] 2.2.1.11.1.1.1.1 Time Zone Information (TS_TIME_ZONE_INFORMATION) defines it
275 * as unsigned.... assume the spec is buggy as an unsigned value only works on half of the
276 * world.
277 */
278 Stream_Write_INT32(s, tz->DaylightBias);
279
280 return TRUE;
281}