/src/FreeRDP/client/common/cmdline.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /**  | 
2  |  |  * FreeRDP: A Remote Desktop Protocol Implementation  | 
3  |  |  * FreeRDP Client Command-Line Interface  | 
4  |  |  *  | 
5  |  |  * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>  | 
6  |  |  * Copyright 2014 Norbert Federa <norbert.federa@thincast.com>  | 
7  |  |  * Copyright 2016 Armin Novak <armin.novak@gmail.com>  | 
8  |  |  *  | 
9  |  |  * Licensed under the Apache License, Version 2.0 (the "License");  | 
10  |  |  * you may not use this file except in compliance with the License.  | 
11  |  |  * You may obtain a copy of the License at  | 
12  |  |  *  | 
13  |  |  *     http://www.apache.org/licenses/LICENSE-2.0  | 
14  |  |  *  | 
15  |  |  * Unless required by applicable law or agreed to in writing, software  | 
16  |  |  * distributed under the License is distributed on an "AS IS" BASIS,  | 
17  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
18  |  |  * See the License for the specific language governing permissions and  | 
19  |  |  * limitations under the License.  | 
20  |  |  */  | 
21  |  |  | 
22  |  | #include <freerdp/config.h>  | 
23  |  |  | 
24  |  | #include <ctype.h>  | 
25  |  | #include <errno.h>  | 
26  |  |  | 
27  |  | #include <winpr/assert.h>  | 
28  |  | #include <winpr/crt.h>  | 
29  |  | #include <winpr/wlog.h>  | 
30  |  | #include <winpr/path.h>  | 
31  |  | #include <winpr/ncrypt.h>  | 
32  |  | #include <winpr/environment.h>  | 
33  |  |  | 
34  |  | #include <freerdp/freerdp.h>  | 
35  |  | #include <freerdp/addin.h>  | 
36  |  | #include <freerdp/settings.h>  | 
37  |  | #include <freerdp/client.h>  | 
38  |  | #include <freerdp/client/channels.h>  | 
39  |  | #include <freerdp/channels/drdynvc.h>  | 
40  |  | #include <freerdp/channels/cliprdr.h>  | 
41  |  | #include <freerdp/channels/encomsp.h>  | 
42  |  | #include <freerdp/channels/rdp2tcp.h>  | 
43  |  | #include <freerdp/channels/remdesk.h>  | 
44  |  | #include <freerdp/channels/rdpsnd.h>  | 
45  |  | #include <freerdp/channels/disp.h>  | 
46  |  | #include <freerdp/crypto/crypto.h>  | 
47  |  | #include <freerdp/locale/keyboard.h>  | 
48  |  | #include <freerdp/utils/passphrase.h>  | 
49  |  | #include <freerdp/utils/proxy_utils.h>  | 
50  |  | #include <freerdp/channels/urbdrc.h>  | 
51  |  | #include <freerdp/channels/rdpdr.h>  | 
52  |  |  | 
53  |  | #if defined(CHANNEL_AINPUT_CLIENT)  | 
54  |  | #include <freerdp/channels/ainput.h>  | 
55  |  | #endif  | 
56  |  |  | 
57  |  | #include <freerdp/channels/audin.h>  | 
58  |  | #include <freerdp/channels/echo.h>  | 
59  |  |  | 
60  |  | #include <freerdp/client/cmdline.h>  | 
61  |  | #include <freerdp/version.h>  | 
62  |  | #include <freerdp/client/utils/smartcard_cli.h>  | 
63  |  |  | 
64  |  | #include <openssl/tls1.h>  | 
65  |  | #include "cmdline.h"  | 
66  |  |  | 
67  |  | #include <freerdp/log.h>  | 
68  | 0  | #define TAG CLIENT_TAG("common.cmdline") | 
69  |  |  | 
70  |  | static const char* option_starts_with(const char* what, const char* val);  | 
71  |  | static BOOL option_ends_with(const char* str, const char* ext);  | 
72  |  | static BOOL option_equals(const char* what, const char* val);  | 
73  |  |  | 
74  |  | static BOOL freerdp_client_print_codepages(const char* arg)  | 
75  | 0  | { | 
76  | 0  |   size_t count = 0;  | 
77  | 0  |   DWORD column = 2;  | 
78  | 0  |   const char* filter = NULL;  | 
79  | 0  |   RDP_CODEPAGE* pages = NULL;  | 
80  |  | 
  | 
81  | 0  |   if (arg)  | 
82  | 0  |   { | 
83  | 0  |     filter = strchr(arg, ',');  | 
84  | 0  |     if (!filter)  | 
85  | 0  |       filter = arg;  | 
86  | 0  |     else  | 
87  | 0  |       filter++;  | 
88  | 0  |   }  | 
89  | 0  |   pages = freerdp_keyboard_get_matching_codepages(column, filter, &count);  | 
90  | 0  |   if (!pages)  | 
91  | 0  |     return TRUE;  | 
92  |  |  | 
93  | 0  |   printf("%-10s %-8s %-60s %-36s %-48s\n", "<id>", "<locale>", "<win langid>", "<language>", | 
94  | 0  |          "<country>");  | 
95  | 0  |   for (size_t x = 0; x < count; x++)  | 
96  | 0  |   { | 
97  | 0  |     const RDP_CODEPAGE* page = &pages[x];  | 
98  | 0  |     char buffer[520] = { 0 }; | 
99  |  | 
  | 
100  | 0  |     if (strnlen(page->subLanguageSymbol, ARRAYSIZE(page->subLanguageSymbol)) > 0)  | 
101  | 0  |       _snprintf(buffer, sizeof(buffer), "[%s|%s]", page->primaryLanguageSymbol,  | 
102  | 0  |                 page->subLanguageSymbol);  | 
103  | 0  |     else  | 
104  | 0  |       _snprintf(buffer, sizeof(buffer), "[%s]", page->primaryLanguageSymbol);  | 
105  | 0  |     printf("id=0x%04" PRIx16 ": [%-6s] %-60s %-36s %-48s\n", page->id, page->locale, buffer, | 
106  | 0  |            page->primaryLanguage, page->subLanguage);  | 
107  | 0  |   }  | 
108  | 0  |   freerdp_codepages_free(pages);  | 
109  | 0  |   return TRUE;  | 
110  | 0  | }  | 
111  |  |  | 
112  |  | static BOOL freerdp_path_valid(const char* path, BOOL* special)  | 
113  | 0  | { | 
114  | 0  |   const char DynamicDrives[] = "DynamicDrives";  | 
115  | 0  |   BOOL isPath = FALSE;  | 
116  | 0  |   BOOL isSpecial = 0;  | 
117  | 0  |   if (!path)  | 
118  | 0  |     return FALSE;  | 
119  |  |  | 
120  | 0  |   isSpecial =  | 
121  | 0  |       (option_equals("*", path) || option_equals(DynamicDrives, path) || option_equals("%", path)) | 
122  | 0  |           ? TRUE  | 
123  | 0  |           : FALSE;  | 
124  | 0  |   if (!isSpecial)  | 
125  | 0  |     isPath = winpr_PathFileExists(path);  | 
126  |  | 
  | 
127  | 0  |   if (special)  | 
128  | 0  |     *special = isSpecial;  | 
129  |  | 
  | 
130  | 0  |   return isSpecial || isPath;  | 
131  | 0  | }  | 
132  |  |  | 
133  |  | static BOOL freerdp_sanitize_drive_name(char* name, const char* invalid, const char* replacement)  | 
134  | 0  | { | 
135  | 0  |   if (!name || !invalid || !replacement)  | 
136  | 0  |     return FALSE;  | 
137  | 0  |   if (strlen(invalid) != strlen(replacement))  | 
138  | 0  |     return FALSE;  | 
139  |  |  | 
140  | 0  |   while (*invalid != '\0')  | 
141  | 0  |   { | 
142  | 0  |     const char what = *invalid++;  | 
143  | 0  |     const char with = *replacement++;  | 
144  |  | 
  | 
145  | 0  |     char* cur = name;  | 
146  | 0  |     while ((cur = strchr(cur, what)) != NULL)  | 
147  | 0  |       *cur = with;  | 
148  | 0  |   }  | 
149  | 0  |   return TRUE;  | 
150  | 0  | }  | 
151  |  |  | 
152  |  | static char* name_from_path(const char* path)  | 
153  | 0  | { | 
154  | 0  |   const char* name = "NULL";  | 
155  | 0  |   if (path)  | 
156  | 0  |   { | 
157  | 0  |     if (option_equals("%", path)) | 
158  | 0  |       name = "home";  | 
159  | 0  |     else if (option_equals("*", path)) | 
160  | 0  |       name = "hotplug-all";  | 
161  | 0  |     else if (option_equals("DynamicDrives", path)) | 
162  | 0  |       name = "hotplug";  | 
163  | 0  |     else  | 
164  | 0  |       name = path;  | 
165  | 0  |   }  | 
166  | 0  |   return _strdup(name);  | 
167  | 0  | }  | 
168  |  |  | 
169  |  | static BOOL freerdp_client_add_drive(rdpSettings* settings, const char* path, const char* name)  | 
170  | 0  | { | 
171  | 0  |   char* dname = NULL;  | 
172  | 0  |   RDPDR_DEVICE* device = NULL;  | 
173  |  | 
  | 
174  | 0  |   if (name)  | 
175  | 0  |   { | 
176  | 0  |     BOOL skip = FALSE;  | 
177  | 0  |     if (path)  | 
178  | 0  |     { | 
179  | 0  |       switch (path[0])  | 
180  | 0  |       { | 
181  | 0  |         case '*':  | 
182  | 0  |         case '%':  | 
183  | 0  |           skip = TRUE;  | 
184  | 0  |           break;  | 
185  | 0  |         default:  | 
186  | 0  |           break;  | 
187  | 0  |       }  | 
188  | 0  |     }  | 
189  |  |     /* Path was entered as secondary argument, swap */  | 
190  | 0  |     if (!skip && winpr_PathFileExists(name))  | 
191  | 0  |     { | 
192  | 0  |       if (!winpr_PathFileExists(path) || (!PathIsRelativeA(name) && PathIsRelativeA(path)))  | 
193  | 0  |       { | 
194  | 0  |         const char* tmp = path;  | 
195  | 0  |         path = name;  | 
196  | 0  |         name = tmp;  | 
197  | 0  |       }  | 
198  | 0  |     }  | 
199  | 0  |   }  | 
200  |  |  | 
201  | 0  |   if (name)  | 
202  | 0  |     dname = _strdup(name);  | 
203  | 0  |   else /* We need a name to send to the server. */  | 
204  | 0  |     dname = name_from_path(path);  | 
205  |  | 
  | 
206  | 0  |   if (freerdp_sanitize_drive_name(dname, "\\/", "__"))  | 
207  | 0  |   { | 
208  | 0  |     const char* args[] = { dname, path }; | 
209  | 0  |     device = freerdp_device_new(RDPDR_DTYP_FILESYSTEM, ARRAYSIZE(args), args);  | 
210  | 0  |   }  | 
211  | 0  |   free(dname);  | 
212  | 0  |   if (!device)  | 
213  | 0  |     goto fail;  | 
214  |  |  | 
215  | 0  |   if (!path)  | 
216  | 0  |     goto fail;  | 
217  |  |  | 
218  | 0  |   { | 
219  | 0  |     BOOL isSpecial = FALSE;  | 
220  | 0  |     BOOL isPath = freerdp_path_valid(path, &isSpecial);  | 
221  |  | 
  | 
222  | 0  |     if (!isPath && !isSpecial)  | 
223  | 0  |     { | 
224  | 0  |       WLog_WARN(TAG, "Invalid drive to redirect: '%s' does not exist, skipping.", path);  | 
225  | 0  |       freerdp_device_free(device);  | 
226  | 0  |     }  | 
227  | 0  |     else if (!freerdp_device_collection_add(settings, device))  | 
228  | 0  |       goto fail;  | 
229  | 0  |   }  | 
230  |  |  | 
231  | 0  |   return TRUE;  | 
232  |  |  | 
233  | 0  | fail:  | 
234  | 0  |   freerdp_device_free(device);  | 
235  | 0  |   return FALSE;  | 
236  | 0  | }  | 
237  |  |  | 
238  |  | static BOOL value_to_int(const char* value, LONGLONG* result, LONGLONG min, LONGLONG max)  | 
239  | 0  | { | 
240  | 0  |   long long rc = 0;  | 
241  |  | 
  | 
242  | 0  |   if (!value || !result)  | 
243  | 0  |     return FALSE;  | 
244  |  |  | 
245  | 0  |   errno = 0;  | 
246  | 0  |   rc = _strtoi64(value, NULL, 0);  | 
247  |  | 
  | 
248  | 0  |   if (errno != 0)  | 
249  | 0  |     return FALSE;  | 
250  |  |  | 
251  | 0  |   if ((rc < min) || (rc > max))  | 
252  | 0  |     return FALSE;  | 
253  |  |  | 
254  | 0  |   *result = rc;  | 
255  | 0  |   return TRUE;  | 
256  | 0  | }  | 
257  |  |  | 
258  |  | static BOOL value_to_uint(const char* value, ULONGLONG* result, ULONGLONG min, ULONGLONG max)  | 
259  | 0  | { | 
260  | 0  |   unsigned long long rc = 0;  | 
261  |  | 
  | 
262  | 0  |   if (!value || !result)  | 
263  | 0  |     return FALSE;  | 
264  |  |  | 
265  | 0  |   errno = 0;  | 
266  | 0  |   rc = _strtoui64(value, NULL, 0);  | 
267  |  | 
  | 
268  | 0  |   if (errno != 0)  | 
269  | 0  |     return FALSE;  | 
270  |  |  | 
271  | 0  |   if ((rc < min) || (rc > max))  | 
272  | 0  |     return FALSE;  | 
273  |  |  | 
274  | 0  |   *result = rc;  | 
275  | 0  |   return TRUE;  | 
276  | 0  | }  | 
277  |  |  | 
278  |  | BOOL freerdp_client_print_version(void)  | 
279  | 0  | { | 
280  | 0  |   printf("This is FreeRDP version %s (%s)\n", FREERDP_VERSION_FULL, FREERDP_GIT_REVISION); | 
281  | 0  |   return TRUE;  | 
282  | 0  | }  | 
283  |  |  | 
284  |  | BOOL freerdp_client_print_buildconfig(void)  | 
285  | 0  | { | 
286  | 0  |   printf("%s", freerdp_get_build_config()); | 
287  | 0  |   return TRUE;  | 
288  | 0  | }  | 
289  |  |  | 
290  |  | static void freerdp_client_print_scancodes(void)  | 
291  | 0  | { | 
292  | 0  |   printf("RDP scancodes and their name for use with /kbd:remap\n"); | 
293  |  | 
  | 
294  | 0  |   for (UINT32 x = 0; x < UINT16_MAX; x++)  | 
295  | 0  |   { | 
296  | 0  |     const char* name = freerdp_keyboard_scancode_name(x);  | 
297  | 0  |     if (name)  | 
298  | 0  |       printf("0x%04" PRIx32 "  --> %s\n", x, name); | 
299  | 0  |   }  | 
300  | 0  | }  | 
301  |  |  | 
302  |  | static BOOL is_delimiter(char c, const char* delimiters)  | 
303  | 0  | { | 
304  | 0  |   char d = 0;  | 
305  | 0  |   while ((d = *delimiters++) != '\0')  | 
306  | 0  |   { | 
307  | 0  |     if (c == d)  | 
308  | 0  |       return TRUE;  | 
309  | 0  |   }  | 
310  | 0  |   return FALSE;  | 
311  | 0  | }  | 
312  |  |  | 
313  |  | static const char* get_last(const char* start, size_t len, const char* delimiters)  | 
314  | 0  | { | 
315  | 0  |   const char* last = NULL;  | 
316  | 0  |   for (size_t x = 0; x < len; x++)  | 
317  | 0  |   { | 
318  | 0  |     char c = start[x];  | 
319  | 0  |     if (is_delimiter(c, delimiters))  | 
320  | 0  |       last = &start[x];  | 
321  | 0  |   }  | 
322  | 0  |   return last;  | 
323  | 0  | }  | 
324  |  |  | 
325  |  | static SSIZE_T next_delimiter(const char* text, size_t len, size_t max, const char* delimiters)  | 
326  | 0  | { | 
327  | 0  |   if (len < max)  | 
328  | 0  |     return -1;  | 
329  |  |  | 
330  | 0  |   const char* last = get_last(text, max, delimiters);  | 
331  | 0  |   if (!last)  | 
332  | 0  |     return -1;  | 
333  |  |  | 
334  | 0  |   return (SSIZE_T)(last - text);  | 
335  | 0  | }  | 
336  |  |  | 
337  |  | static SSIZE_T forced_newline_at(const char* text, size_t len, size_t limit,  | 
338  |  |                                  const char* force_newline)  | 
339  | 0  | { | 
340  | 0  |   char d = 0;  | 
341  | 0  |   while ((d = *force_newline++) != '\0')  | 
342  | 0  |   { | 
343  | 0  |     const char* tok = strchr(text, d);  | 
344  | 0  |     if (tok)  | 
345  | 0  |     { | 
346  | 0  |       const size_t offset = tok - text;  | 
347  | 0  |       if ((offset > len) || (offset > limit))  | 
348  | 0  |         continue;  | 
349  | 0  |       return (SSIZE_T)(offset);  | 
350  | 0  |     }  | 
351  | 0  |   }  | 
352  | 0  |   return -1;  | 
353  | 0  | }  | 
354  |  |  | 
355  |  | static BOOL print_align(size_t start_offset, size_t* current)  | 
356  | 0  | { | 
357  | 0  |   WINPR_ASSERT(current);  | 
358  | 0  |   if (*current < start_offset)  | 
359  | 0  |   { | 
360  | 0  |     const int rc = printf("%*c", (int)(start_offset - *current), ' '); | 
361  | 0  |     if (rc < 0)  | 
362  | 0  |       return FALSE;  | 
363  | 0  |     *current += (size_t)rc;  | 
364  | 0  |   }  | 
365  | 0  |   return TRUE;  | 
366  | 0  | }  | 
367  |  |  | 
368  |  | static char* print_token(char* text, size_t start_offset, size_t* current, size_t limit,  | 
369  |  |                          const char* delimiters, const char* force_newline)  | 
370  | 0  | { | 
371  | 0  |   int rc = 0;  | 
372  | 0  |   const size_t tlen = strnlen(text, limit);  | 
373  | 0  |   size_t len = tlen;  | 
374  | 0  |   const SSIZE_T force_at = forced_newline_at(text, len, limit - *current, force_newline);  | 
375  | 0  |   BOOL isForce = (force_at >= 0);  | 
376  |  | 
  | 
377  | 0  |   if (isForce)  | 
378  | 0  |     len = MIN(len, (size_t)force_at);  | 
379  |  | 
  | 
380  | 0  |   if (!print_align(start_offset, current))  | 
381  | 0  |     return NULL;  | 
382  |  |  | 
383  | 0  |   const SSIZE_T delim = next_delimiter(text, len, limit - *current, delimiters);  | 
384  | 0  |   const BOOL isDelim = delim > 0;  | 
385  | 0  |   if (isDelim)  | 
386  | 0  |   { | 
387  | 0  |     len = MIN(len, (size_t)delim + 1);  | 
388  | 0  |   }  | 
389  |  | 
  | 
390  | 0  |   rc = printf("%.*s", (int)len, text); | 
391  | 0  |   if (rc < 0)  | 
392  | 0  |     return NULL;  | 
393  |  |  | 
394  | 0  |   if (isForce || isDelim)  | 
395  | 0  |   { | 
396  | 0  |     printf("\n"); | 
397  | 0  |     *current = 0;  | 
398  |  | 
  | 
399  | 0  |     const size_t offset = len + ((isForce && (force_at == 0)) ? 1 : 0);  | 
400  | 0  |     return &text[offset];  | 
401  | 0  |   }  | 
402  |  |  | 
403  | 0  |   *current += (size_t)rc;  | 
404  |  | 
  | 
405  | 0  |   if (tlen == (size_t)rc)  | 
406  | 0  |     return NULL;  | 
407  | 0  |   return &text[(size_t)rc];  | 
408  | 0  | }  | 
409  |  |  | 
410  |  | static size_t print_optionals(const char* text, size_t start_offset, size_t current)  | 
411  | 0  | { | 
412  | 0  |   const size_t limit = 80;  | 
413  | 0  |   char* str = _strdup(text);  | 
414  | 0  |   char* cur = str;  | 
415  |  | 
  | 
416  | 0  |   do  | 
417  | 0  |   { | 
418  | 0  |     cur = print_token(cur, start_offset + 1, ¤t, limit, "[], ", "\r\n");  | 
419  | 0  |   } while (cur != NULL);  | 
420  |  | 
  | 
421  | 0  |   free(str);  | 
422  | 0  |   return current;  | 
423  | 0  | }  | 
424  |  |  | 
425  |  | static size_t print_description(const char* text, size_t start_offset, size_t current)  | 
426  | 0  | { | 
427  | 0  |   const size_t limit = 80;  | 
428  | 0  |   char* str = _strdup(text);  | 
429  | 0  |   char* cur = str;  | 
430  |  | 
  | 
431  | 0  |   do  | 
432  | 0  |   { | 
433  | 0  |     cur = print_token(cur, start_offset, ¤t, limit, " ", "\r\n");  | 
434  | 0  |   } while (cur != NULL);  | 
435  |  | 
  | 
436  | 0  |   free(str);  | 
437  | 0  |   current += (size_t)printf("\n"); | 
438  | 0  |   return current;  | 
439  | 0  | }  | 
440  |  |  | 
441  |  | static int cmp_cmdline_args(const void* pva, const void* pvb)  | 
442  | 0  | { | 
443  | 0  |   const COMMAND_LINE_ARGUMENT_A* a = (const COMMAND_LINE_ARGUMENT_A*)pva;  | 
444  | 0  |   const COMMAND_LINE_ARGUMENT_A* b = (const COMMAND_LINE_ARGUMENT_A*)pvb;  | 
445  |  | 
  | 
446  | 0  |   if (!a->Name && !b->Name)  | 
447  | 0  |     return 0;  | 
448  | 0  |   if (!a->Name)  | 
449  | 0  |     return 1;  | 
450  | 0  |   if (!b->Name)  | 
451  | 0  |     return -1;  | 
452  | 0  |   return strcmp(a->Name, b->Name);  | 
453  | 0  | }  | 
454  |  |  | 
455  |  | static void freerdp_client_print_command_line_args(COMMAND_LINE_ARGUMENT_A* parg, size_t count)  | 
456  | 0  | { | 
457  | 0  |   if (!parg)  | 
458  | 0  |     return;  | 
459  |  |  | 
460  | 0  |   qsort(parg, count, sizeof(COMMAND_LINE_ARGUMENT_A), cmp_cmdline_args);  | 
461  |  | 
  | 
462  | 0  |   const COMMAND_LINE_ARGUMENT_A* arg = parg;  | 
463  | 0  |   do  | 
464  | 0  |   { | 
465  | 0  |     int rc = 0;  | 
466  | 0  |     size_t pos = 0;  | 
467  | 0  |     const size_t description_offset = 30 + 8;  | 
468  |  | 
  | 
469  | 0  |     if (arg->Flags & (COMMAND_LINE_VALUE_BOOL | COMMAND_LINE_VALUE_FLAG))  | 
470  | 0  |     { | 
471  | 0  |       if ((arg->Flags & ~COMMAND_LINE_VALUE_BOOL) == 0)  | 
472  | 0  |         rc = printf("    %s%s", arg->Default ? "-" : "+", arg->Name); | 
473  | 0  |       else if ((arg->Flags & COMMAND_LINE_VALUE_OPTIONAL) != 0)  | 
474  | 0  |         rc = printf("    [%s|/]%s", arg->Default ? "-" : "+", arg->Name); | 
475  | 0  |       else  | 
476  | 0  |       { | 
477  | 0  |         rc = printf("    %s%s", arg->Default ? "-" : "+", arg->Name); | 
478  | 0  |       }  | 
479  | 0  |     }  | 
480  | 0  |     else  | 
481  | 0  |       rc = printf("    /%s", arg->Name); | 
482  |  | 
  | 
483  | 0  |     if (rc < 0)  | 
484  | 0  |       return;  | 
485  | 0  |     pos += (size_t)rc;  | 
486  |  | 
  | 
487  | 0  |     if ((arg->Flags & COMMAND_LINE_VALUE_REQUIRED) ||  | 
488  | 0  |         (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL))  | 
489  | 0  |     { | 
490  | 0  |       if (arg->Format)  | 
491  | 0  |       { | 
492  | 0  |         if (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL)  | 
493  | 0  |         { | 
494  | 0  |           rc = printf("[:"); | 
495  | 0  |           if (rc < 0)  | 
496  | 0  |             return;  | 
497  | 0  |           pos += (size_t)rc;  | 
498  | 0  |           pos = print_optionals(arg->Format, pos, pos);  | 
499  | 0  |           rc = printf("]"); | 
500  | 0  |           if (rc < 0)  | 
501  | 0  |             return;  | 
502  | 0  |           pos += (size_t)rc;  | 
503  | 0  |         }  | 
504  | 0  |         else  | 
505  | 0  |         { | 
506  | 0  |           rc = printf(":"); | 
507  | 0  |           if (rc < 0)  | 
508  | 0  |             return;  | 
509  | 0  |           pos += (size_t)rc;  | 
510  | 0  |           pos = print_optionals(arg->Format, pos, pos);  | 
511  | 0  |         }  | 
512  |  |  | 
513  | 0  |         if (pos > description_offset)  | 
514  | 0  |         { | 
515  | 0  |           printf("\n"); | 
516  | 0  |           pos = 0;  | 
517  | 0  |         }  | 
518  | 0  |       }  | 
519  | 0  |     }  | 
520  |  |  | 
521  | 0  |     rc = printf("%*c", (int)(description_offset - pos), ' '); | 
522  | 0  |     if (rc < 0)  | 
523  | 0  |       return;  | 
524  | 0  |     pos += (size_t)rc;  | 
525  |  | 
  | 
526  | 0  |     if (arg->Flags & COMMAND_LINE_VALUE_BOOL)  | 
527  | 0  |     { | 
528  | 0  |       rc = printf("%s ", arg->Default ? "Disable" : "Enable"); | 
529  | 0  |       if (rc < 0)  | 
530  | 0  |         return;  | 
531  | 0  |       pos += (size_t)rc;  | 
532  | 0  |     }  | 
533  |  |  | 
534  | 0  |     print_description(arg->Text, description_offset, pos);  | 
535  | 0  |   } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);  | 
536  | 0  | }  | 
537  |  |  | 
538  |  | BOOL freerdp_client_print_command_line_help(int argc, char** argv)  | 
539  | 0  | { | 
540  | 0  |   return freerdp_client_print_command_line_help_ex(argc, argv, NULL);  | 
541  | 0  | }  | 
542  |  |  | 
543  |  | static COMMAND_LINE_ARGUMENT_A* create_merged_args(const COMMAND_LINE_ARGUMENT_A* custom,  | 
544  |  |                                                    SSIZE_T count, size_t* pcount)  | 
545  | 0  | { | 
546  | 0  |   WINPR_ASSERT(pcount);  | 
547  | 0  |   if (count < 0)  | 
548  | 0  |   { | 
549  | 0  |     const COMMAND_LINE_ARGUMENT_A* cur = custom;  | 
550  | 0  |     count = 0;  | 
551  | 0  |     while (cur && cur->Name)  | 
552  | 0  |     { | 
553  | 0  |       count++;  | 
554  | 0  |       cur++;  | 
555  | 0  |     }  | 
556  | 0  |   }  | 
557  |  | 
  | 
558  | 0  |   COMMAND_LINE_ARGUMENT_A* largs =  | 
559  | 0  |       calloc(count + ARRAYSIZE(global_cmd_args), sizeof(COMMAND_LINE_ARGUMENT_A));  | 
560  | 0  |   *pcount = 0;  | 
561  | 0  |   if (!largs)  | 
562  | 0  |     return NULL;  | 
563  |  |  | 
564  | 0  |   size_t lcount = 0;  | 
565  | 0  |   const COMMAND_LINE_ARGUMENT_A* cur = custom;  | 
566  | 0  |   while (cur && cur->Name)  | 
567  | 0  |   { | 
568  | 0  |     largs[lcount++] = *cur++;  | 
569  | 0  |   }  | 
570  |  | 
  | 
571  | 0  |   cur = global_cmd_args;  | 
572  | 0  |   while (cur && cur->Name)  | 
573  | 0  |   { | 
574  | 0  |     largs[lcount++] = *cur++;  | 
575  | 0  |   }  | 
576  | 0  |   *pcount = lcount;  | 
577  | 0  |   return largs;  | 
578  | 0  | }  | 
579  |  |  | 
580  |  | BOOL freerdp_client_print_command_line_help_ex(int argc, char** argv,  | 
581  |  |                                                const COMMAND_LINE_ARGUMENT_A* custom)  | 
582  | 0  | { | 
583  | 0  |   const char* name = "FreeRDP";  | 
584  |  |  | 
585  |  |   /* allocate a merged copy of implementation defined and default arguments */  | 
586  | 0  |   size_t lcount = 0;  | 
587  | 0  |   COMMAND_LINE_ARGUMENT_A* largs = create_merged_args(custom, -1, &lcount);  | 
588  | 0  |   if (!largs)  | 
589  | 0  |     return FALSE;  | 
590  |  |  | 
591  | 0  |   if (argc > 0)  | 
592  | 0  |     name = argv[0];  | 
593  |  | 
  | 
594  | 0  |   printf("\n"); | 
595  | 0  |   printf("FreeRDP - A Free Remote Desktop Protocol Implementation\n"); | 
596  | 0  |   printf("See www.freerdp.com for more information\n"); | 
597  | 0  |   printf("\n"); | 
598  | 0  |   printf("Usage: %s [file] [options] [/v:<server>[:port]]\n", argv[0]); | 
599  | 0  |   printf("\n"); | 
600  | 0  |   printf("Syntax:\n"); | 
601  | 0  |   printf("    /flag (enables flag)\n"); | 
602  | 0  |   printf("    /option:<value> (specifies option with value)\n"); | 
603  | 0  |   printf("    +toggle -toggle (enables or disables toggle, where '/' is a synonym of '+')\n"); | 
604  | 0  |   printf("\n"); | 
605  |  | 
  | 
606  | 0  |   freerdp_client_print_command_line_args(largs, lcount);  | 
607  | 0  |   free(largs);  | 
608  |  | 
  | 
609  | 0  |   printf("\n"); | 
610  | 0  |   printf("Examples:\n"); | 
611  | 0  |   printf("    %s connection.rdp /p:Pwd123! /f\n", name); | 
612  | 0  |   printf("    %s /u:CONTOSO\\JohnDoe /p:Pwd123! /v:rdp.contoso.com\n", name); | 
613  | 0  |   printf("    %s /u:JohnDoe /p:Pwd123! /w:1366 /h:768 /v:192.168.1.100:4489\n", name); | 
614  | 0  |   printf("    %s /u:JohnDoe /p:Pwd123! /vmconnect:C824F53E-95D2-46C6-9A18-23A5BB403532 " | 
615  | 0  |          "/v:192.168.1.100\n",  | 
616  | 0  |          name);  | 
617  | 0  |   printf("    %s /u:\\AzureAD\\user@corp.example /p:pwd /v:host\n", name); | 
618  | 0  |   printf("\n"); | 
619  | 0  |   printf("Clipboard Redirection: +clipboard\n"); | 
620  | 0  |   printf("\n"); | 
621  | 0  |   printf("Drive Redirection: /drive:home,/home/user\n"); | 
622  | 0  |   printf("Smartcard Redirection: /smartcard:<device>\n"); | 
623  | 0  |   printf("Smartcard logon with Kerberos authentication: /smartcard-logon /sec:nla\n"); | 
624  |  | 
  | 
625  | 0  |   printf("Serial Port Redirection: /serial:<name>,<device>,[SerCx2|SerCx|Serial],[permissive]\n"); | 
626  | 0  |   printf("Serial Port Redirection: /serial:COM1,/dev/ttyS0\n"); | 
627  | 0  |   printf("Parallel Port Redirection: /parallel:<name>,<device>\n"); | 
628  | 0  |   printf("Printer Redirection: /printer:<device>,<driver>,[default]\n"); | 
629  | 0  |   printf("TCP redirection: /rdp2tcp:/usr/bin/rdp2tcp\n"); | 
630  | 0  |   printf("\n"); | 
631  | 0  |   printf("Audio Output Redirection: /sound:sys:oss,dev:1,format:1\n"); | 
632  | 0  |   printf("Audio Output Redirection: /sound:sys:alsa\n"); | 
633  | 0  |   printf("Audio Input Redirection: /microphone:sys:oss,dev:1,format:1\n"); | 
634  | 0  |   printf("Audio Input Redirection: /microphone:sys:alsa\n"); | 
635  | 0  |   printf("\n"); | 
636  | 0  |   printf("Multimedia Redirection: /video\n"); | 
637  |  | #ifdef CHANNEL_URBDRC_CLIENT  | 
638  |  |   printf("USB Device Redirection: /usb:id:054c:0268#4669:6e6b,addr:04:0c\n"); | 
639  |  | #endif  | 
640  | 0  |   printf("\n"); | 
641  | 0  |   printf("For Gateways, the https_proxy environment variable is respected:\n"); | 
642  |  | #ifdef _WIN32  | 
643  |  |   printf("    set HTTPS_PROXY=http://proxy.contoso.com:3128/\n"); | 
644  |  | #else  | 
645  | 0  |   printf("    export https_proxy=http://proxy.contoso.com:3128/\n"); | 
646  | 0  | #endif  | 
647  | 0  |   printf("    %s /g:rdp.contoso.com ...\n", name); | 
648  | 0  |   printf("\n"); | 
649  | 0  |   printf("More documentation is coming, in the meantime consult source files\n"); | 
650  | 0  |   printf("\n"); | 
651  | 0  |   return TRUE;  | 
652  | 0  | }  | 
653  |  |  | 
654  |  | static BOOL option_is_rdp_file(const char* option)  | 
655  | 0  | { | 
656  | 0  |   WINPR_ASSERT(option);  | 
657  |  |  | 
658  | 0  |   if (option_ends_with(option, ".rdp"))  | 
659  | 0  |     return TRUE;  | 
660  | 0  |   if (option_ends_with(option, ".rdpw"))  | 
661  | 0  |     return TRUE;  | 
662  | 0  |   return FALSE;  | 
663  | 0  | }  | 
664  |  |  | 
665  |  | static BOOL option_is_incident_file(const char* option)  | 
666  | 0  | { | 
667  | 0  |   WINPR_ASSERT(option);  | 
668  |  |  | 
669  | 0  |   if (option_ends_with(option, ".msrcIncident"))  | 
670  | 0  |     return TRUE;  | 
671  | 0  |   return FALSE;  | 
672  | 0  | }  | 
673  |  |  | 
674  |  | static int freerdp_client_command_line_pre_filter(void* context, int index, int argc, LPSTR* argv)  | 
675  | 0  | { | 
676  | 0  |   if (index == 1)  | 
677  | 0  |   { | 
678  | 0  |     size_t length = 0;  | 
679  | 0  |     rdpSettings* settings = NULL;  | 
680  |  | 
  | 
681  | 0  |     if (argc <= index)  | 
682  | 0  |       return -1;  | 
683  |  |  | 
684  | 0  |     length = strlen(argv[index]);  | 
685  |  | 
  | 
686  | 0  |     if (length > 4)  | 
687  | 0  |     { | 
688  | 0  |       if (option_is_rdp_file(argv[index]))  | 
689  | 0  |       { | 
690  | 0  |         settings = (rdpSettings*)context;  | 
691  |  | 
  | 
692  | 0  |         if (!freerdp_settings_set_string(settings, FreeRDP_ConnectionFile, argv[index]))  | 
693  | 0  |           return COMMAND_LINE_ERROR_MEMORY;  | 
694  |  |  | 
695  | 0  |         return 1;  | 
696  | 0  |       }  | 
697  | 0  |     }  | 
698  |  |  | 
699  | 0  |     if (length > 13)  | 
700  | 0  |     { | 
701  | 0  |       if (option_is_incident_file(argv[index]))  | 
702  | 0  |       { | 
703  | 0  |         settings = (rdpSettings*)context;  | 
704  |  | 
  | 
705  | 0  |         if (!freerdp_settings_set_string(settings, FreeRDP_AssistanceFile, argv[index]))  | 
706  | 0  |           return COMMAND_LINE_ERROR_MEMORY;  | 
707  |  |  | 
708  | 0  |         return 1;  | 
709  | 0  |       }  | 
710  | 0  |     }  | 
711  | 0  |   }  | 
712  |  |  | 
713  | 0  |   return 0;  | 
714  | 0  | }  | 
715  |  |  | 
716  |  | BOOL freerdp_client_add_device_channel(rdpSettings* settings, size_t count, const char** params)  | 
717  | 0  | { | 
718  | 0  |   WINPR_ASSERT(settings);  | 
719  | 0  |   WINPR_ASSERT(params);  | 
720  | 0  |   WINPR_ASSERT(count > 0);  | 
721  |  |  | 
722  | 0  |   if (option_equals(params[0], "drive"))  | 
723  | 0  |   { | 
724  | 0  |     BOOL rc = 0;  | 
725  | 0  |     if (count < 2)  | 
726  | 0  |       return FALSE;  | 
727  |  |  | 
728  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))  | 
729  | 0  |       return FALSE;  | 
730  | 0  |     if (count < 3)  | 
731  | 0  |       rc = freerdp_client_add_drive(settings, params[1], NULL);  | 
732  | 0  |     else  | 
733  | 0  |       rc = freerdp_client_add_drive(settings, params[2], params[1]);  | 
734  |  | 
  | 
735  | 0  |     return rc;  | 
736  | 0  |   }  | 
737  | 0  |   else if (option_equals(params[0], "printer"))  | 
738  | 0  |   { | 
739  | 0  |     RDPDR_DEVICE* printer = NULL;  | 
740  |  | 
  | 
741  | 0  |     if (count < 1)  | 
742  | 0  |       return FALSE;  | 
743  |  |  | 
744  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectPrinters, TRUE))  | 
745  | 0  |       return FALSE;  | 
746  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))  | 
747  | 0  |       return FALSE;  | 
748  |  |  | 
749  | 0  |     printer = freerdp_device_new(RDPDR_DTYP_PRINT, count - 1, ¶ms[1]);  | 
750  | 0  |     if (!printer)  | 
751  | 0  |       return FALSE;  | 
752  |  |  | 
753  | 0  |     if (!freerdp_device_collection_add(settings, printer))  | 
754  | 0  |     { | 
755  | 0  |       freerdp_device_free(printer);  | 
756  | 0  |       return FALSE;  | 
757  | 0  |     }  | 
758  |  |  | 
759  | 0  |     return TRUE;  | 
760  | 0  |   }  | 
761  | 0  |   else if (option_equals(params[0], "smartcard"))  | 
762  | 0  |   { | 
763  | 0  |     RDPDR_DEVICE* smartcard = NULL;  | 
764  |  | 
  | 
765  | 0  |     if (count < 1)  | 
766  | 0  |       return FALSE;  | 
767  |  |  | 
768  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSmartCards, TRUE))  | 
769  | 0  |       return FALSE;  | 
770  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))  | 
771  | 0  |       return FALSE;  | 
772  |  |  | 
773  | 0  |     smartcard = freerdp_device_new(RDPDR_DTYP_SMARTCARD, count - 1, ¶ms[1]);  | 
774  |  | 
  | 
775  | 0  |     if (!smartcard)  | 
776  | 0  |       return FALSE;  | 
777  |  |  | 
778  | 0  |     if (!freerdp_device_collection_add(settings, smartcard))  | 
779  | 0  |     { | 
780  | 0  |       freerdp_device_free(smartcard);  | 
781  | 0  |       return FALSE;  | 
782  | 0  |     }  | 
783  |  |  | 
784  | 0  |     return TRUE;  | 
785  | 0  |   }  | 
786  | 0  |   else if (option_equals(params[0], "serial"))  | 
787  | 0  |   { | 
788  | 0  |     RDPDR_DEVICE* serial = NULL;  | 
789  |  | 
  | 
790  | 0  |     if (count < 1)  | 
791  | 0  |       return FALSE;  | 
792  |  |  | 
793  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSerialPorts, TRUE))  | 
794  | 0  |       return FALSE;  | 
795  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))  | 
796  | 0  |       return FALSE;  | 
797  |  |  | 
798  | 0  |     serial = freerdp_device_new(RDPDR_DTYP_SERIAL, count - 1, ¶ms[1]);  | 
799  |  | 
  | 
800  | 0  |     if (!serial)  | 
801  | 0  |       return FALSE;  | 
802  |  |  | 
803  | 0  |     if (!freerdp_device_collection_add(settings, serial))  | 
804  | 0  |     { | 
805  | 0  |       freerdp_device_free(serial);  | 
806  | 0  |       return FALSE;  | 
807  | 0  |     }  | 
808  |  |  | 
809  | 0  |     return TRUE;  | 
810  | 0  |   }  | 
811  | 0  |   else if (option_equals(params[0], "parallel"))  | 
812  | 0  |   { | 
813  | 0  |     RDPDR_DEVICE* parallel = NULL;  | 
814  |  | 
  | 
815  | 0  |     if (count < 1)  | 
816  | 0  |       return FALSE;  | 
817  |  |  | 
818  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectParallelPorts, TRUE))  | 
819  | 0  |       return FALSE;  | 
820  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))  | 
821  | 0  |       return FALSE;  | 
822  |  |  | 
823  | 0  |     parallel = freerdp_device_new(RDPDR_DTYP_PARALLEL, count - 1, ¶ms[1]);  | 
824  |  | 
  | 
825  | 0  |     if (!parallel)  | 
826  | 0  |       return FALSE;  | 
827  |  |  | 
828  | 0  |     if (!freerdp_device_collection_add(settings, parallel))  | 
829  | 0  |     { | 
830  | 0  |       freerdp_device_free(parallel);  | 
831  | 0  |       return FALSE;  | 
832  | 0  |     }  | 
833  |  |  | 
834  | 0  |     return TRUE;  | 
835  | 0  |   }  | 
836  |  |  | 
837  | 0  |   return FALSE;  | 
838  | 0  | }  | 
839  |  |  | 
840  |  | BOOL freerdp_client_del_static_channel(rdpSettings* settings, const char* name)  | 
841  | 0  | { | 
842  | 0  |   return freerdp_static_channel_collection_del(settings, name);  | 
843  | 0  | }  | 
844  |  |  | 
845  |  | BOOL freerdp_client_add_static_channel(rdpSettings* settings, size_t count, const char** params)  | 
846  | 0  | { | 
847  | 0  |   ADDIN_ARGV* _args = NULL;  | 
848  |  | 
  | 
849  | 0  |   if (!settings || !params || !params[0] || (count > INT_MAX))  | 
850  | 0  |     return FALSE;  | 
851  |  |  | 
852  | 0  |   if (freerdp_static_channel_collection_find(settings, params[0]))  | 
853  | 0  |     return TRUE;  | 
854  |  |  | 
855  | 0  |   _args = freerdp_addin_argv_new(count, (const char**)params);  | 
856  |  | 
  | 
857  | 0  |   if (!_args)  | 
858  | 0  |     return FALSE;  | 
859  |  |  | 
860  | 0  |   if (!freerdp_static_channel_collection_add(settings, _args))  | 
861  | 0  |     goto fail;  | 
862  |  |  | 
863  | 0  |   return TRUE;  | 
864  | 0  | fail:  | 
865  | 0  |   freerdp_addin_argv_free(_args);  | 
866  | 0  |   return FALSE;  | 
867  | 0  | }  | 
868  |  |  | 
869  |  | BOOL freerdp_client_del_dynamic_channel(rdpSettings* settings, const char* name)  | 
870  | 0  | { | 
871  | 0  |   return freerdp_dynamic_channel_collection_del(settings, name);  | 
872  | 0  | }  | 
873  |  |  | 
874  |  | BOOL freerdp_client_add_dynamic_channel(rdpSettings* settings, size_t count, const char** params)  | 
875  | 0  | { | 
876  | 0  |   ADDIN_ARGV* _args = NULL;  | 
877  |  | 
  | 
878  | 0  |   if (!settings || !params || !params[0] || (count > INT_MAX))  | 
879  | 0  |     return FALSE;  | 
880  |  |  | 
881  | 0  |   if (freerdp_dynamic_channel_collection_find(settings, params[0]))  | 
882  | 0  |     return TRUE;  | 
883  |  |  | 
884  | 0  |   _args = freerdp_addin_argv_new(count, params);  | 
885  |  | 
  | 
886  | 0  |   if (!_args)  | 
887  | 0  |     return FALSE;  | 
888  |  |  | 
889  | 0  |   if (!freerdp_dynamic_channel_collection_add(settings, _args))  | 
890  | 0  |     goto fail;  | 
891  |  |  | 
892  | 0  |   return TRUE;  | 
893  |  |  | 
894  | 0  | fail:  | 
895  | 0  |   freerdp_addin_argv_free(_args);  | 
896  | 0  |   return FALSE;  | 
897  | 0  | }  | 
898  |  |  | 
899  |  | static BOOL read_pem_file(rdpSettings* settings, FreeRDP_Settings_Keys_String id, const char* file)  | 
900  | 0  | { | 
901  | 0  |   size_t length = 0;  | 
902  | 0  |   char* pem = crypto_read_pem(file, &length);  | 
903  | 0  |   if (!pem || (length == 0))  | 
904  | 0  |   { | 
905  | 0  |     free(pem);  | 
906  | 0  |     return FALSE;  | 
907  | 0  |   }  | 
908  |  |  | 
909  | 0  |   BOOL rc = freerdp_settings_set_string_len(settings, id, pem, length);  | 
910  | 0  |   free(pem);  | 
911  | 0  |   return rc;  | 
912  | 0  | }  | 
913  |  |  | 
914  |  | /** @brief suboption type */  | 
915  |  | typedef enum  | 
916  |  | { | 
917  |  |   CMDLINE_SUBOPTION_STRING,  | 
918  |  |   CMDLINE_SUBOPTION_FILE,  | 
919  |  | } CmdLineSubOptionType;  | 
920  |  |  | 
921  |  | typedef BOOL (*CmdLineSubOptionCb)(const char* value, rdpSettings* settings);  | 
922  |  | typedef struct  | 
923  |  | { | 
924  |  |   const char* optname;  | 
925  |  |   FreeRDP_Settings_Keys_String id;  | 
926  |  |   CmdLineSubOptionType opttype;  | 
927  |  |   CmdLineSubOptionCb cb;  | 
928  |  | } CmdLineSubOptions;  | 
929  |  |  | 
930  |  | static BOOL parseSubOptions(rdpSettings* settings, const CmdLineSubOptions* opts, size_t count,  | 
931  |  |                             const char* arg)  | 
932  | 0  | { | 
933  | 0  |   BOOL found = FALSE;  | 
934  |  | 
  | 
935  | 0  |   for (size_t xx = 0; xx < count; xx++)  | 
936  | 0  |   { | 
937  | 0  |     const CmdLineSubOptions* opt = &opts[xx];  | 
938  |  | 
  | 
939  | 0  |     if (option_starts_with(opt->optname, arg))  | 
940  | 0  |     { | 
941  | 0  |       const size_t optlen = strlen(opt->optname);  | 
942  | 0  |       const char* val = &arg[optlen];  | 
943  | 0  |       BOOL status = 0;  | 
944  |  | 
  | 
945  | 0  |       switch (opt->opttype)  | 
946  | 0  |       { | 
947  | 0  |         case CMDLINE_SUBOPTION_STRING:  | 
948  | 0  |           status = freerdp_settings_set_string(settings, opt->id, val);  | 
949  | 0  |           break;  | 
950  | 0  |         case CMDLINE_SUBOPTION_FILE:  | 
951  | 0  |           status = read_pem_file(settings, opt->id, val);  | 
952  | 0  |           break;  | 
953  | 0  |         default:  | 
954  | 0  |           WLog_ERR(TAG, "invalid subOption type");  | 
955  | 0  |           return FALSE;  | 
956  | 0  |       }  | 
957  |  |  | 
958  | 0  |       if (!status)  | 
959  | 0  |         return FALSE;  | 
960  |  |  | 
961  | 0  |       if (opt->cb && !opt->cb(val, settings))  | 
962  | 0  |         return FALSE;  | 
963  |  |  | 
964  | 0  |       found = TRUE;  | 
965  | 0  |       break;  | 
966  | 0  |     }  | 
967  | 0  |   }  | 
968  |  |  | 
969  | 0  |   if (!found)  | 
970  | 0  |     WLog_ERR(TAG, "option %s not handled", arg);  | 
971  |  | 
  | 
972  | 0  |   return found;  | 
973  | 0  | }  | 
974  |  |  | 
975  |  | static int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT_A* arg)  | 
976  | 0  | { | 
977  | 0  |   rdpSettings* settings = (rdpSettings*)context;  | 
978  | 0  |   BOOL status = TRUE;  | 
979  | 0  |   BOOL enable = arg->Value ? TRUE : FALSE;  | 
980  | 0  |   union  | 
981  | 0  |   { | 
982  | 0  |     char** p;  | 
983  | 0  |     const char** pc;  | 
984  | 0  |   } ptr;  | 
985  |  | 
  | 
986  | 0  |   CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "a")  | 
987  | 0  |   { | 
988  | 0  |     size_t count = 0;  | 
989  | 0  |     ptr.p = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
990  |  | 
  | 
991  | 0  |     if ((status = freerdp_client_add_device_channel(settings, count, ptr.pc)))  | 
992  | 0  |     { | 
993  | 0  |       freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE);  | 
994  | 0  |     }  | 
995  |  | 
  | 
996  | 0  |     free(ptr.p);  | 
997  | 0  |   }  | 
998  | 0  |   CommandLineSwitchCase(arg, "kerberos")  | 
999  | 0  |   { | 
1000  | 0  |     size_t count = 0;  | 
1001  |  | 
  | 
1002  | 0  |     ptr.p = CommandLineParseCommaSeparatedValuesEx("kerberos", arg->Value, &count); | 
1003  | 0  |     if (ptr.pc)  | 
1004  | 0  |     { | 
1005  | 0  |       const CmdLineSubOptions opts[] = { | 
1006  | 0  |         { "kdc-url:", FreeRDP_KerberosKdcUrl, CMDLINE_SUBOPTION_STRING, NULL }, | 
1007  | 0  |         { "start-time:", FreeRDP_KerberosStartTime, CMDLINE_SUBOPTION_STRING, NULL }, | 
1008  | 0  |         { "lifetime:", FreeRDP_KerberosLifeTime, CMDLINE_SUBOPTION_STRING, NULL }, | 
1009  | 0  |         { "renewable-lifetime:", FreeRDP_KerberosRenewableLifeTime, | 
1010  | 0  |           CMDLINE_SUBOPTION_STRING, NULL },  | 
1011  | 0  |         { "cache:", FreeRDP_KerberosCache, CMDLINE_SUBOPTION_STRING, NULL }, | 
1012  | 0  |         { "armor:", FreeRDP_KerberosArmor, CMDLINE_SUBOPTION_STRING, NULL }, | 
1013  | 0  |         { "pkinit-anchors:", FreeRDP_PkinitAnchors, CMDLINE_SUBOPTION_STRING, NULL }, | 
1014  | 0  |         { "pkcs11-module:", FreeRDP_Pkcs11Module, CMDLINE_SUBOPTION_STRING, NULL } | 
1015  | 0  |       };  | 
1016  |  | 
  | 
1017  | 0  |       for (size_t x = 1; x < count; x++)  | 
1018  | 0  |       { | 
1019  | 0  |         const char* cur = ptr.pc[x];  | 
1020  | 0  |         if (!parseSubOptions(settings, opts, ARRAYSIZE(opts), cur))  | 
1021  | 0  |         { | 
1022  | 0  |           free(ptr.p);  | 
1023  | 0  |           return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
1024  | 0  |         }  | 
1025  | 0  |       }  | 
1026  | 0  |     }  | 
1027  | 0  |     free(ptr.p);  | 
1028  | 0  |   }  | 
1029  |  |  | 
1030  | 0  |   CommandLineSwitchCase(arg, "vc")  | 
1031  | 0  |   { | 
1032  | 0  |     size_t count = 0;  | 
1033  | 0  |     ptr.p = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
1034  | 0  |     status = freerdp_client_add_static_channel(settings, count, ptr.pc);  | 
1035  | 0  |     free(ptr.p);  | 
1036  | 0  |   }  | 
1037  | 0  |   CommandLineSwitchCase(arg, "dvc")  | 
1038  | 0  |   { | 
1039  | 0  |     size_t count = 0;  | 
1040  | 0  |     ptr.p = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
1041  | 0  |     status = freerdp_client_add_dynamic_channel(settings, count, ptr.pc);  | 
1042  | 0  |     free(ptr.p);  | 
1043  | 0  |   }  | 
1044  | 0  |   CommandLineSwitchCase(arg, "drive")  | 
1045  | 0  |   { | 
1046  | 0  |     size_t count = 0;  | 
1047  | 0  |     ptr.p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);  | 
1048  | 0  |     status = freerdp_client_add_device_channel(settings, count, ptr.pc);  | 
1049  | 0  |     free(ptr.p);  | 
1050  | 0  |   }  | 
1051  | 0  |   CommandLineSwitchCase(arg, "serial")  | 
1052  | 0  |   { | 
1053  | 0  |     size_t count = 0;  | 
1054  | 0  |     ptr.p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);  | 
1055  | 0  |     status = freerdp_client_add_device_channel(settings, count, ptr.pc);  | 
1056  | 0  |     free(ptr.p);  | 
1057  | 0  |   }  | 
1058  | 0  |   CommandLineSwitchCase(arg, "parallel")  | 
1059  | 0  |   { | 
1060  | 0  |     size_t count = 0;  | 
1061  | 0  |     ptr.p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);  | 
1062  | 0  |     status = freerdp_client_add_device_channel(settings, count, ptr.pc);  | 
1063  | 0  |     free(ptr.p);  | 
1064  | 0  |   }  | 
1065  | 0  |   CommandLineSwitchCase(arg, "smartcard")  | 
1066  | 0  |   { | 
1067  | 0  |     size_t count = 0;  | 
1068  | 0  |     ptr.p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);  | 
1069  | 0  |     status = freerdp_client_add_device_channel(settings, count, ptr.pc);  | 
1070  | 0  |     free(ptr.p);  | 
1071  | 0  |   }  | 
1072  | 0  |   CommandLineSwitchCase(arg, "printer")  | 
1073  | 0  |   { | 
1074  | 0  |     size_t count = 0;  | 
1075  | 0  |     ptr.p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);  | 
1076  | 0  |     status = freerdp_client_add_device_channel(settings, count, ptr.pc);  | 
1077  | 0  |     free(ptr.p);  | 
1078  | 0  |   }  | 
1079  | 0  |   CommandLineSwitchCase(arg, "usb")  | 
1080  | 0  |   { | 
1081  | 0  |     size_t count = 0;  | 
1082  | 0  |     ptr.p = CommandLineParseCommaSeparatedValuesEx(URBDRC_CHANNEL_NAME, arg->Value, &count);  | 
1083  | 0  |     status = freerdp_client_add_dynamic_channel(settings, count, ptr.pc);  | 
1084  | 0  |     free(ptr.p);  | 
1085  | 0  |   }  | 
1086  | 0  |   CommandLineSwitchCase(arg, "multitouch")  | 
1087  | 0  |   { | 
1088  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_MultiTouchInput, enable))  | 
1089  | 0  |       return COMMAND_LINE_ERROR;  | 
1090  | 0  |   }  | 
1091  | 0  |   CommandLineSwitchCase(arg, "gestures")  | 
1092  | 0  |   { | 
1093  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_MultiTouchGestures, enable))  | 
1094  | 0  |       return COMMAND_LINE_ERROR;  | 
1095  | 0  |   }  | 
1096  | 0  |   CommandLineSwitchCase(arg, "echo")  | 
1097  | 0  |   { | 
1098  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_SupportEchoChannel, enable))  | 
1099  | 0  |       return COMMAND_LINE_ERROR;  | 
1100  | 0  |   }  | 
1101  | 0  |   CommandLineSwitchCase(arg, "ssh-agent")  | 
1102  | 0  |   { | 
1103  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_SupportSSHAgentChannel, enable))  | 
1104  | 0  |       return COMMAND_LINE_ERROR;  | 
1105  | 0  |   }  | 
1106  | 0  |   CommandLineSwitchCase(arg, "disp")  | 
1107  | 0  |   { | 
1108  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDisplayControl, enable))  | 
1109  | 0  |       return COMMAND_LINE_ERROR;  | 
1110  | 0  |   }  | 
1111  | 0  |   CommandLineSwitchCase(arg, "geometry")  | 
1112  | 0  |   { | 
1113  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGeometryTracking, enable))  | 
1114  | 0  |       return COMMAND_LINE_ERROR;  | 
1115  | 0  |   }  | 
1116  | 0  |   CommandLineSwitchCase(arg, "video")  | 
1117  | 0  |   { | 
1118  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGeometryTracking,  | 
1119  | 0  |                                    enable)) /* this requires geometry tracking */  | 
1120  | 0  |       return COMMAND_LINE_ERROR;  | 
1121  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_SupportVideoOptimized, enable))  | 
1122  | 0  |       return COMMAND_LINE_ERROR;  | 
1123  | 0  |   }  | 
1124  | 0  |   CommandLineSwitchCase(arg, "sound")  | 
1125  | 0  |   { | 
1126  | 0  |     size_t count = 0;  | 
1127  | 0  |     ptr.p = CommandLineParseCommaSeparatedValuesEx(RDPSND_CHANNEL_NAME, arg->Value, &count);  | 
1128  | 0  |     status = freerdp_client_add_static_channel(settings, count, ptr.pc);  | 
1129  | 0  |     if (status)  | 
1130  | 0  |     { | 
1131  | 0  |       status = freerdp_client_add_dynamic_channel(settings, count, ptr.pc);  | 
1132  | 0  |     }  | 
1133  | 0  |     free(ptr.p);  | 
1134  | 0  |   }  | 
1135  | 0  |   CommandLineSwitchCase(arg, "microphone")  | 
1136  | 0  |   { | 
1137  | 0  |     size_t count = 0;  | 
1138  | 0  |     ptr.p = CommandLineParseCommaSeparatedValuesEx(AUDIN_CHANNEL_NAME, arg->Value, &count);  | 
1139  | 0  |     status = freerdp_client_add_dynamic_channel(settings, count, ptr.pc);  | 
1140  | 0  |     free(ptr.p);  | 
1141  | 0  |   }  | 
1142  |  | #if defined(CHANNEL_TSMF_CLIENT)  | 
1143  |  |   CommandLineSwitchCase(arg, "multimedia")  | 
1144  |  |   { | 
1145  |  |     size_t count = 0;  | 
1146  |  |     ptr.p = CommandLineParseCommaSeparatedValuesEx("tsmf", arg->Value, &count); | 
1147  |  |     status = freerdp_client_add_dynamic_channel(settings, count, ptr.pc);  | 
1148  |  |     free(ptr.p);  | 
1149  |  |   }  | 
1150  |  | #endif  | 
1151  | 0  |   CommandLineSwitchCase(arg, "heartbeat")  | 
1152  | 0  |   { | 
1153  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_SupportHeartbeatPdu, enable))  | 
1154  | 0  |       return COMMAND_LINE_ERROR;  | 
1155  | 0  |   }  | 
1156  | 0  |   CommandLineSwitchCase(arg, "multitransport")  | 
1157  | 0  |   { | 
1158  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMultitransport, enable))  | 
1159  | 0  |       return COMMAND_LINE_ERROR;  | 
1160  |  |  | 
1161  | 0  |     UINT32 flags = 0;  | 
1162  | 0  |     if (freerdp_settings_get_bool(settings, FreeRDP_SupportMultitransport))  | 
1163  | 0  |       flags =  | 
1164  | 0  |           (TRANSPORT_TYPE_UDP_FECR | TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED);  | 
1165  |  | 
  | 
1166  | 0  |     if (!freerdp_settings_set_uint32(settings, FreeRDP_MultitransportFlags, flags))  | 
1167  | 0  |       return COMMAND_LINE_ERROR;  | 
1168  | 0  |   }  | 
1169  | 0  |   CommandLineSwitchEnd(arg)  | 
1170  |  |  | 
1171  | 0  |           return status  | 
1172  | 0  |       ? 1  | 
1173  | 0  |       : -1;  | 
1174  | 0  | }  | 
1175  |  |  | 
1176  |  | static BOOL freerdp_parse_username_ptr(const char* username, const char** user, size_t* userlen,  | 
1177  |  |                                        const char** domain, size_t* domainlen)  | 
1178  | 0  | { | 
1179  | 0  |   WINPR_ASSERT(user);  | 
1180  | 0  |   WINPR_ASSERT(userlen);  | 
1181  | 0  |   WINPR_ASSERT(domain);  | 
1182  | 0  |   WINPR_ASSERT(domainlen);  | 
1183  |  |  | 
1184  | 0  |   if (!username)  | 
1185  | 0  |     return FALSE;  | 
1186  |  |  | 
1187  | 0  |   const char* p = strchr(username, '\\');  | 
1188  |  | 
  | 
1189  | 0  |   *user = NULL;  | 
1190  | 0  |   *userlen = 0;  | 
1191  |  | 
  | 
1192  | 0  |   *domain = NULL;  | 
1193  | 0  |   *domainlen = 0;  | 
1194  |  | 
  | 
1195  | 0  |   if (p)  | 
1196  | 0  |   { | 
1197  | 0  |     const size_t length = (size_t)(p - username);  | 
1198  | 0  |     *user = &p[1];  | 
1199  | 0  |     *userlen = strlen(*user);  | 
1200  |  | 
  | 
1201  | 0  |     *domain = username;  | 
1202  | 0  |     *domainlen = length;  | 
1203  | 0  |   }  | 
1204  | 0  |   else  | 
1205  | 0  |   { | 
1206  |  |     /* Do not break up the name for '@'; both credSSP and the  | 
1207  |  |      * ClientInfo PDU expect 'user@corp.net' to be transmitted  | 
1208  |  |      * as username 'user@corp.net', domain empty (not NULL!).  | 
1209  |  |      */  | 
1210  | 0  |     *user = username;  | 
1211  | 0  |     *userlen = strlen(username);  | 
1212  | 0  |   }  | 
1213  |  | 
  | 
1214  | 0  |   return TRUE;  | 
1215  | 0  | }  | 
1216  |  |  | 
1217  |  | static BOOL freerdp_parse_username_settings(const char* username, rdpSettings* settings,  | 
1218  |  |                                             FreeRDP_Settings_Keys_String userID,  | 
1219  |  |                                             FreeRDP_Settings_Keys_String domainID)  | 
1220  | 0  | { | 
1221  | 0  |   const char* user = NULL;  | 
1222  | 0  |   const char* domain = NULL;  | 
1223  | 0  |   size_t userlen = 0;  | 
1224  | 0  |   size_t domainlen = 0;  | 
1225  |  | 
  | 
1226  | 0  |   const BOOL rc = freerdp_parse_username_ptr(username, &user, &userlen, &domain, &domainlen);  | 
1227  | 0  |   if (!rc)  | 
1228  | 0  |     return FALSE;  | 
1229  | 0  |   if (!freerdp_settings_set_string_len(settings, userID, user, userlen))  | 
1230  | 0  |     return FALSE;  | 
1231  | 0  |   return freerdp_settings_set_string_len(settings, domainID, domain, domainlen);  | 
1232  | 0  | }  | 
1233  |  |  | 
1234  |  | BOOL freerdp_parse_username(const char* username, char** puser, char** pdomain)  | 
1235  | 0  | { | 
1236  | 0  |   const char* user = NULL;  | 
1237  | 0  |   const char* domain = NULL;  | 
1238  | 0  |   size_t userlen = 0;  | 
1239  | 0  |   size_t domainlen = 0;  | 
1240  |  | 
  | 
1241  | 0  |   *puser = NULL;  | 
1242  | 0  |   *pdomain = NULL;  | 
1243  |  | 
  | 
1244  | 0  |   const BOOL rc = freerdp_parse_username_ptr(username, &user, &userlen, &domain, &domainlen);  | 
1245  | 0  |   if (!rc)  | 
1246  | 0  |     return FALSE;  | 
1247  |  |  | 
1248  | 0  |   if (userlen > 0)  | 
1249  | 0  |   { | 
1250  | 0  |     *puser = strndup(user, userlen);  | 
1251  | 0  |     if (!*puser)  | 
1252  | 0  |       return FALSE;  | 
1253  | 0  |   }  | 
1254  |  |  | 
1255  | 0  |   if (domainlen > 0)  | 
1256  | 0  |   { | 
1257  | 0  |     *pdomain = strndup(domain, domainlen);  | 
1258  | 0  |     if (!*pdomain)  | 
1259  | 0  |     { | 
1260  | 0  |       free(*puser);  | 
1261  | 0  |       *puser = NULL;  | 
1262  | 0  |       return FALSE;  | 
1263  | 0  |     }  | 
1264  | 0  |   }  | 
1265  |  |  | 
1266  | 0  |   return TRUE;  | 
1267  | 0  | }  | 
1268  |  |  | 
1269  |  | BOOL freerdp_parse_hostname(const char* hostname, char** host, int* port)  | 
1270  | 0  | { | 
1271  | 0  |   char* p = NULL;  | 
1272  | 0  |   p = strrchr(hostname, ':');  | 
1273  |  | 
  | 
1274  | 0  |   if (p)  | 
1275  | 0  |   { | 
1276  | 0  |     size_t length = (size_t)(p - hostname);  | 
1277  | 0  |     LONGLONG val = 0;  | 
1278  |  | 
  | 
1279  | 0  |     if (!value_to_int(p + 1, &val, 1, UINT16_MAX))  | 
1280  | 0  |       return FALSE;  | 
1281  |  |  | 
1282  | 0  |     *host = (char*)calloc(length + 1UL, sizeof(char));  | 
1283  |  | 
  | 
1284  | 0  |     if (!(*host))  | 
1285  | 0  |       return FALSE;  | 
1286  |  |  | 
1287  | 0  |     CopyMemory(*host, hostname, length);  | 
1288  | 0  |     (*host)[length] = '\0';  | 
1289  | 0  |     *port = (UINT16)val;  | 
1290  | 0  |   }  | 
1291  | 0  |   else  | 
1292  | 0  |   { | 
1293  | 0  |     *host = _strdup(hostname);  | 
1294  |  | 
  | 
1295  | 0  |     if (!(*host))  | 
1296  | 0  |       return FALSE;  | 
1297  |  |  | 
1298  | 0  |     *port = -1;  | 
1299  | 0  |   }  | 
1300  |  |  | 
1301  | 0  |   return TRUE;  | 
1302  | 0  | }  | 
1303  |  |  | 
1304  |  | static BOOL freerdp_apply_connection_type(rdpSettings* settings, UINT32 type)  | 
1305  | 0  | { | 
1306  | 0  |   struct network_settings  | 
1307  | 0  |   { | 
1308  | 0  |     FreeRDP_Settings_Keys_Bool id;  | 
1309  | 0  |     BOOL value[7];  | 
1310  | 0  |   };  | 
1311  | 0  |   const struct network_settings config[] = { | 
1312  | 0  |     { FreeRDP_DisableWallpaper, { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE } }, | 
1313  | 0  |     { FreeRDP_AllowFontSmoothing, { FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE } }, | 
1314  | 0  |     { FreeRDP_AllowDesktopComposition, { FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE } }, | 
1315  | 0  |     { FreeRDP_DisableFullWindowDrag, { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE } }, | 
1316  | 0  |     { FreeRDP_DisableMenuAnims, { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE } }, | 
1317  | 0  |     { FreeRDP_DisableThemes, { TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE } } | 
1318  | 0  |   };  | 
1319  |  | 
  | 
1320  | 0  |   switch (type)  | 
1321  | 0  |   { | 
1322  | 0  |     case CONNECTION_TYPE_INVALID:  | 
1323  | 0  |       return TRUE;  | 
1324  |  |  | 
1325  | 0  |     case CONNECTION_TYPE_MODEM:  | 
1326  | 0  |     case CONNECTION_TYPE_BROADBAND_LOW:  | 
1327  | 0  |     case CONNECTION_TYPE_BROADBAND_HIGH:  | 
1328  | 0  |     case CONNECTION_TYPE_SATELLITE:  | 
1329  | 0  |     case CONNECTION_TYPE_WAN:  | 
1330  | 0  |     case CONNECTION_TYPE_LAN:  | 
1331  | 0  |     case CONNECTION_TYPE_AUTODETECT:  | 
1332  | 0  |       break;  | 
1333  | 0  |     default:  | 
1334  | 0  |       WLog_WARN(TAG, "Unknown ConnectionType %" PRIu32 ", aborting", type);  | 
1335  | 0  |       return FALSE;  | 
1336  | 0  |   }  | 
1337  |  |  | 
1338  | 0  |   for (size_t x = 0; x < ARRAYSIZE(config); x++)  | 
1339  | 0  |   { | 
1340  | 0  |     const struct network_settings* cur = &config[x];  | 
1341  | 0  |     if (!freerdp_settings_set_bool(settings, cur->id, cur->value[type - 1]))  | 
1342  | 0  |       return FALSE;  | 
1343  | 0  |   }  | 
1344  | 0  |   return TRUE;  | 
1345  | 0  | }  | 
1346  |  |  | 
1347  |  | BOOL freerdp_set_connection_type(rdpSettings* settings, UINT32 type)  | 
1348  | 0  | { | 
1349  |  | 
  | 
1350  | 0  |   if (!freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, type))  | 
1351  | 0  |     return FALSE;  | 
1352  |  |  | 
1353  | 0  |   switch (type)  | 
1354  | 0  |   { | 
1355  | 0  |     case CONNECTION_TYPE_INVALID:  | 
1356  | 0  |     case CONNECTION_TYPE_MODEM:  | 
1357  | 0  |     case CONNECTION_TYPE_BROADBAND_LOW:  | 
1358  | 0  |     case CONNECTION_TYPE_SATELLITE:  | 
1359  | 0  |     case CONNECTION_TYPE_BROADBAND_HIGH:  | 
1360  | 0  |     case CONNECTION_TYPE_WAN:  | 
1361  | 0  |     case CONNECTION_TYPE_LAN:  | 
1362  | 0  |       if (!freerdp_apply_connection_type(settings, type))  | 
1363  | 0  |         return FALSE;  | 
1364  | 0  |       break;  | 
1365  | 0  |     case CONNECTION_TYPE_AUTODETECT:  | 
1366  | 0  |       if (!freerdp_apply_connection_type(settings, type))  | 
1367  | 0  |         return FALSE;  | 
1368  |  |         /* Automatically activate GFX and RFX codec support */  | 
1369  |  | #ifdef WITH_GFX_H264  | 
1370  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444v2, TRUE) ||  | 
1371  |  |           !freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, TRUE) ||  | 
1372  |  |           !freerdp_settings_set_bool(settings, FreeRDP_GfxH264, TRUE))  | 
1373  |  |         return FALSE;  | 
1374  |  | #endif  | 
1375  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE) ||  | 
1376  | 0  |           !freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE))  | 
1377  | 0  |         return FALSE;  | 
1378  | 0  |       break;  | 
1379  | 0  |     default:  | 
1380  | 0  |       WLog_WARN(TAG, "Unknown ConnectionType %" PRIu32 ", aborting", type);  | 
1381  | 0  |       return FALSE;  | 
1382  | 0  |   }  | 
1383  |  |  | 
1384  | 0  |   return TRUE;  | 
1385  | 0  | }  | 
1386  |  |  | 
1387  |  | static UINT32 freerdp_get_keyboard_layout_for_type(const char* name, DWORD type)  | 
1388  | 0  | { | 
1389  | 0  |   UINT32 res = 0;  | 
1390  | 0  |   size_t count = 0;  | 
1391  | 0  |   RDP_KEYBOARD_LAYOUT* layouts =  | 
1392  | 0  |       freerdp_keyboard_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_STANDARD, &count);  | 
1393  |  | 
  | 
1394  | 0  |   if (!layouts || (count == 0))  | 
1395  | 0  |     goto fail;  | 
1396  |  |  | 
1397  | 0  |   for (size_t x = 0; x < count; x++)  | 
1398  | 0  |   { | 
1399  | 0  |     const RDP_KEYBOARD_LAYOUT* layout = &layouts[x];  | 
1400  | 0  |     if (option_equals(layout->name, name))  | 
1401  | 0  |     { | 
1402  | 0  |       res = layout->code;  | 
1403  | 0  |       break;  | 
1404  | 0  |     }  | 
1405  | 0  |   }  | 
1406  |  | 
  | 
1407  | 0  | fail:  | 
1408  | 0  |   freerdp_keyboard_layouts_free(layouts, count);  | 
1409  | 0  |   return res;  | 
1410  | 0  | }  | 
1411  |  |  | 
1412  |  | static UINT32 freerdp_map_keyboard_layout_name_to_id(const char* name)  | 
1413  | 0  | { | 
1414  | 0  |   const UINT32 variants[] = { RDP_KEYBOARD_LAYOUT_TYPE_STANDARD, RDP_KEYBOARD_LAYOUT_TYPE_VARIANT, | 
1415  | 0  |                             RDP_KEYBOARD_LAYOUT_TYPE_IME };  | 
1416  |  | 
  | 
1417  | 0  |   for (size_t x = 0; x < ARRAYSIZE(variants); x++)  | 
1418  | 0  |   { | 
1419  | 0  |     UINT32 rc = freerdp_get_keyboard_layout_for_type(name, variants[x]);  | 
1420  | 0  |     if (rc > 0)  | 
1421  | 0  |       return rc;  | 
1422  | 0  |   }  | 
1423  |  |  | 
1424  | 0  |   return 0;  | 
1425  | 0  | }  | 
1426  |  |  | 
1427  |  | static int freerdp_detect_command_line_pre_filter(void* context, int index, int argc, LPSTR* argv)  | 
1428  | 0  | { | 
1429  | 0  |   size_t length = 0;  | 
1430  | 0  |   WINPR_UNUSED(context);  | 
1431  |  | 
  | 
1432  | 0  |   if (index == 1)  | 
1433  | 0  |   { | 
1434  | 0  |     if (argc < index)  | 
1435  | 0  |       return -1;  | 
1436  |  |  | 
1437  | 0  |     length = strlen(argv[index]);  | 
1438  |  | 
  | 
1439  | 0  |     if (length > 4)  | 
1440  | 0  |     { | 
1441  | 0  |       if (option_is_rdp_file(argv[index]))  | 
1442  | 0  |       { | 
1443  | 0  |         return 1;  | 
1444  | 0  |       }  | 
1445  | 0  |     }  | 
1446  |  |  | 
1447  | 0  |     if (length > 13)  | 
1448  | 0  |     { | 
1449  | 0  |       if (option_is_incident_file(argv[index]))  | 
1450  | 0  |       { | 
1451  | 0  |         return 1;  | 
1452  | 0  |       }  | 
1453  | 0  |     }  | 
1454  | 0  |   }  | 
1455  |  |  | 
1456  | 0  |   return 0;  | 
1457  | 0  | }  | 
1458  |  |  | 
1459  |  | static int freerdp_detect_windows_style_command_line_syntax(int argc, char** argv, size_t* count,  | 
1460  |  |                                                             BOOL ignoreUnknown)  | 
1461  | 0  | { | 
1462  | 0  |   int status = 0;  | 
1463  | 0  |   DWORD flags = 0;  | 
1464  | 0  |   int detect_status = 0;  | 
1465  | 0  |   const COMMAND_LINE_ARGUMENT_A* arg = NULL;  | 
1466  | 0  |   COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(global_cmd_args)];  | 
1467  | 0  |   memcpy(largs, global_cmd_args, sizeof(global_cmd_args));  | 
1468  |  | 
  | 
1469  | 0  |   flags = COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_SILENCE_PARSER;  | 
1470  | 0  |   flags |= COMMAND_LINE_SIGIL_SLASH | COMMAND_LINE_SIGIL_PLUS_MINUS;  | 
1471  |  | 
  | 
1472  | 0  |   if (ignoreUnknown)  | 
1473  | 0  |   { | 
1474  | 0  |     flags |= COMMAND_LINE_IGN_UNKNOWN_KEYWORD;  | 
1475  | 0  |   }  | 
1476  |  | 
  | 
1477  | 0  |   *count = 0;  | 
1478  | 0  |   detect_status = 0;  | 
1479  | 0  |   CommandLineClearArgumentsA(largs);  | 
1480  | 0  |   status = CommandLineParseArgumentsA(argc, argv, largs, flags, NULL,  | 
1481  | 0  |                                       freerdp_detect_command_line_pre_filter, NULL);  | 
1482  |  | 
  | 
1483  | 0  |   if (status < 0)  | 
1484  | 0  |     return status;  | 
1485  |  |  | 
1486  | 0  |   arg = largs;  | 
1487  |  | 
  | 
1488  | 0  |   do  | 
1489  | 0  |   { | 
1490  | 0  |     if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))  | 
1491  | 0  |       continue;  | 
1492  |  |  | 
1493  | 0  |     (*count)++;  | 
1494  | 0  |   } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);  | 
1495  |  |  | 
1496  | 0  |   if ((status <= COMMAND_LINE_ERROR) && (status >= COMMAND_LINE_ERROR_LAST))  | 
1497  | 0  |     detect_status = -1;  | 
1498  |  | 
  | 
1499  | 0  |   return detect_status;  | 
1500  | 0  | }  | 
1501  |  |  | 
1502  |  | static int freerdp_detect_posix_style_command_line_syntax(int argc, char** argv, size_t* count,  | 
1503  |  |                                                           BOOL ignoreUnknown)  | 
1504  | 0  | { | 
1505  | 0  |   int status = 0;  | 
1506  | 0  |   DWORD flags = 0;  | 
1507  | 0  |   int detect_status = 0;  | 
1508  | 0  |   const COMMAND_LINE_ARGUMENT_A* arg = NULL;  | 
1509  | 0  |   COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(global_cmd_args)];  | 
1510  | 0  |   memcpy(largs, global_cmd_args, sizeof(global_cmd_args));  | 
1511  |  | 
  | 
1512  | 0  |   flags = COMMAND_LINE_SEPARATOR_SPACE | COMMAND_LINE_SILENCE_PARSER;  | 
1513  | 0  |   flags |= COMMAND_LINE_SIGIL_DASH | COMMAND_LINE_SIGIL_DOUBLE_DASH;  | 
1514  | 0  |   flags |= COMMAND_LINE_SIGIL_ENABLE_DISABLE;  | 
1515  |  | 
  | 
1516  | 0  |   if (ignoreUnknown)  | 
1517  | 0  |   { | 
1518  | 0  |     flags |= COMMAND_LINE_IGN_UNKNOWN_KEYWORD;  | 
1519  | 0  |   }  | 
1520  |  | 
  | 
1521  | 0  |   *count = 0;  | 
1522  | 0  |   detect_status = 0;  | 
1523  | 0  |   CommandLineClearArgumentsA(largs);  | 
1524  | 0  |   status = CommandLineParseArgumentsA(argc, argv, largs, flags, NULL,  | 
1525  | 0  |                                       freerdp_detect_command_line_pre_filter, NULL);  | 
1526  |  | 
  | 
1527  | 0  |   if (status < 0)  | 
1528  | 0  |     return status;  | 
1529  |  |  | 
1530  | 0  |   arg = largs;  | 
1531  |  | 
  | 
1532  | 0  |   do  | 
1533  | 0  |   { | 
1534  | 0  |     if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))  | 
1535  | 0  |       continue;  | 
1536  |  |  | 
1537  | 0  |     (*count)++;  | 
1538  | 0  |   } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);  | 
1539  |  |  | 
1540  | 0  |   if ((status <= COMMAND_LINE_ERROR) && (status >= COMMAND_LINE_ERROR_LAST))  | 
1541  | 0  |     detect_status = -1;  | 
1542  |  | 
  | 
1543  | 0  |   return detect_status;  | 
1544  | 0  | }  | 
1545  |  |  | 
1546  |  | static BOOL freerdp_client_detect_command_line(int argc, char** argv, DWORD* flags)  | 
1547  | 0  | { | 
1548  | 0  |   int posix_cli_status = 0;  | 
1549  | 0  |   size_t posix_cli_count = 0;  | 
1550  | 0  |   int windows_cli_status = 0;  | 
1551  | 0  |   size_t windows_cli_count = 0;  | 
1552  | 0  |   const BOOL ignoreUnknown = TRUE;  | 
1553  | 0  |   windows_cli_status = freerdp_detect_windows_style_command_line_syntax(  | 
1554  | 0  |       argc, argv, &windows_cli_count, ignoreUnknown);  | 
1555  | 0  |   posix_cli_status =  | 
1556  | 0  |       freerdp_detect_posix_style_command_line_syntax(argc, argv, &posix_cli_count, ignoreUnknown);  | 
1557  |  |  | 
1558  |  |   /* Default is POSIX syntax */  | 
1559  | 0  |   *flags = COMMAND_LINE_SEPARATOR_SPACE;  | 
1560  | 0  |   *flags |= COMMAND_LINE_SIGIL_DASH | COMMAND_LINE_SIGIL_DOUBLE_DASH;  | 
1561  | 0  |   *flags |= COMMAND_LINE_SIGIL_ENABLE_DISABLE;  | 
1562  |  | 
  | 
1563  | 0  |   if (posix_cli_status <= COMMAND_LINE_STATUS_PRINT)  | 
1564  | 0  |     return FALSE;  | 
1565  |  |  | 
1566  |  |   /* Check, if this may be windows style syntax... */  | 
1567  | 0  |   if ((windows_cli_count && (windows_cli_count >= posix_cli_count)) ||  | 
1568  | 0  |       (windows_cli_status <= COMMAND_LINE_STATUS_PRINT))  | 
1569  | 0  |   { | 
1570  | 0  |     windows_cli_count = 1;  | 
1571  | 0  |     *flags = COMMAND_LINE_SEPARATOR_COLON;  | 
1572  | 0  |     *flags |= COMMAND_LINE_SIGIL_SLASH | COMMAND_LINE_SIGIL_PLUS_MINUS;  | 
1573  | 0  |   }  | 
1574  |  | 
  | 
1575  | 0  |   WLog_DBG(TAG, "windows: %d/%" PRIuz " posix: %d/%" PRIuz "", windows_cli_status,  | 
1576  | 0  |            windows_cli_count, posix_cli_status, posix_cli_count);  | 
1577  | 0  |   if ((posix_cli_count == 0) && (windows_cli_count == 0))  | 
1578  | 0  |   { | 
1579  | 0  |     if ((posix_cli_status == COMMAND_LINE_ERROR) && (windows_cli_status == COMMAND_LINE_ERROR))  | 
1580  | 0  |       return TRUE;  | 
1581  | 0  |   }  | 
1582  | 0  |   return FALSE;  | 
1583  | 0  | }  | 
1584  |  |  | 
1585  |  | int freerdp_client_settings_command_line_status_print(rdpSettings* settings, int status, int argc,  | 
1586  |  |                                                       char** argv)  | 
1587  | 0  | { | 
1588  | 0  |   return freerdp_client_settings_command_line_status_print_ex(settings, status, argc, argv, NULL);  | 
1589  | 0  | }  | 
1590  |  |  | 
1591  |  | static void freerdp_client_print_keyboard_type_list(const char* msg, DWORD type)  | 
1592  | 0  | { | 
1593  | 0  |   size_t count = 0;  | 
1594  | 0  |   RDP_KEYBOARD_LAYOUT* layouts = NULL;  | 
1595  | 0  |   layouts = freerdp_keyboard_get_layouts(type, &count);  | 
1596  |  | 
  | 
1597  | 0  |   printf("\n%s\n", msg); | 
1598  |  | 
  | 
1599  | 0  |   for (size_t x = 0; x < count; x++)  | 
1600  | 0  |   { | 
1601  | 0  |     const RDP_KEYBOARD_LAYOUT* layout = &layouts[x];  | 
1602  | 0  |     printf("0x%08" PRIX32 "\t%s\n", layout->code, layout->name); | 
1603  | 0  |   }  | 
1604  |  | 
  | 
1605  | 0  |   freerdp_keyboard_layouts_free(layouts, count);  | 
1606  | 0  | }  | 
1607  |  |  | 
1608  |  | static void freerdp_client_print_keyboard_list(void)  | 
1609  | 0  | { | 
1610  | 0  |   freerdp_client_print_keyboard_type_list("Keyboard Layouts", RDP_KEYBOARD_LAYOUT_TYPE_STANDARD); | 
1611  | 0  |   freerdp_client_print_keyboard_type_list("Keyboard Layout Variants", | 
1612  | 0  |                                           RDP_KEYBOARD_LAYOUT_TYPE_VARIANT);  | 
1613  | 0  |   freerdp_client_print_keyboard_type_list("Keyboard Layout Variants", | 
1614  | 0  |                                           RDP_KEYBOARD_LAYOUT_TYPE_IME);  | 
1615  | 0  | }  | 
1616  |  |  | 
1617  |  | static void freerdp_client_print_tune_list(const rdpSettings* settings)  | 
1618  | 0  | { | 
1619  | 0  |   SSIZE_T type = 0;  | 
1620  |  | 
  | 
1621  | 0  |   printf("%s\t%50s\t%s\t%s", "<index>", "<key>", "<type>", "<default value>\n"); | 
1622  | 0  |   for (size_t x = 0; x < FreeRDP_Settings_StableAPI_MAX; x++)  | 
1623  | 0  |   { | 
1624  | 0  |     const char* name = freerdp_settings_get_name_for_key(x);  | 
1625  | 0  |     type = freerdp_settings_get_type_for_key(x);  | 
1626  |  | 
  | 
1627  | 0  |     switch (type)  | 
1628  | 0  |     { | 
1629  | 0  |       case RDP_SETTINGS_TYPE_BOOL:  | 
1630  | 0  |         printf("%" PRIuz "\t%50s\tBOOL\t%s\n", x, name, | 
1631  | 0  |                freerdp_settings_get_bool(settings, (FreeRDP_Settings_Keys_Bool)x)  | 
1632  | 0  |                    ? "TRUE"  | 
1633  | 0  |                    : "FALSE");  | 
1634  | 0  |         break;  | 
1635  | 0  |       case RDP_SETTINGS_TYPE_UINT16:  | 
1636  | 0  |         printf("%" PRIuz "\t%50s\tUINT16\t%" PRIu16 "\n", x, name, | 
1637  | 0  |                freerdp_settings_get_uint16(settings, (FreeRDP_Settings_Keys_UInt16)x));  | 
1638  | 0  |         break;  | 
1639  | 0  |       case RDP_SETTINGS_TYPE_INT16:  | 
1640  | 0  |         printf("%" PRIuz "\t%50s\tINT16\t%" PRId16 "\n", x, name, | 
1641  | 0  |                freerdp_settings_get_int16(settings, (FreeRDP_Settings_Keys_Int16)x));  | 
1642  | 0  |         break;  | 
1643  | 0  |       case RDP_SETTINGS_TYPE_UINT32:  | 
1644  | 0  |         printf("%" PRIuz "\t%50s\tUINT32\t%" PRIu32 "\n", x, name, | 
1645  | 0  |                freerdp_settings_get_uint32(settings, (FreeRDP_Settings_Keys_UInt32)x));  | 
1646  | 0  |         break;  | 
1647  | 0  |       case RDP_SETTINGS_TYPE_INT32:  | 
1648  | 0  |         printf("%" PRIuz "\t%50s\tINT32\t%" PRId32 "\n", x, name, | 
1649  | 0  |                freerdp_settings_get_int32(settings, (FreeRDP_Settings_Keys_Int32)x));  | 
1650  | 0  |         break;  | 
1651  | 0  |       case RDP_SETTINGS_TYPE_UINT64:  | 
1652  | 0  |         printf("%" PRIuz "\t%50s\tUINT64\t%" PRIu64 "\n", x, name, | 
1653  | 0  |                freerdp_settings_get_uint64(settings, (FreeRDP_Settings_Keys_UInt64)x));  | 
1654  | 0  |         break;  | 
1655  | 0  |       case RDP_SETTINGS_TYPE_INT64:  | 
1656  | 0  |         printf("%" PRIuz "\t%50s\tINT64\t%" PRId64 "\n", x, name, | 
1657  | 0  |                freerdp_settings_get_int64(settings, (FreeRDP_Settings_Keys_Int64)x));  | 
1658  | 0  |         break;  | 
1659  | 0  |       case RDP_SETTINGS_TYPE_STRING:  | 
1660  | 0  |         printf("%" PRIuz "\t%50s\tSTRING\t%s" | 
1661  | 0  |                "\n",  | 
1662  | 0  |                x, name,  | 
1663  | 0  |                freerdp_settings_get_string(settings, (FreeRDP_Settings_Keys_String)x));  | 
1664  | 0  |         break;  | 
1665  | 0  |       case RDP_SETTINGS_TYPE_POINTER:  | 
1666  | 0  |         printf("%" PRIuz "\t%50s\tPOINTER\t%p" | 
1667  | 0  |                "\n",  | 
1668  | 0  |                x, name,  | 
1669  | 0  |                freerdp_settings_get_pointer(settings, (FreeRDP_Settings_Keys_Pointer)x));  | 
1670  | 0  |         break;  | 
1671  | 0  |       default:  | 
1672  | 0  |         break;  | 
1673  | 0  |     }  | 
1674  | 0  |   }  | 
1675  | 0  | }  | 
1676  |  |  | 
1677  |  | int freerdp_client_settings_command_line_status_print_ex(rdpSettings* settings, int status,  | 
1678  |  |                                                          int argc, char** argv,  | 
1679  |  |                                                          const COMMAND_LINE_ARGUMENT_A* custom)  | 
1680  | 0  | { | 
1681  | 0  |   const COMMAND_LINE_ARGUMENT_A* arg = NULL;  | 
1682  | 0  |   COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(global_cmd_args)];  | 
1683  | 0  |   memcpy(largs, global_cmd_args, sizeof(global_cmd_args));  | 
1684  |  | 
  | 
1685  | 0  |   if (status == COMMAND_LINE_STATUS_PRINT_VERSION)  | 
1686  | 0  |   { | 
1687  | 0  |     freerdp_client_print_version();  | 
1688  | 0  |     goto out;  | 
1689  | 0  |   }  | 
1690  |  |  | 
1691  | 0  |   if (status == COMMAND_LINE_STATUS_PRINT_BUILDCONFIG)  | 
1692  | 0  |   { | 
1693  | 0  |     freerdp_client_print_version();  | 
1694  | 0  |     freerdp_client_print_buildconfig();  | 
1695  | 0  |     goto out;  | 
1696  | 0  |   }  | 
1697  | 0  |   else if (status == COMMAND_LINE_STATUS_PRINT)  | 
1698  | 0  |   { | 
1699  | 0  |     CommandLineParseArgumentsA(argc, argv, largs, 0x112, NULL, NULL, NULL);  | 
1700  |  | 
  | 
1701  | 0  |     arg = CommandLineFindArgumentA(largs, "list");  | 
1702  | 0  |     WINPR_ASSERT(arg);  | 
1703  |  |  | 
1704  | 0  |     if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)  | 
1705  | 0  |     { | 
1706  | 0  |       if (option_equals("tune", arg->Value)) | 
1707  | 0  |         freerdp_client_print_tune_list(settings);  | 
1708  | 0  |       else if (option_equals("kbd", arg->Value)) | 
1709  | 0  |         freerdp_client_print_keyboard_list();  | 
1710  | 0  |       else if (option_starts_with("kbd-lang", arg->Value)) | 
1711  | 0  |       { | 
1712  | 0  |         const char* val = NULL;  | 
1713  | 0  |         if (option_starts_with("kbd-lang:", arg->Value)) | 
1714  | 0  |           val = &arg->Value[9];  | 
1715  | 0  |         else if (!option_equals("kbd-lang", arg->Value)) | 
1716  | 0  |           return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
1717  |  |  | 
1718  | 0  |         if (val && strchr(val, ','))  | 
1719  | 0  |           return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
1720  | 0  |         freerdp_client_print_codepages(val);  | 
1721  | 0  |       }  | 
1722  | 0  |       else if (option_equals("kbd-scancode", arg->Value)) | 
1723  | 0  |         freerdp_client_print_scancodes();  | 
1724  | 0  |       else if (option_equals("monitor", arg->Value)) | 
1725  | 0  |       { | 
1726  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_ListMonitors, TRUE))  | 
1727  | 0  |           return COMMAND_LINE_ERROR;  | 
1728  | 0  |       }  | 
1729  | 0  |       else if (option_starts_with("smartcard", arg->Value)) | 
1730  | 0  |       { | 
1731  | 0  |         BOOL opts = FALSE;  | 
1732  | 0  |         if (option_starts_with("smartcard:", arg->Value)) | 
1733  | 0  |           opts = TRUE;  | 
1734  | 0  |         else if (!option_equals("smartcard", arg->Value)) | 
1735  | 0  |           return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
1736  |  |  | 
1737  | 0  |         if (opts)  | 
1738  | 0  |         { | 
1739  | 0  |           const char* sub = strchr(arg->Value, ':') + 1;  | 
1740  | 0  |           const CmdLineSubOptions options[] = { | 
1741  | 0  |             { "pkinit-anchors:", FreeRDP_PkinitAnchors, CMDLINE_SUBOPTION_STRING, | 
1742  | 0  |               NULL },  | 
1743  | 0  |             { "pkcs11-module:", FreeRDP_Pkcs11Module, CMDLINE_SUBOPTION_STRING, NULL } | 
1744  | 0  |           };  | 
1745  |  | 
  | 
1746  | 0  |           size_t count = 0;  | 
1747  |  | 
  | 
1748  | 0  |           char** ptr = CommandLineParseCommaSeparatedValuesEx("smartcard", sub, &count); | 
1749  | 0  |           if (!ptr)  | 
1750  | 0  |             return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
1751  | 0  |           if (count < 2)  | 
1752  | 0  |           { | 
1753  | 0  |             free(ptr);  | 
1754  | 0  |             return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
1755  | 0  |           }  | 
1756  |  |  | 
1757  | 0  |           for (size_t x = 1; x < count; x++)  | 
1758  | 0  |           { | 
1759  | 0  |             const char* cur = ptr[x];  | 
1760  | 0  |             if (!parseSubOptions(settings, options, ARRAYSIZE(options), cur))  | 
1761  | 0  |             { | 
1762  | 0  |               free(ptr);  | 
1763  | 0  |               return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
1764  | 0  |             }  | 
1765  | 0  |           }  | 
1766  |  |  | 
1767  | 0  |           free(ptr);  | 
1768  | 0  |         }  | 
1769  |  |  | 
1770  | 0  |         freerdp_smartcard_list(settings);  | 
1771  | 0  |       }  | 
1772  | 0  |       else  | 
1773  | 0  |       { | 
1774  | 0  |         freerdp_client_print_command_line_help_ex(argc, argv, custom);  | 
1775  | 0  |         return COMMAND_LINE_ERROR;  | 
1776  | 0  |       }  | 
1777  | 0  |     }  | 
1778  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
1779  |  |     arg = CommandLineFindArgumentA(largs, "tune-list");  | 
1780  |  |     WINPR_ASSERT(arg);  | 
1781  |  |  | 
1782  |  |     if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)  | 
1783  |  |     { | 
1784  |  |       WLog_WARN(TAG, "Option /tune-list is deprecated, use /list:tune instead");  | 
1785  |  |       freerdp_client_print_tune_list(settings);  | 
1786  |  |     }  | 
1787  |  |  | 
1788  |  |     arg = CommandLineFindArgumentA(largs, "kbd-lang-list");  | 
1789  |  |     WINPR_ASSERT(arg);  | 
1790  |  |  | 
1791  |  |     if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)  | 
1792  |  |     { | 
1793  |  |       WLog_WARN(TAG, "Option /kbd-lang-list is deprecated, use /list:kbd-lang instead");  | 
1794  |  |       freerdp_client_print_codepages(arg->Value);  | 
1795  |  |     }  | 
1796  |  |  | 
1797  |  |     arg = CommandLineFindArgumentA(largs, "kbd-list");  | 
1798  |  |     WINPR_ASSERT(arg);  | 
1799  |  |  | 
1800  |  |     if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
1801  |  |     { | 
1802  |  |       WLog_WARN(TAG, "Option /kbd-list is deprecated, use /list:kbd instead");  | 
1803  |  |       freerdp_client_print_keyboard_list();  | 
1804  |  |     }  | 
1805  |  |  | 
1806  |  |     arg = CommandLineFindArgumentA(largs, "monitor-list");  | 
1807  |  |     WINPR_ASSERT(arg);  | 
1808  |  |  | 
1809  |  |     if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
1810  |  |     { | 
1811  |  |       WLog_WARN(TAG, "Option /monitor-list is deprecated, use /list:monitor instead");  | 
1812  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_ListMonitors, TRUE))  | 
1813  |  |         return COMMAND_LINE_ERROR;  | 
1814  |  |     }  | 
1815  |  |  | 
1816  |  |     arg = CommandLineFindArgumentA(largs, "smartcard-list");  | 
1817  |  |     WINPR_ASSERT(arg);  | 
1818  |  |  | 
1819  |  |     if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
1820  |  |     { | 
1821  |  |       WLog_WARN(TAG, "Option /smartcard-list is deprecated, use /list:smartcard instead");  | 
1822  |  |       freerdp_smartcard_list(settings);  | 
1823  |  |     }  | 
1824  |  |  | 
1825  |  |     arg = CommandLineFindArgumentA(largs, "kbd-scancode-list");  | 
1826  |  |     WINPR_ASSERT(arg);  | 
1827  |  |  | 
1828  |  |     if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
1829  |  |     { | 
1830  |  |       WLog_WARN(TAG,  | 
1831  |  |                 "Option /kbd-scancode-list is deprecated, use /list:kbd-scancode instead");  | 
1832  |  |       freerdp_client_print_scancodes();  | 
1833  |  |       goto out;  | 
1834  |  |     }  | 
1835  |  | #endif  | 
1836  | 0  |     goto out;  | 
1837  | 0  |   }  | 
1838  | 0  |   else if (status < 0)  | 
1839  | 0  |   { | 
1840  | 0  |     freerdp_client_print_command_line_help_ex(argc, argv, custom);  | 
1841  | 0  |     goto out;  | 
1842  | 0  |   }  | 
1843  |  |  | 
1844  | 0  | out:  | 
1845  | 0  |   if (status <= COMMAND_LINE_STATUS_PRINT && status >= COMMAND_LINE_STATUS_PRINT_LAST)  | 
1846  | 0  |     return 0;  | 
1847  | 0  |   return status;  | 
1848  | 0  | }  | 
1849  |  |  | 
1850  |  | /**  | 
1851  |  |  * parses a string value with the format <v1>x<v2>  | 
1852  |  |  *  | 
1853  |  |  * @param input input string  | 
1854  |  |  * @param v1 pointer to output v1  | 
1855  |  |  * @param v2 pointer to output v2  | 
1856  |  |  * @return if the parsing was successful  | 
1857  |  |  */  | 
1858  |  | static BOOL parseSizeValue(const char* input, unsigned long* v1, unsigned long* v2)  | 
1859  | 0  | { | 
1860  | 0  |   const char* xcharpos = NULL;  | 
1861  | 0  |   char* endPtr = NULL;  | 
1862  | 0  |   unsigned long v = 0;  | 
1863  | 0  |   errno = 0;  | 
1864  | 0  |   v = strtoul(input, &endPtr, 10);  | 
1865  |  | 
  | 
1866  | 0  |   if ((v == 0 || v == ULONG_MAX) && (errno != 0))  | 
1867  | 0  |     return FALSE;  | 
1868  |  |  | 
1869  | 0  |   if (v1)  | 
1870  | 0  |     *v1 = v;  | 
1871  |  | 
  | 
1872  | 0  |   xcharpos = strchr(input, 'x');  | 
1873  |  | 
  | 
1874  | 0  |   if (!xcharpos || xcharpos != endPtr)  | 
1875  | 0  |     return FALSE;  | 
1876  |  |  | 
1877  | 0  |   errno = 0;  | 
1878  | 0  |   v = strtoul(xcharpos + 1, &endPtr, 10);  | 
1879  |  | 
  | 
1880  | 0  |   if ((v == 0 || v == ULONG_MAX) && (errno != 0))  | 
1881  | 0  |     return FALSE;  | 
1882  |  |  | 
1883  | 0  |   if (*endPtr != '\0')  | 
1884  | 0  |     return FALSE;  | 
1885  |  |  | 
1886  | 0  |   if (v2)  | 
1887  | 0  |     *v2 = v;  | 
1888  |  | 
  | 
1889  | 0  |   return TRUE;  | 
1890  | 0  | }  | 
1891  |  |  | 
1892  |  | static BOOL prepare_default_settings(rdpSettings* settings, COMMAND_LINE_ARGUMENT_A* args,  | 
1893  |  |                                      BOOL rdp_file)  | 
1894  | 0  | { | 
1895  | 0  |   const char* arguments[] = { "network", "gfx", "rfx", "bpp" }; | 
1896  | 0  |   WINPR_ASSERT(settings);  | 
1897  | 0  |   WINPR_ASSERT(args);  | 
1898  |  |  | 
1899  | 0  |   if (rdp_file)  | 
1900  | 0  |     return FALSE;  | 
1901  |  |  | 
1902  | 0  |   for (size_t x = 0; x < ARRAYSIZE(arguments); x++)  | 
1903  | 0  |   { | 
1904  | 0  |     const char* arg = arguments[x];  | 
1905  | 0  |     const COMMAND_LINE_ARGUMENT_A* p = CommandLineFindArgumentA(args, arg);  | 
1906  | 0  |     if (p && (p->Flags & COMMAND_LINE_ARGUMENT_PRESENT))  | 
1907  | 0  |       return FALSE;  | 
1908  | 0  |   }  | 
1909  |  |  | 
1910  | 0  |   return freerdp_set_connection_type(settings, CONNECTION_TYPE_AUTODETECT);  | 
1911  | 0  | }  | 
1912  |  |  | 
1913  |  | static BOOL setSmartcardEmulation(const char* value, rdpSettings* settings)  | 
1914  | 0  | { | 
1915  | 0  |   return freerdp_settings_set_bool(settings, FreeRDP_SmartcardEmulation, TRUE);  | 
1916  | 0  | }  | 
1917  |  |  | 
1918  |  | const char* option_starts_with(const char* what, const char* val)  | 
1919  | 0  | { | 
1920  | 0  |   WINPR_ASSERT(what);  | 
1921  | 0  |   WINPR_ASSERT(val);  | 
1922  | 0  |   const size_t wlen = strlen(what);  | 
1923  |  | 
  | 
1924  | 0  |   if (_strnicmp(what, val, wlen) != 0)  | 
1925  | 0  |     return NULL;  | 
1926  | 0  |   return &val[wlen];  | 
1927  | 0  | }  | 
1928  |  |  | 
1929  |  | BOOL option_ends_with(const char* str, const char* ext)  | 
1930  | 0  | { | 
1931  | 0  |   WINPR_ASSERT(str);  | 
1932  | 0  |   WINPR_ASSERT(ext);  | 
1933  | 0  |   const size_t strLen = strlen(str);  | 
1934  | 0  |   const size_t extLen = strlen(ext);  | 
1935  |  | 
  | 
1936  | 0  |   if (strLen < extLen)  | 
1937  | 0  |     return FALSE;  | 
1938  |  |  | 
1939  | 0  |   return _strnicmp(&str[strLen - extLen], ext, extLen) == 0;  | 
1940  | 0  | }  | 
1941  |  |  | 
1942  |  | BOOL option_equals(const char* what, const char* val)  | 
1943  | 0  | { | 
1944  | 0  |   WINPR_ASSERT(what);  | 
1945  | 0  |   WINPR_ASSERT(val);  | 
1946  | 0  |   return _stricmp(what, val) == 0;  | 
1947  | 0  | }  | 
1948  |  |  | 
1949  |  | typedef enum  | 
1950  |  | { | 
1951  |  |   PARSE_ON,  | 
1952  |  |   PARSE_OFF,  | 
1953  |  |   PARSE_NONE,  | 
1954  |  |   PARSE_FAIL  | 
1955  |  | } PARSE_ON_OFF_RESULT;  | 
1956  |  |  | 
1957  |  | static PARSE_ON_OFF_RESULT parse_on_off_option(const char* value)  | 
1958  | 0  | { | 
1959  | 0  |   WINPR_ASSERT(value);  | 
1960  | 0  |   const char* sep = strchr(value, ':');  | 
1961  | 0  |   if (!sep)  | 
1962  | 0  |     return PARSE_NONE;  | 
1963  | 0  |   if (option_equals("on", &sep[1])) | 
1964  | 0  |     return PARSE_ON;  | 
1965  | 0  |   if (option_equals("off", &sep[1])) | 
1966  | 0  |     return PARSE_OFF;  | 
1967  | 0  |   return PARSE_FAIL;  | 
1968  | 0  | }  | 
1969  |  |  | 
1970  |  | typedef enum  | 
1971  |  | { | 
1972  |  |   CLIP_DIR_PARSE_ALL,  | 
1973  |  |   CLIP_DIR_PARSE_OFF,  | 
1974  |  |   CLIP_DIR_PARSE_LOCAL,  | 
1975  |  |   CLIP_DIR_PARSE_REMOTE,  | 
1976  |  |   CLIP_DIR_PARSE_FAIL  | 
1977  |  | } PARSE_CLIP_DIR_RESULT;  | 
1978  |  |  | 
1979  |  | static PARSE_CLIP_DIR_RESULT parse_clip_direciton_to_option(const char* value)  | 
1980  | 0  | { | 
1981  | 0  |   WINPR_ASSERT(value);  | 
1982  | 0  |   const char* sep = strchr(value, ':');  | 
1983  | 0  |   if (!sep)  | 
1984  | 0  |     return CLIP_DIR_PARSE_FAIL;  | 
1985  | 0  |   if (option_equals("all", &sep[1])) | 
1986  | 0  |     return CLIP_DIR_PARSE_ALL;  | 
1987  | 0  |   if (option_equals("off", &sep[1])) | 
1988  | 0  |     return CLIP_DIR_PARSE_OFF;  | 
1989  | 0  |   if (option_equals("local", &sep[1])) | 
1990  | 0  |     return CLIP_DIR_PARSE_LOCAL;  | 
1991  | 0  |   if (option_equals("remote", &sep[1])) | 
1992  | 0  |     return CLIP_DIR_PARSE_REMOTE;  | 
1993  | 0  |   return CLIP_DIR_PARSE_FAIL;  | 
1994  | 0  | }  | 
1995  |  |  | 
1996  |  | static int parse_tls_ciphers(rdpSettings* settings, const char* Value)  | 
1997  | 0  | { | 
1998  | 0  |   const char* ciphers = NULL;  | 
1999  | 0  |   if (!Value)  | 
2000  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2001  |  |  | 
2002  | 0  |   if (option_equals(Value, "netmon"))  | 
2003  | 0  |   { | 
2004  | 0  |     ciphers = "ALL:!ECDH:!ADH:!DHE";  | 
2005  | 0  |   }  | 
2006  | 0  |   else if (option_equals(Value, "ma"))  | 
2007  | 0  |   { | 
2008  | 0  |     ciphers = "AES128-SHA";  | 
2009  | 0  |   }  | 
2010  | 0  |   else  | 
2011  | 0  |   { | 
2012  | 0  |     ciphers = Value;  | 
2013  | 0  |   }  | 
2014  |  | 
  | 
2015  | 0  |   if (!freerdp_settings_set_string(settings, FreeRDP_AllowedTlsCiphers, ciphers))  | 
2016  | 0  |     return COMMAND_LINE_ERROR_MEMORY;  | 
2017  | 0  |   return 0;  | 
2018  | 0  | }  | 
2019  |  |  | 
2020  |  | static int parse_tls_seclevel(rdpSettings* settings, const char* Value)  | 
2021  | 0  | { | 
2022  | 0  |   LONGLONG val = 0;  | 
2023  |  | 
  | 
2024  | 0  |   if (!value_to_int(Value, &val, 0, 5))  | 
2025  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2026  |  |  | 
2027  | 0  |   if (!freerdp_settings_set_uint32(settings, FreeRDP_TlsSecLevel, (UINT32)val))  | 
2028  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2029  | 0  |   return 0;  | 
2030  | 0  | }  | 
2031  |  |  | 
2032  |  | static int parse_tls_secrets_file(rdpSettings* settings, const char* Value)  | 
2033  | 0  | { | 
2034  | 0  |   if (!Value)  | 
2035  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2036  |  |  | 
2037  | 0  |   if (!freerdp_settings_set_string(settings, FreeRDP_TlsSecretsFile, Value))  | 
2038  | 0  |     return COMMAND_LINE_ERROR_MEMORY;  | 
2039  | 0  |   return 0;  | 
2040  | 0  | }  | 
2041  |  |  | 
2042  |  | static int parse_tls_enforce(rdpSettings* settings, const char* Value)  | 
2043  | 0  | { | 
2044  | 0  |   UINT16 version = TLS1_2_VERSION;  | 
2045  |  | 
  | 
2046  | 0  |   if (Value)  | 
2047  | 0  |   { | 
2048  | 0  |     struct map_t  | 
2049  | 0  |     { | 
2050  | 0  |       const char* name;  | 
2051  | 0  |       UINT16 version;  | 
2052  | 0  |     };  | 
2053  | 0  |     const struct map_t map[] = { { "1.0", TLS1_VERSION }, | 
2054  | 0  |                                { "1.1", TLS1_1_VERSION }, | 
2055  | 0  |                                { "1.2", TLS1_2_VERSION } | 
2056  | 0  | #if defined(TLS1_3_VERSION)  | 
2057  | 0  |                                ,  | 
2058  | 0  |                                { "1.3", TLS1_3_VERSION } | 
2059  | 0  | #endif  | 
2060  | 0  |     };  | 
2061  |  | 
  | 
2062  | 0  |     for (size_t x = 0; x < ARRAYSIZE(map); x++)  | 
2063  | 0  |     { | 
2064  | 0  |       const struct map_t* cur = &map[x];  | 
2065  | 0  |       if (option_equals(cur->name, Value))  | 
2066  | 0  |       { | 
2067  | 0  |         version = cur->version;  | 
2068  | 0  |         break;  | 
2069  | 0  |       }  | 
2070  | 0  |     }  | 
2071  | 0  |   }  | 
2072  |  | 
  | 
2073  | 0  |   if (!(freerdp_settings_set_uint16(settings, FreeRDP_TLSMinVersion, version) &&  | 
2074  | 0  |         freerdp_settings_set_uint16(settings, FreeRDP_TLSMaxVersion, version)))  | 
2075  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2076  | 0  |   return 0;  | 
2077  | 0  | }  | 
2078  |  |  | 
2079  |  | static int parse_tls_cipher_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2080  | 0  | { | 
2081  | 0  |   int rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2082  | 0  |   CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "tls")  | 
2083  | 0  |   { | 
2084  | 0  |     if (option_starts_with("ciphers:", arg->Value)) | 
2085  | 0  |       rc = parse_tls_ciphers(settings, &arg->Value[8]);  | 
2086  | 0  |     else if (option_starts_with("seclevel:", arg->Value)) | 
2087  | 0  |       rc = parse_tls_seclevel(settings, &arg->Value[9]);  | 
2088  | 0  |     else if (option_starts_with("secrets-file:", arg->Value)) | 
2089  | 0  |       rc = parse_tls_secrets_file(settings, &arg->Value[13]);  | 
2090  | 0  |     else if (option_starts_with("enforce:", arg->Value)) | 
2091  | 0  |       rc = parse_tls_enforce(settings, &arg->Value[8]);  | 
2092  | 0  |   }  | 
2093  |  |  | 
2094  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
2095  |  |   CommandLineSwitchCase(arg, "tls-ciphers")  | 
2096  |  |   { | 
2097  |  |     WLog_WARN(TAG, "Option /tls-ciphers is deprecated, use /tls:ciphers instead");  | 
2098  |  |     rc = parse_tls_ciphers(settings, arg->Value);  | 
2099  |  |   }  | 
2100  |  |   CommandLineSwitchCase(arg, "tls-seclevel")  | 
2101  |  |   { | 
2102  |  |     WLog_WARN(TAG, "Option /tls-seclevel is deprecated, use /tls:seclevel instead");  | 
2103  |  |     rc = parse_tls_seclevel(settings, arg->Value);  | 
2104  |  |   }  | 
2105  |  |   CommandLineSwitchCase(arg, "tls-secrets-file")  | 
2106  |  |   { | 
2107  |  |     WLog_WARN(TAG, "Option /tls-secrets-file is deprecated, use /tls:secrets-file instead");  | 
2108  |  |     rc = parse_tls_secrets_file(settings, arg->Value);  | 
2109  |  |   }  | 
2110  |  |   CommandLineSwitchCase(arg, "enforce-tlsv1_2")  | 
2111  |  |   { | 
2112  |  |     WLog_WARN(TAG, "Option /enforce-tlsv1_2 is deprecated, use /tls:enforce:1.2 instead");  | 
2113  |  |     rc = parse_tls_enforce(settings, "1.2");  | 
2114  |  |   }  | 
2115  |  | #endif  | 
2116  | 0  |   CommandLineSwitchDefault(arg)  | 
2117  | 0  |   { | 
2118  | 0  |   }  | 
2119  | 0  |   CommandLineSwitchEnd(arg)  | 
2120  |  | 
  | 
2121  | 0  |       return rc;  | 
2122  | 0  | }  | 
2123  |  |  | 
2124  |  | static int parse_tls_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2125  | 0  | { | 
2126  | 0  |   WINPR_ASSERT(settings);  | 
2127  | 0  |   WINPR_ASSERT(arg);  | 
2128  |  |  | 
2129  | 0  |   size_t count = 0;  | 
2130  | 0  |   char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
2131  | 0  |   for (size_t x = 0; x < count; x++)  | 
2132  | 0  |   { | 
2133  | 0  |     COMMAND_LINE_ARGUMENT_A larg = *arg;  | 
2134  | 0  |     larg.Value = ptr[x];  | 
2135  |  | 
  | 
2136  | 0  |     int rc = parse_tls_cipher_options(settings, &larg);  | 
2137  | 0  |     if (rc != 0)  | 
2138  | 0  |     { | 
2139  | 0  |       free(ptr);  | 
2140  | 0  |       return rc;  | 
2141  | 0  |     }  | 
2142  | 0  |   }  | 
2143  | 0  |   free(ptr);  | 
2144  | 0  |   return 0;  | 
2145  | 0  | }  | 
2146  |  |  | 
2147  |  | static int parse_gfx_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2148  | 0  | { | 
2149  | 0  |   WINPR_ASSERT(settings);  | 
2150  | 0  |   WINPR_ASSERT(arg);  | 
2151  |  |  | 
2152  | 0  |   if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE))  | 
2153  | 0  |     return COMMAND_LINE_ERROR;  | 
2154  |  |  | 
2155  | 0  |   if (arg->Value)  | 
2156  | 0  |   { | 
2157  | 0  |     int rc = CHANNEL_RC_OK;  | 
2158  | 0  |     size_t count = 0;  | 
2159  | 0  |     char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
2160  | 0  |     if (!ptr || (count == 0))  | 
2161  | 0  |       rc = COMMAND_LINE_ERROR;  | 
2162  | 0  |     else  | 
2163  | 0  |     { | 
2164  | 0  |       BOOL GfxH264 = FALSE;  | 
2165  | 0  |       BOOL GfxAVC444 = FALSE;  | 
2166  | 0  |       BOOL RemoteFxCodec = FALSE;  | 
2167  | 0  |       BOOL GfxProgressive = FALSE;  | 
2168  | 0  |       BOOL codecSelected = FALSE;  | 
2169  |  | 
  | 
2170  | 0  |       for (size_t x = 0; x < count; x++)  | 
2171  | 0  |       { | 
2172  | 0  |         const char* val = ptr[x];  | 
2173  |  | #ifdef WITH_GFX_H264  | 
2174  |  |         if (option_starts_with("AVC444", val)) | 
2175  |  |         { | 
2176  |  |           const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);  | 
2177  |  |           if (bval == PARSE_FAIL)  | 
2178  |  |             rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2179  |  |           else  | 
2180  |  |             GfxAVC444 = bval != PARSE_OFF;  | 
2181  |  |           codecSelected = TRUE;  | 
2182  |  |         }  | 
2183  |  |         else if (option_starts_with("AVC420", val)) | 
2184  |  |         { | 
2185  |  |           const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);  | 
2186  |  |           if (bval == PARSE_FAIL)  | 
2187  |  |             rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2188  |  |           else  | 
2189  |  |             GfxH264 = bval != PARSE_OFF;  | 
2190  |  |           codecSelected = TRUE;  | 
2191  |  |         }  | 
2192  |  |         else  | 
2193  |  | #endif  | 
2194  | 0  |             if (option_starts_with("RFX", val)) | 
2195  | 0  |         { | 
2196  | 0  |           const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);  | 
2197  | 0  |           if (bval == PARSE_FAIL)  | 
2198  | 0  |             rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2199  | 0  |           else  | 
2200  | 0  |             RemoteFxCodec = bval != PARSE_OFF;  | 
2201  | 0  |           codecSelected = TRUE;  | 
2202  | 0  |         }  | 
2203  | 0  |         else if (option_starts_with("progressive", val)) | 
2204  | 0  |         { | 
2205  | 0  |           const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);  | 
2206  | 0  |           if (bval == PARSE_FAIL)  | 
2207  | 0  |             rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2208  | 0  |           else  | 
2209  | 0  |             GfxProgressive = bval != PARSE_OFF;  | 
2210  | 0  |           codecSelected = TRUE;  | 
2211  | 0  |         }  | 
2212  | 0  |         else if (option_starts_with("mask:", val)) | 
2213  | 0  |         { | 
2214  | 0  |           ULONGLONG v = 0;  | 
2215  | 0  |           const char* uv = &val[5];  | 
2216  | 0  |           if (!value_to_uint(uv, &v, 0, UINT32_MAX))  | 
2217  | 0  |             rc = COMMAND_LINE_ERROR;  | 
2218  | 0  |           else  | 
2219  | 0  |           { | 
2220  | 0  |             if (!freerdp_settings_set_uint32(settings, FreeRDP_GfxCapsFilter, v))  | 
2221  | 0  |               rc = COMMAND_LINE_ERROR;  | 
2222  | 0  |           }  | 
2223  | 0  |         }  | 
2224  | 0  |         else if (option_starts_with("small-cache", val)) | 
2225  | 0  |         { | 
2226  | 0  |           const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);  | 
2227  | 0  |           if (bval == PARSE_FAIL)  | 
2228  | 0  |             rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2229  | 0  |           else if (!freerdp_settings_set_bool(settings, FreeRDP_GfxSmallCache,  | 
2230  | 0  |                                               bval != PARSE_OFF))  | 
2231  | 0  |             rc = COMMAND_LINE_ERROR;  | 
2232  | 0  |         }  | 
2233  | 0  |         else if (option_starts_with("thin-client", val)) | 
2234  | 0  |         { | 
2235  | 0  |           const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);  | 
2236  | 0  |           if (bval == PARSE_FAIL)  | 
2237  | 0  |             rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2238  | 0  |           else if (!freerdp_settings_set_bool(settings, FreeRDP_GfxThinClient,  | 
2239  | 0  |                                               bval != PARSE_OFF))  | 
2240  | 0  |             rc = COMMAND_LINE_ERROR;  | 
2241  | 0  |           if ((rc == CHANNEL_RC_OK) && (bval > 0))  | 
2242  | 0  |           { | 
2243  | 0  |             if (!freerdp_settings_set_bool(settings, FreeRDP_GfxSmallCache,  | 
2244  | 0  |                                            bval != PARSE_OFF))  | 
2245  | 0  |               rc = COMMAND_LINE_ERROR;  | 
2246  | 0  |           }  | 
2247  | 0  |         }  | 
2248  | 0  |       }  | 
2249  |  | 
  | 
2250  | 0  |       if ((rc == CHANNEL_RC_OK) && codecSelected)  | 
2251  | 0  |       { | 
2252  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, GfxAVC444))  | 
2253  | 0  |           rc = COMMAND_LINE_ERROR;  | 
2254  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444v2, GfxAVC444))  | 
2255  | 0  |           rc = COMMAND_LINE_ERROR;  | 
2256  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_GfxH264, GfxH264))  | 
2257  | 0  |           rc = COMMAND_LINE_ERROR;  | 
2258  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, RemoteFxCodec))  | 
2259  | 0  |           rc = COMMAND_LINE_ERROR;  | 
2260  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_GfxProgressive, GfxProgressive))  | 
2261  | 0  |           rc = COMMAND_LINE_ERROR;  | 
2262  | 0  |       }  | 
2263  | 0  |     }  | 
2264  | 0  |     free(ptr);  | 
2265  | 0  |     if (rc != CHANNEL_RC_OK)  | 
2266  | 0  |       return rc;  | 
2267  | 0  |   }  | 
2268  | 0  |   return CHANNEL_RC_OK;  | 
2269  | 0  | }  | 
2270  |  |  | 
2271  |  | static int parse_kbd_layout(rdpSettings* settings, const char* value)  | 
2272  | 0  | { | 
2273  | 0  |   WINPR_ASSERT(settings);  | 
2274  | 0  |   WINPR_ASSERT(value);  | 
2275  |  |  | 
2276  | 0  |   int rc = 0;  | 
2277  | 0  |   LONGLONG ival = 0;  | 
2278  | 0  |   const BOOL isInt = value_to_int(value, &ival, 1, UINT32_MAX);  | 
2279  | 0  |   if (!isInt)  | 
2280  | 0  |   { | 
2281  | 0  |     ival = freerdp_map_keyboard_layout_name_to_id(value);  | 
2282  |  | 
  | 
2283  | 0  |     if (ival == 0)  | 
2284  | 0  |     { | 
2285  | 0  |       WLog_ERR(TAG, "Could not identify keyboard layout: %s", value);  | 
2286  | 0  |       WLog_ERR(TAG, "Use /list:kbd to list available layouts");  | 
2287  | 0  |       rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2288  | 0  |     }  | 
2289  | 0  |   }  | 
2290  |  | 
  | 
2291  | 0  |   if (rc == 0)  | 
2292  | 0  |   { | 
2293  | 0  |     if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardLayout, (UINT32)ival))  | 
2294  | 0  |       rc = COMMAND_LINE_ERROR;  | 
2295  | 0  |   }  | 
2296  | 0  |   return rc;  | 
2297  | 0  | }  | 
2298  |  |  | 
2299  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
2300  |  | static int parse_codec_cache_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2301  |  | { | 
2302  |  |   WINPR_ASSERT(settings);  | 
2303  |  |   WINPR_ASSERT(arg);  | 
2304  |  |  | 
2305  |  |   if (!arg->Value)  | 
2306  |  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2307  |  |   if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheV3Enabled, TRUE))  | 
2308  |  |     return COMMAND_LINE_ERROR;  | 
2309  |  |  | 
2310  |  |   if (option_equals(arg->Value, "rfx"))  | 
2311  |  |   { | 
2312  |  |     if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))  | 
2313  |  |       return COMMAND_LINE_ERROR;  | 
2314  |  |   }  | 
2315  |  |   else if (option_equals(arg->Value, "nsc"))  | 
2316  |  |   { | 
2317  |  |     if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE))  | 
2318  |  |       return COMMAND_LINE_ERROR;  | 
2319  |  |   }  | 
2320  |  |  | 
2321  |  | #if defined(WITH_JPEG)  | 
2322  |  |   else if (option_equals(arg->Value, "jpeg"))  | 
2323  |  |   { | 
2324  |  |     if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, TRUE))  | 
2325  |  |       return COMMAND_LINE_ERROR;  | 
2326  |  |  | 
2327  |  |     if (freerdp_settings_get_uint32(settings, FreeRDP_JpegQuality) == 0)  | 
2328  |  |     { | 
2329  |  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_JpegQuality, 75))  | 
2330  |  |         return COMMAND_LINE_ERROR;  | 
2331  |  |     }  | 
2332  |  |   }  | 
2333  |  |  | 
2334  |  | #endif  | 
2335  |  |   return 0;  | 
2336  |  | }  | 
2337  |  | #endif  | 
2338  |  |  | 
2339  |  | static BOOL check_kbd_remap_valid(const char* token)  | 
2340  | 0  | { | 
2341  | 0  |   DWORD key = 0;  | 
2342  | 0  |   DWORD value = 0;  | 
2343  |  | 
  | 
2344  | 0  |   WINPR_ASSERT(token);  | 
2345  |  |   /* The remapping is only allowed for scancodes, so maximum is 999=999 */  | 
2346  | 0  |   if (strlen(token) > 10)  | 
2347  | 0  |     return FALSE;  | 
2348  |  |  | 
2349  | 0  |   int rc = sscanf(token, "%" PRIu32 "=%" PRIu32, &key, &value);  | 
2350  | 0  |   if (rc != 2)  | 
2351  | 0  |     rc = sscanf(token, "%" PRIx32 "=%" PRIx32 "", &key, &value);  | 
2352  | 0  |   if (rc != 2)  | 
2353  | 0  |     rc = sscanf(token, "%" PRIu32 "=%" PRIx32, &key, &value);  | 
2354  | 0  |   if (rc != 2)  | 
2355  | 0  |     rc = sscanf(token, "%" PRIx32 "=%" PRIu32, &key, &value);  | 
2356  | 0  |   if (rc != 2)  | 
2357  | 0  |   { | 
2358  | 0  |     WLog_WARN(TAG, "/kbd:remap invalid entry '%s'", token);  | 
2359  | 0  |     return FALSE;  | 
2360  | 0  |   }  | 
2361  | 0  |   return TRUE;  | 
2362  | 0  | }  | 
2363  |  |  | 
2364  |  | static int parse_host_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2365  | 0  | { | 
2366  | 0  |   WINPR_ASSERT(settings);  | 
2367  | 0  |   WINPR_ASSERT(arg);  | 
2368  |  |  | 
2369  | 0  |   if (!arg->Value)  | 
2370  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2371  | 0  |   freerdp_settings_set_string(settings, FreeRDP_ServerHostname, NULL);  | 
2372  | 0  |   char* p = strchr(arg->Value, '[');  | 
2373  |  |  | 
2374  |  |   /* ipv4 */  | 
2375  | 0  |   if (!p)  | 
2376  | 0  |   { | 
2377  | 0  |     const char scheme[] = "://";  | 
2378  | 0  |     const char* val = strstr(arg->Value, scheme);  | 
2379  | 0  |     if (val)  | 
2380  | 0  |       val += strnlen(scheme, sizeof(scheme));  | 
2381  | 0  |     else  | 
2382  | 0  |       val = arg->Value;  | 
2383  | 0  |     p = strchr(val, ':');  | 
2384  |  | 
  | 
2385  | 0  |     if (p)  | 
2386  | 0  |     { | 
2387  | 0  |       LONGLONG lval = 0;  | 
2388  | 0  |       size_t length = 0;  | 
2389  |  | 
  | 
2390  | 0  |       if (!value_to_int(&p[1], &lval, 1, UINT16_MAX))  | 
2391  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2392  |  |  | 
2393  | 0  |       length = (size_t)(p - arg->Value);  | 
2394  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, lval))  | 
2395  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2396  | 0  |       if (!freerdp_settings_set_string_len(settings, FreeRDP_ServerHostname, arg->Value,  | 
2397  | 0  |                                            length))  | 
2398  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2399  | 0  |     }  | 
2400  | 0  |     else  | 
2401  | 0  |     { | 
2402  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_ServerHostname, arg->Value))  | 
2403  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
2404  | 0  |     }  | 
2405  | 0  |   }  | 
2406  | 0  |   else /* ipv6 */  | 
2407  | 0  |   { | 
2408  | 0  |     size_t length = 0;  | 
2409  | 0  |     char* p2 = strchr(arg->Value, ']');  | 
2410  |  |  | 
2411  |  |     /* not a valid [] ipv6 addr found */  | 
2412  | 0  |     if (!p2)  | 
2413  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2414  |  |  | 
2415  | 0  |     length = (size_t)(p2 - p);  | 
2416  | 0  |     if (!freerdp_settings_set_string_len(settings, FreeRDP_ServerHostname, p + 1, length - 1))  | 
2417  | 0  |       return COMMAND_LINE_ERROR_MEMORY;  | 
2418  |  |  | 
2419  | 0  |     if (*(p2 + 1) == ':')  | 
2420  | 0  |     { | 
2421  | 0  |       LONGLONG val = 0;  | 
2422  |  | 
  | 
2423  | 0  |       if (!value_to_int(&p2[2], &val, 0, UINT16_MAX))  | 
2424  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2425  |  |  | 
2426  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, (UINT16)val))  | 
2427  | 0  |         return COMMAND_LINE_ERROR;  | 
2428  | 0  |     }  | 
2429  |  |  | 
2430  | 0  |     printf("hostname %s port %" PRIu32 "\n", | 
2431  | 0  |            freerdp_settings_get_string(settings, FreeRDP_ServerHostname),  | 
2432  | 0  |            freerdp_settings_get_uint32(settings, FreeRDP_ServerPort));  | 
2433  | 0  |   }  | 
2434  | 0  |   return 0;  | 
2435  | 0  | }  | 
2436  |  |  | 
2437  |  | static int parse_redirect_prefer_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2438  | 0  | { | 
2439  | 0  |   WINPR_ASSERT(settings);  | 
2440  | 0  |   WINPR_ASSERT(arg);  | 
2441  |  |  | 
2442  | 0  |   size_t count = 0;  | 
2443  | 0  |   char* cur = arg->Value;  | 
2444  | 0  |   if (!arg->Value)  | 
2445  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2446  | 0  |   if (!freerdp_settings_set_uint32(settings, FreeRDP_RedirectionPreferType, 0))  | 
2447  | 0  |     return COMMAND_LINE_ERROR;  | 
2448  |  |  | 
2449  | 0  |   UINT32 value = 0;  | 
2450  | 0  |   do  | 
2451  | 0  |   { | 
2452  | 0  |     UINT32 mask = 0;  | 
2453  | 0  |     char* next = strchr(cur, ',');  | 
2454  |  | 
  | 
2455  | 0  |     if (next)  | 
2456  | 0  |     { | 
2457  | 0  |       *next = '\0';  | 
2458  | 0  |       next++;  | 
2459  | 0  |     }  | 
2460  |  | 
  | 
2461  | 0  |     if (option_equals("fqdn", cur)) | 
2462  | 0  |       mask = 0x06U;  | 
2463  | 0  |     else if (option_equals("ip", cur)) | 
2464  | 0  |       mask = 0x05U;  | 
2465  | 0  |     else if (option_equals("netbios", cur)) | 
2466  | 0  |       mask = 0x03U;  | 
2467  | 0  |     else  | 
2468  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2469  |  |  | 
2470  | 0  |     cur = next;  | 
2471  | 0  |     mask = (mask & 0x07);  | 
2472  | 0  |     value |= mask << (count * 3);  | 
2473  | 0  |     count++;  | 
2474  | 0  |   } while (cur != NULL);  | 
2475  |  |  | 
2476  | 0  |   if (!freerdp_settings_set_uint32(settings, FreeRDP_RedirectionPreferType, value))  | 
2477  | 0  |     return COMMAND_LINE_ERROR;  | 
2478  |  |  | 
2479  | 0  |   if (count > 3)  | 
2480  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2481  | 0  |   return 0;  | 
2482  | 0  | }  | 
2483  |  |  | 
2484  |  | static int parse_prevent_session_lock_options(rdpSettings* settings,  | 
2485  |  |                                               const COMMAND_LINE_ARGUMENT_A* arg)  | 
2486  | 0  | { | 
2487  | 0  |   WINPR_ASSERT(settings);  | 
2488  | 0  |   WINPR_ASSERT(arg);  | 
2489  |  |  | 
2490  | 0  |   if (!freerdp_settings_set_uint32(settings, FreeRDP_FakeMouseMotionInterval, 180))  | 
2491  | 0  |     return COMMAND_LINE_ERROR_MEMORY;  | 
2492  |  |  | 
2493  | 0  |   if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
2494  | 0  |   { | 
2495  | 0  |     LONGLONG val = 0;  | 
2496  |  | 
  | 
2497  | 0  |     if (!value_to_int(arg->Value, &val, 1, UINT32_MAX))  | 
2498  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2499  |  |  | 
2500  | 0  |     if (!freerdp_settings_set_uint32(settings, FreeRDP_FakeMouseMotionInterval, (UINT32)val))  | 
2501  | 0  |       return COMMAND_LINE_ERROR_MEMORY;  | 
2502  | 0  |   }  | 
2503  |  |  | 
2504  | 0  |   return 0;  | 
2505  | 0  | }  | 
2506  |  |  | 
2507  |  | static int parse_vmconnect_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2508  | 0  | { | 
2509  | 0  |   WINPR_ASSERT(settings);  | 
2510  | 0  |   WINPR_ASSERT(arg);  | 
2511  |  |  | 
2512  | 0  |   if (!freerdp_settings_set_bool(settings, FreeRDP_VmConnectMode, TRUE))  | 
2513  | 0  |     return COMMAND_LINE_ERROR;  | 
2514  | 0  |   if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, 2179))  | 
2515  | 0  |     return COMMAND_LINE_ERROR;  | 
2516  | 0  |   if (!freerdp_settings_set_bool(settings, FreeRDP_NegotiateSecurityLayer, FALSE))  | 
2517  | 0  |     return COMMAND_LINE_ERROR;  | 
2518  |  |  | 
2519  | 0  |   if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
2520  | 0  |   { | 
2521  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_SendPreconnectionPdu, TRUE))  | 
2522  | 0  |       return COMMAND_LINE_ERROR;  | 
2523  |  |  | 
2524  | 0  |     if (!freerdp_settings_set_string(settings, FreeRDP_PreconnectionBlob, arg->Value))  | 
2525  | 0  |       return COMMAND_LINE_ERROR_MEMORY;  | 
2526  | 0  |   }  | 
2527  | 0  |   return 0;  | 
2528  | 0  | }  | 
2529  |  |  | 
2530  |  | static int parse_size_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2531  | 0  | { | 
2532  | 0  |   int status = 0;  | 
2533  | 0  |   WINPR_ASSERT(settings);  | 
2534  | 0  |   WINPR_ASSERT(arg);  | 
2535  |  |  | 
2536  | 0  |   if (!arg->Value)  | 
2537  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2538  | 0  |   char* p = strchr(arg->Value, 'x');  | 
2539  |  | 
  | 
2540  | 0  |   if (p)  | 
2541  | 0  |   { | 
2542  | 0  |     unsigned long w = 0;  | 
2543  | 0  |     unsigned long h = 0;  | 
2544  |  | 
  | 
2545  | 0  |     if (!parseSizeValue(arg->Value, &w, &h) || (w > UINT16_MAX) || (h > UINT16_MAX))  | 
2546  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2547  |  |  | 
2548  | 0  |     if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, (UINT32)w))  | 
2549  | 0  |       return COMMAND_LINE_ERROR;  | 
2550  | 0  |     if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, (UINT32)h))  | 
2551  | 0  |       return COMMAND_LINE_ERROR;  | 
2552  | 0  |   }  | 
2553  | 0  |   else  | 
2554  | 0  |   { | 
2555  | 0  |     char* str = _strdup(arg->Value);  | 
2556  | 0  |     if (!str)  | 
2557  | 0  |       return COMMAND_LINE_ERROR_MEMORY;  | 
2558  |  |  | 
2559  | 0  |     p = strchr(str, '%');  | 
2560  |  | 
  | 
2561  | 0  |     if (p)  | 
2562  | 0  |     { | 
2563  | 0  |       BOOL partial = FALSE;  | 
2564  |  | 
  | 
2565  | 0  |       status = COMMAND_LINE_ERROR;  | 
2566  | 0  |       if (strchr(p, 'w'))  | 
2567  | 0  |       { | 
2568  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_PercentScreenUseWidth, TRUE))  | 
2569  | 0  |           goto fail;  | 
2570  | 0  |         partial = TRUE;  | 
2571  | 0  |       }  | 
2572  |  |  | 
2573  | 0  |       if (strchr(p, 'h'))  | 
2574  | 0  |       { | 
2575  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_PercentScreenUseHeight, TRUE))  | 
2576  | 0  |           goto fail;  | 
2577  | 0  |         partial = TRUE;  | 
2578  | 0  |       }  | 
2579  |  |  | 
2580  | 0  |       if (!partial)  | 
2581  | 0  |       { | 
2582  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_PercentScreenUseWidth, TRUE))  | 
2583  | 0  |           goto fail;  | 
2584  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_PercentScreenUseHeight, TRUE))  | 
2585  | 0  |           goto fail;  | 
2586  | 0  |       }  | 
2587  |  |  | 
2588  | 0  |       *p = '\0';  | 
2589  | 0  |       { | 
2590  | 0  |         LONGLONG val = 0;  | 
2591  |  | 
  | 
2592  | 0  |         if (!value_to_int(str, &val, 0, 100))  | 
2593  | 0  |         { | 
2594  | 0  |           status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2595  | 0  |           goto fail;  | 
2596  | 0  |         }  | 
2597  |  |  | 
2598  | 0  |         if (!freerdp_settings_set_uint32(settings, FreeRDP_PercentScreen, (UINT32)val))  | 
2599  | 0  |           goto fail;  | 
2600  | 0  |       }  | 
2601  |  |  | 
2602  | 0  |       status = 0;  | 
2603  | 0  |     }  | 
2604  |  |  | 
2605  | 0  |   fail:  | 
2606  | 0  |     free(str);  | 
2607  | 0  |   }  | 
2608  |  |  | 
2609  | 0  |   return status;  | 
2610  | 0  | }  | 
2611  |  |  | 
2612  |  | static int parse_monitors_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2613  | 0  | { | 
2614  | 0  |   WINPR_ASSERT(settings);  | 
2615  | 0  |   WINPR_ASSERT(arg);  | 
2616  |  |  | 
2617  | 0  |   if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
2618  | 0  |   { | 
2619  | 0  |     union  | 
2620  | 0  |     { | 
2621  | 0  |       char** p;  | 
2622  | 0  |       const char** pc;  | 
2623  | 0  |     } ptr;  | 
2624  | 0  |     size_t count = 0;  | 
2625  | 0  |     UINT32* MonitorIds = NULL;  | 
2626  | 0  |     ptr.p = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
2627  |  | 
  | 
2628  | 0  |     if (!ptr.pc)  | 
2629  | 0  |       return COMMAND_LINE_ERROR_MEMORY;  | 
2630  |  |  | 
2631  | 0  |     if (count > 16)  | 
2632  | 0  |       count = 16;  | 
2633  |  | 
  | 
2634  | 0  |     if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, NULL, count))  | 
2635  | 0  |     { | 
2636  | 0  |       free(ptr.p);  | 
2637  | 0  |       return FALSE;  | 
2638  | 0  |     }  | 
2639  |  |  | 
2640  | 0  |     MonitorIds = freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorIds, 0);  | 
2641  | 0  |     for (UINT32 i = 0; i < count; i++)  | 
2642  | 0  |     { | 
2643  | 0  |       LONGLONG val = 0;  | 
2644  |  | 
  | 
2645  | 0  |       if (!value_to_int(ptr.pc[i], &val, 0, UINT16_MAX))  | 
2646  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2647  |  |  | 
2648  | 0  |       MonitorIds[i] = (UINT32)val;  | 
2649  | 0  |     }  | 
2650  |  |  | 
2651  | 0  |     free(ptr.p);  | 
2652  | 0  |   }  | 
2653  |  |  | 
2654  | 0  |   return 0;  | 
2655  | 0  | }  | 
2656  |  |  | 
2657  |  | static int parse_dynamic_resolution_options(rdpSettings* settings,  | 
2658  |  |                                             const COMMAND_LINE_ARGUMENT_A* arg)  | 
2659  | 0  | { | 
2660  | 0  |   WINPR_ASSERT(settings);  | 
2661  | 0  |   WINPR_ASSERT(arg);  | 
2662  |  |  | 
2663  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_SmartSizing))  | 
2664  | 0  |   { | 
2665  | 0  |     WLog_ERR(TAG, "Smart sizing and dynamic resolution are mutually exclusive options");  | 
2666  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2667  | 0  |   }  | 
2668  |  |  | 
2669  | 0  |   if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDisplayControl, TRUE))  | 
2670  | 0  |     return COMMAND_LINE_ERROR;  | 
2671  | 0  |   if (!freerdp_settings_set_bool(settings, FreeRDP_DynamicResolutionUpdate, TRUE))  | 
2672  | 0  |     return COMMAND_LINE_ERROR;  | 
2673  |  |  | 
2674  | 0  |   return 0;  | 
2675  | 0  | }  | 
2676  |  |  | 
2677  |  | static int parse_smart_sizing_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2678  | 0  | { | 
2679  | 0  |   WINPR_ASSERT(settings);  | 
2680  | 0  |   WINPR_ASSERT(arg);  | 
2681  |  |  | 
2682  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate))  | 
2683  | 0  |   { | 
2684  | 0  |     WLog_ERR(TAG, "Smart sizing and dynamic resolution are mutually exclusive options");  | 
2685  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2686  | 0  |   }  | 
2687  |  |  | 
2688  | 0  |   if (!freerdp_settings_set_bool(settings, FreeRDP_SmartSizing, TRUE))  | 
2689  | 0  |     return COMMAND_LINE_ERROR;  | 
2690  |  |  | 
2691  | 0  |   if (arg->Value)  | 
2692  | 0  |   { | 
2693  | 0  |     unsigned long w = 0;  | 
2694  | 0  |     unsigned long h = 0;  | 
2695  |  | 
  | 
2696  | 0  |     if (!parseSizeValue(arg->Value, &w, &h) || (w > UINT16_MAX) || (h > UINT16_MAX))  | 
2697  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2698  |  |  | 
2699  | 0  |     if (!freerdp_settings_set_uint32(settings, FreeRDP_SmartSizingWidth, (UINT32)w))  | 
2700  | 0  |       return COMMAND_LINE_ERROR;  | 
2701  | 0  |     if (!freerdp_settings_set_uint32(settings, FreeRDP_SmartSizingHeight, (UINT32)h))  | 
2702  | 0  |       return COMMAND_LINE_ERROR;  | 
2703  | 0  |   }  | 
2704  | 0  |   return 0;  | 
2705  | 0  | }  | 
2706  |  |  | 
2707  |  | static int parse_bpp_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2708  | 0  | { | 
2709  | 0  |   WINPR_ASSERT(settings);  | 
2710  | 0  |   WINPR_ASSERT(arg);  | 
2711  |  |  | 
2712  | 0  |   LONGLONG val = 0;  | 
2713  |  | 
  | 
2714  | 0  |   if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))  | 
2715  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2716  |  |  | 
2717  | 0  |   switch (val)  | 
2718  | 0  |   { | 
2719  | 0  |     case 32:  | 
2720  | 0  |     case 24:  | 
2721  | 0  |     case 16:  | 
2722  | 0  |     case 15:  | 
2723  | 0  |     case 8:  | 
2724  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, (UINT32)val))  | 
2725  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2726  | 0  |       break;  | 
2727  |  |  | 
2728  | 0  |     default:  | 
2729  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2730  | 0  |   }  | 
2731  | 0  |   return 0;  | 
2732  | 0  | }  | 
2733  |  |  | 
2734  |  | static int parse_kbd_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2735  | 0  | { | 
2736  | 0  |   WINPR_ASSERT(settings);  | 
2737  | 0  |   WINPR_ASSERT(arg);  | 
2738  |  |  | 
2739  | 0  |   int rc = CHANNEL_RC_OK;  | 
2740  | 0  |   size_t count = 0;  | 
2741  | 0  |   char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
2742  | 0  |   if (!ptr || (count == 0))  | 
2743  | 0  |     rc = COMMAND_LINE_ERROR;  | 
2744  | 0  |   else  | 
2745  | 0  |   { | 
2746  | 0  |     for (size_t x = 0; x < count; x++)  | 
2747  | 0  |     { | 
2748  | 0  |       const char* val = ptr[x];  | 
2749  |  | 
  | 
2750  | 0  |       if (option_starts_with("remap:", val)) | 
2751  | 0  |       { | 
2752  |  |         /* Append this new occurance to the already existing list */  | 
2753  | 0  |         char* now = _strdup(&val[6]);  | 
2754  | 0  |         const char* old =  | 
2755  | 0  |             freerdp_settings_get_string(settings, FreeRDP_KeyboardRemappingList);  | 
2756  |  |  | 
2757  |  |         /* Basic sanity test. Entries must be like <key>=<value>, e.g. 1=2 */  | 
2758  | 0  |         if (!check_kbd_remap_valid(now))  | 
2759  | 0  |           rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2760  | 0  |         else if (old)  | 
2761  | 0  |         { | 
2762  | 0  |           const size_t olen = strlen(old);  | 
2763  | 0  |           const size_t alen = strlen(now);  | 
2764  | 0  |           const size_t tlen = olen + alen + 2;  | 
2765  | 0  |           char* tmp = calloc(tlen, sizeof(char));  | 
2766  | 0  |           if (!tmp)  | 
2767  | 0  |             rc = COMMAND_LINE_ERROR_MEMORY;  | 
2768  | 0  |           else  | 
2769  | 0  |             _snprintf(tmp, tlen, "%s,%s", old, now);  | 
2770  | 0  |           free(now);  | 
2771  | 0  |           now = tmp;  | 
2772  | 0  |         }  | 
2773  |  | 
  | 
2774  | 0  |         if (rc == 0)  | 
2775  | 0  |         { | 
2776  | 0  |           if (!freerdp_settings_set_string(settings, FreeRDP_KeyboardRemappingList, now))  | 
2777  | 0  |             rc = COMMAND_LINE_ERROR;  | 
2778  | 0  |         }  | 
2779  | 0  |         free(now);  | 
2780  | 0  |       }  | 
2781  | 0  |       else if (option_starts_with("layout:", val)) | 
2782  | 0  |       { | 
2783  | 0  |         rc = parse_kbd_layout(settings, &val[7]);  | 
2784  | 0  |       }  | 
2785  | 0  |       else if (option_starts_with("lang:", val)) | 
2786  | 0  |       { | 
2787  | 0  |         LONGLONG ival = 0;  | 
2788  | 0  |         const BOOL isInt = value_to_int(&val[5], &ival, 1, UINT32_MAX);  | 
2789  | 0  |         if (!isInt)  | 
2790  | 0  |           rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2791  | 0  |         else if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardCodePage,  | 
2792  | 0  |                                               (UINT32)ival))  | 
2793  | 0  |           rc = COMMAND_LINE_ERROR;  | 
2794  | 0  |       }  | 
2795  | 0  |       else if (option_starts_with("type:", val)) | 
2796  | 0  |       { | 
2797  | 0  |         LONGLONG ival = 0;  | 
2798  | 0  |         const BOOL isInt = value_to_int(&val[5], &ival, 1, UINT32_MAX);  | 
2799  | 0  |         if (!isInt)  | 
2800  | 0  |           rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2801  | 0  |         else if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardType, (UINT32)ival))  | 
2802  | 0  |           rc = COMMAND_LINE_ERROR;  | 
2803  | 0  |       }  | 
2804  | 0  |       else if (option_starts_with("subtype:", val)) | 
2805  | 0  |       { | 
2806  | 0  |         LONGLONG ival = 0;  | 
2807  | 0  |         const BOOL isInt = value_to_int(&val[8], &ival, 1, UINT32_MAX);  | 
2808  | 0  |         if (!isInt)  | 
2809  | 0  |           rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2810  | 0  |         else if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardSubType,  | 
2811  | 0  |                                               (UINT32)ival))  | 
2812  | 0  |           rc = COMMAND_LINE_ERROR;  | 
2813  | 0  |       }  | 
2814  | 0  |       else if (option_starts_with("fn-key:", val)) | 
2815  | 0  |       { | 
2816  | 0  |         LONGLONG ival = 0;  | 
2817  | 0  |         const BOOL isInt = value_to_int(&val[7], &ival, 1, UINT32_MAX);  | 
2818  | 0  |         if (!isInt)  | 
2819  | 0  |           rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2820  | 0  |         else if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardFunctionKey,  | 
2821  | 0  |                                               (UINT32)ival))  | 
2822  | 0  |           rc = COMMAND_LINE_ERROR;  | 
2823  | 0  |       }  | 
2824  | 0  |       else if (option_starts_with("unicode", val)) | 
2825  | 0  |       { | 
2826  | 0  |         const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);  | 
2827  | 0  |         if (bval == PARSE_FAIL)  | 
2828  | 0  |           rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2829  | 0  |         else if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput,  | 
2830  | 0  |                                             bval != PARSE_OFF))  | 
2831  | 0  |           rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2832  | 0  |       }  | 
2833  | 0  |       else if (option_starts_with("pipe:", val)) | 
2834  | 0  |       { | 
2835  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, TRUE))  | 
2836  | 0  |           rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2837  | 0  |         else if (!freerdp_settings_set_string(settings, FreeRDP_KeyboardPipeName, &val[5]))  | 
2838  | 0  |           rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2839  | 0  |       }  | 
2840  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
2841  |  |       else if (count == 1)  | 
2842  |  |       { | 
2843  |  |         /* Legacy, allow /kbd:<value> for setting keyboard layout */  | 
2844  |  |         rc = parse_kbd_layout(settings, val);  | 
2845  |  |       }  | 
2846  |  | #endif  | 
2847  | 0  |       else  | 
2848  | 0  |         rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2849  |  | 
  | 
2850  | 0  |       if (rc != 0)  | 
2851  | 0  |         break;  | 
2852  | 0  |     }  | 
2853  | 0  |   }  | 
2854  | 0  |   free(ptr);  | 
2855  | 0  |   return rc;  | 
2856  | 0  | }  | 
2857  |  |  | 
2858  |  | static int parse_proxy_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2859  | 0  | { | 
2860  | 0  |   WINPR_ASSERT(settings);  | 
2861  | 0  |   WINPR_ASSERT(arg);  | 
2862  |  |  | 
2863  |  |   /* initial value */  | 
2864  | 0  |   if (!freerdp_settings_set_uint32(settings, FreeRDP_ProxyType, PROXY_TYPE_HTTP))  | 
2865  | 0  |     return COMMAND_LINE_ERROR_MEMORY;  | 
2866  |  |  | 
2867  | 0  |   if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
2868  | 0  |   { | 
2869  | 0  |     const char* cur = arg->Value;  | 
2870  |  | 
  | 
2871  | 0  |     if (!cur)  | 
2872  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2873  |  |     /* value is [scheme://][user:password@]hostname:port */  | 
2874  | 0  |     if (!proxy_parse_uri(settings, cur))  | 
2875  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2876  | 0  |   }  | 
2877  | 0  |   else  | 
2878  | 0  |   { | 
2879  | 0  |     WLog_ERR(TAG, "Option http-proxy needs argument.");  | 
2880  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2881  | 0  |   }  | 
2882  | 0  |   return 0;  | 
2883  | 0  | }  | 
2884  |  |  | 
2885  |  | static int parse_dump_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2886  | 0  | { | 
2887  | 0  |   WINPR_ASSERT(settings);  | 
2888  | 0  |   WINPR_ASSERT(arg);  | 
2889  |  |  | 
2890  | 0  |   BOOL failed = FALSE;  | 
2891  | 0  |   size_t count = 0;  | 
2892  | 0  |   char** args = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
2893  | 0  |   if (!args)  | 
2894  | 0  |     failed = TRUE;  | 
2895  | 0  |   else  | 
2896  | 0  |   { | 
2897  | 0  |     BOOL modernsyntax = FALSE;  | 
2898  | 0  |     BOOL oldsyntax = FALSE;  | 
2899  | 0  |     for (size_t x = 0; (x < count) && !failed; x++)  | 
2900  | 0  |     { | 
2901  | 0  |       const char* carg = args[x];  | 
2902  | 0  |       if (option_starts_with("file:", carg)) | 
2903  | 0  |       { | 
2904  | 0  |         const char* val = &carg[5];  | 
2905  | 0  |         if (oldsyntax)  | 
2906  | 0  |           failed = TRUE;  | 
2907  | 0  |         else if (!freerdp_settings_set_string(settings, FreeRDP_TransportDumpFile, val))  | 
2908  | 0  |           failed = TRUE;  | 
2909  | 0  |         modernsyntax = TRUE;  | 
2910  | 0  |       }  | 
2911  | 0  |       else if (option_equals("replay", carg)) | 
2912  | 0  |       { | 
2913  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDump, FALSE))  | 
2914  | 0  |           failed = TRUE;  | 
2915  | 0  |         else if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplay, TRUE))  | 
2916  | 0  |           failed = TRUE;  | 
2917  | 0  |       }  | 
2918  | 0  |       else if (option_equals("record", carg)) | 
2919  | 0  |       { | 
2920  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDump, TRUE))  | 
2921  | 0  |           failed = TRUE;  | 
2922  | 0  |         else if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplay, FALSE))  | 
2923  | 0  |           failed = TRUE;  | 
2924  | 0  |       }  | 
2925  | 0  |       else if (option_equals("nodelay", carg)) | 
2926  | 0  |       { | 
2927  | 0  |         if (oldsyntax)  | 
2928  | 0  |           failed = TRUE;  | 
2929  | 0  |         else if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplayNodelay,  | 
2930  | 0  |                                             TRUE))  | 
2931  | 0  |           failed = TRUE;  | 
2932  | 0  |         modernsyntax = TRUE;  | 
2933  | 0  |       }  | 
2934  | 0  |       else  | 
2935  | 0  |       { | 
2936  |  |         /* compat:  | 
2937  |  |          * support syntax record,<filename> and replay,<filename>  | 
2938  |  |          */  | 
2939  | 0  |         if (modernsyntax)  | 
2940  | 0  |           failed = TRUE;  | 
2941  | 0  |         else if (!freerdp_settings_set_string(settings, FreeRDP_TransportDumpFile, carg))  | 
2942  | 0  |           failed = TRUE;  | 
2943  | 0  |         oldsyntax = TRUE;  | 
2944  | 0  |       }  | 
2945  | 0  |     }  | 
2946  |  | 
  | 
2947  | 0  |     if (oldsyntax && (count != 2))  | 
2948  | 0  |       failed = TRUE;  | 
2949  | 0  |   }  | 
2950  | 0  |   free(args);  | 
2951  | 0  |   if (failed)  | 
2952  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
2953  | 0  |   return 0;  | 
2954  | 0  | }  | 
2955  |  |  | 
2956  |  | static int parse_clipboard_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
2957  | 0  | { | 
2958  | 0  |   WINPR_ASSERT(settings);  | 
2959  | 0  |   WINPR_ASSERT(arg);  | 
2960  |  |  | 
2961  | 0  |   if (arg->Value == BoolValueTrue || arg->Value == BoolValueFalse)  | 
2962  | 0  |   { | 
2963  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard,  | 
2964  | 0  |                                    (arg->Value == BoolValueTrue)))  | 
2965  | 0  |       return COMMAND_LINE_ERROR;  | 
2966  | 0  |   }  | 
2967  | 0  |   else  | 
2968  | 0  |   { | 
2969  | 0  |     int rc = 0;  | 
2970  | 0  |     union  | 
2971  | 0  |     { | 
2972  | 0  |       char** p;  | 
2973  | 0  |       const char** pc;  | 
2974  | 0  |     } ptr;  | 
2975  | 0  |     size_t count = 0;  | 
2976  | 0  |     ptr.p = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
2977  | 0  |     for (size_t x = 0; (x < count) && (rc == 0); x++)  | 
2978  | 0  |     { | 
2979  | 0  |       const char* usesel = "use-selection:";  | 
2980  |  | 
  | 
2981  | 0  |       const char* cur = ptr.pc[x];  | 
2982  | 0  |       if (option_starts_with(usesel, cur))  | 
2983  | 0  |       { | 
2984  | 0  |         const char* val = &cur[strlen(usesel)];  | 
2985  | 0  |         if (!freerdp_settings_set_string(settings, FreeRDP_ClipboardUseSelection, val))  | 
2986  | 0  |           rc = COMMAND_LINE_ERROR_MEMORY;  | 
2987  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, TRUE))  | 
2988  | 0  |           return COMMAND_LINE_ERROR;  | 
2989  | 0  |       }  | 
2990  | 0  |       else if (option_starts_with("direction-to", cur)) | 
2991  | 0  |       { | 
2992  | 0  |         const UINT32 mask =  | 
2993  | 0  |             freerdp_settings_get_uint32(settings, FreeRDP_ClipboardFeatureMask) &  | 
2994  | 0  |             ~(CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_REMOTE_TO_LOCAL);  | 
2995  | 0  |         const PARSE_CLIP_DIR_RESULT bval = parse_clip_direciton_to_option(cur);  | 
2996  | 0  |         UINT32 bflags = 0;  | 
2997  | 0  |         switch (bval)  | 
2998  | 0  |         { | 
2999  | 0  |           case CLIP_DIR_PARSE_ALL:  | 
3000  | 0  |             bflags |= CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_REMOTE_TO_LOCAL;  | 
3001  | 0  |             break;  | 
3002  | 0  |           case CLIP_DIR_PARSE_LOCAL:  | 
3003  | 0  |             bflags |= CLIPRDR_FLAG_REMOTE_TO_LOCAL;  | 
3004  | 0  |             break;  | 
3005  | 0  |           case CLIP_DIR_PARSE_REMOTE:  | 
3006  | 0  |             bflags |= CLIPRDR_FLAG_LOCAL_TO_REMOTE;  | 
3007  | 0  |             break;  | 
3008  | 0  |           case CLIP_DIR_PARSE_OFF:  | 
3009  | 0  |             break;  | 
3010  | 0  |           case CLIP_DIR_PARSE_FAIL:  | 
3011  | 0  |           default:  | 
3012  | 0  |             rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3013  | 0  |             break;  | 
3014  | 0  |         }  | 
3015  |  |  | 
3016  | 0  |         if (!freerdp_settings_set_uint32(settings, FreeRDP_ClipboardFeatureMask,  | 
3017  | 0  |                                          mask | bflags))  | 
3018  | 0  |           rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3019  | 0  |       }  | 
3020  | 0  |       else if (option_starts_with("files-to", cur)) | 
3021  | 0  |       { | 
3022  | 0  |         const UINT32 mask =  | 
3023  | 0  |             freerdp_settings_get_uint32(settings, FreeRDP_ClipboardFeatureMask) &  | 
3024  | 0  |             ~(CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES);  | 
3025  | 0  |         const PARSE_CLIP_DIR_RESULT bval = parse_clip_direciton_to_option(cur);  | 
3026  | 0  |         UINT32 bflags = 0;  | 
3027  | 0  |         switch (bval)  | 
3028  | 0  |         { | 
3029  | 0  |           case CLIP_DIR_PARSE_ALL:  | 
3030  | 0  |             bflags |=  | 
3031  | 0  |                 CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES;  | 
3032  | 0  |             break;  | 
3033  | 0  |           case CLIP_DIR_PARSE_LOCAL:  | 
3034  | 0  |             bflags |= CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES;  | 
3035  | 0  |             break;  | 
3036  | 0  |           case CLIP_DIR_PARSE_REMOTE:  | 
3037  | 0  |             bflags |= CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES;  | 
3038  | 0  |             break;  | 
3039  | 0  |           case CLIP_DIR_PARSE_OFF:  | 
3040  | 0  |             break;  | 
3041  | 0  |           case CLIP_DIR_PARSE_FAIL:  | 
3042  | 0  |           default:  | 
3043  | 0  |             rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3044  | 0  |             break;  | 
3045  | 0  |         }  | 
3046  |  |  | 
3047  | 0  |         if (!freerdp_settings_set_uint32(settings, FreeRDP_ClipboardFeatureMask,  | 
3048  | 0  |                                          mask | bflags))  | 
3049  | 0  |           rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3050  | 0  |       }  | 
3051  | 0  |       else  | 
3052  | 0  |         rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3053  | 0  |     }  | 
3054  | 0  |     free(ptr.p);  | 
3055  |  | 
  | 
3056  | 0  |     if (rc)  | 
3057  | 0  |       return rc;  | 
3058  | 0  |   }  | 
3059  | 0  |   return 0;  | 
3060  | 0  | }  | 
3061  |  |  | 
3062  |  | static int parse_audio_mode_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3063  | 0  | { | 
3064  | 0  |   WINPR_ASSERT(settings);  | 
3065  | 0  |   WINPR_ASSERT(arg);  | 
3066  |  |  | 
3067  | 0  |   LONGLONG val = 0;  | 
3068  |  | 
  | 
3069  | 0  |   if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))  | 
3070  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3071  |  |  | 
3072  | 0  |   switch (val)  | 
3073  | 0  |   { | 
3074  | 0  |     case AUDIO_MODE_REDIRECT:  | 
3075  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, TRUE))  | 
3076  | 0  |         return COMMAND_LINE_ERROR;  | 
3077  | 0  |       break;  | 
3078  |  |  | 
3079  | 0  |     case AUDIO_MODE_PLAY_ON_SERVER:  | 
3080  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, TRUE))  | 
3081  | 0  |         return COMMAND_LINE_ERROR;  | 
3082  | 0  |       break;  | 
3083  |  |  | 
3084  | 0  |     case AUDIO_MODE_NONE:  | 
3085  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, FALSE))  | 
3086  | 0  |         return COMMAND_LINE_ERROR;  | 
3087  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, FALSE))  | 
3088  | 0  |         return COMMAND_LINE_ERROR;  | 
3089  | 0  |       break;  | 
3090  |  |  | 
3091  | 0  |     default:  | 
3092  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3093  | 0  |   }  | 
3094  | 0  |   return 0;  | 
3095  | 0  | }  | 
3096  |  |  | 
3097  |  | static int parse_network_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3098  | 0  | { | 
3099  | 0  |   WINPR_ASSERT(settings);  | 
3100  | 0  |   WINPR_ASSERT(arg);  | 
3101  |  |  | 
3102  | 0  |   UINT32 type = CONNECTION_TYPE_INVALID;  | 
3103  |  | 
  | 
3104  | 0  |   if (option_equals(arg->Value, "invalid"))  | 
3105  | 0  |     type = CONNECTION_TYPE_INVALID;  | 
3106  | 0  |   else if (option_equals(arg->Value, "modem"))  | 
3107  | 0  |     type = CONNECTION_TYPE_MODEM;  | 
3108  | 0  |   else if (option_equals(arg->Value, "broadband"))  | 
3109  | 0  |     type = CONNECTION_TYPE_BROADBAND_HIGH;  | 
3110  | 0  |   else if (option_equals(arg->Value, "broadband-low"))  | 
3111  | 0  |     type = CONNECTION_TYPE_BROADBAND_LOW;  | 
3112  | 0  |   else if (option_equals(arg->Value, "broadband-high"))  | 
3113  | 0  |     type = CONNECTION_TYPE_BROADBAND_HIGH;  | 
3114  | 0  |   else if (option_equals(arg->Value, "wan"))  | 
3115  | 0  |     type = CONNECTION_TYPE_WAN;  | 
3116  | 0  |   else if (option_equals(arg->Value, "lan"))  | 
3117  | 0  |     type = CONNECTION_TYPE_LAN;  | 
3118  | 0  |   else if ((option_equals(arg->Value, "autodetect")) || (option_equals(arg->Value, "auto")) ||  | 
3119  | 0  |            (option_equals(arg->Value, "detect")))  | 
3120  | 0  |   { | 
3121  | 0  |     type = CONNECTION_TYPE_AUTODETECT;  | 
3122  | 0  |   }  | 
3123  | 0  |   else  | 
3124  | 0  |   { | 
3125  | 0  |     LONGLONG val = 0;  | 
3126  |  | 
  | 
3127  | 0  |     if (!value_to_int(arg->Value, &val, 0, 7))  | 
3128  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3129  |  |  | 
3130  | 0  |     type = (UINT32)val;  | 
3131  | 0  |   }  | 
3132  |  |  | 
3133  | 0  |   if (!freerdp_set_connection_type(settings, type))  | 
3134  | 0  |     return COMMAND_LINE_ERROR;  | 
3135  | 0  |   return 0;  | 
3136  | 0  | }  | 
3137  |  |  | 
3138  |  | static int parse_sec_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3139  | 0  | { | 
3140  | 0  |   WINPR_ASSERT(settings);  | 
3141  | 0  |   WINPR_ASSERT(arg);  | 
3142  |  |  | 
3143  | 0  |   size_t count = 0;  | 
3144  | 0  |   char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
3145  | 0  |   if (count == 0)  | 
3146  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3147  |  |  | 
3148  | 0  |   FreeRDP_Settings_Keys_Bool singleOptionWithoutOnOff = FreeRDP_BOOL_UNUSED;  | 
3149  | 0  |   for (size_t x = 0; x < count; x++)  | 
3150  | 0  |   { | 
3151  | 0  |     const char* cur = ptr[x];  | 
3152  | 0  |     const PARSE_ON_OFF_RESULT bval = parse_on_off_option(cur);  | 
3153  | 0  |     if (bval == PARSE_FAIL)  | 
3154  | 0  |     { | 
3155  | 0  |       free(ptr);  | 
3156  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3157  | 0  |     }  | 
3158  |  |  | 
3159  | 0  |     const BOOL val = bval != PARSE_OFF;  | 
3160  | 0  |     FreeRDP_Settings_Keys_Bool id = FreeRDP_BOOL_UNUSED;  | 
3161  | 0  |     if (option_starts_with("rdp", cur)) /* Standard RDP */ | 
3162  | 0  |     { | 
3163  | 0  |       id = FreeRDP_RdpSecurity;  | 
3164  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, val))  | 
3165  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3166  | 0  |     }  | 
3167  | 0  |     else if (option_starts_with("tls", cur)) /* TLS */ | 
3168  | 0  |       id = FreeRDP_TlsSecurity;  | 
3169  | 0  |     else if (option_starts_with("nla", cur)) /* NLA */ | 
3170  | 0  |       id = FreeRDP_NlaSecurity;  | 
3171  | 0  |     else if (option_starts_with("ext", cur)) /* NLA Extended */ | 
3172  | 0  |       id = FreeRDP_ExtSecurity;  | 
3173  | 0  |     else if (option_equals("aad", cur)) /* RDSAAD */ | 
3174  | 0  |       id = FreeRDP_AadSecurity;  | 
3175  | 0  |     else  | 
3176  | 0  |     { | 
3177  | 0  |       WLog_ERR(TAG, "unknown protocol security: %s", arg->Value);  | 
3178  | 0  |       free(ptr);  | 
3179  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3180  | 0  |     }  | 
3181  |  |  | 
3182  | 0  |     if ((bval == PARSE_NONE) && (count == 1))  | 
3183  | 0  |       singleOptionWithoutOnOff = id;  | 
3184  | 0  |     if (!freerdp_settings_set_bool(settings, id, val))  | 
3185  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3186  | 0  |   }  | 
3187  |  |  | 
3188  | 0  |   if (singleOptionWithoutOnOff != FreeRDP_BOOL_UNUSED)  | 
3189  | 0  |   { | 
3190  | 0  |     const FreeRDP_Settings_Keys_Bool options[] = { FreeRDP_AadSecurity, | 
3191  | 0  |                                                  FreeRDP_UseRdpSecurityLayer,  | 
3192  | 0  |                                                  FreeRDP_RdpSecurity, FreeRDP_NlaSecurity,  | 
3193  | 0  |                                                  FreeRDP_TlsSecurity };  | 
3194  |  | 
  | 
3195  | 0  |     for (size_t i = 0; i < ARRAYSIZE(options); i++)  | 
3196  | 0  |     { | 
3197  | 0  |       if (!freerdp_settings_set_bool(settings, options[i], FALSE))  | 
3198  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3199  | 0  |     }  | 
3200  |  |  | 
3201  | 0  |     if (!freerdp_settings_set_bool(settings, singleOptionWithoutOnOff, TRUE))  | 
3202  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3203  | 0  |     if (singleOptionWithoutOnOff == FreeRDP_RdpSecurity)  | 
3204  | 0  |     { | 
3205  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, TRUE))  | 
3206  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3207  | 0  |     }  | 
3208  | 0  |   }  | 
3209  | 0  |   free(ptr);  | 
3210  | 0  |   return 0;  | 
3211  | 0  | }  | 
3212  |  |  | 
3213  |  | static int parse_encryption_methods_options(rdpSettings* settings,  | 
3214  |  |                                             const COMMAND_LINE_ARGUMENT_A* arg)  | 
3215  | 0  | { | 
3216  | 0  |   WINPR_ASSERT(settings);  | 
3217  | 0  |   WINPR_ASSERT(arg);  | 
3218  |  |  | 
3219  | 0  |   if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
3220  | 0  |   { | 
3221  | 0  |     union  | 
3222  | 0  |     { | 
3223  | 0  |       char** p;  | 
3224  | 0  |       const char** pc;  | 
3225  | 0  |     } ptr;  | 
3226  | 0  |     size_t count = 0;  | 
3227  | 0  |     ptr.p = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
3228  |  | 
  | 
3229  | 0  |     UINT32 EncryptionMethods = 0;  | 
3230  | 0  |     for (UINT32 i = 0; i < count; i++)  | 
3231  | 0  |     { | 
3232  | 0  |       if (option_equals(ptr.pc[i], "40"))  | 
3233  | 0  |         EncryptionMethods |= ENCRYPTION_METHOD_40BIT;  | 
3234  | 0  |       else if (option_equals(ptr.pc[i], "56"))  | 
3235  | 0  |         EncryptionMethods |= ENCRYPTION_METHOD_56BIT;  | 
3236  | 0  |       else if (option_equals(ptr.pc[i], "128"))  | 
3237  | 0  |         EncryptionMethods |= ENCRYPTION_METHOD_128BIT;  | 
3238  | 0  |       else if (option_equals(ptr.pc[i], "FIPS"))  | 
3239  | 0  |         EncryptionMethods |= ENCRYPTION_METHOD_FIPS;  | 
3240  | 0  |       else  | 
3241  | 0  |         WLog_ERR(TAG, "unknown encryption method '%s'", ptr.pc[i]);  | 
3242  | 0  |     }  | 
3243  |  | 
  | 
3244  | 0  |     if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionMethods, EncryptionMethods))  | 
3245  | 0  |       return COMMAND_LINE_ERROR;  | 
3246  | 0  |     free(ptr.p);  | 
3247  | 0  |   }  | 
3248  | 0  |   return 0;  | 
3249  | 0  | }  | 
3250  |  |  | 
3251  |  | static int parse_cert_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3252  | 0  | { | 
3253  | 0  |   WINPR_ASSERT(settings);  | 
3254  | 0  |   WINPR_ASSERT(arg);  | 
3255  |  |  | 
3256  | 0  |   int rc = 0;  | 
3257  | 0  |   union  | 
3258  | 0  |   { | 
3259  | 0  |     char** p;  | 
3260  | 0  |     const char** pc;  | 
3261  | 0  |   } ptr;  | 
3262  | 0  |   size_t count = 0;  | 
3263  | 0  |   ptr.p = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
3264  | 0  |   for (size_t x = 0; (x < count) && (rc == 0); x++)  | 
3265  | 0  |   { | 
3266  | 0  |     const char deny[] = "deny";  | 
3267  | 0  |     const char ignore[] = "ignore";  | 
3268  | 0  |     const char tofu[] = "tofu";  | 
3269  | 0  |     const char name[] = "name:";  | 
3270  | 0  |     const char fingerprints[] = "fingerprint:";  | 
3271  |  | 
  | 
3272  | 0  |     const char* cur = ptr.pc[x];  | 
3273  | 0  |     if (option_equals(deny, cur))  | 
3274  | 0  |     { | 
3275  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AutoDenyCertificate, TRUE))  | 
3276  | 0  |         return COMMAND_LINE_ERROR;  | 
3277  | 0  |     }  | 
3278  | 0  |     else if (option_equals(ignore, cur))  | 
3279  | 0  |     { | 
3280  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_IgnoreCertificate, TRUE))  | 
3281  | 0  |         return COMMAND_LINE_ERROR;  | 
3282  | 0  |     }  | 
3283  | 0  |     else if (option_equals(tofu, cur))  | 
3284  | 0  |     { | 
3285  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AutoAcceptCertificate, TRUE))  | 
3286  | 0  |         return COMMAND_LINE_ERROR;  | 
3287  | 0  |     }  | 
3288  | 0  |     else if (option_starts_with(name, cur))  | 
3289  | 0  |     { | 
3290  | 0  |       const char* val = &cur[strnlen(name, sizeof(name))];  | 
3291  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_CertificateName, val))  | 
3292  | 0  |         rc = COMMAND_LINE_ERROR_MEMORY;  | 
3293  | 0  |     }  | 
3294  | 0  |     else if (option_starts_with(fingerprints, cur))  | 
3295  | 0  |     { | 
3296  | 0  |       const char* val = &cur[strnlen(fingerprints, sizeof(fingerprints))];  | 
3297  | 0  |       if (!freerdp_settings_append_string(settings, FreeRDP_CertificateAcceptedFingerprints,  | 
3298  | 0  |                                           ",", val))  | 
3299  | 0  |         rc = COMMAND_LINE_ERROR_MEMORY;  | 
3300  | 0  |     }  | 
3301  | 0  |     else  | 
3302  | 0  |       rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3303  | 0  |   }  | 
3304  | 0  |   free(ptr.p);  | 
3305  |  | 
  | 
3306  | 0  |   return rc;  | 
3307  | 0  | }  | 
3308  |  |  | 
3309  |  | static int parse_mouse_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3310  | 0  | { | 
3311  | 0  |   WINPR_ASSERT(settings);  | 
3312  | 0  |   WINPR_ASSERT(arg);  | 
3313  |  |  | 
3314  | 0  |   size_t count = 0;  | 
3315  | 0  |   char** ptr = CommandLineParseCommaSeparatedValuesEx("mouse", arg->Value, &count); | 
3316  | 0  |   UINT rc = 0;  | 
3317  | 0  |   if (ptr)  | 
3318  | 0  |   { | 
3319  | 0  |     for (size_t x = 1; x < count; x++)  | 
3320  | 0  |     { | 
3321  | 0  |       const char* cur = ptr[x];  | 
3322  |  | 
  | 
3323  | 0  |       const PARSE_ON_OFF_RESULT bval = parse_on_off_option(cur);  | 
3324  | 0  |       if (bval == PARSE_FAIL)  | 
3325  | 0  |         rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3326  | 0  |       else  | 
3327  | 0  |       { | 
3328  | 0  |         const BOOL val = bval != PARSE_OFF;  | 
3329  |  | 
  | 
3330  | 0  |         if (option_starts_with("relative", cur)) | 
3331  | 0  |         { | 
3332  | 0  |           if (!freerdp_settings_set_bool(settings, FreeRDP_MouseUseRelativeMove, val))  | 
3333  | 0  |             rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3334  | 0  |         }  | 
3335  | 0  |         else if (option_starts_with("grab", cur)) | 
3336  | 0  |         { | 
3337  | 0  |           if (!freerdp_settings_set_bool(settings, FreeRDP_GrabMouse, val))  | 
3338  | 0  |             rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3339  | 0  |         }  | 
3340  | 0  |       }  | 
3341  |  | 
  | 
3342  | 0  |       if (rc != 0)  | 
3343  | 0  |         break;  | 
3344  | 0  |     }  | 
3345  | 0  |   }  | 
3346  | 0  |   free(ptr);  | 
3347  |  | 
  | 
3348  | 0  |   return rc;  | 
3349  | 0  | }  | 
3350  |  |  | 
3351  |  | static int parse_floatbar_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3352  | 0  | { | 
3353  | 0  |   WINPR_ASSERT(settings);  | 
3354  | 0  |   WINPR_ASSERT(arg);  | 
3355  |  |  | 
3356  |  |   /* Defaults are enabled, visible, sticky, fullscreen */  | 
3357  | 0  |   UINT32 Floatbar = 0x0017;  | 
3358  |  | 
  | 
3359  | 0  |   if (arg->Value)  | 
3360  | 0  |   { | 
3361  | 0  |     char* start = arg->Value;  | 
3362  |  | 
  | 
3363  | 0  |     do  | 
3364  | 0  |     { | 
3365  | 0  |       char* cur = start;  | 
3366  | 0  |       start = strchr(start, ',');  | 
3367  |  | 
  | 
3368  | 0  |       if (start)  | 
3369  | 0  |       { | 
3370  | 0  |         *start = '\0';  | 
3371  | 0  |         start = start + 1;  | 
3372  | 0  |       }  | 
3373  |  |  | 
3374  |  |       /* sticky:[on|off] */  | 
3375  | 0  |       if (option_starts_with("sticky:", cur)) | 
3376  | 0  |       { | 
3377  | 0  |         Floatbar &= ~0x02u;  | 
3378  |  | 
  | 
3379  | 0  |         const PARSE_ON_OFF_RESULT bval = parse_on_off_option(cur);  | 
3380  | 0  |         switch (bval)  | 
3381  | 0  |         { | 
3382  | 0  |           case PARSE_ON:  | 
3383  | 0  |           case PARSE_NONE:  | 
3384  | 0  |             Floatbar |= 0x02u;  | 
3385  | 0  |             break;  | 
3386  | 0  |           case PARSE_OFF:  | 
3387  | 0  |             Floatbar &= ~0x02u;  | 
3388  | 0  |             break;  | 
3389  | 0  |           case PARSE_FAIL:  | 
3390  | 0  |           default:  | 
3391  | 0  |             return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3392  | 0  |         }  | 
3393  | 0  |       }  | 
3394  |  |       /* default:[visible|hidden] */  | 
3395  | 0  |       else if (option_starts_with("default:", cur)) | 
3396  | 0  |       { | 
3397  | 0  |         const char* val = cur + 8;  | 
3398  | 0  |         Floatbar &= ~0x04u;  | 
3399  |  | 
  | 
3400  | 0  |         if (option_equals("visible", val)) | 
3401  | 0  |           Floatbar |= 0x04u;  | 
3402  | 0  |         else if (option_equals("hidden", val)) | 
3403  | 0  |           Floatbar &= ~0x04u;  | 
3404  | 0  |         else  | 
3405  | 0  |           return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3406  | 0  |       }  | 
3407  |  |       /* show:[always|fullscreen|window] */  | 
3408  | 0  |       else if (option_starts_with("show:", cur)) | 
3409  | 0  |       { | 
3410  | 0  |         const char* val = cur + 5;  | 
3411  | 0  |         Floatbar &= ~0x30u;  | 
3412  |  | 
  | 
3413  | 0  |         if (option_equals("always", val)) | 
3414  | 0  |           Floatbar |= 0x30u;  | 
3415  | 0  |         else if (option_equals("fullscreen", val)) | 
3416  | 0  |           Floatbar |= 0x10u;  | 
3417  | 0  |         else if (option_equals("window", val)) | 
3418  | 0  |           Floatbar |= 0x20u;  | 
3419  | 0  |         else  | 
3420  | 0  |           return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3421  | 0  |       }  | 
3422  | 0  |       else  | 
3423  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3424  | 0  |     } while (start);  | 
3425  | 0  |   }  | 
3426  | 0  |   if (!freerdp_settings_set_uint32(settings, FreeRDP_Floatbar, Floatbar))  | 
3427  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3428  | 0  |   return 0;  | 
3429  | 0  | }  | 
3430  |  |  | 
3431  |  | static int parse_reconnect_cookie_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3432  | 0  | { | 
3433  | 0  |   WINPR_ASSERT(settings);  | 
3434  | 0  |   WINPR_ASSERT(arg);  | 
3435  |  |  | 
3436  | 0  |   BYTE* base64 = NULL;  | 
3437  | 0  |   size_t length = 0;  | 
3438  | 0  |   if (!arg->Value)  | 
3439  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3440  |  |  | 
3441  | 0  |   crypto_base64_decode((const char*)(arg->Value), strlen(arg->Value), &base64, &length);  | 
3442  |  | 
  | 
3443  | 0  |   if ((base64 != NULL) && (length == sizeof(ARC_SC_PRIVATE_PACKET)))  | 
3444  | 0  |   { | 
3445  | 0  |     if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerAutoReconnectCookie, base64,  | 
3446  | 0  |                                           1))  | 
3447  | 0  |       return COMMAND_LINE_ERROR;  | 
3448  | 0  |   }  | 
3449  | 0  |   else  | 
3450  | 0  |   { | 
3451  | 0  |     WLog_ERR(TAG, "reconnect-cookie:  invalid base64 '%s'", arg->Value);  | 
3452  | 0  |   }  | 
3453  |  |  | 
3454  | 0  |   free(base64);  | 
3455  | 0  |   return 0;  | 
3456  | 0  | }  | 
3457  |  |  | 
3458  |  | static int parse_scale_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3459  | 0  | { | 
3460  | 0  |   WINPR_ASSERT(settings);  | 
3461  | 0  |   WINPR_ASSERT(arg);  | 
3462  |  |  | 
3463  | 0  |   LONGLONG val = 0;  | 
3464  |  | 
  | 
3465  | 0  |   if (!value_to_int(arg->Value, &val, 100, 180))  | 
3466  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3467  |  |  | 
3468  | 0  |   switch (val)  | 
3469  | 0  |   { | 
3470  | 0  |     case 100:  | 
3471  | 0  |     case 140:  | 
3472  | 0  |     case 180:  | 
3473  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopScaleFactor, (UINT32)val))  | 
3474  | 0  |         return COMMAND_LINE_ERROR;  | 
3475  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_DeviceScaleFactor, (UINT32)val))  | 
3476  | 0  |         return COMMAND_LINE_ERROR;  | 
3477  | 0  |       break;  | 
3478  |  |  | 
3479  | 0  |     default:  | 
3480  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3481  | 0  |   }  | 
3482  | 0  |   return 0;  | 
3483  | 0  | }  | 
3484  |  |  | 
3485  |  | static int parse_scale_device_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3486  | 0  | { | 
3487  | 0  |   WINPR_ASSERT(settings);  | 
3488  | 0  |   WINPR_ASSERT(arg);  | 
3489  |  |  | 
3490  | 0  |   LONGLONG val = 0;  | 
3491  |  | 
  | 
3492  | 0  |   if (!value_to_int(arg->Value, &val, 100, 180))  | 
3493  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3494  |  |  | 
3495  | 0  |   switch (val)  | 
3496  | 0  |   { | 
3497  | 0  |     case 100:  | 
3498  | 0  |     case 140:  | 
3499  | 0  |     case 180:  | 
3500  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_DeviceScaleFactor, (UINT32)val))  | 
3501  | 0  |         return COMMAND_LINE_ERROR;  | 
3502  | 0  |       break;  | 
3503  |  |  | 
3504  | 0  |     default:  | 
3505  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3506  | 0  |   }  | 
3507  | 0  |   return 0;  | 
3508  | 0  | }  | 
3509  |  |  | 
3510  |  | static int parse_smartcard_logon_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3511  | 0  | { | 
3512  | 0  |   WINPR_ASSERT(settings);  | 
3513  | 0  |   WINPR_ASSERT(arg);  | 
3514  |  |  | 
3515  | 0  |   size_t count = 0;  | 
3516  | 0  |   union  | 
3517  | 0  |   { | 
3518  | 0  |     char** p;  | 
3519  | 0  |     const char** pc;  | 
3520  | 0  |   } ptr;  | 
3521  |  | 
  | 
3522  | 0  |   if (!freerdp_settings_set_bool(settings, FreeRDP_SmartcardLogon, TRUE))  | 
3523  | 0  |     return COMMAND_LINE_ERROR;  | 
3524  |  |  | 
3525  | 0  |   ptr.p = CommandLineParseCommaSeparatedValuesEx("smartcard-logon", arg->Value, &count); | 
3526  | 0  |   if (ptr.pc)  | 
3527  | 0  |   { | 
3528  | 0  |     const CmdLineSubOptions opts[] = { | 
3529  | 0  |       { "cert:", FreeRDP_SmartcardCertificate, CMDLINE_SUBOPTION_FILE, | 
3530  | 0  |         setSmartcardEmulation },  | 
3531  | 0  |       { "key:", FreeRDP_SmartcardPrivateKey, CMDLINE_SUBOPTION_FILE, setSmartcardEmulation }, | 
3532  | 0  |       { "pin:", FreeRDP_Password, CMDLINE_SUBOPTION_STRING, NULL }, | 
3533  | 0  |       { "csp:", FreeRDP_CspName, CMDLINE_SUBOPTION_STRING, NULL }, | 
3534  | 0  |       { "reader:", FreeRDP_ReaderName, CMDLINE_SUBOPTION_STRING, NULL }, | 
3535  | 0  |       { "card:", FreeRDP_CardName, CMDLINE_SUBOPTION_STRING, NULL }, | 
3536  | 0  |       { "container:", FreeRDP_ContainerName, CMDLINE_SUBOPTION_STRING, NULL } | 
3537  | 0  |     };  | 
3538  |  | 
  | 
3539  | 0  |     for (size_t x = 1; x < count; x++)  | 
3540  | 0  |     { | 
3541  | 0  |       const char* cur = ptr.pc[x];  | 
3542  | 0  |       if (!parseSubOptions(settings, opts, ARRAYSIZE(opts), cur))  | 
3543  | 0  |       { | 
3544  | 0  |         free(ptr.p);  | 
3545  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3546  | 0  |       }  | 
3547  | 0  |     }  | 
3548  | 0  |   }  | 
3549  | 0  |   free(ptr.p);  | 
3550  | 0  |   return 0;  | 
3551  | 0  | }  | 
3552  |  |  | 
3553  |  | static int parse_tune_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3554  | 0  | { | 
3555  | 0  |   WINPR_ASSERT(settings);  | 
3556  | 0  |   WINPR_ASSERT(arg);  | 
3557  |  |  | 
3558  | 0  |   size_t count = 0;  | 
3559  | 0  |   union  | 
3560  | 0  |   { | 
3561  | 0  |     char** p;  | 
3562  | 0  |     const char** pc;  | 
3563  | 0  |   } ptr;  | 
3564  | 0  |   ptr.p = CommandLineParseCommaSeparatedValuesEx("tune", arg->Value, &count); | 
3565  | 0  |   if (!ptr.pc)  | 
3566  | 0  |     return COMMAND_LINE_ERROR;  | 
3567  | 0  |   for (size_t x = 1; x < count; x++)  | 
3568  | 0  |   { | 
3569  | 0  |     const char* cur = ptr.pc[x];  | 
3570  | 0  |     char* sep = strchr(cur, ':');  | 
3571  | 0  |     if (!sep)  | 
3572  | 0  |     { | 
3573  | 0  |       free(ptr.p);  | 
3574  | 0  |       return COMMAND_LINE_ERROR;  | 
3575  | 0  |     }  | 
3576  | 0  |     *sep++ = '\0';  | 
3577  | 0  |     if (!freerdp_settings_set_value_for_name(settings, cur, sep))  | 
3578  | 0  |     { | 
3579  | 0  |       free(ptr.p);  | 
3580  | 0  |       return COMMAND_LINE_ERROR;  | 
3581  | 0  |     }  | 
3582  | 0  |   }  | 
3583  |  |  | 
3584  | 0  |   free(ptr.p);  | 
3585  | 0  |   return 0;  | 
3586  | 0  | }  | 
3587  |  |  | 
3588  |  | static int parse_app_option_program(rdpSettings* settings, const char* cmd)  | 
3589  | 0  | { | 
3590  | 0  |   const FreeRDP_Settings_Keys_Bool ids[] = { FreeRDP_RemoteApplicationMode, | 
3591  | 0  |                                            FreeRDP_RemoteAppLanguageBarSupported,  | 
3592  | 0  |                                            FreeRDP_Workarea, FreeRDP_DisableWallpaper,  | 
3593  | 0  |                                            FreeRDP_DisableFullWindowDrag };  | 
3594  |  | 
  | 
3595  | 0  |   if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationProgram, cmd))  | 
3596  | 0  |     return COMMAND_LINE_ERROR_MEMORY;  | 
3597  |  |  | 
3598  | 0  |   for (size_t y = 0; y < ARRAYSIZE(ids); y++)  | 
3599  | 0  |   { | 
3600  | 0  |     if (!freerdp_settings_set_bool(settings, ids[y], TRUE))  | 
3601  | 0  |       return COMMAND_LINE_ERROR;  | 
3602  | 0  |   }  | 
3603  | 0  |   return CHANNEL_RC_OK;  | 
3604  | 0  | }  | 
3605  |  |  | 
3606  |  | static int parse_app_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3607  | 0  | { | 
3608  | 0  |   WINPR_ASSERT(settings);  | 
3609  | 0  |   WINPR_ASSERT(arg);  | 
3610  |  |  | 
3611  | 0  |   int rc = CHANNEL_RC_OK;  | 
3612  | 0  |   size_t count = 0;  | 
3613  | 0  |   char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
3614  | 0  |   if (!ptr || (count == 0))  | 
3615  | 0  |     rc = COMMAND_LINE_ERROR;  | 
3616  | 0  |   else  | 
3617  | 0  |   { | 
3618  | 0  |     struct app_map  | 
3619  | 0  |     { | 
3620  | 0  |       const char* name;  | 
3621  | 0  |       SSIZE_T id;  | 
3622  | 0  |       int (*fkt)(rdpSettings* settings, const char* value);  | 
3623  | 0  |     };  | 
3624  | 0  |     const struct app_map amap[] = { { "program:", FreeRDP_RemoteApplicationProgram, | 
3625  | 0  |                                     parse_app_option_program },  | 
3626  | 0  |                                   { "workdir:", FreeRDP_RemoteApplicationWorkingDir, NULL }, | 
3627  | 0  |                                   { "name:", FreeRDP_RemoteApplicationName, NULL }, | 
3628  | 0  |                                   { "icon:", FreeRDP_RemoteApplicationIcon, NULL }, | 
3629  | 0  |                                   { "cmd:", FreeRDP_RemoteApplicationCmdLine, NULL }, | 
3630  | 0  |                                   { "file:", FreeRDP_RemoteApplicationFile, NULL }, | 
3631  | 0  |                                   { "guid:", FreeRDP_RemoteApplicationGuid, NULL }, | 
3632  | 0  |                                   { "hidef:", FreeRDP_HiDefRemoteApp, NULL } }; | 
3633  | 0  |     for (size_t x = 0; x < count; x++)  | 
3634  | 0  |     { | 
3635  | 0  |       BOOL handled = FALSE;  | 
3636  | 0  |       const char* val = ptr[x];  | 
3637  |  | 
  | 
3638  | 0  |       for (size_t y = 0; y < ARRAYSIZE(amap); y++)  | 
3639  | 0  |       { | 
3640  | 0  |         const struct app_map* cur = &amap[y];  | 
3641  | 0  |         if (option_starts_with(cur->name, val))  | 
3642  | 0  |         { | 
3643  | 0  |           const char* xval = &val[strlen(cur->name)];  | 
3644  | 0  |           if (cur->fkt)  | 
3645  | 0  |             rc = cur->fkt(settings, xval);  | 
3646  | 0  |           else  | 
3647  | 0  |           { | 
3648  | 0  |             const char* name = freerdp_settings_get_name_for_key(cur->id);  | 
3649  | 0  |             if (!freerdp_settings_set_value_for_name(settings, name, xval))  | 
3650  | 0  |               rc = COMMAND_LINE_ERROR_MEMORY;  | 
3651  | 0  |           }  | 
3652  |  | 
  | 
3653  | 0  |           handled = TRUE;  | 
3654  | 0  |           break;  | 
3655  | 0  |         }  | 
3656  | 0  |       }  | 
3657  |  | 
  | 
3658  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
3659  |  |       if (!handled && (count == 1))  | 
3660  |  |       { | 
3661  |  |         /* Legacy path, allow /app:command and /app:||command syntax */  | 
3662  |  |         rc = parse_app_option_program(settings, val);  | 
3663  |  |       }  | 
3664  |  |       else  | 
3665  |  | #endif  | 
3666  | 0  |           if (!handled)  | 
3667  | 0  |         rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3668  |  | 
  | 
3669  | 0  |       if (rc != 0)  | 
3670  | 0  |         break;  | 
3671  | 0  |     }  | 
3672  | 0  |   }  | 
3673  |  | 
  | 
3674  | 0  |   free(ptr);  | 
3675  | 0  |   return rc;  | 
3676  | 0  | }  | 
3677  |  |  | 
3678  |  | static int parse_cache_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3679  | 0  | { | 
3680  | 0  |   WINPR_ASSERT(settings);  | 
3681  | 0  |   WINPR_ASSERT(arg);  | 
3682  |  |  | 
3683  | 0  |   int rc = CHANNEL_RC_OK;  | 
3684  | 0  |   size_t count = 0;  | 
3685  | 0  |   char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
3686  | 0  |   if (!ptr || (count == 0))  | 
3687  | 0  |     return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3688  |  |  | 
3689  | 0  |   for (size_t x = 0; x < count; x++)  | 
3690  | 0  |   { | 
3691  | 0  |     const char* val = ptr[x];  | 
3692  |  | 
  | 
3693  | 0  |     if (option_starts_with("codec:", val)) | 
3694  | 0  |     { | 
3695  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheV3Enabled, TRUE))  | 
3696  | 0  |         rc = COMMAND_LINE_ERROR;  | 
3697  | 0  |       else if (option_equals(arg->Value, "rfx"))  | 
3698  | 0  |       { | 
3699  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))  | 
3700  | 0  |           rc = COMMAND_LINE_ERROR;  | 
3701  | 0  |       }  | 
3702  | 0  |       else if (option_equals(arg->Value, "nsc"))  | 
3703  | 0  |       { | 
3704  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE))  | 
3705  | 0  |           rc = COMMAND_LINE_ERROR;  | 
3706  | 0  |       }  | 
3707  |  | 
  | 
3708  |  | #if defined(WITH_JPEG)  | 
3709  |  |       else if (option_equals(arg->Value, "jpeg"))  | 
3710  |  |       { | 
3711  |  |         if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, TRUE))  | 
3712  |  |           rc = COMMAND_LINE_ERROR;  | 
3713  |  |  | 
3714  |  |         if (freerdp_settings_get_uint32(settings, FreeRDP_JpegQuality) == 0)  | 
3715  |  |         { | 
3716  |  |           if (!freerdp_settings_set_uint32(settings, FreeRDP_JpegQuality, 75))  | 
3717  |  |             return COMMAND_LINE_ERROR;  | 
3718  |  |         }  | 
3719  |  |       }  | 
3720  |  |  | 
3721  |  | #endif  | 
3722  | 0  |     }  | 
3723  | 0  |     else if (option_starts_with("persist-file:", val)) | 
3724  | 0  |     { | 
3725  |  | 
  | 
3726  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_BitmapCachePersistFile, &val[13]))  | 
3727  | 0  |         rc = COMMAND_LINE_ERROR_MEMORY;  | 
3728  | 0  |       else if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, TRUE))  | 
3729  | 0  |         rc = COMMAND_LINE_ERROR;  | 
3730  | 0  |     }  | 
3731  | 0  |     else  | 
3732  | 0  |     { | 
3733  | 0  |       const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);  | 
3734  | 0  |       if (bval == PARSE_FAIL)  | 
3735  | 0  |         rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
3736  | 0  |       else  | 
3737  | 0  |       { | 
3738  | 0  |         if (option_starts_with("bitmap", val)) | 
3739  | 0  |         { | 
3740  | 0  |           if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled,  | 
3741  | 0  |                                          bval != PARSE_OFF))  | 
3742  | 0  |             rc = COMMAND_LINE_ERROR;  | 
3743  | 0  |         }  | 
3744  | 0  |         else if (option_starts_with("glyph", val)) | 
3745  | 0  |         { | 
3746  | 0  |           if (!freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel,  | 
3747  | 0  |                                            bval != PARSE_OFF ? GLYPH_SUPPORT_FULL  | 
3748  | 0  |                                                              : GLYPH_SUPPORT_NONE))  | 
3749  | 0  |             rc = COMMAND_LINE_ERROR;  | 
3750  | 0  |         }  | 
3751  | 0  |         else if (option_starts_with("persist", val)) | 
3752  | 0  |         { | 
3753  | 0  |           if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,  | 
3754  | 0  |                                          bval != PARSE_OFF))  | 
3755  | 0  |             rc = COMMAND_LINE_ERROR;  | 
3756  | 0  |         }  | 
3757  | 0  |         else if (option_starts_with("offscreen", val)) | 
3758  | 0  |         { | 
3759  | 0  |           if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenSupportLevel,  | 
3760  | 0  |                                            bval != PARSE_OFF))  | 
3761  | 0  |             rc = COMMAND_LINE_ERROR;  | 
3762  | 0  |         }  | 
3763  | 0  |       }  | 
3764  | 0  |     }  | 
3765  | 0  |   }  | 
3766  |  | 
  | 
3767  | 0  |   free(ptr);  | 
3768  | 0  |   return rc;  | 
3769  | 0  | }  | 
3770  |  |  | 
3771  |  | static BOOL parse_gateway_host_option(rdpSettings* settings, const char* host)  | 
3772  | 0  | { | 
3773  | 0  |   WINPR_ASSERT(settings);  | 
3774  | 0  |   WINPR_ASSERT(host);  | 
3775  |  |  | 
3776  | 0  |   char* name = NULL;  | 
3777  | 0  |   int port = -1;  | 
3778  | 0  |   if (!freerdp_parse_hostname(host, &name, &port))  | 
3779  | 0  |     return FALSE;  | 
3780  | 0  |   const BOOL rc = freerdp_settings_set_string(settings, FreeRDP_GatewayHostname, name);  | 
3781  | 0  |   free(name);  | 
3782  | 0  |   if (!rc)  | 
3783  | 0  |     return FALSE;  | 
3784  | 0  |   if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayUseSameCredentials, TRUE))  | 
3785  | 0  |     return FALSE;  | 
3786  | 0  |   if (!freerdp_set_gateway_usage_method(settings, TSC_PROXY_MODE_DIRECT))  | 
3787  | 0  |     return FALSE;  | 
3788  |  |  | 
3789  | 0  |   return TRUE;  | 
3790  | 0  | }  | 
3791  |  |  | 
3792  |  | static BOOL parse_gateway_cred_option(rdpSettings* settings, const char* value,  | 
3793  |  |                                       FreeRDP_Settings_Keys_String what)  | 
3794  | 0  | { | 
3795  | 0  |   WINPR_ASSERT(settings);  | 
3796  | 0  |   WINPR_ASSERT(value);  | 
3797  |  |  | 
3798  | 0  |   switch (what)  | 
3799  | 0  |   { | 
3800  | 0  |     case FreeRDP_GatewayUsername:  | 
3801  | 0  |       if (!freerdp_parse_username_settings(value, settings, FreeRDP_GatewayUsername,  | 
3802  | 0  |                                            FreeRDP_GatewayDomain))  | 
3803  | 0  |         return FALSE;  | 
3804  | 0  |       break;  | 
3805  | 0  |     default:  | 
3806  | 0  |       if (!freerdp_settings_set_string(settings, what, value))  | 
3807  | 0  |         return FALSE;  | 
3808  | 0  |       break;  | 
3809  | 0  |   }  | 
3810  |  |  | 
3811  | 0  |   return freerdp_settings_set_bool(settings, FreeRDP_GatewayUseSameCredentials, FALSE);  | 
3812  | 0  | }  | 
3813  |  |  | 
3814  |  | static BOOL parse_gateway_type_option(rdpSettings* settings, const char* value)  | 
3815  | 0  | { | 
3816  | 0  |   WINPR_ASSERT(settings);  | 
3817  | 0  |   WINPR_ASSERT(value);  | 
3818  |  |  | 
3819  | 0  |   if (option_equals(value, "rpc"))  | 
3820  | 0  |   { | 
3821  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, TRUE) ||  | 
3822  | 0  |         !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, FALSE) ||  | 
3823  | 0  |         !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, FALSE) ||  | 
3824  | 0  |         !freerdp_settings_set_bool(settings, FreeRDP_GatewayArmTransport, FALSE))  | 
3825  | 0  |       return FALSE;  | 
3826  | 0  |   }  | 
3827  | 0  |   else  | 
3828  | 0  |   { | 
3829  | 0  |     if (option_equals(value, "http"))  | 
3830  | 0  |     { | 
3831  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, FALSE) ||  | 
3832  | 0  |           !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, TRUE) ||  | 
3833  | 0  |           !freerdp_settings_set_bool(settings, FreeRDP_GatewayArmTransport, FALSE))  | 
3834  | 0  |         return FALSE;  | 
3835  | 0  |     }  | 
3836  | 0  |     else if (option_equals(value, "auto"))  | 
3837  | 0  |     { | 
3838  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, TRUE) ||  | 
3839  | 0  |           !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, TRUE) ||  | 
3840  | 0  |           !freerdp_settings_set_bool(settings, FreeRDP_GatewayArmTransport, FALSE))  | 
3841  | 0  |         return FALSE;  | 
3842  | 0  |     }  | 
3843  | 0  |     else if (option_equals(value, "arm"))  | 
3844  | 0  |     { | 
3845  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, FALSE) ||  | 
3846  | 0  |           !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, FALSE) ||  | 
3847  | 0  |           !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, FALSE) ||  | 
3848  | 0  |           !freerdp_settings_set_bool(settings, FreeRDP_GatewayArmTransport, TRUE))  | 
3849  | 0  |         return FALSE;  | 
3850  | 0  |     }  | 
3851  | 0  |   }  | 
3852  | 0  |   return TRUE;  | 
3853  | 0  | }  | 
3854  |  |  | 
3855  |  | static BOOL parse_gateway_usage_option(rdpSettings* settings, const char* value)  | 
3856  | 0  | { | 
3857  | 0  |   UINT32 type = 0;  | 
3858  |  | 
  | 
3859  | 0  |   WINPR_ASSERT(settings);  | 
3860  | 0  |   WINPR_ASSERT(value);  | 
3861  |  |  | 
3862  | 0  |   if (option_equals(value, "none"))  | 
3863  | 0  |     type = TSC_PROXY_MODE_NONE_DIRECT;  | 
3864  | 0  |   else if (option_equals(value, "direct"))  | 
3865  | 0  |     type = TSC_PROXY_MODE_DIRECT;  | 
3866  | 0  |   else if (option_equals(value, "detect"))  | 
3867  | 0  |     type = TSC_PROXY_MODE_DETECT;  | 
3868  | 0  |   else if (option_equals(value, "default"))  | 
3869  | 0  |     type = TSC_PROXY_MODE_DEFAULT;  | 
3870  | 0  |   else  | 
3871  | 0  |   { | 
3872  | 0  |     LONGLONG val = 0;  | 
3873  |  | 
  | 
3874  | 0  |     if (!value_to_int(value, &val, TSC_PROXY_MODE_NONE_DIRECT, TSC_PROXY_MODE_NONE_DETECT))  | 
3875  | 0  |       return FALSE;  | 
3876  | 0  |   }  | 
3877  |  |  | 
3878  | 0  |   return freerdp_set_gateway_usage_method(settings, type);  | 
3879  | 0  | }  | 
3880  |  |  | 
3881  |  | static BOOL parse_gateway_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)  | 
3882  | 0  | { | 
3883  | 0  |   BOOL rc = FALSE;  | 
3884  |  | 
  | 
3885  | 0  |   WINPR_ASSERT(settings);  | 
3886  | 0  |   WINPR_ASSERT(arg);  | 
3887  |  |  | 
3888  | 0  |   size_t count = 0;  | 
3889  | 0  |   char** args = CommandLineParseCommaSeparatedValues(arg->Value, &count);  | 
3890  | 0  |   if (count == 0)  | 
3891  | 0  |     return TRUE;  | 
3892  | 0  |   WINPR_ASSERT(args);  | 
3893  |  |  | 
3894  | 0  |   if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayEnabled, TRUE))  | 
3895  | 0  |     goto fail;  | 
3896  |  |  | 
3897  | 0  |   BOOL allowHttpOpts = FALSE;  | 
3898  | 0  |   for (size_t x = 0; x < count; x++)  | 
3899  | 0  |   { | 
3900  | 0  |     BOOL validOption = FALSE;  | 
3901  | 0  |     const char* argval = args[x];  | 
3902  |  | 
  | 
3903  | 0  |     WINPR_ASSERT(argval);  | 
3904  |  |  | 
3905  | 0  |     const char* gw = option_starts_with("g:", argval); | 
3906  | 0  |     if (gw)  | 
3907  | 0  |     { | 
3908  | 0  |       if (!parse_gateway_host_option(settings, gw))  | 
3909  | 0  |         goto fail;  | 
3910  | 0  |       validOption = TRUE;  | 
3911  | 0  |       allowHttpOpts = FALSE;  | 
3912  | 0  |     }  | 
3913  |  |  | 
3914  | 0  |     const char* gu = option_starts_with("u:", argval); | 
3915  | 0  |     if (gu)  | 
3916  | 0  |     { | 
3917  | 0  |       if (!parse_gateway_cred_option(settings, gu, FreeRDP_GatewayUsername))  | 
3918  | 0  |         goto fail;  | 
3919  | 0  |       validOption = TRUE;  | 
3920  | 0  |       allowHttpOpts = FALSE;  | 
3921  | 0  |     }  | 
3922  |  |  | 
3923  | 0  |     const char* gd = option_starts_with("d:", argval); | 
3924  | 0  |     if (gd)  | 
3925  | 0  |     { | 
3926  | 0  |       if (!parse_gateway_cred_option(settings, gd, FreeRDP_GatewayDomain))  | 
3927  | 0  |         goto fail;  | 
3928  | 0  |       validOption = TRUE;  | 
3929  | 0  |       allowHttpOpts = FALSE;  | 
3930  | 0  |     }  | 
3931  |  |  | 
3932  | 0  |     const char* gp = option_starts_with("p:", argval); | 
3933  | 0  |     if (gp)  | 
3934  | 0  |     { | 
3935  | 0  |       if (!parse_gateway_cred_option(settings, gp, FreeRDP_GatewayPassword))  | 
3936  | 0  |         goto fail;  | 
3937  | 0  |       validOption = TRUE;  | 
3938  | 0  |       allowHttpOpts = FALSE;  | 
3939  | 0  |     }  | 
3940  |  |  | 
3941  | 0  |     const char* gt = option_starts_with("type:", argval); | 
3942  | 0  |     if (gt)  | 
3943  | 0  |     { | 
3944  | 0  |       if (!parse_gateway_type_option(settings, gt))  | 
3945  | 0  |         goto fail;  | 
3946  | 0  |       validOption = TRUE;  | 
3947  | 0  |       allowHttpOpts = freerdp_settings_get_bool(settings, FreeRDP_GatewayHttpTransport);  | 
3948  | 0  |     }  | 
3949  |  |  | 
3950  | 0  |     const char* gat = option_starts_with("access-token:", argval); | 
3951  | 0  |     if (gat)  | 
3952  | 0  |     { | 
3953  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAccessToken, gat))  | 
3954  | 0  |         goto fail;  | 
3955  | 0  |       validOption = TRUE;  | 
3956  | 0  |       allowHttpOpts = FALSE;  | 
3957  | 0  |     }  | 
3958  |  |  | 
3959  | 0  |     const char* bearer = option_starts_with("bearer:", argval); | 
3960  | 0  |     if (bearer)  | 
3961  | 0  |     { | 
3962  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_GatewayHttpExtAuthBearer, bearer))  | 
3963  | 0  |         goto fail;  | 
3964  | 0  |       validOption = TRUE;  | 
3965  | 0  |       allowHttpOpts = FALSE;  | 
3966  | 0  |     }  | 
3967  |  |  | 
3968  | 0  |     const char* gwurl = option_starts_with("url:", argval); | 
3969  | 0  |     if (gwurl)  | 
3970  | 0  |     { | 
3971  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_GatewayUrl, gwurl))  | 
3972  | 0  |         goto fail;  | 
3973  | 0  |       if (!freerdp_set_gateway_usage_method(settings, TSC_PROXY_MODE_DIRECT))  | 
3974  | 0  |         goto fail;  | 
3975  | 0  |       validOption = TRUE;  | 
3976  | 0  |       allowHttpOpts = FALSE;  | 
3977  | 0  |     }  | 
3978  |  |  | 
3979  | 0  |     const char* um = option_starts_with("usage-method:", argval); | 
3980  | 0  |     if (um)  | 
3981  | 0  |     { | 
3982  | 0  |       if (!parse_gateway_usage_option(settings, um))  | 
3983  | 0  |         goto fail;  | 
3984  | 0  |       validOption = TRUE;  | 
3985  | 0  |       allowHttpOpts = FALSE;  | 
3986  | 0  |     }  | 
3987  |  |  | 
3988  | 0  |     if (allowHttpOpts)  | 
3989  | 0  |     { | 
3990  | 0  |       if (option_equals(argval, "no-websockets"))  | 
3991  | 0  |       { | 
3992  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, FALSE))  | 
3993  | 0  |           goto fail;  | 
3994  | 0  |         validOption = TRUE;  | 
3995  | 0  |       }  | 
3996  | 0  |       else if (option_equals(argval, "extauth-sspi-ntlm"))  | 
3997  | 0  |       { | 
3998  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpExtAuthSspiNtlm, TRUE))  | 
3999  | 0  |           goto fail;  | 
4000  | 0  |         validOption = TRUE;  | 
4001  | 0  |       }  | 
4002  | 0  |     }  | 
4003  |  |  | 
4004  | 0  |     if (!validOption)  | 
4005  | 0  |       goto fail;  | 
4006  | 0  |   }  | 
4007  |  |  | 
4008  | 0  |   rc = TRUE;  | 
4009  | 0  | fail:  | 
4010  | 0  |   free(args);  | 
4011  | 0  |   return rc;  | 
4012  | 0  | }  | 
4013  |  |  | 
4014  |  | static void fill_credential_string(COMMAND_LINE_ARGUMENT_A* args, const char* value)  | 
4015  | 0  | { | 
4016  | 0  |   WINPR_ASSERT(args);  | 
4017  | 0  |   WINPR_ASSERT(value);  | 
4018  |  |  | 
4019  | 0  |   const COMMAND_LINE_ARGUMENT_A* arg = CommandLineFindArgumentA(args, value);  | 
4020  | 0  |   if (!arg)  | 
4021  | 0  |     return;  | 
4022  |  |  | 
4023  | 0  |   if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
4024  | 0  |     FillMemory(arg->Value, strlen(arg->Value), '*');  | 
4025  | 0  | }  | 
4026  |  |  | 
4027  |  | static void fill_credential_strings(COMMAND_LINE_ARGUMENT_A* args)  | 
4028  | 0  | { | 
4029  | 0  |   const char* credentials[] = { | 
4030  | 0  |     "p",  | 
4031  | 0  |     "smartcard-logon",  | 
4032  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
4033  |  |     "gp",  | 
4034  |  |     "gat",  | 
4035  |  | #endif  | 
4036  | 0  |     "pth",  | 
4037  | 0  |     "reconnect-cookie",  | 
4038  | 0  |     "assistance"  | 
4039  | 0  |   };  | 
4040  |  | 
  | 
4041  | 0  |   for (size_t x = 0; x < ARRAYSIZE(credentials); x++)  | 
4042  | 0  |   { | 
4043  | 0  |     const char* cred = credentials[x];  | 
4044  | 0  |     fill_credential_string(args, cred);  | 
4045  | 0  |   }  | 
4046  |  | 
  | 
4047  | 0  |   const COMMAND_LINE_ARGUMENT_A* arg = CommandLineFindArgumentA(args, "gateway");  | 
4048  | 0  |   if (arg && ((arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT) != 0))  | 
4049  | 0  |   { | 
4050  | 0  |     const char* gwcreds[] = { "p:", "access-token:" }; | 
4051  | 0  |     char* tok = strtok(arg->Value, ",");  | 
4052  | 0  |     while (tok)  | 
4053  | 0  |     { | 
4054  | 0  |       for (size_t x = 0; x < ARRAYSIZE(gwcreds); x++)  | 
4055  | 0  |       { | 
4056  | 0  |         const char* opt = gwcreds[x];  | 
4057  | 0  |         if (option_starts_with(opt, tok))  | 
4058  | 0  |         { | 
4059  | 0  |           char* val = &tok[strlen(opt)];  | 
4060  | 0  |           FillMemory(val, strlen(val), '*');  | 
4061  | 0  |         }  | 
4062  | 0  |       }  | 
4063  | 0  |       tok = strtok(NULL, ",");  | 
4064  | 0  |     }  | 
4065  | 0  |   }  | 
4066  | 0  | }  | 
4067  |  |  | 
4068  |  | static int freerdp_client_settings_parse_command_line_arguments_int(  | 
4069  |  |     rdpSettings* settings, int argc, char* argv[], BOOL allowUnknown,  | 
4070  |  |     COMMAND_LINE_ARGUMENT_A* largs, size_t count,  | 
4071  |  |     int (*handle_option)(const COMMAND_LINE_ARGUMENT* arg, void* custom), void* handle_userdata)  | 
4072  | 0  | { | 
4073  | 0  |   char* user = NULL;  | 
4074  | 0  |   int status = 0;  | 
4075  | 0  |   BOOL ext = FALSE;  | 
4076  | 0  |   BOOL assist = FALSE;  | 
4077  | 0  |   DWORD flags = 0;  | 
4078  | 0  |   BOOL promptForPassword = FALSE;  | 
4079  | 0  |   BOOL compatibility = FALSE;  | 
4080  | 0  |   const COMMAND_LINE_ARGUMENT_A* arg = NULL;  | 
4081  |  |  | 
4082  |  |   /* Command line detection fails if only a .rdp or .msrcIncident file  | 
4083  |  |    * is supplied. Check this case first, only then try to detect  | 
4084  |  |    * legacy command line syntax. */  | 
4085  | 0  |   if (argc > 1)  | 
4086  | 0  |   { | 
4087  | 0  |     ext = option_is_rdp_file(argv[1]);  | 
4088  | 0  |     assist = option_is_incident_file(argv[1]);  | 
4089  | 0  |   }  | 
4090  |  | 
  | 
4091  | 0  |   if (!ext && !assist)  | 
4092  | 0  |     compatibility = freerdp_client_detect_command_line(argc, argv, &flags);  | 
4093  | 0  |   else  | 
4094  | 0  |     compatibility = freerdp_client_detect_command_line(argc - 1, &argv[1], &flags);  | 
4095  |  | 
  | 
4096  | 0  |   freerdp_settings_set_string(settings, FreeRDP_ProxyHostname, NULL);  | 
4097  | 0  |   freerdp_settings_set_string(settings, FreeRDP_ProxyUsername, NULL);  | 
4098  | 0  |   freerdp_settings_set_string(settings, FreeRDP_ProxyPassword, NULL);  | 
4099  |  | 
  | 
4100  | 0  |   if (compatibility)  | 
4101  | 0  |   { | 
4102  | 0  |     WLog_WARN(TAG, "Unsupported command line syntax!");  | 
4103  | 0  |     WLog_WARN(TAG, "FreeRDP 1.0 style syntax was dropped with version 3!");  | 
4104  | 0  |     return -1;  | 
4105  | 0  |   }  | 
4106  | 0  |   else  | 
4107  | 0  |   { | 
4108  | 0  |     if (allowUnknown)  | 
4109  | 0  |       flags |= COMMAND_LINE_IGN_UNKNOWN_KEYWORD;  | 
4110  |  | 
  | 
4111  | 0  |     if (ext)  | 
4112  | 0  |     { | 
4113  | 0  |       if (freerdp_client_settings_parse_connection_file(settings, argv[1]))  | 
4114  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4115  | 0  |     }  | 
4116  |  |  | 
4117  | 0  |     if (assist)  | 
4118  | 0  |     { | 
4119  | 0  |       if (freerdp_client_settings_parse_assistance_file(settings, argc, argv) < 0)  | 
4120  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4121  | 0  |     }  | 
4122  |  |  | 
4123  | 0  |     CommandLineClearArgumentsA(largs);  | 
4124  | 0  |     status = CommandLineParseArgumentsA(argc, argv, largs, flags, settings,  | 
4125  | 0  |                                         freerdp_client_command_line_pre_filter,  | 
4126  | 0  |                                         freerdp_client_command_line_post_filter);  | 
4127  |  | 
  | 
4128  | 0  |     if (status < 0)  | 
4129  | 0  |       return status;  | 
4130  |  |  | 
4131  | 0  |     prepare_default_settings(settings, largs, ext);  | 
4132  | 0  |   }  | 
4133  |  |  | 
4134  | 0  |   CommandLineFindArgumentA(largs, "v");  | 
4135  | 0  |   arg = largs;  | 
4136  | 0  |   errno = 0;  | 
4137  |  |  | 
4138  |  |   /* Disable unicode input unless requested. */  | 
4139  | 0  |   if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, FALSE))  | 
4140  | 0  |     return COMMAND_LINE_ERROR_MEMORY;  | 
4141  |  |  | 
4142  | 0  |   do  | 
4143  | 0  |   { | 
4144  | 0  |     BOOL enable = arg->Value ? TRUE : FALSE;  | 
4145  |  | 
  | 
4146  | 0  |     if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))  | 
4147  | 0  |       continue;  | 
4148  |  |  | 
4149  | 0  |     CommandLineSwitchStart(arg)  | 
4150  |  |  | 
4151  | 0  |         CommandLineSwitchCase(arg, "v")  | 
4152  | 0  |     { | 
4153  | 0  |       const int rc = parse_host_options(settings, arg);  | 
4154  | 0  |       if (rc != 0)  | 
4155  | 0  |         return rc;  | 
4156  | 0  |     }  | 
4157  | 0  |     CommandLineSwitchCase(arg, "spn-class")  | 
4158  | 0  |     { | 
4159  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_AuthenticationServiceClass,  | 
4160  | 0  |                                        arg->Value))  | 
4161  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4162  | 0  |     }  | 
4163  | 0  |     CommandLineSwitchCase(arg, "sspi-module")  | 
4164  | 0  |     { | 
4165  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_SspiModule, arg->Value))  | 
4166  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4167  | 0  |     }  | 
4168  | 0  |     CommandLineSwitchCase(arg, "winscard-module")  | 
4169  | 0  |     { | 
4170  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_WinSCardModule, arg->Value))  | 
4171  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4172  | 0  |     }  | 
4173  | 0  |     CommandLineSwitchCase(arg, "redirect-prefer")  | 
4174  | 0  |     { | 
4175  | 0  |       const int rc = parse_redirect_prefer_options(settings, arg);  | 
4176  | 0  |       if (rc != 0)  | 
4177  | 0  |         return rc;  | 
4178  | 0  |     }  | 
4179  | 0  |     CommandLineSwitchCase(arg, "credentials-delegation")  | 
4180  | 0  |     { | 
4181  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_DisableCredentialsDelegation, !enable))  | 
4182  | 0  |         return COMMAND_LINE_ERROR;  | 
4183  | 0  |     }  | 
4184  | 0  |     CommandLineSwitchCase(arg, "prevent-session-lock")  | 
4185  | 0  |     { | 
4186  | 0  |       const int rc = parse_prevent_session_lock_options(settings, arg);  | 
4187  | 0  |       if (rc != 0)  | 
4188  | 0  |         return rc;  | 
4189  | 0  |     }  | 
4190  | 0  |     CommandLineSwitchCase(arg, "vmconnect")  | 
4191  | 0  |     { | 
4192  | 0  |       const int rc = parse_vmconnect_options(settings, arg);  | 
4193  | 0  |       if (rc != 0)  | 
4194  | 0  |         return rc;  | 
4195  | 0  |     }  | 
4196  | 0  |     CommandLineSwitchCase(arg, "w")  | 
4197  | 0  |     { | 
4198  | 0  |       LONGLONG val = 0;  | 
4199  |  | 
  | 
4200  | 0  |       if (!value_to_int(arg->Value, &val, -1, UINT32_MAX))  | 
4201  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4202  |  |  | 
4203  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, (UINT32)val))  | 
4204  | 0  |         return COMMAND_LINE_ERROR;  | 
4205  | 0  |     }  | 
4206  | 0  |     CommandLineSwitchCase(arg, "h")  | 
4207  | 0  |     { | 
4208  | 0  |       LONGLONG val = 0;  | 
4209  |  | 
  | 
4210  | 0  |       if (!value_to_int(arg->Value, &val, -1, UINT32_MAX))  | 
4211  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4212  |  |  | 
4213  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, (UINT32)val))  | 
4214  | 0  |         return COMMAND_LINE_ERROR;  | 
4215  | 0  |     }  | 
4216  | 0  |     CommandLineSwitchCase(arg, "size")  | 
4217  | 0  |     { | 
4218  | 0  |       const int rc = parse_size_options(settings, arg);  | 
4219  | 0  |       if (rc != 0)  | 
4220  | 0  |         return rc;  | 
4221  | 0  |     }  | 
4222  | 0  |     CommandLineSwitchCase(arg, "f")  | 
4223  | 0  |     { | 
4224  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_Fullscreen, enable))  | 
4225  | 0  |         return COMMAND_LINE_ERROR;  | 
4226  | 0  |     }  | 
4227  | 0  |     CommandLineSwitchCase(arg, "suppress-output")  | 
4228  | 0  |     { | 
4229  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_SuppressOutput, enable))  | 
4230  | 0  |         return COMMAND_LINE_ERROR;  | 
4231  | 0  |     }  | 
4232  | 0  |     CommandLineSwitchCase(arg, "multimon")  | 
4233  | 0  |     { | 
4234  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_UseMultimon, TRUE))  | 
4235  | 0  |         return COMMAND_LINE_ERROR;  | 
4236  |  |  | 
4237  | 0  |       if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
4238  | 0  |       { | 
4239  | 0  |         if (option_equals(arg->Value, "force"))  | 
4240  | 0  |         { | 
4241  | 0  |           if (!freerdp_settings_set_bool(settings, FreeRDP_ForceMultimon, TRUE))  | 
4242  | 0  |             return COMMAND_LINE_ERROR;  | 
4243  | 0  |         }  | 
4244  | 0  |       }  | 
4245  | 0  |     }  | 
4246  | 0  |     CommandLineSwitchCase(arg, "span")  | 
4247  | 0  |     { | 
4248  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_SpanMonitors, enable))  | 
4249  | 0  |         return COMMAND_LINE_ERROR;  | 
4250  | 0  |     }  | 
4251  | 0  |     CommandLineSwitchCase(arg, "workarea")  | 
4252  | 0  |     { | 
4253  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_Workarea, enable))  | 
4254  | 0  |         return COMMAND_LINE_ERROR;  | 
4255  | 0  |     }  | 
4256  | 0  |     CommandLineSwitchCase(arg, "monitors")  | 
4257  | 0  |     { | 
4258  | 0  |       const int rc = parse_monitors_options(settings, arg);  | 
4259  | 0  |       if (rc != 0)  | 
4260  | 0  |         return rc;  | 
4261  | 0  |     }  | 
4262  | 0  |     CommandLineSwitchCase(arg, "t")  | 
4263  | 0  |     { | 
4264  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_WindowTitle, arg->Value))  | 
4265  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4266  | 0  |     }  | 
4267  | 0  |     CommandLineSwitchCase(arg, "decorations")  | 
4268  | 0  |     { | 
4269  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_Decorations, enable))  | 
4270  | 0  |         return COMMAND_LINE_ERROR;  | 
4271  | 0  |     }  | 
4272  | 0  |     CommandLineSwitchCase(arg, "dynamic-resolution")  | 
4273  | 0  |     { | 
4274  | 0  |       const int rc = parse_dynamic_resolution_options(settings, arg);  | 
4275  | 0  |       if (rc != 0)  | 
4276  | 0  |         return rc;  | 
4277  | 0  |     }  | 
4278  | 0  |     CommandLineSwitchCase(arg, "smart-sizing")  | 
4279  | 0  |     { | 
4280  | 0  |       const int rc = parse_smart_sizing_options(settings, arg);  | 
4281  | 0  |       if (rc != 0)  | 
4282  | 0  |         return rc;  | 
4283  | 0  |     }  | 
4284  | 0  |     CommandLineSwitchCase(arg, "bpp")  | 
4285  | 0  |     { | 
4286  | 0  |       const int rc = parse_bpp_options(settings, arg);  | 
4287  | 0  |       if (rc != 0)  | 
4288  | 0  |         return rc;  | 
4289  | 0  |     }  | 
4290  | 0  |     CommandLineSwitchCase(arg, "admin")  | 
4291  | 0  |     { | 
4292  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_ConsoleSession, enable))  | 
4293  | 0  |         return COMMAND_LINE_ERROR;  | 
4294  | 0  |     }  | 
4295  | 0  |     CommandLineSwitchCase(arg, "relax-order-checks")  | 
4296  | 0  |     { | 
4297  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AllowUnanouncedOrdersFromServer,  | 
4298  | 0  |                                      enable))  | 
4299  | 0  |         return COMMAND_LINE_ERROR;  | 
4300  | 0  |     }  | 
4301  | 0  |     CommandLineSwitchCase(arg, "restricted-admin")  | 
4302  | 0  |     { | 
4303  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_ConsoleSession, enable))  | 
4304  | 0  |         return COMMAND_LINE_ERROR;  | 
4305  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_RestrictedAdminModeRequired, enable))  | 
4306  | 0  |         return COMMAND_LINE_ERROR;  | 
4307  | 0  |     }  | 
4308  | 0  |     CommandLineSwitchCase(arg, "pth")  | 
4309  | 0  |     { | 
4310  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_ConsoleSession, TRUE))  | 
4311  | 0  |         return COMMAND_LINE_ERROR;  | 
4312  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_RestrictedAdminModeRequired, TRUE))  | 
4313  | 0  |         return COMMAND_LINE_ERROR;  | 
4314  |  |  | 
4315  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_PasswordHash, arg->Value))  | 
4316  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4317  | 0  |     }  | 
4318  | 0  |     CommandLineSwitchCase(arg, "client-hostname")  | 
4319  | 0  |     { | 
4320  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, arg->Value))  | 
4321  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4322  | 0  |     }  | 
4323  | 0  |     CommandLineSwitchCase(arg, "kbd")  | 
4324  | 0  |     { | 
4325  | 0  |       int rc = parse_kbd_options(settings, arg);  | 
4326  | 0  |       if (rc != 0)  | 
4327  | 0  |         return rc;  | 
4328  | 0  |     }  | 
4329  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
4330  |  |     CommandLineSwitchCase(arg, "kbd-remap")  | 
4331  |  |     { | 
4332  |  |       WLog_WARN(TAG, "/kbd-remap:<key>=<value>,<key2>=<value2> is deprecated, use "  | 
4333  |  |                      "/kbd:remap:<key>=<value>,remap:<key2>=<value2>,... instead");  | 
4334  |  |       if (!freerdp_settings_set_string(settings, FreeRDP_KeyboardRemappingList, arg->Value))  | 
4335  |  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4336  |  |     }  | 
4337  |  |     CommandLineSwitchCase(arg, "kbd-lang")  | 
4338  |  |     { | 
4339  |  |       LONGLONG val = 0;  | 
4340  |  |  | 
4341  |  |       WLog_WARN(TAG, "/kbd-lang:<value> is deprecated, use /kbd:lang:<value> instead");  | 
4342  |  |       if (!value_to_int(arg->Value, &val, 1, UINT32_MAX))  | 
4343  |  |       { | 
4344  |  |         WLog_ERR(TAG, "Could not identify keyboard active language %s", arg->Value);  | 
4345  |  |         WLog_ERR(TAG, "Use /list:kbd-lang to list available layouts");  | 
4346  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4347  |  |       }  | 
4348  |  |  | 
4349  |  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardCodePage, (UINT32)val))  | 
4350  |  |         return COMMAND_LINE_ERROR;  | 
4351  |  |     }  | 
4352  |  |     CommandLineSwitchCase(arg, "kbd-type")  | 
4353  |  |     { | 
4354  |  |       LONGLONG val = 0;  | 
4355  |  |  | 
4356  |  |       WLog_WARN(TAG, "/kbd-type:<value> is deprecated, use /kbd:type:<value> instead");  | 
4357  |  |       if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))  | 
4358  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4359  |  |  | 
4360  |  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardType, (UINT32)val))  | 
4361  |  |         return COMMAND_LINE_ERROR;  | 
4362  |  |     }  | 
4363  |  |     CommandLineSwitchCase(arg, "kbd-unicode")  | 
4364  |  |     { | 
4365  |  |       WLog_WARN(TAG, "/kbd-unicode is deprecated, use /kbd:unicode[:on|off] instead");  | 
4366  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, enable))  | 
4367  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4368  |  |     }  | 
4369  |  |     CommandLineSwitchCase(arg, "kbd-subtype")  | 
4370  |  |     { | 
4371  |  |       LONGLONG val = 0;  | 
4372  |  |  | 
4373  |  |       WLog_WARN(TAG, "/kbd-subtype:<value> is deprecated, use /kbd:subtype:<value> instead");  | 
4374  |  |       if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))  | 
4375  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4376  |  |  | 
4377  |  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardSubType, (UINT32)val))  | 
4378  |  |         return COMMAND_LINE_ERROR;  | 
4379  |  |     }  | 
4380  |  |     CommandLineSwitchCase(arg, "kbd-fn-key")  | 
4381  |  |     { | 
4382  |  |       LONGLONG val = 0;  | 
4383  |  |  | 
4384  |  |       WLog_WARN(TAG, "/kbd-fn-key:<value> is deprecated, use /kbd:fn-key:<value> instead");  | 
4385  |  |       if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))  | 
4386  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4387  |  |  | 
4388  |  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardFunctionKey, (UINT32)val))  | 
4389  |  |         return COMMAND_LINE_ERROR;  | 
4390  |  |     }  | 
4391  |  | #endif  | 
4392  | 0  |     CommandLineSwitchCase(arg, "u")  | 
4393  | 0  |     { | 
4394  | 0  |       WINPR_ASSERT(arg->Value);  | 
4395  | 0  |       user = arg->Value;  | 
4396  | 0  |     }  | 
4397  | 0  |     CommandLineSwitchCase(arg, "d")  | 
4398  | 0  |     { | 
4399  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_Domain, arg->Value))  | 
4400  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4401  | 0  |     }  | 
4402  | 0  |     CommandLineSwitchCase(arg, "p")  | 
4403  | 0  |     { | 
4404  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_Password, arg->Value))  | 
4405  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4406  | 0  |     }  | 
4407  | 0  |     CommandLineSwitchCase(arg, "gateway")  | 
4408  | 0  |     { | 
4409  | 0  |       if (!parse_gateway_options(settings, arg))  | 
4410  | 0  |         return COMMAND_LINE_ERROR;  | 
4411  | 0  |     }  | 
4412  | 0  |     CommandLineSwitchCase(arg, "proxy")  | 
4413  | 0  |     { | 
4414  | 0  |       const int rc = parse_proxy_options(settings, arg);  | 
4415  | 0  |       if (rc != 0)  | 
4416  | 0  |         return rc;  | 
4417  | 0  |     }  | 
4418  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
4419  |  |     CommandLineSwitchCase(arg, "g")  | 
4420  |  |     { | 
4421  |  |       if (!parse_gateway_host_option(settings, arg->Value))  | 
4422  |  |         return FALSE;  | 
4423  |  |     }  | 
4424  |  |     CommandLineSwitchCase(arg, "gu")  | 
4425  |  |     { | 
4426  |  |       if (!parse_gateway_cred_option(settings, arg->Value, FreeRDP_GatewayUsername))  | 
4427  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4428  |  |     }  | 
4429  |  |     CommandLineSwitchCase(arg, "gd")  | 
4430  |  |     { | 
4431  |  |       if (!parse_gateway_cred_option(settings, arg->Value, FreeRDP_GatewayDomain))  | 
4432  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4433  |  |     }  | 
4434  |  |     CommandLineSwitchCase(arg, "gp")  | 
4435  |  |     { | 
4436  |  |       if (!parse_gateway_cred_option(settings, arg->Value, FreeRDP_GatewayPassword))  | 
4437  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4438  |  |     }  | 
4439  |  |     CommandLineSwitchCase(arg, "gt")  | 
4440  |  |     { | 
4441  |  |       if (!parse_gateway_type_option(settings, arg->Value))  | 
4442  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4443  |  |     }  | 
4444  |  |     CommandLineSwitchCase(arg, "gat")  | 
4445  |  |     { | 
4446  |  |       if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAccessToken, arg->Value))  | 
4447  |  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4448  |  |     }  | 
4449  |  |     CommandLineSwitchCase(arg, "gateway-usage-method")  | 
4450  |  |     { | 
4451  |  |       if (!parse_gateway_usage_option(settings, arg->Value))  | 
4452  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4453  |  |     }  | 
4454  |  | #endif  | 
4455  | 0  |     CommandLineSwitchCase(arg, "app")  | 
4456  | 0  |     { | 
4457  | 0  |       int rc = parse_app_options(settings, arg);  | 
4458  | 0  |       if (rc != 0)  | 
4459  | 0  |         return rc;  | 
4460  | 0  |     }  | 
4461  | 0  |     CommandLineSwitchCase(arg, "load-balance-info")  | 
4462  | 0  |     { | 
4463  | 0  |       if (!freerdp_settings_set_pointer_len(settings, FreeRDP_LoadBalanceInfo, arg->Value,  | 
4464  | 0  |                                             strlen(arg->Value)))  | 
4465  | 0  |         return COMMAND_LINE_ERROR;  | 
4466  | 0  |     }  | 
4467  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
4468  |  |     CommandLineSwitchCase(arg, "app-workdir")  | 
4469  |  |     { | 
4470  |  |       WLog_WARN(  | 
4471  |  |           TAG,  | 
4472  |  |           "/app-workdir:<directory> is deprecated, use /app:workdir:<directory> instead");  | 
4473  |  |       if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationWorkingDir,  | 
4474  |  |                                        arg->Value))  | 
4475  |  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4476  |  |     }  | 
4477  |  |     CommandLineSwitchCase(arg, "app-name")  | 
4478  |  |     { | 
4479  |  |       WLog_WARN(TAG, "/app-name:<directory> is deprecated, use /app:name:<name> instead");  | 
4480  |  |       if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationName, arg->Value))  | 
4481  |  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4482  |  |     }  | 
4483  |  |     CommandLineSwitchCase(arg, "app-icon")  | 
4484  |  |     { | 
4485  |  |       WLog_WARN(TAG, "/app-icon:<filename> is deprecated, use /app:icon:<filename> instead");  | 
4486  |  |       if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationIcon, arg->Value))  | 
4487  |  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4488  |  |     }  | 
4489  |  |     CommandLineSwitchCase(arg, "app-cmd")  | 
4490  |  |     { | 
4491  |  |       WLog_WARN(TAG, "/app-cmd:<command> is deprecated, use /app:cmd:<command> instead");  | 
4492  |  |       if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationCmdLine,  | 
4493  |  |                                        arg->Value))  | 
4494  |  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4495  |  |     }  | 
4496  |  |     CommandLineSwitchCase(arg, "app-file")  | 
4497  |  |     { | 
4498  |  |       WLog_WARN(TAG, "/app-file:<filename> is deprecated, use /app:file:<filename> instead");  | 
4499  |  |       if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationFile, arg->Value))  | 
4500  |  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4501  |  |     }  | 
4502  |  |     CommandLineSwitchCase(arg, "app-guid")  | 
4503  |  |     { | 
4504  |  |       WLog_WARN(TAG, "/app-guid:<guid> is deprecated, use /app:guid:<guid> instead");  | 
4505  |  |       if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationGuid, arg->Value))  | 
4506  |  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4507  |  |     }  | 
4508  |  | #endif  | 
4509  | 0  |     CommandLineSwitchCase(arg, "compression")  | 
4510  | 0  |     { | 
4511  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, enable))  | 
4512  | 0  |         return COMMAND_LINE_ERROR;  | 
4513  | 0  |     }  | 
4514  | 0  |     CommandLineSwitchCase(arg, "compression-level")  | 
4515  | 0  |     { | 
4516  | 0  |       LONGLONG val = 0;  | 
4517  |  | 
  | 
4518  | 0  |       if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))  | 
4519  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4520  |  |  | 
4521  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_CompressionLevel, (UINT32)val))  | 
4522  | 0  |         return COMMAND_LINE_ERROR;  | 
4523  | 0  |     }  | 
4524  | 0  |     CommandLineSwitchCase(arg, "drives")  | 
4525  | 0  |     { | 
4526  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectDrives, enable))  | 
4527  | 0  |         return COMMAND_LINE_ERROR;  | 
4528  | 0  |     }  | 
4529  | 0  |     CommandLineSwitchCase(arg, "dump")  | 
4530  | 0  |     { | 
4531  | 0  |       const int rc = parse_dump_options(settings, arg);  | 
4532  | 0  |       if (rc != 0)  | 
4533  | 0  |         return rc;  | 
4534  | 0  |     }  | 
4535  | 0  |     CommandLineSwitchCase(arg, "disable-output")  | 
4536  | 0  |     { | 
4537  | 0  |       freerdp_settings_set_bool(settings, FreeRDP_DeactivateClientDecoding, enable);  | 
4538  | 0  |     }  | 
4539  | 0  |     CommandLineSwitchCase(arg, "home-drive")  | 
4540  | 0  |     { | 
4541  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectHomeDrive, enable))  | 
4542  | 0  |         return COMMAND_LINE_ERROR;  | 
4543  | 0  |     }  | 
4544  | 0  |     CommandLineSwitchCase(arg, "ipv6")  | 
4545  | 0  |     { | 
4546  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_PreferIPv6OverIPv4, enable))  | 
4547  | 0  |         return COMMAND_LINE_ERROR;  | 
4548  | 0  |     }  | 
4549  | 0  |     CommandLineSwitchCase(arg, "clipboard")  | 
4550  | 0  |     { | 
4551  | 0  |       const int rc = parse_clipboard_options(settings, arg);  | 
4552  | 0  |       if (rc != 0)  | 
4553  | 0  |         return rc;  | 
4554  | 0  |     }  | 
4555  | 0  |     CommandLineSwitchCase(arg, "server-name")  | 
4556  | 0  |     { | 
4557  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_UserSpecifiedServerName, arg->Value))  | 
4558  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4559  | 0  |     }  | 
4560  | 0  |     CommandLineSwitchCase(arg, "shell")  | 
4561  | 0  |     { | 
4562  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_AlternateShell, arg->Value))  | 
4563  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4564  | 0  |     }  | 
4565  | 0  |     CommandLineSwitchCase(arg, "shell-dir")  | 
4566  | 0  |     { | 
4567  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_ShellWorkingDirectory, arg->Value))  | 
4568  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4569  | 0  |     }  | 
4570  | 0  |     CommandLineSwitchCase(arg, "audio-mode")  | 
4571  | 0  |     { | 
4572  | 0  |       const int rc = parse_audio_mode_options(settings, arg);  | 
4573  | 0  |       if (rc != 0)  | 
4574  | 0  |         return rc;  | 
4575  | 0  |     }  | 
4576  | 0  |     CommandLineSwitchCase(arg, "network")  | 
4577  | 0  |     { | 
4578  | 0  |       const int rc = parse_network_options(settings, arg);  | 
4579  | 0  |       if (rc != 0)  | 
4580  | 0  |         return rc;  | 
4581  | 0  |     }  | 
4582  | 0  |     CommandLineSwitchCase(arg, "fonts")  | 
4583  | 0  |     { | 
4584  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, enable))  | 
4585  | 0  |         return COMMAND_LINE_ERROR;  | 
4586  | 0  |     }  | 
4587  | 0  |     CommandLineSwitchCase(arg, "wallpaper")  | 
4588  | 0  |     { | 
4589  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, !enable))  | 
4590  | 0  |         return COMMAND_LINE_ERROR;  | 
4591  | 0  |     }  | 
4592  | 0  |     CommandLineSwitchCase(arg, "window-drag")  | 
4593  | 0  |     { | 
4594  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, !enable))  | 
4595  | 0  |         return COMMAND_LINE_ERROR;  | 
4596  | 0  |     }  | 
4597  | 0  |     CommandLineSwitchCase(arg, "window-position")  | 
4598  | 0  |     { | 
4599  | 0  |       unsigned long x = 0;  | 
4600  | 0  |       unsigned long y = 0;  | 
4601  |  | 
  | 
4602  | 0  |       if (!arg->Value)  | 
4603  | 0  |         return COMMAND_LINE_ERROR_MISSING_ARGUMENT;  | 
4604  |  |  | 
4605  | 0  |       if (!parseSizeValue(arg->Value, &x, &y) || x > UINT16_MAX || y > UINT16_MAX)  | 
4606  | 0  |       { | 
4607  | 0  |         WLog_ERR(TAG, "invalid window-position argument");  | 
4608  | 0  |         return COMMAND_LINE_ERROR_MISSING_ARGUMENT;  | 
4609  | 0  |       }  | 
4610  |  |  | 
4611  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPosX, (UINT32)x))  | 
4612  | 0  |         return COMMAND_LINE_ERROR;  | 
4613  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPosY, (UINT32)y))  | 
4614  | 0  |         return COMMAND_LINE_ERROR;  | 
4615  | 0  |     }  | 
4616  | 0  |     CommandLineSwitchCase(arg, "menu-anims")  | 
4617  | 0  |     { | 
4618  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, !enable))  | 
4619  | 0  |         return COMMAND_LINE_ERROR;  | 
4620  | 0  |     }  | 
4621  | 0  |     CommandLineSwitchCase(arg, "themes")  | 
4622  | 0  |     { | 
4623  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, !enable))  | 
4624  | 0  |         return COMMAND_LINE_ERROR;  | 
4625  | 0  |     }  | 
4626  | 0  |     CommandLineSwitchCase(arg, "timeout")  | 
4627  | 0  |     { | 
4628  | 0  |       ULONGLONG val = 0;  | 
4629  | 0  |       if (!value_to_uint(arg->Value, &val, 1, 600000))  | 
4630  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4631  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_TcpAckTimeout, (UINT32)val))  | 
4632  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4633  | 0  |     }  | 
4634  | 0  |     CommandLineSwitchCase(arg, "aero")  | 
4635  | 0  |     { | 
4636  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, enable))  | 
4637  | 0  |         return COMMAND_LINE_ERROR;  | 
4638  | 0  |     }  | 
4639  | 0  |     CommandLineSwitchCase(arg, "gdi")  | 
4640  | 0  |     { | 
4641  | 0  |       if (option_equals(arg->Value, "sw"))  | 
4642  | 0  |       { | 
4643  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_SoftwareGdi, TRUE))  | 
4644  | 0  |           return COMMAND_LINE_ERROR;  | 
4645  | 0  |       }  | 
4646  | 0  |       else if (option_equals(arg->Value, "hw"))  | 
4647  | 0  |       { | 
4648  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_SoftwareGdi, FALSE))  | 
4649  | 0  |           return COMMAND_LINE_ERROR;  | 
4650  | 0  |       }  | 
4651  | 0  |       else  | 
4652  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4653  | 0  |     }  | 
4654  | 0  |     CommandLineSwitchCase(arg, "gfx")  | 
4655  | 0  |     { | 
4656  | 0  |       int rc = parse_gfx_options(settings, arg);  | 
4657  | 0  |       if (rc != 0)  | 
4658  | 0  |         return rc;  | 
4659  | 0  |     }  | 
4660  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
4661  |  |     CommandLineSwitchCase(arg, "gfx-thin-client")  | 
4662  |  |     { | 
4663  |  |       WLog_WARN(TAG, "/gfx-thin-client is deprecated, use /gfx:thin-client[:on|off] instead");  | 
4664  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_GfxThinClient, enable))  | 
4665  |  |         return COMMAND_LINE_ERROR;  | 
4666  |  |  | 
4667  |  |       if (freerdp_settings_get_bool(settings, FreeRDP_GfxThinClient))  | 
4668  |  |       { | 
4669  |  |         if (!freerdp_settings_set_bool(settings, FreeRDP_GfxSmallCache, TRUE))  | 
4670  |  |           return COMMAND_LINE_ERROR;  | 
4671  |  |       }  | 
4672  |  |  | 
4673  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE))  | 
4674  |  |         return COMMAND_LINE_ERROR;  | 
4675  |  |     }  | 
4676  |  |     CommandLineSwitchCase(arg, "gfx-small-cache")  | 
4677  |  |     { | 
4678  |  |       WLog_WARN(TAG, "/gfx-small-cache is deprecated, use /gfx:small-cache[:on|off] instead");  | 
4679  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_GfxSmallCache, enable))  | 
4680  |  |         return COMMAND_LINE_ERROR;  | 
4681  |  |  | 
4682  |  |       if (enable)  | 
4683  |  |         if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE))  | 
4684  |  |           return COMMAND_LINE_ERROR;  | 
4685  |  |     }  | 
4686  |  |     CommandLineSwitchCase(arg, "gfx-progressive")  | 
4687  |  |     { | 
4688  |  |       WLog_WARN(TAG, "/gfx-progressive is deprecated, use /gfx:progressive[:on|off] instead");  | 
4689  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_GfxProgressive, enable))  | 
4690  |  |         return COMMAND_LINE_ERROR;  | 
4691  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_GfxThinClient, !enable))  | 
4692  |  |         return COMMAND_LINE_ERROR;  | 
4693  |  |  | 
4694  |  |       if (enable)  | 
4695  |  |       { | 
4696  |  |         if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE))  | 
4697  |  |           return COMMAND_LINE_ERROR;  | 
4698  |  |       }  | 
4699  |  |     }  | 
4700  |  | #ifdef WITH_GFX_H264  | 
4701  |  |     CommandLineSwitchCase(arg, "gfx-h264")  | 
4702  |  |     { | 
4703  |  |       WLog_WARN(TAG, "/gfx-h264 is deprecated, use /gfx:avc420 instead");  | 
4704  |  |       int rc = parse_gfx_options(settings, arg);  | 
4705  |  |       if (rc != 0)  | 
4706  |  |         return rc;  | 
4707  |  |     }  | 
4708  |  | #endif  | 
4709  |  | #endif  | 
4710  | 0  |     CommandLineSwitchCase(arg, "rfx")  | 
4711  | 0  |     { | 
4712  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, enable))  | 
4713  | 0  |         return COMMAND_LINE_ERROR;  | 
4714  | 0  |     }  | 
4715  | 0  |     CommandLineSwitchCase(arg, "rfx-mode")  | 
4716  | 0  |     { | 
4717  | 0  |       if (!arg->Value)  | 
4718  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4719  |  |  | 
4720  | 0  |       if (option_equals(arg->Value, "video"))  | 
4721  | 0  |       { | 
4722  | 0  |         if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x00))  | 
4723  | 0  |           return COMMAND_LINE_ERROR;  | 
4724  | 0  |       }  | 
4725  | 0  |       else if (option_equals(arg->Value, "image"))  | 
4726  | 0  |       { | 
4727  | 0  |         if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, TRUE))  | 
4728  | 0  |           return COMMAND_LINE_ERROR;  | 
4729  | 0  |         if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x02))  | 
4730  | 0  |           return COMMAND_LINE_ERROR;  | 
4731  | 0  |       }  | 
4732  | 0  |     }  | 
4733  | 0  |     CommandLineSwitchCase(arg, "frame-ack")  | 
4734  | 0  |     { | 
4735  | 0  |       LONGLONG val = 0;  | 
4736  |  | 
  | 
4737  | 0  |       if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))  | 
4738  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4739  |  |  | 
4740  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_FrameAcknowledge, (UINT32)val))  | 
4741  | 0  |         return COMMAND_LINE_ERROR;  | 
4742  | 0  |     }  | 
4743  | 0  |     CommandLineSwitchCase(arg, "nsc")  | 
4744  | 0  |     { | 
4745  | 0  |       freerdp_settings_set_bool(settings, FreeRDP_NSCodec, enable);  | 
4746  | 0  |     }  | 
4747  |  | #if defined(WITH_JPEG)  | 
4748  |  |     CommandLineSwitchCase(arg, "jpeg")  | 
4749  |  |     { | 
4750  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, enable))  | 
4751  |  |         return COMMAND_LINE_ERROR;  | 
4752  |  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_JpegQuality, 75))  | 
4753  |  |         return COMMAND_LINE_ERROR;  | 
4754  |  |     }  | 
4755  |  |     CommandLineSwitchCase(arg, "jpeg-quality")  | 
4756  |  |     { | 
4757  |  |       LONGLONG val = 0;  | 
4758  |  |  | 
4759  |  |       if (!value_to_int(arg->Value, &val, 0, 100))  | 
4760  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4761  |  |  | 
4762  |  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_JpegQuality, (UINT32)val))  | 
4763  |  |         return COMMAND_LINE_ERROR;  | 
4764  |  |     }  | 
4765  |  | #endif  | 
4766  | 0  |     CommandLineSwitchCase(arg, "nego")  | 
4767  | 0  |     { | 
4768  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_NegotiateSecurityLayer, enable))  | 
4769  | 0  |         return COMMAND_LINE_ERROR;  | 
4770  | 0  |     }  | 
4771  | 0  |     CommandLineSwitchCase(arg, "pcb")  | 
4772  | 0  |     { | 
4773  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_SendPreconnectionPdu, TRUE))  | 
4774  | 0  |         return COMMAND_LINE_ERROR;  | 
4775  |  |  | 
4776  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_PreconnectionBlob, arg->Value))  | 
4777  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4778  | 0  |     }  | 
4779  | 0  |     CommandLineSwitchCase(arg, "pcid")  | 
4780  | 0  |     { | 
4781  | 0  |       LONGLONG val = 0;  | 
4782  |  | 
  | 
4783  | 0  |       if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))  | 
4784  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4785  |  |  | 
4786  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_SendPreconnectionPdu, TRUE))  | 
4787  | 0  |         return COMMAND_LINE_ERROR;  | 
4788  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_PreconnectionId, (UINT32)val))  | 
4789  | 0  |         return COMMAND_LINE_ERROR;  | 
4790  | 0  |     }  | 
4791  |  | #ifdef _WIN32  | 
4792  |  |     CommandLineSwitchCase(arg, "connect-child-session")  | 
4793  |  |     { | 
4794  |  |       if (!freerdp_settings_set_string(settings, FreeRDP_AuthenticationServiceClass,  | 
4795  |  |                                        "vs-debug") ||  | 
4796  |  |           !freerdp_settings_set_string(settings, FreeRDP_ServerHostname, "localhost") ||  | 
4797  |  |           !freerdp_settings_set_string(settings, FreeRDP_AuthenticationPackageList, "ntlm") ||  | 
4798  |  |           !freerdp_settings_set_string(settings, FreeRDP_ClientAddress, "0.0.0.0") ||  | 
4799  |  |           !freerdp_settings_set_bool(settings, FreeRDP_NegotiateSecurityLayer, FALSE) ||  | 
4800  |  |           !freerdp_settings_set_bool(settings, FreeRDP_VmConnectMode, TRUE) ||  | 
4801  |  |           !freerdp_settings_set_bool(settings, FreeRDP_ConnectChildSession, TRUE) ||  | 
4802  |  |           !freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, TRUE) ||  | 
4803  |  |           !freerdp_settings_set_uint32(settings, FreeRDP_AuthenticationLevel, 0) ||  | 
4804  |  |           !freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect, TRUE) ||  | 
4805  |  |           !freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, CONNECTION_TYPE_LAN))  | 
4806  |  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4807  |  |     }  | 
4808  |  | #endif  | 
4809  | 0  |     CommandLineSwitchCase(arg, "sec")  | 
4810  | 0  |     { | 
4811  | 0  |       const int rc = parse_sec_options(settings, arg);  | 
4812  | 0  |       if (rc != 0)  | 
4813  | 0  |         return rc;  | 
4814  | 0  |     }  | 
4815  | 0  |     CommandLineSwitchCase(arg, "encryption-methods")  | 
4816  | 0  |     { | 
4817  | 0  |       const int rc = parse_encryption_methods_options(settings, arg);  | 
4818  | 0  |       if (rc != 0)  | 
4819  | 0  |         return rc;  | 
4820  | 0  |     }  | 
4821  | 0  |     CommandLineSwitchCase(arg, "args-from")  | 
4822  | 0  |     { | 
4823  | 0  |       WLog_ERR(TAG, "/args-from:%s can not be used in combination with other arguments!",  | 
4824  | 0  |                arg->Value);  | 
4825  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4826  | 0  |     }  | 
4827  | 0  |     CommandLineSwitchCase(arg, "from-stdin")  | 
4828  | 0  |     { | 
4829  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_CredentialsFromStdin, TRUE))  | 
4830  | 0  |         return COMMAND_LINE_ERROR;  | 
4831  |  |  | 
4832  | 0  |       if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)  | 
4833  | 0  |       { | 
4834  | 0  |         if (!arg->Value)  | 
4835  | 0  |           return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
4836  | 0  |         promptForPassword = (option_equals(arg->Value, "force"));  | 
4837  |  | 
  | 
4838  | 0  |         if (!promptForPassword)  | 
4839  | 0  |           return COMMAND_LINE_ERROR;  | 
4840  | 0  |       }  | 
4841  | 0  |     }  | 
4842  | 0  |     CommandLineSwitchCase(arg, "log-level")  | 
4843  | 0  |     { | 
4844  | 0  |       wLog* root = WLog_GetRoot();  | 
4845  |  | 
  | 
4846  | 0  |       if (!WLog_SetStringLogLevel(root, arg->Value))  | 
4847  | 0  |         return COMMAND_LINE_ERROR;  | 
4848  | 0  |     }  | 
4849  | 0  |     CommandLineSwitchCase(arg, "log-filters")  | 
4850  | 0  |     { | 
4851  | 0  |       if (!WLog_AddStringLogFilters(arg->Value))  | 
4852  | 0  |         return COMMAND_LINE_ERROR;  | 
4853  | 0  |     }  | 
4854  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
4855  |  |     CommandLineSwitchCase(arg, "sec-rdp")  | 
4856  |  |     { | 
4857  |  |       WLog_WARN(TAG, "/sec-rdp is deprecated, use /sec:rdp[:on|off] instead");  | 
4858  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, enable))  | 
4859  |  |         return COMMAND_LINE_ERROR;  | 
4860  |  |     }  | 
4861  |  |     CommandLineSwitchCase(arg, "sec-tls")  | 
4862  |  |     { | 
4863  |  |       WLog_WARN(TAG, "/sec-tls is deprecated, use /sec:tls[:on|off] instead");  | 
4864  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, enable))  | 
4865  |  |         return COMMAND_LINE_ERROR;  | 
4866  |  |     }  | 
4867  |  |     CommandLineSwitchCase(arg, "sec-nla")  | 
4868  |  |     { | 
4869  |  |       WLog_WARN(TAG, "/sec-nla is deprecated, use /sec:nla[:on|off] instead");  | 
4870  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, enable))  | 
4871  |  |         return COMMAND_LINE_ERROR;  | 
4872  |  |     }  | 
4873  |  |     CommandLineSwitchCase(arg, "sec-ext")  | 
4874  |  |     { | 
4875  |  |       WLog_WARN(TAG, "/sec-ext is deprecated, use /sec:ext[:on|off] instead");  | 
4876  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, enable))  | 
4877  |  |         return COMMAND_LINE_ERROR;  | 
4878  |  |     }  | 
4879  |  | #endif  | 
4880  | 0  |     CommandLineSwitchCase(arg, "tls")  | 
4881  | 0  |     { | 
4882  | 0  |       int rc = parse_tls_options(settings, arg);  | 
4883  | 0  |       if (rc != 0)  | 
4884  | 0  |         return rc;  | 
4885  | 0  |     }  | 
4886  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
4887  |  |     CommandLineSwitchCase(arg, "tls-ciphers")  | 
4888  |  |     { | 
4889  |  |       WLog_WARN(TAG, "/tls-ciphers:<cipher list> is deprecated, use "  | 
4890  |  |                      "/tls:ciphers:<cipher list> instead");  | 
4891  |  |       int rc = parse_tls_cipher_options(settings, arg);  | 
4892  |  |       if (rc != 0)  | 
4893  |  |         return rc;  | 
4894  |  |     }  | 
4895  |  |     CommandLineSwitchCase(arg, "tls-seclevel")  | 
4896  |  |     { | 
4897  |  |       WLog_WARN(TAG,  | 
4898  |  |                 "/tls-seclevel:<level> is deprecated, use /tls:sec-level:<level> instead");  | 
4899  |  |       int rc = parse_tls_cipher_options(settings, arg);  | 
4900  |  |       if (rc != 0)  | 
4901  |  |         return rc;  | 
4902  |  |     }  | 
4903  |  |     CommandLineSwitchCase(arg, "tls-secrets-file")  | 
4904  |  |     { | 
4905  |  |       WLog_WARN(TAG, "/tls-secrets-file:<filename> is deprecated, use "  | 
4906  |  |                      "/tls:secrets-file:<filename> instead");  | 
4907  |  |       int rc = parse_tls_cipher_options(settings, arg);  | 
4908  |  |       if (rc != 0)  | 
4909  |  |         return rc;  | 
4910  |  |     }  | 
4911  |  |     CommandLineSwitchCase(arg, "enforce-tlsv1_2")  | 
4912  |  |     { | 
4913  |  |       WLog_WARN(TAG, "/enforce-tlsv1_2 is deprecated, use /tls:enforce:1.2 instead");  | 
4914  |  |       int rc = parse_tls_cipher_options(settings, arg);  | 
4915  |  |       if (rc != 0)  | 
4916  |  |         return rc;  | 
4917  |  |     }  | 
4918  |  | #endif  | 
4919  | 0  |     CommandLineSwitchCase(arg, "cert")  | 
4920  | 0  |     { | 
4921  | 0  |       const int rc = parse_cert_options(settings, arg);  | 
4922  | 0  |       if (rc != 0)  | 
4923  | 0  |         return rc;  | 
4924  | 0  |     }  | 
4925  |  |  | 
4926  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
4927  |  |     CommandLineSwitchCase(arg, "cert-name")  | 
4928  |  |     { | 
4929  |  |       WLog_WARN(TAG, "/cert-name is deprecated, use /cert:name instead");  | 
4930  |  |       if (!freerdp_settings_set_string(settings, FreeRDP_CertificateName, arg->Value))  | 
4931  |  |         return COMMAND_LINE_ERROR_MEMORY;  | 
4932  |  |     }  | 
4933  |  |     CommandLineSwitchCase(arg, "cert-ignore")  | 
4934  |  |     { | 
4935  |  |       WLog_WARN(TAG, "/cert-ignore is deprecated, use /cert:ignore instead");  | 
4936  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_IgnoreCertificate, enable))  | 
4937  |  |         return COMMAND_LINE_ERROR;  | 
4938  |  |     }  | 
4939  |  |     CommandLineSwitchCase(arg, "cert-tofu")  | 
4940  |  |     { | 
4941  |  |       WLog_WARN(TAG, "/cert-tofu is deprecated, use /cert:tofu instead");  | 
4942  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AutoAcceptCertificate, enable))  | 
4943  |  |         return COMMAND_LINE_ERROR;  | 
4944  |  |     }  | 
4945  |  |     CommandLineSwitchCase(arg, "cert-deny")  | 
4946  |  |     { | 
4947  |  |       WLog_WARN(TAG, "/cert-deny is deprecated, use /cert:deny instead");  | 
4948  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AutoDenyCertificate, enable))  | 
4949  |  |         return COMMAND_LINE_ERROR;  | 
4950  |  |     }  | 
4951  |  | #endif  | 
4952  | 0  |     CommandLineSwitchCase(arg, "authentication")  | 
4953  | 0  |     { | 
4954  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_Authentication, enable))  | 
4955  | 0  |         return COMMAND_LINE_ERROR;  | 
4956  | 0  |     }  | 
4957  | 0  |     CommandLineSwitchCase(arg, "encryption")  | 
4958  | 0  |     { | 
4959  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, !enable))  | 
4960  | 0  |         return COMMAND_LINE_ERROR;  | 
4961  | 0  |     }  | 
4962  | 0  |     CommandLineSwitchCase(arg, "grab-keyboard")  | 
4963  | 0  |     { | 
4964  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_GrabKeyboard, enable))  | 
4965  | 0  |         return COMMAND_LINE_ERROR;  | 
4966  | 0  |     }  | 
4967  | 0  |     CommandLineSwitchCase(arg, "grab-mouse")  | 
4968  | 0  |     { | 
4969  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_GrabMouse, enable))  | 
4970  | 0  |         return COMMAND_LINE_ERROR;  | 
4971  | 0  |     }  | 
4972  | 0  |     CommandLineSwitchCase(arg, "mouse-relative")  | 
4973  | 0  |     { | 
4974  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_MouseUseRelativeMove, enable))  | 
4975  | 0  |         return COMMAND_LINE_ERROR;  | 
4976  | 0  |     }  | 
4977  | 0  |     CommandLineSwitchCase(arg, "mouse")  | 
4978  | 0  |     { | 
4979  | 0  |       const int rc = parse_mouse_options(settings, arg);  | 
4980  | 0  |       if (rc != 0)  | 
4981  | 0  |         return rc;  | 
4982  | 0  |     }  | 
4983  | 0  |     CommandLineSwitchCase(arg, "unmap-buttons")  | 
4984  | 0  |     { | 
4985  | 0  |       freerdp_settings_set_bool(settings, FreeRDP_UnmapButtons, enable);  | 
4986  | 0  |     }  | 
4987  | 0  |     CommandLineSwitchCase(arg, "toggle-fullscreen")  | 
4988  | 0  |     { | 
4989  | 0  |       freerdp_settings_set_bool(settings, FreeRDP_ToggleFullscreen, enable);  | 
4990  | 0  |     }  | 
4991  | 0  |     CommandLineSwitchCase(arg, "force-console-callbacks")  | 
4992  | 0  |     { | 
4993  | 0  |       freerdp_settings_set_bool(settings, FreeRDP_UseCommonStdioCallbacks, enable);  | 
4994  | 0  |     }  | 
4995  | 0  |     CommandLineSwitchCase(arg, "floatbar")  | 
4996  | 0  |     { | 
4997  | 0  |       const int rc = parse_floatbar_options(settings, arg);  | 
4998  | 0  |       if (rc != 0)  | 
4999  | 0  |         return rc;  | 
5000  | 0  |     }  | 
5001  | 0  |     CommandLineSwitchCase(arg, "mouse-motion")  | 
5002  | 0  |     { | 
5003  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_MouseMotion, enable))  | 
5004  | 0  |         return COMMAND_LINE_ERROR;  | 
5005  | 0  |     }  | 
5006  | 0  |     CommandLineSwitchCase(arg, "parent-window")  | 
5007  | 0  |     { | 
5008  | 0  |       ULONGLONG val = 0;  | 
5009  |  | 
  | 
5010  | 0  |       if (!value_to_uint(arg->Value, &val, 0, UINT64_MAX))  | 
5011  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
5012  |  |  | 
5013  | 0  |       if (!freerdp_settings_set_uint64(settings, FreeRDP_ParentWindowId, (UINT64)val))  | 
5014  | 0  |         return COMMAND_LINE_ERROR;  | 
5015  | 0  |     }  | 
5016  | 0  |     CommandLineSwitchCase(arg, "client-build-number")  | 
5017  | 0  |     { | 
5018  | 0  |       ULONGLONG val = 0;  | 
5019  |  | 
  | 
5020  | 0  |       if (!value_to_uint(arg->Value, &val, 0, UINT32_MAX))  | 
5021  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
5022  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_ClientBuild, (UINT32)val))  | 
5023  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
5024  | 0  |     }  | 
5025  | 0  |     CommandLineSwitchCase(arg, "cache")  | 
5026  | 0  |     { | 
5027  | 0  |       int rc = parse_cache_options(settings, arg);  | 
5028  | 0  |       if (rc != 0)  | 
5029  | 0  |         return rc;  | 
5030  | 0  |     }  | 
5031  |  | #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)  | 
5032  |  |     CommandLineSwitchCase(arg, "bitmap-cache")  | 
5033  |  |     { | 
5034  |  |       WLog_WARN(TAG, "/bitmap-cache is deprecated, use /cache:bitmap[:on|off] instead");  | 
5035  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, enable))  | 
5036  |  |         return COMMAND_LINE_ERROR;  | 
5037  |  |     }  | 
5038  |  |     CommandLineSwitchCase(arg, "persist-cache")  | 
5039  |  |     { | 
5040  |  |       WLog_WARN(TAG, "/persist-cache is deprecated, use /cache:persist[:on|off] instead");  | 
5041  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, enable))  | 
5042  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
5043  |  |     }  | 
5044  |  |     CommandLineSwitchCase(arg, "persist-cache-file")  | 
5045  |  |     { | 
5046  |  |       WLog_WARN(TAG, "/persist-cache-file:<filename> is deprecated, use "  | 
5047  |  |                      "/cache:persist-file:<filename> instead");  | 
5048  |  |       if (!freerdp_settings_set_string(settings, FreeRDP_BitmapCachePersistFile, arg->Value))  | 
5049  |  |         return COMMAND_LINE_ERROR_MEMORY;  | 
5050  |  |  | 
5051  |  |       if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, TRUE))  | 
5052  |  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
5053  |  |     }  | 
5054  |  |     CommandLineSwitchCase(arg, "offscreen-cache")  | 
5055  |  |     { | 
5056  |  |       WLog_WARN(TAG, "/bitmap-cache is deprecated, use /cache:bitmap[:on|off] instead");  | 
5057  |  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenSupportLevel,  | 
5058  |  |                                        (UINT32)enable))  | 
5059  |  |         return COMMAND_LINE_ERROR;  | 
5060  |  |     }  | 
5061  |  |     CommandLineSwitchCase(arg, "glyph-cache")  | 
5062  |  |     { | 
5063  |  |       WLog_WARN(TAG, "/glyph-cache is deprecated, use /cache:glyph[:on|off] instead");  | 
5064  |  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel,  | 
5065  |  |                                        arg->Value ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE))  | 
5066  |  |         return COMMAND_LINE_ERROR;  | 
5067  |  |     }  | 
5068  |  |     CommandLineSwitchCase(arg, "codec-cache")  | 
5069  |  |     { | 
5070  |  |       WLog_WARN(TAG,  | 
5071  |  |                 "/codec-cache:<option> is deprecated, use /cache:codec:<option> instead");  | 
5072  |  |       const int rc = parse_codec_cache_options(settings, arg);  | 
5073  |  |       if (rc != 0)  | 
5074  |  |         return rc;  | 
5075  |  |     }  | 
5076  |  | #endif  | 
5077  | 0  |     CommandLineSwitchCase(arg, "max-fast-path-size")  | 
5078  | 0  |     { | 
5079  | 0  |       LONGLONG val = 0;  | 
5080  |  | 
  | 
5081  | 0  |       if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))  | 
5082  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
5083  |  |  | 
5084  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,  | 
5085  | 0  |                                        (UINT32)val))  | 
5086  | 0  |         return COMMAND_LINE_ERROR;  | 
5087  | 0  |     }  | 
5088  | 0  |     CommandLineSwitchCase(arg, "auto-request-control")  | 
5089  | 0  |     { | 
5090  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteAssistanceRequestControl,  | 
5091  | 0  |                                      enable))  | 
5092  | 0  |         return COMMAND_LINE_ERROR;  | 
5093  | 0  |     }  | 
5094  | 0  |     CommandLineSwitchCase(arg, "async-update")  | 
5095  | 0  |     { | 
5096  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AsyncUpdate, enable))  | 
5097  | 0  |         return COMMAND_LINE_ERROR;  | 
5098  | 0  |     }  | 
5099  | 0  |     CommandLineSwitchCase(arg, "async-channels")  | 
5100  | 0  |     { | 
5101  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AsyncChannels, enable))  | 
5102  | 0  |         return COMMAND_LINE_ERROR;  | 
5103  | 0  |     }  | 
5104  | 0  |     CommandLineSwitchCase(arg, "wm-class")  | 
5105  | 0  |     { | 
5106  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_WmClass, arg->Value))  | 
5107  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
5108  | 0  |     }  | 
5109  | 0  |     CommandLineSwitchCase(arg, "play-rfx")  | 
5110  | 0  |     { | 
5111  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_PlayRemoteFxFile, arg->Value))  | 
5112  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
5113  |  |  | 
5114  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_PlayRemoteFx, TRUE))  | 
5115  | 0  |         return COMMAND_LINE_ERROR;  | 
5116  | 0  |     }  | 
5117  | 0  |     CommandLineSwitchCase(arg, "auth-only")  | 
5118  | 0  |     { | 
5119  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AuthenticationOnly, enable))  | 
5120  | 0  |         return COMMAND_LINE_ERROR;  | 
5121  | 0  |     }  | 
5122  | 0  |     CommandLineSwitchCase(arg, "auth-pkg-list")  | 
5123  | 0  |     { | 
5124  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_AuthenticationPackageList,  | 
5125  | 0  |                                        arg->Value))  | 
5126  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
5127  | 0  |     }  | 
5128  | 0  |     CommandLineSwitchCase(arg, "auto-reconnect")  | 
5129  | 0  |     { | 
5130  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_AutoReconnectionEnabled, enable))  | 
5131  | 0  |         return COMMAND_LINE_ERROR;  | 
5132  | 0  |     }  | 
5133  | 0  |     CommandLineSwitchCase(arg, "auto-reconnect-max-retries")  | 
5134  | 0  |     { | 
5135  | 0  |       LONGLONG val = 0;  | 
5136  |  | 
  | 
5137  | 0  |       if (!value_to_int(arg->Value, &val, 0, 1000))  | 
5138  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
5139  |  |  | 
5140  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_AutoReconnectMaxRetries,  | 
5141  | 0  |                                        (UINT32)val))  | 
5142  | 0  |         return COMMAND_LINE_ERROR;  | 
5143  | 0  |     }  | 
5144  | 0  |     CommandLineSwitchCase(arg, "reconnect-cookie")  | 
5145  | 0  |     { | 
5146  | 0  |       const int rc = parse_reconnect_cookie_options(settings, arg);  | 
5147  | 0  |       if (rc != 0)  | 
5148  | 0  |         return rc;  | 
5149  | 0  |     }  | 
5150  | 0  |     CommandLineSwitchCase(arg, "print-reconnect-cookie")  | 
5151  | 0  |     { | 
5152  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_PrintReconnectCookie, enable))  | 
5153  | 0  |         return COMMAND_LINE_ERROR;  | 
5154  | 0  |     }  | 
5155  | 0  |     CommandLineSwitchCase(arg, "pwidth")  | 
5156  | 0  |     { | 
5157  | 0  |       LONGLONG val = 0;  | 
5158  |  | 
  | 
5159  | 0  |       if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))  | 
5160  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
5161  |  |  | 
5162  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPhysicalWidth, (UINT32)val))  | 
5163  | 0  |         return COMMAND_LINE_ERROR;  | 
5164  | 0  |     }  | 
5165  | 0  |     CommandLineSwitchCase(arg, "pheight")  | 
5166  | 0  |     { | 
5167  | 0  |       LONGLONG val = 0;  | 
5168  |  | 
  | 
5169  | 0  |       if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))  | 
5170  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
5171  |  |  | 
5172  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPhysicalHeight, (UINT32)val))  | 
5173  | 0  |         return COMMAND_LINE_ERROR;  | 
5174  | 0  |     }  | 
5175  | 0  |     CommandLineSwitchCase(arg, "orientation")  | 
5176  | 0  |     { | 
5177  | 0  |       LONGLONG val = 0;  | 
5178  |  | 
  | 
5179  | 0  |       if (!value_to_int(arg->Value, &val, 0, UINT16_MAX))  | 
5180  | 0  |         return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
5181  |  |  | 
5182  | 0  |       if (!freerdp_settings_set_uint16(settings, FreeRDP_DesktopOrientation, (UINT16)val))  | 
5183  | 0  |         return COMMAND_LINE_ERROR;  | 
5184  | 0  |     }  | 
5185  | 0  |     CommandLineSwitchCase(arg, "old-license")  | 
5186  | 0  |     { | 
5187  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_OldLicenseBehaviour, TRUE))  | 
5188  | 0  |         return COMMAND_LINE_ERROR;  | 
5189  | 0  |     }  | 
5190  | 0  |     CommandLineSwitchCase(arg, "scale")  | 
5191  | 0  |     { | 
5192  | 0  |       const int rc = parse_scale_options(settings, arg);  | 
5193  | 0  |       if (rc != 0)  | 
5194  | 0  |         return rc;  | 
5195  | 0  |     }  | 
5196  | 0  |     CommandLineSwitchCase(arg, "scale-desktop")  | 
5197  | 0  |     { | 
5198  | 0  |       LONGLONG val = 0;  | 
5199  |  | 
  | 
5200  | 0  |       if (!value_to_int(arg->Value, &val, 100, 500))  | 
5201  | 0  |         return FALSE;  | 
5202  |  |  | 
5203  | 0  |       if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopScaleFactor, (UINT32)val))  | 
5204  | 0  |         return COMMAND_LINE_ERROR;  | 
5205  | 0  |     }  | 
5206  | 0  |     CommandLineSwitchCase(arg, "scale-device")  | 
5207  | 0  |     { | 
5208  | 0  |       const int rc = parse_scale_device_options(settings, arg);  | 
5209  | 0  |       if (rc != 0)  | 
5210  | 0  |         return rc;  | 
5211  | 0  |     }  | 
5212  | 0  |     CommandLineSwitchCase(arg, "action-script")  | 
5213  | 0  |     { | 
5214  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_ActionScript, arg->Value))  | 
5215  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
5216  | 0  |     }  | 
5217  | 0  |     CommandLineSwitchCase(arg, RDP2TCP_DVC_CHANNEL_NAME)  | 
5218  | 0  |     { | 
5219  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_RDP2TCPArgs, arg->Value))  | 
5220  | 0  |         return COMMAND_LINE_ERROR_MEMORY;  | 
5221  | 0  |     }  | 
5222  | 0  |     CommandLineSwitchCase(arg, "fipsmode")  | 
5223  | 0  |     { | 
5224  | 0  |       if (!freerdp_settings_set_bool(settings, FreeRDP_FIPSMode, enable))  | 
5225  | 0  |         return COMMAND_LINE_ERROR;  | 
5226  | 0  |     }  | 
5227  | 0  |     CommandLineSwitchCase(arg, "smartcard-logon")  | 
5228  | 0  |     { | 
5229  | 0  |       const int rc = parse_smartcard_logon_options(settings, arg);  | 
5230  | 0  |       if (rc != 0)  | 
5231  | 0  |         return rc;  | 
5232  | 0  |     }  | 
5233  | 0  |     CommandLineSwitchCase(arg, "tune")  | 
5234  | 0  |     { | 
5235  | 0  |       const int rc = parse_tune_options(settings, arg);  | 
5236  | 0  |       if (rc != 0)  | 
5237  | 0  |         return rc;  | 
5238  | 0  |     }  | 
5239  | 0  |     CommandLineSwitchDefault(arg)  | 
5240  | 0  |     { | 
5241  | 0  |       if (handle_option)  | 
5242  | 0  |       { | 
5243  | 0  |         const int rc = handle_option(arg, handle_userdata);  | 
5244  | 0  |         if (rc != 0)  | 
5245  | 0  |           return rc;  | 
5246  | 0  |       }  | 
5247  | 0  |     }  | 
5248  | 0  |     CommandLineSwitchEnd(arg)  | 
5249  | 0  |   } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);  | 
5250  |  |  | 
5251  | 0  |   if (user)  | 
5252  | 0  |   { | 
5253  | 0  |     if (!freerdp_settings_get_string(settings, FreeRDP_Domain) && user)  | 
5254  | 0  |     { | 
5255  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_Username, NULL))  | 
5256  | 0  |         return COMMAND_LINE_ERROR;  | 
5257  |  |  | 
5258  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_Domain, NULL))  | 
5259  | 0  |         return COMMAND_LINE_ERROR;  | 
5260  |  |  | 
5261  | 0  |       if (!freerdp_parse_username_settings(user, settings, FreeRDP_Username, FreeRDP_Domain))  | 
5262  | 0  |         return COMMAND_LINE_ERROR;  | 
5263  | 0  |     }  | 
5264  | 0  |     else  | 
5265  | 0  |     { | 
5266  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_Username, user))  | 
5267  | 0  |         return COMMAND_LINE_ERROR;  | 
5268  | 0  |     }  | 
5269  | 0  |   }  | 
5270  |  |  | 
5271  | 0  |   if (promptForPassword)  | 
5272  | 0  |   { | 
5273  | 0  |     freerdp* instance = freerdp_settings_get_pointer_writable(settings, FreeRDP_instance);  | 
5274  | 0  |     if (!freerdp_settings_get_string(settings, FreeRDP_Password))  | 
5275  | 0  |     { | 
5276  | 0  |       char buffer[512 + 1] = { 0 }; | 
5277  |  | 
  | 
5278  | 0  |       if (!freerdp_passphrase_read(instance->context, "Password: ", buffer,  | 
5279  | 0  |                                    ARRAYSIZE(buffer) - 1, 1))  | 
5280  | 0  |         return COMMAND_LINE_ERROR;  | 
5281  | 0  |       if (!freerdp_settings_set_string(settings, FreeRDP_Password, buffer))  | 
5282  | 0  |         return COMMAND_LINE_ERROR;  | 
5283  | 0  |     }  | 
5284  |  |  | 
5285  | 0  |     if (freerdp_settings_get_bool(settings, FreeRDP_GatewayEnabled) &&  | 
5286  | 0  |         !freerdp_settings_get_bool(settings, FreeRDP_GatewayUseSameCredentials))  | 
5287  | 0  |     { | 
5288  | 0  |       if (!freerdp_settings_get_string(settings, FreeRDP_GatewayPassword))  | 
5289  | 0  |       { | 
5290  | 0  |         char buffer[512 + 1] = { 0 }; | 
5291  |  | 
  | 
5292  | 0  |         if (!freerdp_passphrase_read(instance->context, "Gateway Password: ", buffer,  | 
5293  | 0  |                                      ARRAYSIZE(buffer) - 1, 1))  | 
5294  | 0  |           return COMMAND_LINE_ERROR;  | 
5295  | 0  |         if (!freerdp_settings_set_string(settings, FreeRDP_GatewayPassword, buffer))  | 
5296  | 0  |           return COMMAND_LINE_ERROR;  | 
5297  | 0  |       }  | 
5298  | 0  |     }  | 
5299  | 0  |   }  | 
5300  |  |  | 
5301  | 0  |   freerdp_performance_flags_make(settings);  | 
5302  |  | 
  | 
5303  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec) ||  | 
5304  | 0  |       freerdp_settings_get_bool(settings, FreeRDP_NSCodec) ||  | 
5305  | 0  |       freerdp_settings_get_bool(settings, FreeRDP_SupportGraphicsPipeline))  | 
5306  | 0  |   { | 
5307  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathOutput, TRUE))  | 
5308  | 0  |       return COMMAND_LINE_ERROR;  | 
5309  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_FrameMarkerCommandEnabled, TRUE))  | 
5310  | 0  |       return COMMAND_LINE_ERROR;  | 
5311  | 0  |   }  | 
5312  |  |  | 
5313  | 0  |   arg = CommandLineFindArgumentA(largs, "port");  | 
5314  | 0  |   if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)  | 
5315  | 0  |   { | 
5316  | 0  |     LONGLONG val = 0;  | 
5317  |  | 
  | 
5318  | 0  |     if (!value_to_int(arg->Value, &val, 1, UINT16_MAX))  | 
5319  | 0  |       return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;  | 
5320  |  |  | 
5321  | 0  |     if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, (UINT32)val))  | 
5322  | 0  |       return COMMAND_LINE_ERROR;  | 
5323  | 0  |   }  | 
5324  |  |  | 
5325  | 0  |   fill_credential_strings(largs);  | 
5326  |  | 
  | 
5327  | 0  |   return status;  | 
5328  | 0  | }  | 
5329  |  |  | 
5330  |  | static void argv_free(int* pargc, char** pargv[])  | 
5331  | 0  | { | 
5332  | 0  |   WINPR_ASSERT(pargc);  | 
5333  | 0  |   WINPR_ASSERT(pargv);  | 
5334  | 0  |   const int argc = *pargc;  | 
5335  | 0  |   char** argv = *pargv;  | 
5336  | 0  |   *pargc = 0;  | 
5337  | 0  |   *pargv = NULL;  | 
5338  |  | 
  | 
5339  | 0  |   if (!argv)  | 
5340  | 0  |     return;  | 
5341  | 0  |   for (int x = 0; x < argc; x++)  | 
5342  | 0  |     free(argv[x]);  | 
5343  | 0  |   free(argv);  | 
5344  | 0  | }  | 
5345  |  |  | 
5346  |  | static BOOL argv_append(int* pargc, char** pargv[], char* what)  | 
5347  | 0  | { | 
5348  | 0  |   WINPR_ASSERT(pargc);  | 
5349  | 0  |   WINPR_ASSERT(pargv);  | 
5350  |  |  | 
5351  | 0  |   if (*pargc < 0)  | 
5352  | 0  |     return FALSE;  | 
5353  |  |  | 
5354  | 0  |   if (!what)  | 
5355  | 0  |     return FALSE;  | 
5356  |  |  | 
5357  | 0  |   int nargc = *pargc + 1;  | 
5358  | 0  |   char** tmp = realloc(*pargv, nargc * sizeof(char*));  | 
5359  | 0  |   if (!tmp)  | 
5360  | 0  |     return FALSE;  | 
5361  |  |  | 
5362  | 0  |   tmp[*pargc] = what;  | 
5363  | 0  |   *pargv = tmp;  | 
5364  | 0  |   *pargc = nargc;  | 
5365  | 0  |   return TRUE;  | 
5366  | 0  | }  | 
5367  |  |  | 
5368  |  | static BOOL argv_append_dup(int* pargc, char** pargv[], const char* what)  | 
5369  | 0  | { | 
5370  | 0  |   char* copy = NULL;  | 
5371  | 0  |   if (what)  | 
5372  | 0  |     copy = _strdup(what);  | 
5373  |  | 
  | 
5374  | 0  |   const BOOL rc = argv_append(pargc, pargv, copy);  | 
5375  | 0  |   if (!rc)  | 
5376  | 0  |     free(copy);  | 
5377  | 0  |   return rc;  | 
5378  | 0  | }  | 
5379  |  |  | 
5380  |  | static BOOL args_from_fp(FILE* fp, int* aargc, char** aargv[], const char* file, const char* cmd)  | 
5381  | 0  | { | 
5382  | 0  |   BOOL success = FALSE;  | 
5383  |  | 
  | 
5384  | 0  |   WINPR_ASSERT(aargc);  | 
5385  | 0  |   WINPR_ASSERT(aargv);  | 
5386  | 0  |   WINPR_ASSERT(cmd);  | 
5387  |  |  | 
5388  | 0  |   if (!fp)  | 
5389  | 0  |   { | 
5390  | 0  |     WLog_ERR(TAG, "Failed to read command line options from file '%s'", file);  | 
5391  | 0  |     return FALSE;  | 
5392  | 0  |   }  | 
5393  | 0  |   if (!argv_append_dup(aargc, aargv, cmd))  | 
5394  | 0  |     goto fail;  | 
5395  | 0  |   while (!feof(fp))  | 
5396  | 0  |   { | 
5397  | 0  |     char* line = NULL;  | 
5398  | 0  |     size_t size = 0;  | 
5399  | 0  |     INT64 rc = GetLine(&line, &size, fp);  | 
5400  | 0  |     if ((rc < 0) || !line)  | 
5401  | 0  |     { | 
5402  |  |       /* abort if GetLine failed due to reaching EOF */  | 
5403  | 0  |       if (feof(fp))  | 
5404  | 0  |         break;  | 
5405  | 0  |       goto fail;  | 
5406  | 0  |     }  | 
5407  |  |  | 
5408  | 0  |     while (rc > 0)  | 
5409  | 0  |     { | 
5410  | 0  |       const char cur = (line[rc - 1]);  | 
5411  | 0  |       if ((cur == '\n') || (cur == '\r'))  | 
5412  | 0  |       { | 
5413  | 0  |         line[rc - 1] = '\0';  | 
5414  | 0  |         rc--;  | 
5415  | 0  |       }  | 
5416  | 0  |       else  | 
5417  | 0  |         break;  | 
5418  | 0  |     }  | 
5419  |  |     /* abort on empty lines */  | 
5420  | 0  |     if (rc == 0)  | 
5421  | 0  |     { | 
5422  | 0  |       free(line);  | 
5423  | 0  |       break;  | 
5424  | 0  |     }  | 
5425  | 0  |     if (!argv_append(aargc, aargv, line))  | 
5426  | 0  |     { | 
5427  | 0  |       free(line);  | 
5428  | 0  |       goto fail;  | 
5429  | 0  |     }  | 
5430  | 0  |   }  | 
5431  |  |  | 
5432  | 0  |   success = TRUE;  | 
5433  | 0  | fail:  | 
5434  | 0  |   fclose(fp);  | 
5435  | 0  |   if (!success)  | 
5436  | 0  |     argv_free(aargc, aargv);  | 
5437  | 0  |   return success;  | 
5438  | 0  | }  | 
5439  |  |  | 
5440  |  | static BOOL args_from_env(const char* name, int* aargc, char** aargv[], const char* arg,  | 
5441  |  |                           const char* cmd)  | 
5442  | 0  | { | 
5443  | 0  |   BOOL success = FALSE;  | 
5444  | 0  |   char* env = NULL;  | 
5445  |  | 
  | 
5446  | 0  |   WINPR_ASSERT(aargc);  | 
5447  | 0  |   WINPR_ASSERT(aargv);  | 
5448  | 0  |   WINPR_ASSERT(cmd);  | 
5449  |  |  | 
5450  | 0  |   if (!name)  | 
5451  | 0  |   { | 
5452  | 0  |     WLog_ERR(TAG, "%s - environment variable name empty", arg);  | 
5453  | 0  |     goto cleanup;  | 
5454  | 0  |   }  | 
5455  |  |  | 
5456  | 0  |   const DWORD size = GetEnvironmentVariableX(name, env, 0);  | 
5457  | 0  |   if (size == 0)  | 
5458  | 0  |   { | 
5459  | 0  |     WLog_ERR(TAG, "%s - no environment variable '%s'", arg, name);  | 
5460  | 0  |     goto cleanup;  | 
5461  | 0  |   }  | 
5462  | 0  |   env = calloc(size + 1, sizeof(char));  | 
5463  | 0  |   if (!env)  | 
5464  | 0  |     goto cleanup;  | 
5465  | 0  |   const DWORD rc = GetEnvironmentVariableX(name, env, size);  | 
5466  | 0  |   if (rc != size - 1)  | 
5467  | 0  |     goto cleanup;  | 
5468  | 0  |   if (rc == 0)  | 
5469  | 0  |   { | 
5470  | 0  |     WLog_ERR(TAG, "%s - environment variable '%s' is empty", arg);  | 
5471  | 0  |     goto cleanup;  | 
5472  | 0  |   }  | 
5473  |  |  | 
5474  | 0  |   if (!argv_append_dup(aargc, aargv, cmd))  | 
5475  | 0  |     goto cleanup;  | 
5476  |  |  | 
5477  | 0  |   char* context = NULL;  | 
5478  | 0  |   char* tok = strtok_s(env, "\n", &context);  | 
5479  | 0  |   while (tok)  | 
5480  | 0  |   { | 
5481  | 0  |     if (!argv_append_dup(aargc, aargv, tok))  | 
5482  | 0  |       goto cleanup;  | 
5483  | 0  |     tok = strtok_s(NULL, "\n", &context);  | 
5484  | 0  |   }  | 
5485  |  |  | 
5486  | 0  |   success = TRUE;  | 
5487  | 0  | cleanup:  | 
5488  | 0  |   free(env);  | 
5489  | 0  |   if (!success)  | 
5490  | 0  |     argv_free(aargc, aargv);  | 
5491  | 0  |   return success;  | 
5492  | 0  | }  | 
5493  |  |  | 
5494  |  | int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, int oargc,  | 
5495  |  |                                                          char* oargv[], BOOL allowUnknown)  | 
5496  | 0  | { | 
5497  | 0  |   return freerdp_client_settings_parse_command_line_arguments_ex(  | 
5498  | 0  |       settings, oargc, oargv, allowUnknown, NULL, 0, NULL, NULL);  | 
5499  | 0  | }  | 
5500  |  |  | 
5501  |  | int freerdp_client_settings_parse_command_line_arguments_ex(  | 
5502  |  |     rdpSettings* settings, int oargc, char** oargv, BOOL allowUnknown,  | 
5503  |  |     COMMAND_LINE_ARGUMENT_A* args, size_t count,  | 
5504  |  |     int (*handle_option)(const COMMAND_LINE_ARGUMENT* arg, void* custom), void* handle_userdata)  | 
5505  | 0  | { | 
5506  | 0  |   int argc = oargc;  | 
5507  | 0  |   char** argv = oargv;  | 
5508  | 0  |   int res = -1;  | 
5509  | 0  |   int aargc = 0;  | 
5510  | 0  |   char** aargv = NULL;  | 
5511  | 0  |   if ((argc == 2) && option_starts_with("/args-from:", argv[1])) | 
5512  | 0  |   { | 
5513  | 0  |     BOOL success = FALSE;  | 
5514  | 0  |     const char* file = strchr(argv[1], ':') + 1;  | 
5515  | 0  |     FILE* fp = stdin;  | 
5516  |  | 
  | 
5517  | 0  |     if (option_starts_with("fd:", file)) | 
5518  | 0  |     { | 
5519  | 0  |       ULONGLONG result = 0;  | 
5520  | 0  |       const char* val = strchr(file, ':') + 1;  | 
5521  | 0  |       if (!value_to_uint(val, &result, 0, INT_MAX))  | 
5522  | 0  |         return -1;  | 
5523  | 0  |       fp = fdopen((int)result, "r");  | 
5524  | 0  |       success = args_from_fp(fp, &aargc, &aargv, file, oargv[0]);  | 
5525  | 0  |     }  | 
5526  | 0  |     else if (strncmp(file, "env:", 4) == 0)  | 
5527  | 0  |     { | 
5528  | 0  |       const char* name = strchr(file, ':') + 1;  | 
5529  | 0  |       success = args_from_env(name, &aargc, &aargv, oargv[1], oargv[0]);  | 
5530  | 0  |     }  | 
5531  | 0  |     else if (strcmp(file, "stdin") != 0)  | 
5532  | 0  |     { | 
5533  | 0  |       fp = winpr_fopen(file, "r");  | 
5534  | 0  |       success = args_from_fp(fp, &aargc, &aargv, file, oargv[0]);  | 
5535  | 0  |     }  | 
5536  | 0  |     else  | 
5537  | 0  |       success = args_from_fp(fp, &aargc, &aargv, file, oargv[0]);  | 
5538  |  |  | 
5539  | 0  |     if (!success)  | 
5540  | 0  |       return -1;  | 
5541  | 0  |     argc = aargc;  | 
5542  | 0  |     argv = aargv;  | 
5543  | 0  |   }  | 
5544  |  |  | 
5545  | 0  |   size_t lcount = 0;  | 
5546  | 0  |   COMMAND_LINE_ARGUMENT_A* largs = create_merged_args(args, count, &lcount);  | 
5547  | 0  |   if (!largs)  | 
5548  | 0  |     goto fail;  | 
5549  |  |  | 
5550  | 0  |   res = freerdp_client_settings_parse_command_line_arguments_int(  | 
5551  | 0  |       settings, argc, argv, allowUnknown, largs, lcount, handle_option, handle_userdata);  | 
5552  | 0  | fail:  | 
5553  | 0  |   free(largs);  | 
5554  | 0  |   argv_free(&aargc, &aargv);  | 
5555  | 0  |   return res;  | 
5556  | 0  | }  | 
5557  |  |  | 
5558  |  | static BOOL freerdp_client_load_static_channel_addin(rdpChannels* channels, rdpSettings* settings,  | 
5559  |  |                                                      const char* name, void* data)  | 
5560  | 0  | { | 
5561  | 0  |   PVIRTUALCHANNELENTRY entry = NULL;  | 
5562  | 0  |   PVIRTUALCHANNELENTRYEX entryEx = NULL;  | 
5563  | 0  |   entryEx = (PVIRTUALCHANNELENTRYEX)(void*)freerdp_load_channel_addin_entry(  | 
5564  | 0  |       name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX);  | 
5565  |  | 
  | 
5566  | 0  |   if (!entryEx)  | 
5567  | 0  |     entry = freerdp_load_channel_addin_entry(name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC);  | 
5568  |  | 
  | 
5569  | 0  |   if (entryEx)  | 
5570  | 0  |   { | 
5571  | 0  |     if (freerdp_channels_client_load_ex(channels, settings, entryEx, data) == 0)  | 
5572  | 0  |     { | 
5573  | 0  |       WLog_DBG(TAG, "loading channelEx %s", name);  | 
5574  | 0  |       return TRUE;  | 
5575  | 0  |     }  | 
5576  | 0  |   }  | 
5577  | 0  |   else if (entry)  | 
5578  | 0  |   { | 
5579  | 0  |     if (freerdp_channels_client_load(channels, settings, entry, data) == 0)  | 
5580  | 0  |     { | 
5581  | 0  |       WLog_DBG(TAG, "loading channel %s", name);  | 
5582  | 0  |       return TRUE;  | 
5583  | 0  |     }  | 
5584  | 0  |   }  | 
5585  |  |  | 
5586  | 0  |   return FALSE;  | 
5587  | 0  | }  | 
5588  |  |  | 
5589  |  | typedef struct  | 
5590  |  | { | 
5591  |  |   FreeRDP_Settings_Keys_Bool settingId;  | 
5592  |  |   const char* channelName;  | 
5593  |  |   void* args;  | 
5594  |  | } ChannelToLoad;  | 
5595  |  |  | 
5596  |  | BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings)  | 
5597  | 0  | { | 
5598  | 0  |   ChannelToLoad dynChannels[] = { | 
5599  | 0  | #if defined(CHANNEL_AINPUT_CLIENT)  | 
5600  | 0  |     { FreeRDP_BOOL_UNUSED, AINPUT_CHANNEL_NAME, NULL }, /* always loaded */ | 
5601  | 0  | #endif  | 
5602  | 0  |     { FreeRDP_AudioCapture, AUDIN_CHANNEL_NAME, NULL }, | 
5603  | 0  |     { FreeRDP_AudioPlayback, RDPSND_CHANNEL_NAME, NULL }, | 
5604  | 0  | #ifdef CHANNEL_RDPEI_CLIENT  | 
5605  | 0  |     { FreeRDP_MultiTouchInput, RDPEI_CHANNEL_NAME, NULL }, | 
5606  | 0  | #endif  | 
5607  | 0  |     { FreeRDP_SupportGraphicsPipeline, RDPGFX_CHANNEL_NAME, NULL }, | 
5608  | 0  |     { FreeRDP_SupportEchoChannel, ECHO_CHANNEL_NAME, NULL }, | 
5609  | 0  |     { FreeRDP_SupportSSHAgentChannel, "sshagent", NULL }, | 
5610  | 0  |     { FreeRDP_SupportDisplayControl, DISP_CHANNEL_NAME, NULL }, | 
5611  | 0  |     { FreeRDP_SupportGeometryTracking, GEOMETRY_CHANNEL_NAME, NULL }, | 
5612  | 0  |     { FreeRDP_SupportVideoOptimized, VIDEO_CHANNEL_NAME, NULL }, | 
5613  | 0  |   };  | 
5614  |  | 
  | 
5615  | 0  |   ChannelToLoad staticChannels[] = { | 
5616  | 0  |     { FreeRDP_AudioPlayback, RDPSND_CHANNEL_NAME, NULL }, | 
5617  | 0  |     { FreeRDP_RedirectClipboard, CLIPRDR_SVC_CHANNEL_NAME, NULL }, | 
5618  | 0  | #if defined(CHANNEL_ENCOMSP_CLIENT)  | 
5619  | 0  |     { FreeRDP_EncomspVirtualChannel, ENCOMSP_SVC_CHANNEL_NAME, settings }, | 
5620  | 0  | #endif  | 
5621  | 0  |     { FreeRDP_RemdeskVirtualChannel, REMDESK_SVC_CHANNEL_NAME, settings }, | 
5622  | 0  |     { FreeRDP_RemoteApplicationMode, RAIL_SVC_CHANNEL_NAME, settings } | 
5623  | 0  |   };  | 
5624  |  |  | 
5625  |  |   /**  | 
5626  |  |    * Step 1: first load dynamic channels according to the settings  | 
5627  |  |    */  | 
5628  | 0  |   for (size_t i = 0; i < ARRAYSIZE(dynChannels); i++)  | 
5629  | 0  |   { | 
5630  | 0  |     if ((dynChannels[i].settingId == FreeRDP_BOOL_UNUSED) ||  | 
5631  | 0  |         freerdp_settings_get_bool(settings, dynChannels[i].settingId))  | 
5632  | 0  |     { | 
5633  | 0  |       const char* p[] = { dynChannels[i].channelName }; | 
5634  |  | 
  | 
5635  | 0  |       if (!freerdp_client_add_dynamic_channel(settings, ARRAYSIZE(p), p))  | 
5636  | 0  |         return FALSE;  | 
5637  | 0  |     }  | 
5638  | 0  |   }  | 
5639  |  |  | 
5640  |  |   /**  | 
5641  |  |    * step 2: do various adjustements in the settings, to handle channels and settings dependencies  | 
5642  |  |    */  | 
5643  | 0  |   if ((freerdp_static_channel_collection_find(settings, RDPSND_CHANNEL_NAME)) ||  | 
5644  | 0  |       (freerdp_dynamic_channel_collection_find(settings, RDPSND_CHANNEL_NAME))  | 
5645  |  | #if defined(CHANNEL_TSMF_CLIENT)  | 
5646  |  |       || (freerdp_dynamic_channel_collection_find(settings, "tsmf"))  | 
5647  |  | #endif  | 
5648  | 0  |   )  | 
5649  | 0  |   { | 
5650  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))  | 
5651  | 0  |       return COMMAND_LINE_ERROR; /* rdpsnd requires rdpdr to be registered */  | 
5652  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, TRUE))  | 
5653  | 0  |       return COMMAND_LINE_ERROR; /* Both rdpsnd and tsmf require this flag to be set */  | 
5654  | 0  |   }  | 
5655  |  |  | 
5656  | 0  |   if (freerdp_dynamic_channel_collection_find(settings, AUDIN_CHANNEL_NAME))  | 
5657  | 0  |   { | 
5658  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_AudioCapture, TRUE))  | 
5659  | 0  |       return COMMAND_LINE_ERROR;  | 
5660  | 0  |   }  | 
5661  |  |  | 
5662  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect) ||  | 
5663  | 0  |       freerdp_settings_get_bool(settings, FreeRDP_SupportHeartbeatPdu) ||  | 
5664  | 0  |       freerdp_settings_get_bool(settings, FreeRDP_SupportMultitransport))  | 
5665  | 0  |   { | 
5666  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))  | 
5667  | 0  |       return COMMAND_LINE_ERROR; /* these RDP8 features require rdpdr to be registered */  | 
5668  | 0  |   }  | 
5669  |  |  | 
5670  | 0  |   const char* DrivesToRedirect = freerdp_settings_get_string(settings, FreeRDP_DrivesToRedirect);  | 
5671  |  | 
  | 
5672  | 0  |   if (DrivesToRedirect && (strlen(DrivesToRedirect) != 0))  | 
5673  | 0  |   { | 
5674  |  |     /*  | 
5675  |  |      * Drives to redirect:  | 
5676  |  |      *  | 
5677  |  |      * Very similar to DevicesToRedirect, but can contain a  | 
5678  |  |      * comma-separated list of drive letters to redirect.  | 
5679  |  |      */  | 
5680  | 0  |     char* value = NULL;  | 
5681  | 0  |     char* tok = NULL;  | 
5682  | 0  |     char* context = NULL;  | 
5683  |  | 
  | 
5684  | 0  |     value = _strdup(DrivesToRedirect);  | 
5685  | 0  |     if (!value)  | 
5686  | 0  |       return FALSE;  | 
5687  |  |  | 
5688  | 0  |     tok = strtok_s(value, ";", &context);  | 
5689  | 0  |     if (!tok)  | 
5690  | 0  |     { | 
5691  | 0  |       WLog_ERR(TAG, "DrivesToRedirect contains invalid data: '%s'", DrivesToRedirect);  | 
5692  | 0  |       free(value);  | 
5693  | 0  |       return FALSE;  | 
5694  | 0  |     }  | 
5695  |  |  | 
5696  | 0  |     while (tok)  | 
5697  | 0  |     { | 
5698  |  |       /* Syntax: Comma seperated list of the following entries:  | 
5699  |  |        * '*'              ... Redirect all drives, including hotplug  | 
5700  |  |        * 'DynamicDrives'  ... hotplug  | 
5701  |  |        * '%'              ... user home directory  | 
5702  |  |        * <label>(<path>)  ... One or more paths to redirect.  | 
5703  |  |        * <path>(<label>)  ... One or more paths to redirect.  | 
5704  |  |        * <path>           ... One or more paths to redirect.  | 
5705  |  |        */  | 
5706  |  |       /* TODO: Need to properly escape labels and paths */  | 
5707  | 0  |       BOOL success = 0;  | 
5708  | 0  |       const char* name = NULL;  | 
5709  | 0  |       const char* drive = tok;  | 
5710  | 0  |       char* subcontext = NULL;  | 
5711  | 0  |       char* start = strtok_s(tok, "(", &subcontext); | 
5712  | 0  |       char* end = strtok_s(NULL, ")", &subcontext);  | 
5713  | 0  |       if (start && end)  | 
5714  | 0  |         name = end;  | 
5715  |  | 
  | 
5716  | 0  |       if (freerdp_path_valid(name, NULL) && freerdp_path_valid(drive, NULL))  | 
5717  | 0  |       { | 
5718  | 0  |         success = freerdp_client_add_drive(settings, name, NULL);  | 
5719  | 0  |         if (success)  | 
5720  | 0  |           success = freerdp_client_add_drive(settings, drive, NULL);  | 
5721  | 0  |       }  | 
5722  | 0  |       else  | 
5723  | 0  |         success = freerdp_client_add_drive(settings, drive, name);  | 
5724  |  | 
  | 
5725  | 0  |       if (!success)  | 
5726  | 0  |       { | 
5727  | 0  |         free(value);  | 
5728  | 0  |         return FALSE;  | 
5729  | 0  |       }  | 
5730  |  |  | 
5731  | 0  |       tok = strtok_s(NULL, ";", &context);  | 
5732  | 0  |     }  | 
5733  | 0  |     free(value);  | 
5734  |  | 
  | 
5735  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))  | 
5736  | 0  |       return FALSE;  | 
5737  |  |  | 
5738  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))  | 
5739  | 0  |       return COMMAND_LINE_ERROR;  | 
5740  | 0  |   }  | 
5741  | 0  |   else if (freerdp_settings_get_bool(settings, FreeRDP_RedirectDrives))  | 
5742  | 0  |   { | 
5743  | 0  |     if (!freerdp_device_collection_find(settings, "drive"))  | 
5744  | 0  |     { | 
5745  | 0  |       const char* params[] = { "drive", "media", "*" }; | 
5746  |  | 
  | 
5747  | 0  |       if (!freerdp_client_add_device_channel(settings, ARRAYSIZE(params), params))  | 
5748  | 0  |         return FALSE;  | 
5749  | 0  |     }  | 
5750  | 0  |   }  | 
5751  |  |  | 
5752  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_RedirectDrives) ||  | 
5753  | 0  |       freerdp_settings_get_bool(settings, FreeRDP_RedirectHomeDrive) ||  | 
5754  | 0  |       freerdp_settings_get_bool(settings, FreeRDP_RedirectSerialPorts) ||  | 
5755  | 0  |       freerdp_settings_get_bool(settings, FreeRDP_RedirectSmartCards) ||  | 
5756  | 0  |       freerdp_settings_get_bool(settings, FreeRDP_RedirectPrinters))  | 
5757  | 0  |   { | 
5758  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))  | 
5759  | 0  |       return COMMAND_LINE_ERROR; /* All of these features require rdpdr */  | 
5760  | 0  |   }  | 
5761  |  |  | 
5762  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_RedirectHomeDrive))  | 
5763  | 0  |   { | 
5764  | 0  |     if (!freerdp_device_collection_find(settings, "drive"))  | 
5765  | 0  |     { | 
5766  | 0  |       const char* params[] = { "drive", "home", "%" }; | 
5767  |  | 
  | 
5768  | 0  |       if (!freerdp_client_add_device_channel(settings, ARRAYSIZE(params), params))  | 
5769  | 0  |         return FALSE;  | 
5770  | 0  |     }  | 
5771  | 0  |   }  | 
5772  |  |  | 
5773  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_DeviceRedirection))  | 
5774  | 0  |   { | 
5775  | 0  |     if (!freerdp_client_load_static_channel_addin(channels, settings, RDPDR_SVC_CHANNEL_NAME,  | 
5776  | 0  |                                                   settings))  | 
5777  | 0  |       return FALSE;  | 
5778  |  |  | 
5779  | 0  |     if (!freerdp_static_channel_collection_find(settings, RDPSND_CHANNEL_NAME) &&  | 
5780  | 0  |         !freerdp_dynamic_channel_collection_find(settings, RDPSND_CHANNEL_NAME))  | 
5781  | 0  |     { | 
5782  | 0  |       const char* params[] = { RDPSND_CHANNEL_NAME, "sys:fake" }; | 
5783  |  | 
  | 
5784  | 0  |       if (!freerdp_client_add_static_channel(settings, ARRAYSIZE(params), params))  | 
5785  | 0  |         return FALSE;  | 
5786  |  |  | 
5787  | 0  |       if (!freerdp_client_add_dynamic_channel(settings, ARRAYSIZE(params), params))  | 
5788  | 0  |         return FALSE;  | 
5789  | 0  |     }  | 
5790  | 0  |   }  | 
5791  |  |  | 
5792  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_RedirectSmartCards))  | 
5793  | 0  |   { | 
5794  | 0  |     if (!freerdp_device_collection_find_type(settings, RDPDR_DTYP_SMARTCARD))  | 
5795  | 0  |     { | 
5796  | 0  |       RDPDR_DEVICE* smartcard = freerdp_device_new(RDPDR_DTYP_SMARTCARD, 0, NULL);  | 
5797  |  | 
  | 
5798  | 0  |       if (!smartcard)  | 
5799  | 0  |         return FALSE;  | 
5800  |  |  | 
5801  | 0  |       if (!freerdp_device_collection_add(settings, smartcard))  | 
5802  | 0  |       { | 
5803  | 0  |         freerdp_device_free(smartcard);  | 
5804  | 0  |         return FALSE;  | 
5805  | 0  |       }  | 
5806  | 0  |     }  | 
5807  | 0  |   }  | 
5808  |  |  | 
5809  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_RedirectPrinters))  | 
5810  | 0  |   { | 
5811  | 0  |     if (!freerdp_device_collection_find_type(settings, RDPDR_DTYP_PRINT))  | 
5812  | 0  |     { | 
5813  | 0  |       RDPDR_DEVICE* printer = freerdp_device_new(RDPDR_DTYP_PRINT, 0, NULL);  | 
5814  |  | 
  | 
5815  | 0  |       if (!printer)  | 
5816  | 0  |         return FALSE;  | 
5817  |  |  | 
5818  | 0  |       if (!freerdp_device_collection_add(settings, printer))  | 
5819  | 0  |       { | 
5820  | 0  |         freerdp_device_free(printer);  | 
5821  | 0  |         return FALSE;  | 
5822  | 0  |       }  | 
5823  | 0  |     }  | 
5824  | 0  |   }  | 
5825  |  |  | 
5826  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_LyncRdpMode))  | 
5827  | 0  |   { | 
5828  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_EncomspVirtualChannel, TRUE))  | 
5829  | 0  |       return FALSE;  | 
5830  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_RemdeskVirtualChannel, TRUE))  | 
5831  | 0  |       return FALSE;  | 
5832  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, FALSE))  | 
5833  | 0  |       return FALSE;  | 
5834  | 0  |   }  | 
5835  |  |  | 
5836  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_RemoteAssistanceMode))  | 
5837  | 0  |   { | 
5838  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_EncomspVirtualChannel, TRUE))  | 
5839  | 0  |       return FALSE;  | 
5840  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_RemdeskVirtualChannel, TRUE))  | 
5841  | 0  |       return FALSE;  | 
5842  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))  | 
5843  | 0  |       return FALSE;  | 
5844  | 0  |   }  | 
5845  |  |  | 
5846  |  |   /* step 3: schedule some static channels to load depending on the settings */  | 
5847  | 0  |   for (size_t i = 0; i < ARRAYSIZE(staticChannels); i++)  | 
5848  | 0  |   { | 
5849  | 0  |     if ((staticChannels[i].settingId == 0) ||  | 
5850  | 0  |         freerdp_settings_get_bool(settings, staticChannels[i].settingId))  | 
5851  | 0  |     { | 
5852  | 0  |       if (staticChannels[i].args)  | 
5853  | 0  |       { | 
5854  | 0  |         if (!freerdp_client_load_static_channel_addin(  | 
5855  | 0  |                 channels, settings, staticChannels[i].channelName, staticChannels[i].args))  | 
5856  | 0  |           return FALSE;  | 
5857  | 0  |       }  | 
5858  | 0  |       else  | 
5859  | 0  |       { | 
5860  | 0  |         const char* p[] = { staticChannels[i].channelName }; | 
5861  | 0  |         if (!freerdp_client_add_static_channel(settings, ARRAYSIZE(p), p))  | 
5862  | 0  |           return FALSE;  | 
5863  | 0  |       }  | 
5864  | 0  |     }  | 
5865  | 0  |   }  | 
5866  |  |  | 
5867  | 0  |   char* RDP2TCPArgs = freerdp_settings_get_string_writable(settings, FreeRDP_RDP2TCPArgs);  | 
5868  | 0  |   if (RDP2TCPArgs)  | 
5869  | 0  |   { | 
5870  | 0  |     if (!freerdp_client_load_static_channel_addin(channels, settings, RDP2TCP_DVC_CHANNEL_NAME,  | 
5871  | 0  |                                                   RDP2TCPArgs))  | 
5872  | 0  |       return FALSE;  | 
5873  | 0  |   }  | 
5874  |  |  | 
5875  |  |   /* step 4: do the static channels loading and init */  | 
5876  | 0  |   for (UINT32 i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_StaticChannelCount); i++)  | 
5877  | 0  |   { | 
5878  | 0  |     ADDIN_ARGV* _args =  | 
5879  | 0  |         freerdp_settings_get_pointer_array_writable(settings, FreeRDP_StaticChannelArray, i);  | 
5880  |  | 
  | 
5881  | 0  |     if (!freerdp_client_load_static_channel_addin(channels, settings, _args->argv[0], _args))  | 
5882  | 0  |       return FALSE;  | 
5883  | 0  |   }  | 
5884  |  |  | 
5885  | 0  |   if (freerdp_settings_get_uint32(settings, FreeRDP_DynamicChannelCount) > 0)  | 
5886  | 0  |   { | 
5887  | 0  |     if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDynamicChannels, TRUE))  | 
5888  | 0  |       return FALSE;  | 
5889  | 0  |   }  | 
5890  |  |  | 
5891  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_SupportDynamicChannels))  | 
5892  | 0  |   { | 
5893  | 0  |     if (!freerdp_client_load_static_channel_addin(channels, settings, DRDYNVC_SVC_CHANNEL_NAME,  | 
5894  | 0  |                                                   settings))  | 
5895  | 0  |       return FALSE;  | 
5896  | 0  |   }  | 
5897  |  |  | 
5898  | 0  |   return TRUE;  | 
5899  | 0  | }  | 
5900  |  |  | 
5901  |  | void freerdp_client_warn_unmaintained(int argc, char* argv[])  | 
5902  | 0  | { | 
5903  | 0  |   const char* app = (argc > 0) ? argv[0] : "INVALID_ARGV";  | 
5904  | 0  |   const DWORD log_level = WLOG_WARN;  | 
5905  | 0  |   wLog* log = WLog_Get(TAG);  | 
5906  | 0  |   WINPR_ASSERT(log);  | 
5907  |  |  | 
5908  | 0  |   if (!WLog_IsLevelActive(log, log_level))  | 
5909  | 0  |     return;  | 
5910  |  |  | 
5911  | 0  |   WLog_Print_unchecked(log, log_level, "[unmaintained] %s client is currently unmaintained!",  | 
5912  | 0  |                        app);  | 
5913  | 0  |   WLog_Print_unchecked(  | 
5914  | 0  |       log, log_level,  | 
5915  | 0  |       " If problems occur please check https://github.com/FreeRDP/FreeRDP/issues for "  | 
5916  | 0  |       "known issues!");  | 
5917  | 0  |   WLog_Print_unchecked(  | 
5918  | 0  |       log, log_level,  | 
5919  | 0  |       "Be prepared to fix issues yourself though as nobody is actively working on this.");  | 
5920  | 0  |   WLog_Print_unchecked(  | 
5921  | 0  |       log, log_level,  | 
5922  | 0  |       " Developers hang out in https://matrix.to/#/#FreeRDP:matrix.org?via=matrix.org "  | 
5923  | 0  |       "- dont hesitate to ask some questions. (replies might take some time depending "  | 
5924  | 0  |       "on your timezone) - if you intend using this component write us a message");  | 
5925  | 0  | }  | 
5926  |  |  | 
5927  |  | void freerdp_client_warn_experimental(int argc, char* argv[])  | 
5928  | 0  | { | 
5929  | 0  |   const char* app = (argc > 0) ? argv[0] : "INVALID_ARGV";  | 
5930  | 0  |   const DWORD log_level = WLOG_WARN;  | 
5931  | 0  |   wLog* log = WLog_Get(TAG);  | 
5932  | 0  |   WINPR_ASSERT(log);  | 
5933  |  |  | 
5934  | 0  |   if (!WLog_IsLevelActive(log, log_level))  | 
5935  | 0  |     return;  | 
5936  |  |  | 
5937  | 0  |   WLog_Print_unchecked(log, log_level, "[experimental] %s client is currently experimental!",  | 
5938  | 0  |                        app);  | 
5939  | 0  |   WLog_Print_unchecked(  | 
5940  | 0  |       log, log_level,  | 
5941  | 0  |       " If problems occur please check https://github.com/FreeRDP/FreeRDP/issues for "  | 
5942  | 0  |       "known issues or create a new one!");  | 
5943  | 0  |   WLog_Print_unchecked(  | 
5944  | 0  |       log, log_level,  | 
5945  | 0  |       " Developers hang out in https://matrix.to/#/#FreeRDP:matrix.org?via=matrix.org "  | 
5946  | 0  |       "- dont hesitate to ask some questions. (replies might take some time depending "  | 
5947  | 0  |       "on your timezone)");  | 
5948  | 0  | }  | 
5949  |  |  | 
5950  |  | void freerdp_client_warn_deprecated(int argc, char* argv[])  | 
5951  | 0  | { | 
5952  | 0  |   const char* app = (argc > 0) ? argv[0] : "INVALID_ARGV";  | 
5953  | 0  |   const DWORD log_level = WLOG_WARN;  | 
5954  | 0  |   wLog* log = WLog_Get(TAG);  | 
5955  | 0  |   WINPR_ASSERT(log);  | 
5956  |  |  | 
5957  | 0  |   if (!WLog_IsLevelActive(log, log_level))  | 
5958  | 0  |     return;  | 
5959  |  |  | 
5960  | 0  |   WLog_Print_unchecked(log, log_level, "[deprecated] %s client has been deprecated", app);  | 
5961  | 0  |   WLog_Print_unchecked(log, log_level, "As replacement there is a SDL based client available.");  | 
5962  | 0  |   WLog_Print_unchecked(  | 
5963  | 0  |       log, log_level,  | 
5964  | 0  |       "If you are interested in keeping %s alive get in touch with the developers", app);  | 
5965  | 0  |   WLog_Print_unchecked(  | 
5966  | 0  |       log, log_level,  | 
5967  | 0  |       "The project is hosted at https://github.com/freerdp/freerdp and "  | 
5968  | 0  |       " developers hang out in https://matrix.to/#/#FreeRDP:matrix.org?via=matrix.org "  | 
5969  | 0  |       "- dont hesitate to ask some questions. (replies might take some time depending "  | 
5970  | 0  |       "on your timezone)");  | 
5971  | 0  | }  |