diff --git a/config.h.in b/config.h.in index a91b3f59d..2051c47c0 100644 --- a/config.h.in +++ b/config.h.in @@ -1,6 +1,8 @@ #ifndef __CONFIG_H #define __CONFIG_H +#define FREERDP_VERSION_FULL "${FREERDP_VERSION_FULL}" + /* Include files */ #cmakedefine HAVE_SYS_PARAM_H #cmakedefine HAVE_SYS_SOCKET_H diff --git a/cunit/test_utils.c b/cunit/test_utils.c index a2b0bb725..459e5b897 100644 --- a/cunit/test_utils.c +++ b/cunit/test_utils.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "test_utils.h" @@ -46,6 +47,7 @@ int add_utils_suite(void) add_test_function(semaphore); add_test_function(load_plugin); add_test_function(wait_obj); + add_test_function(args); return 0; } @@ -100,3 +102,55 @@ void test_wait_obj(void) wait_obj_free(wo); } + +static int process_plugin_args(rdpSettings* settings, const char* name, + FRDP_PLUGIN_DATA* plugin_data, void* user_data) +{ + /*printf("load plugin: %s\n", name);*/ + return 1; +} + +static int process_ui_args(rdpSettings* settings, const char* opt, + const char* val, void* user_data) +{ + /*printf("ui arg: %s %s\n", opt, val);*/ + return 1; +} + +void test_args(void) +{ + char* argv_c[] = + { + "-a", "8", "-u", "testuser", "-d", "testdomain", "-g", "640x480", "address1:3389", + "-a", "16", "-u", "testuser", "-d", "testdomain", "-g", "1280x960", "address2:3390" + }; + char** argv = argv_c; + int argc = sizeof(argv_c) / sizeof(char*); + int i; + int c; + rdpSettings* settings; + + i = 0; + while (argc > 0) + { + settings = settings_new(); + + i++; + c = freerdp_parse_args(settings, argc, argv, process_plugin_args, NULL, process_ui_args, NULL); + CU_ASSERT(c > 0); + if (c == 0) + { + settings_free(settings); + break; + } + CU_ASSERT(settings->color_depth == i * 8); + CU_ASSERT(settings->width == i * 640); + CU_ASSERT(settings->height == i * 480); + CU_ASSERT(settings->port == i + 3388); + + settings_free(settings); + argc -= c; + argv += c; + } + CU_ASSERT(i == 2); +} diff --git a/cunit/test_utils.h b/cunit/test_utils.h index 8c1e8268b..f0d4819b6 100644 --- a/cunit/test_utils.h +++ b/cunit/test_utils.h @@ -27,3 +27,4 @@ void test_mutex(void); void test_semaphore(void); void test_load_plugin(void); void test_wait_obj(void); +void test_args(void); diff --git a/include/freerdp/utils/args.h b/include/freerdp/utils/args.h new file mode 100644 index 000000000..3ccc492b5 --- /dev/null +++ b/include/freerdp/utils/args.h @@ -0,0 +1,38 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * Arguments Parsing + * + * Copyright 2011 Vic Lee + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ARGS_UTILS_H +#define __ARGS_UTILS_H + +#include +#include + +/* Returns 1 if succeed, otherwise returns zero */ +typedef int (*ProcessPluginArgs) (rdpSettings* settings, const char* name, + FRDP_PLUGIN_DATA* plugin_data, void* user_data); + +/* Returns number of arguments processed (1 or 2), otherwise returns zero */ +typedef int (*ProcessUIArgs) (rdpSettings* settings, const char* opt, + const char* val, void* user_data); + +int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, + ProcessPluginArgs plugin_callback, void* plugin_user_data, + ProcessUIArgs ui_callback, void* ui_user_data); + +#endif /* __ARGS_UTILS_H */ diff --git a/libfreerdp-utils/CMakeLists.txt b/libfreerdp-utils/CMakeLists.txt index dd2636caf..d1c08a159 100644 --- a/libfreerdp-utils/CMakeLists.txt +++ b/libfreerdp-utils/CMakeLists.txt @@ -18,6 +18,7 @@ # limitations under the License. set(FREERDP_UTILS_SRCS + args.c blob.c event.c hexdump.c diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c new file mode 100644 index 000000000..8cbc56b6a --- /dev/null +++ b/libfreerdp-utils/args.c @@ -0,0 +1,392 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * Arguments Parsing + * + * Copyright 2009-2011 Jay Sorg + * Copyright 2011 Vic Lee + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#include +#include +#include +#include +#include + +#define MAX_PLUGIN_DATA 20 + +/** + * Parse command-line arguments and update rdpSettings members accordingly. + * @param settings pointer to rdpSettings struct to be updated. + * @param argc number of arguments available. + * @param argv string array of the arguments. + * @param plugin_callback function to be called when a plugin needs to be loaded. + * @param plugin_user_data pointer to be passed to the plugin_callback function. + * @param ui_callback function to be called when a UI-specific argument is being processed. + * @param ui_user_data pointer to be passed to the ui_callback function. + * @return number of arguments that has been parsed, or 0 if error occurred. + */ +int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, + ProcessPluginArgs plugin_callback, void* plugin_user_data, + ProcessUIArgs ui_callback, void* ui_user_data) +{ + int index = 0; + int num_extensions = 0; + int i, j; + int t; + char* p; + FRDP_PLUGIN_DATA plugin_data[MAX_PLUGIN_DATA + 1]; + + while (index < argc) + { + if (strcmp("-a", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing color depth\n"); + return 0; + } + settings->color_depth = atoi(argv[index]); + } + else if (strcmp("-u", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing username\n"); + return 0; + } + settings->username = (uint8*)xstrdup(argv[index]); + } + else if (strcmp("-p", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing password\n"); + return 0; + } + settings->password = (uint8*)xstrdup(argv[index]); + settings->autologon = 1; + + /* + * Overwrite original password which could be revealed by a simple "ps aux" command. + * This approach won't hide the password length, but it is better than nothing. + */ + + memset(argv[index], '*', strlen(argv[index])); + } + else if (strcmp("-d", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing domain\n"); + return 0; + } + settings->domain = (uint8*)xstrdup(argv[index]); + } + else if (strcmp("-s", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing shell\n"); + return 0; + } + settings->shell = (uint8*)xstrdup(argv[index]); + } + else if (strcmp("-c", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing directory\n"); + return 0; + } + settings->directory = (uint8*)xstrdup(argv[index]); + } + else if (strcmp("-g", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing width\n"); + return 0; + } + settings->width = strtol(argv[index], &p, 10); + if (*p == 'x') + { + settings->height = strtol(p + 1, &p, 10); + } + else + { + ui_callback(settings, "-g", p, ui_user_data); + } + } + else if (strcmp("-t", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing port number\n"); + return 0; + } + settings->port = atoi(argv[index]); + } + else if (strcmp("-n", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing client hostname\n"); + return 0; + } + strncpy(settings->client_hostname, argv[index], sizeof(settings->client_hostname) - 1); + settings->client_hostname[sizeof(settings->client_hostname) - 1] = 0; + } + else if (strcmp("-o", argv[index]) == 0) + { + settings->console_audio = 1; + } + else if (strcmp("-0", argv[index]) == 0) + { + settings->console_session = 1; + } + else if (strcmp("-z", argv[index]) == 0) + { + settings->compression = 1; + } + else if (strcmp("--no-osb", argv[index]) == 0) + { + settings->off_screen_bitmaps = 0; + } + else if (strcmp("--rfx", argv[index]) == 0) + { + settings->rfx_flags = 1; + settings->ui_decode_flags = 1; + settings->use_frame_ack = 0; + settings->color_depth = 32; + settings->performance_flags = PERF_FLAG_NONE; + } + else if (strcmp("-m", argv[index]) == 0) + { + settings->mouse_motion = 0; + } + else if (strcmp("--app", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing application name\n"); + return 0; + } + strncpy(settings->app_name, argv[index], sizeof(settings->app_name) - 1); + settings->app_name[sizeof(settings->app_name) - 1] = 0; + settings->remote_app = 1; + } + else if (strcmp("-x", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing performance flag\n"); + return 0; + } + if (argv[index][0] == 'm') /* modem */ + { + settings->performance_flags = PERF_DISABLE_WALLPAPER | + PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS | + PERF_DISABLE_THEMING; + } + else if (argv[index][0] == 'b') /* broadband */ + { + settings->performance_flags = PERF_DISABLE_WALLPAPER; + } + else if (argv[index][0] == 'l') /* lan */ + { + settings->performance_flags = PERF_FLAG_NONE; + } + else + { + settings->performance_flags = strtol(argv[index], 0, 16); + } + } + else if (strcmp("--no-rdp", argv[index]) == 0) + { + settings->rdp_security = 0; + } + else if (strcmp("--no-tls", argv[index]) == 0) + { + settings->tls_security = 0; + } + else if (strcmp("--no-nla", argv[index]) == 0) + { + settings->nla_security = 0; + } + else if (strcmp("--sec", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing protocol security\n"); + return 0; + } + if (strncmp("rdp", argv[index], 1) == 0) /* Standard RDP */ + { + settings->rdp_security = 1; + settings->tls_security = 0; + settings->nla_security = 0; + } + else if (strncmp("tls", argv[index], 1) == 0) /* TLS */ + { + settings->rdp_security = 0; + settings->tls_security = 1; + settings->nla_security = 0; + } + else if (strncmp("nla", argv[index], 1) == 0) /* NLA */ + { + settings->rdp_security = 0; + settings->tls_security = 0; + settings->nla_security = 1; + } + else + { + printf("unknown protocol security\n"); + return 0; + } + } + else if (strcmp("--plugin", argv[index]) == 0) + { + t = index; + index++; + if (index == argc) + { + printf("missing plugin name\n"); + return 0; + } + memset(plugin_data, 0, sizeof(plugin_data)); + if (index < argc - 1 && strcmp("--data", argv[index + 1]) == 0) + { + index += 2; + i = 0; + while (index < argc && strcmp("--", argv[index]) != 0 && i < MAX_PLUGIN_DATA) + { + plugin_data[i].size = sizeof(FRDP_PLUGIN_DATA); + for (j = 0, p = argv[index]; j < 4 && p != NULL; j++) + { + if (*p == '\'') + { + plugin_data[i].data[j] = p + 1; + p = strchr(p + 1, '\''); + if (p) + *p++ = 0; + } + else + plugin_data[i].data[j] = p; + + p = strchr(p, ':'); + if (p != NULL) + *p++ = 0; + } + index++; + i++; + } + } + if (!plugin_callback(settings, argv[t], plugin_data, plugin_user_data)) + return 0; + } + else if (strcmp("--ext", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing extension name\n"); + return 0; + } + if (num_extensions >= sizeof(settings->extensions) / sizeof(struct rdp_ext_set)) + { + printf("maximum extensions reached\n"); + return 0; + } + snprintf(settings->extensions[num_extensions].name, + sizeof(settings->extensions[num_extensions].name), + "%s", argv[index]); + settings->extensions[num_extensions].data = NULL; + if (index < argc - 1 && strcmp("--data", argv[index + 1]) == 0) + { + index += 2; + settings->extensions[num_extensions].data = argv[index]; + i = 0; + while (index < argc && strcmp("--", argv[index]) != 0) + { + index++; + i++; + } + } + num_extensions++; + } + else if (strcmp("--version", argv[index]) == 0) + { + printf("This is FreeRDP version %s\n", FREERDP_VERSION_FULL); + return 0; + } + else if (argv[index][0] != '-') + { + if (argv[index][0] == '[' && (p = strchr(argv[index], ']')) + && (p[1] == 0 || (p[1] == ':' && !strchr(p + 2, ':')))) + { + /* Either "[...]" or "[...]:..." with at most one : after the brackets */ + settings->hostname = (uint8*)xstrdup(argv[index] + 1); + if ((p = strchr((char*)settings->hostname, ']'))) + { + *p = 0; + if (p[1] == ':') + settings->port = atoi(p + 2); + } + } + else + { + /* Port number is cut off and used if exactly one : in the string */ + settings->hostname = (uint8*)xstrdup(argv[index]); + if ((p = strchr((char*)settings->hostname, ':')) && !strchr(p + 1, ':')) + { + *p = 0; + settings->port = atoi(p + 1); + } + } + /* server is the last argument for the current session. arguments + followed will be parsed for the next session. */ + index++; + + return index; + } + else + { + t = ui_callback(settings, argv[index], (index + 1 < argc && argv[index + 1][0] != '-' ? + argv[index + 1] : NULL), ui_user_data); + if (t == 0) + { + printf("invalid option: %s\n", argv[index]); + return 0; + } + index += t - 1; + } + index++; + } + printf("missing server name\n"); + return 0; +}