diff --git a/.source_version b/.source_version index b196adb..598672a 100644 --- a/.source_version +++ b/.source_version @@ -1 +1 @@ -e21b72c95+debian +2693389a+debian diff --git a/CMakeLists.txt b/CMakeLists.txt index 0199269..fd36e0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSTION_STRING "2.0.0-rc4") +set(RAW_VERSTION_STRING "2.0.0-dev5") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSTION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) @@ -482,7 +482,7 @@ if(WIN32) add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS) set(CMAKE_USE_RELATIVE_PATH ON) - if (${CMAKE_GENERATOR} MATCHES "NMake Makefile*" OR ${CMAKE_GENERATOR} MATCHES "Ninja*") + if (${CMAKE_GENERATOR} MATCHES "NMake Makefile*" OR ${CMAKE_GENERATOR} MATCHES "Ninja*" OR ${CMAKE_GENERATOR} MATCHES "Unix Makefiles") set(CMAKE_PDB_BINARY_DIR ${CMAKE_BINARY_DIR}) elseif (${CMAKE_GENERATOR} MATCHES "Visual Studio*") set(CMAKE_PDB_BINARY_DIR "${CMAKE_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}") @@ -490,12 +490,6 @@ if(WIN32) message(FATAL_ERROR "Unknown generator ${CMAKE_GENERATOR}") endif() - # Set product and vendor for dll and exe version information. - set(RC_VERSION_VENDOR ${VENDOR}) - set(RC_VERSION_PRODUCT ${PRODUCT}) - set(RC_VERSION_PATCH ${BUILD_NUMBER}) - set(RC_VERSION_DESCRIPTION ${GIT_REVISION}) - string(TIMESTAMP RC_VERSION_YEAR "%Y") if(NOT DEFINED CMAKE_WINDOWS_VERSION) @@ -512,6 +506,12 @@ if(WIN32) add_definitions(-DWINVER=0x0A00 -D_WIN32_WINNT=0x0A00) endif() + # Set product and vendor for dll and exe version information. + set(RC_VERSION_VENDOR ${VENDOR}) + set(RC_VERSION_PRODUCT ${PRODUCT}) + set(RC_VERSION_PATCH ${BUILD_NUMBER}) + set(RC_VERSION_DESCRIPTION "${FREERDP_VERSION_FULL} ${GIT_REVISION} ${CMAKE_WINDOWS_VERSION} ${CMAKE_SYSTEM_PROCESSOR}") + if (FREERDP_EXTERNAL_SSL_PATH) set(OPENSSL_ROOT_DIR ${FREERDP_EXTERNAL_SSL_PATH}) endif() @@ -682,10 +682,6 @@ set(X11_FEATURE_DESCRIPTION "X11 client and server") set(WAYLAND_FEATURE_PURPOSE "Wayland") set(WAYLAND_FEATURE_DESCRIPTION "Wayland client") -set(DIRECTFB_FEATURE_TYPE "OPTIONAL") -set(DIRECTFB_FEATURE_PURPOSE "DirectFB") -set(DIRECTFB_FEATURE_DESCRIPTION "DirectFB client") - set(ZLIB_FEATURE_TYPE "REQUIRED") set(ZLIB_FEATURE_PURPOSE "compression") set(ZLIB_FEATURE_DESCRIPTION "data compression") @@ -782,7 +778,6 @@ if(WIN32) set(X11_FEATURE_TYPE "DISABLED") set(WAYLAND_FEATURE_TYPE "DISABLED") set(ZLIB_FEATURE_TYPE "DISABLED") - set(DIRECTFB_FEATURE_TYPE "DISABLED") set(OSS_FEATURE_TYPE "DISABLED") set(ALSA_FEATURE_TYPE "DISABLED") set(PULSE_FEATURE_TYPE "DISABLED") @@ -796,7 +791,6 @@ if(WIN32) endif() if(APPLE) - set(DIRECTFB_FEATURE_TYPE "DISABLED") set(FFMPEG_FEATURE_TYPE "OPTIONAL") set(VAAPI_FEATURE_TYPE "DISABLED") set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL") @@ -833,7 +827,6 @@ endif(UNIX AND NOT ANDROID) if(ANDROID) set(X11_FEATURE_TYPE "DISABLED") set(WAYLAND_FEATURE_TYPE "DISABLED") - set(DIRECTFB_FEATURE_TYPE "DISABLED") set(OSS_FEATURE_TYPE "DISABLED") set(ALSA_FEATURE_TYPE "DISABLED") set(PULSE_FEATURE_TYPE "DISABLED") @@ -848,10 +841,6 @@ endif() find_feature(X11 ${X11_FEATURE_TYPE} ${X11_FEATURE_PURPOSE} ${X11_FEATURE_DESCRIPTION}) find_feature(Wayland ${WAYLAND_FEATURE_TYPE} ${WAYLAND_FEATURE_PURPOSE} ${WAYLAND_FEATURE_DESCRIPTION}) -find_feature(DirectFB ${DIRECTFB_FEATURE_TYPE} ${DIRECTFB_FEATURE_PURPOSE} ${DIRECTFB_FEATURE_DESCRIPTION}) -if (${WITH_DIRECTFB}) - message(WARNING "DIRECTFB is orphaned and not maintained see docs/README.directfb for details") -endif() find_feature(ZLIB ${ZLIB_FEATURE_TYPE} ${ZLIB_FEATURE_PURPOSE} ${ZLIB_FEATURE_DESCRIPTION}) find_feature(OpenSSL ${OPENSSL_FEATURE_TYPE} ${OPENSSL_FEATURE_PURPOSE} ${OPENSSL_FEATURE_DESCRIPTION}) @@ -881,6 +870,10 @@ find_feature(soxr ${SOXR_FEATURE_TYPE} ${SOXR_FEATURE_PURPOSE} ${SOXR_FEATURE_DE find_feature(GSSAPI ${GSSAPI_FEATURE_TYPE} ${GSSAPI_FEATURE_PURPOSE} ${GSSAPI_FEATURE_DESCRIPTION}) +if (WITH_OPENH264 AND NOT WITH_OPENH264_LOADING) + set(WITH_OPENH264_LOADING OFF) +endif (WITH_OPENH264 AND NOT WITH_OPENH264_LOADING) + if ((WITH_FFMPEG OR WITH_DSP_FFMPEG) AND NOT FFMPEG_FOUND) message(FATAL_ERROR "FFMPEG support requested but not detected") endif() @@ -945,6 +938,7 @@ endif() if(OPENSSL_FOUND) add_definitions("-DWITH_OPENSSL") message(STATUS "Using OpenSSL Version: ${OPENSSL_VERSION}") + include_directories(${OPENSSL_INCLUDE_DIR}) endif() if(MBEDTLS_FOUND) @@ -1062,7 +1056,7 @@ add_subdirectory(include) add_subdirectory(libfreerdp) if (IOS) - set(CMAKE_OSX_DEPLOYMENT_TARGET "") + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.0") if (IOS_PLATFORM MATCHES "SIMULATOR") set(CMAKE_OSX_SYSROOT "iphonesimulator") else() diff --git a/ChangeLog b/ChangeLog index 6ae0546..26f9010 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,1376 @@ +2019-02-01 08:37:24 +0100 akallabeth (2693389a1) + + * Merge pull request #5236 from chipitsine/master + +2019-02-01 03:50:51 +0500 Ilya Shipitsin (d1939cfc4) + + * client/Wayland/wlf_cliprdr.c: resolve possible null pointer + dereference found by cppcheck + +2019-01-30 18:22:45 +0100 David Fort (85161c718) + + * Merge pull request #5223 from akallabeth/scanbuild_null_fixes + +2019-01-30 16:26:41 +0100 Bernhard Miklautz (acebd43ac) + + * Merge pull request #5147 from jphein/master + +2019-01-28 10:56:48 +0100 Armin Novak (2dab77810) + + * Fixed NULL dereferences and uninitialized values + +2019-01-28 10:56:23 +0100 Armin Novak (ef1728faf) + + * Fixed NULL dereferences and uninitialized values + +2019-01-28 10:55:56 +0100 Armin Novak (2a582ed19) + + * Fixed NULL dereferences and uninitialized values + +2019-01-28 10:55:24 +0100 Armin Novak (fe9dcfacc) + + * Fixed NULL dereferences and uninitialized values + +2019-01-30 00:08:55 +0100 David Fort (138a83b47) + + * Merge pull request #5227 from akallabeth/compiler_warnings_fixes + +2019-01-29 17:46:47 +0100 Armin Novak (9033df501) + + * Fixed compiler warnings for TRIO_CONST and limited data type. + +2019-01-29 17:48:05 +0100 Armin Novak (79416f5d3) + + * Fixed missing initializers + +2019-01-29 17:24:29 +0100 Armin Novak (87c7ddeda) + + * Asserting arg->Value to silence clang analyzer NULL argument + checks. + +2019-01-29 17:16:46 +0100 Armin Novak (2e5fd8d16) + + * Fixed clang analyzer false positive memory leaks. + +2019-01-29 17:06:08 +0100 Armin Novak (d5720b799) + + * Fixed clang scanbuild false positive memory leak. + +2019-01-29 16:53:30 +0100 Armin Novak (0dae6933c) + + * Fixed uninitialized return value. + +2019-01-29 16:22:46 +0100 Armin Novak (6a1ff5c48) + + * Fixed compiler warnings #5210 + +2019-01-29 16:15:33 +0100 Armin Novak (5c930dc4a) + + * Fixed compiler warnings #5210 + +2019-01-29 16:15:23 +0100 Armin Novak (51039f653) + + * Fixed compiler warnings #5210 + +2019-01-29 16:14:55 +0100 Armin Novak (9d680904c) + + * Fixed compiler warnings #5210 + +2019-01-29 16:14:29 +0100 Armin Novak (03ec36440) + + * Fixed compiler warnings #5210 + +2019-01-29 15:18:53 +0100 David Fort (70805402b) + + * Merge pull request #5140 from akallabeth/print_custom_component + +2019-01-29 15:11:38 +0100 David Fort (72ad4af35) + + * Merge pull request #5221 from akallabeth/wayland_mouse_cursor + +2019-01-29 14:21:58 +0100 Armin Novak (dd9814df8) + + * Fixed review remarks. + +2019-01-29 13:34:27 +0100 Armin Novak (32d539b70) + + * Removed debug messages. + +2019-01-29 11:07:44 +0100 Armin Novak (f64db12a2) + + * Fixed uninitialized value. + +2019-01-29 10:47:36 +0100 akallabeth (4b95bcfa6) + + * Merge pull request #5224 from hardening/serverStatusInfo + +2019-01-29 10:46:21 +0100 akallabeth (0a8ebcfca) + + * Merge pull request #5187 from astrand/mingw-part1 + +2019-01-29 10:33:06 +0100 David Fort (53c74bead) + + * rdp: add a callback for ServerStatusInfo + +2019-01-28 15:46:12 +0100 Armin Novak (99c92308a) + + * Fixed wayland library detection. + +2019-01-28 15:29:30 +0100 Armin Novak (2418c43ca) + + * Fixed pointer image update. + +2019-01-25 15:46:55 +0100 Armin Novak (52ef8079e) + + * Added O_TMPFILE support for uwac tempfile generation. + +2019-01-25 15:38:56 +0100 Armin Novak (34adfd571) + + * Added UWAC_EVENT_OUTPUT_GEOMETRY event + +2019-01-25 13:05:51 +0100 Armin Novak (23fa6b918) + + * Added mouse cursor callback stubs. + +2019-01-25 16:59:33 +0100 David Fort (05d9d8979) + + * Merge pull request #5149 from akallabeth/cert_deny + +2019-01-25 12:33:18 +0100 MartinHaimberger (0f68ed390) + + * Merge pull request #5150 from akallabeth/gw_consent_callback + +2019-01-25 12:19:56 +0100 akallabeth (7d226ca59) + + * Merge pull request #5218 from ckelsel/master + +2019-01-25 11:42:38 +0100 David Fort (343bc8c6e) + + * Merge pull request #5213 from akallabeth/wayland_and_warning_fixes + +2019-01-25 17:54:25 +0800 xie.kunming (b8c64b6bf) + + * May crash if GetCommandLineW failed + +2019-01-25 10:50:07 +0100 Armin Novak (b1e6e232e) + + * Fixed buffer submit and callback cleanup. + +2019-01-24 15:10:08 +0100 Armin Novak (823411c2f) + + * Fixed wayland buffer updates + +2019-01-24 13:15:40 +0100 Armin Novak (0fd27e0e3) + + * Fixed wayland clipboard registration, retry if seat is detected + before. + +2019-01-25 10:01:30 +0100 akallabeth (8ed0b9292) + + * Merge pull request #5216 from ckelsel/master + +2019-01-25 16:45:52 +0800 xie.kunming (84493d003) + + * If uElapse is less than USER_TIMER_MINIMUM (0x0000000A), the + timeout is set to USER_TIMER_MINIMUM. + +2019-01-24 12:01:40 +0100 Armin Novak (86e20d764) + + * Removed buffer damage tracking in client, let UWAC handle that. + +2019-01-24 11:19:20 +0100 Armin Novak (0cf898e72) + + * Fixed warnings found by compiler and static analysis. + +2019-01-24 11:14:06 +0100 Armin Novak (728cdfd68) + + * Fixed warnings found by compiler and static analysis. + +2019-01-24 11:03:36 +0100 Armin Novak (7b92b91d9) + + * Fixed warnings found by compiler and static analysis. + +2019-01-24 11:00:48 +0100 Armin Novak (ac12adda9) + + * Fixed warnings found by compiler and static analysis. + +2019-01-24 10:33:59 +0100 Armin Novak (4ba73e0c7) + + * Fixed warnings found by compiler and static analysis. + +2019-01-24 11:53:37 +0100 akallabeth (58f616b68) + + * Merge pull request #5212 from hardening/ddm_fix + +2019-01-24 10:30:04 +0100 David Fort (713e9cd5a) + + * uwac: fix initialization of data_device_manager + +2019-01-23 17:15:59 +0100 David Fort (281c85598) + + * Merge pull request #5160 from akallabeth/wayland_clipboard + +2019-01-23 16:22:29 +0100 Armin Novak (087390b30) + + * Refactored client clipboard function callbacks for const data + pointers. + +2019-01-23 16:22:04 +0100 Armin Novak (65812bdbc) + + * Clipboard data pointer arguments are now const. + +2019-01-23 16:01:36 +0100 Armin Novak (891d9760d) + + * Ignore clipboard events if channel not loaded. + +2019-01-22 11:04:50 +0100 Armin Novak (c8e85338b) + + * Fixed missing return. + +2019-01-22 10:56:10 +0100 Armin Novak (d5b355840) + + * Added log messages for unusual error events. + +2019-01-22 10:52:24 +0100 Armin Novak (ceeccd34e) + + * Added assert + +2019-01-22 10:50:34 +0100 Armin Novak (68b5d47d9) + + * Removed internal checks. + +2019-01-22 10:48:32 +0100 Armin Novak (9eb897ea6) + + * Fixed a log message. + +2019-01-22 10:47:26 +0100 Armin Novak (9cdddb772) + + * Fixed some log messages / missing asserts. + +2019-01-16 15:01:49 +0100 Armin Novak (1cec0e034) + + * Fixed NULL dereference. + +2018-12-19 16:18:13 +0100 Armin Novak (ca2e8e4bc) + + * Implemented wayland clipboard. + +2018-12-19 16:17:59 +0100 Armin Novak (0cba9edc9) + + * Implemented UWAC clipboard handling. + +2019-01-23 15:41:42 +0100 David Fort (2843f1ad6) + + * Merge pull request #5159 from akallabeth/wayland_display + +2019-01-23 14:30:31 +0100 David Fort (b18ba3326) + + * Merge pull request #5192 from akallabeth/dynamic_openh264 + +2019-01-23 10:02:07 +0100 David Fort (4c465e7f1) + + * Merge pull request #5209 from + akallabeth/wayland_protocol_update_and_keyboard_inhibit + +2019-01-22 18:09:53 +0100 Armin Novak (9a0c8a5c5) + + * Removed unused label. + +2019-01-22 11:06:11 +0100 Armin Novak (97dfa0757) + + * Fixed duplicated check. + +2018-12-18 12:30:31 +0100 Armin Novak (42ad7a884) + + * Implemented wayland display resize channel. + +2019-01-22 17:20:19 +0100 Armin Novak (3cd3490fd) + + * Fixed initialization of window decorations. + +2019-01-22 16:13:08 +0100 Armin Novak (5c422b7c9) + + * Added KDE server side window decoration interface as fallback. + +2019-01-22 17:04:37 +0100 Martin Fleisz (b6f2a3f43) + + * Merge pull request #5201 from akallabeth/wayland_refresh_fix + +2019-01-22 16:55:46 +0100 Armin Novak (f2fd78512) + + * Fixed comment. + +2019-01-22 16:43:32 +0100 Martin Fleisz (2095fc3eb) + + * Merge pull request #5156 from akallabeth/flatpak_support + +2019-01-22 16:27:57 +0100 akallabeth (4cbd5e166) + + * Merge pull request #5202 from hardening/server_side_license1 + +2019-01-22 15:45:15 +0100 Armin Novak (afd4baf4d) + + * Added wayland server side decorations. + +2019-01-22 15:18:59 +0100 Armin Novak (84d4ff0f0) + + * Updated flatpak build + +2019-01-22 13:46:46 +0100 Armin Novak (81f1fb934) + + * Implemented keyboard shortcut inhibit support. + +2019-01-22 13:09:59 +0100 Armin Novak (0ef64f8a8) + + * Updated fullscreen shell to current protocol level. + +2019-01-22 13:05:46 +0100 Armin Novak (7f158b97b) + + * Update to xdg-shell stable. + +2019-01-22 10:29:08 +0100 Armin Novak (5ef6b7197) + + * Implemented DesktopResize callback for wayland client. + +2018-11-01 11:02:54 +0100 David Fort (f4b7a27c2) + + * license: implement server-side management + +2019-01-18 18:04:23 +0100 David Fort (ad75ae512) + + * Merge pull request #5200 from akallabeth/os2_fixes + +2019-01-18 14:39:14 +0100 Armin Novak (a5cee1751) + + * Resubmit buffer if necessary. + +2019-01-18 14:38:51 +0100 Armin Novak (0b17406ee) + + * Unified buffer update and screen refresh on focus + +2019-01-18 13:13:41 +0100 Armin Novak (4f1462b73) + + * Added fix for OS2 paths. + +2019-01-18 13:04:34 +0100 Armin Novak (c8587cea8) + + * Fixed WINDOW_ORDER_INFO copy. + +2019-01-18 13:03:36 +0100 Armin Novak (f65b94ed8) + + * Yield in connection wait loops to reduce processor use. + +2019-01-18 13:02:30 +0100 Armin Novak (b08505cbe) + + * Fixed return check in SwitchToThread + +2019-01-18 11:18:34 +0100 Martin Fleisz (cf6348939) + + * Merge pull request #5199 from llyzs/freerdp_rdpsnd_winmm + +2019-01-18 17:48:06 +0800 Vic Lee (e2df67ab3) + + * rdpsnd/winmm: remove an unnecessary blocking event. + +2019-01-18 09:11:48 +0100 Martin Fleisz (6dc179ce4) + + * Merge pull request #5197 from akallabeth/leak_fix_lodepng + +2019-01-17 14:46:55 +0100 Martin Fleisz (b131d8d52) + + * Merge pull request #5191 from akallabeth/mac_mouse_support + +2019-01-17 13:44:04 +0100 Armin Novak (4f99c2946) + + * Unified mouse coordinate scaling. + +2019-01-16 15:23:12 +0100 Armin Novak (4d4f3617b) + + * Fixed memory leak in lodepng. + +2019-01-16 14:13:27 +0100 akallabeth (0e5fe9e11) + + * Merge pull request #5196 from bmiklautz/winprhash + +2019-01-16 12:05:47 +0100 Bernhard Miklautz (3498e7694) + + * fix [winpr/hash]: initialize ssl + +2019-01-15 09:49:48 +0100 Armin Novak (8c41bd21e) + + * Added version check for dynamic OpenH264 use. + +2019-01-14 23:25:26 +0100 David Fort (ac0c91300) + + * Merge pull request #5194 from akallabeth/drive_file_size_fix2 + +2019-01-14 14:54:33 +0100 Armin Novak (805741bdf) + + * Fixed #5185 broken file size initialization. + +2019-01-11 11:40:31 +0100 Armin Novak (1c855068a) + + * Using runtime linking for OpenH264. + +2019-01-10 11:09:57 +0100 Armin Novak (a3cfef4e0) + + * Implemented full mouse support for mac client. + +2019-01-09 11:13:38 +0100 Peter Åstrand (astrand) (a7f4b90f3) + + * Pointer arithmetics require lvalue + +2019-01-09 10:04:38 +0100 Peter Åstrand (astrand) (32ba90ec0) + + * Avoid building POSIX clipboard if WIN32 + +2019-01-09 10:01:44 +0100 Peter Åstrand (astrand) (ea35e2387) + + * Check MSVC_RUNTIME only if MSVC is defined + +2019-01-09 09:54:31 +0100 Peter Åstrand (astrand) (6619de070) + + * freerdp_client_set_window_size should not be static + +2019-01-09 09:52:27 +0100 Peter Åstrand (astrand) (fcf59b9c4) + + * Add msimg32 library through CMake + +2019-01-09 09:36:28 +0100 Peter Åstrand (astrand) (30cd1ba1a) + + * Use lowercase for includes and libs + +2019-01-09 09:30:31 +0100 Peter Åstrand (astrand) (9c19c7361) + + * Support Unix Makefiles + +2019-01-08 13:42:42 +0100 David Fort (6be3ba4df) + + * Merge pull request #5186 from akallabeth/test_leak_fix + +2019-01-08 11:20:00 +0100 Armin Novak (6a175d588) + + * Fixed #5167: Memory leak in unit test. + +2019-01-08 10:18:06 +0100 Martin Fleisz (7bc69cd61) + + * Merge pull request #5155 from akallabeth/ext_debug_functions + +2019-01-08 09:45:25 +0100 Martin Fleisz (f8a200462) + + * Merge pull request #5178 from fodinabor/rds-connectionstring + +2019-01-08 09:13:52 +0100 akallabeth (56a01469f) + + * Merge pull request #5184 from chipitsine/master + +2019-01-08 08:06:28 +0100 Martin Fleisz (b0b0d5ede) + + * Merge pull request #5183 from akallabeth/libressl_version_fix + +2019-01-07 23:01:31 +0500 Ilya Shipitsin (f422fe63c) + + * identical code for both branches, found by coverity + +2019-01-07 22:55:08 +0500 Ilya Shipitsin (4403448a7) + + * client/Windows/wf_cliprdr.c: remove redundant check found by + cppcheck + +2019-01-07 15:21:46 +0100 Martin Fleisz (aa442de05) + + * Merge pull request #5174 from chipitsine/master + +2019-01-07 15:21:03 +0100 Martin Fleisz (abd5cf51f) + + * Merge pull request #5180 from chipitsine/coverity + +2019-01-07 14:18:14 +0100 Armin Novak (0c83efa75) + + * Fix #5170: Disable custom TLS alert for libressl > 2.8.3 + +2019-01-07 13:00:48 +0100 Joachim Meyer (c8358fdda) + + * Reject assistance input if not a RA invitation or connection string + 2. + +2019-01-07 10:47:48 +0100 David Fort (6cc13303b) + + * Merge pull request #5182 from akallabeth/mouse_hwheel_direction_fix + +2019-01-07 10:38:55 +0100 Joachim Meyer (7efbae282) + + * Set the username setting again, if it exists. + +2019-01-07 10:02:04 +0100 Armin Novak (b2ef3e69c) + + * Fixed Wayland horizontal mouse wheel direction. + +2019-01-07 10:01:46 +0100 Armin Novak (2dcc2614d) + + * Fixed X11 horizontal mouse wheel direction. + +2019-01-07 08:39:08 +0100 Martin Fleisz (e034d3552) + + * Merge pull request #5173 from hendwolt/master + +2019-01-04 20:56:57 +0500 Ilya Shipitsin (05462d27f) + + * remove identical code, found by coverity + +2019-01-04 20:55:28 +0500 Ilya Shipitsin (e14ba2018) + + * remove identical code, found by coverity + +2019-01-03 20:58:40 +0100 Joachim Meyer (8d50c4ce2) + + * Add support for standard Remote Assistance Connection String 2 + without the extensions of the invitation file format. + +2019-01-02 21:20:39 +0000 Bernhard Miklautz (bab79a995) + + * Merge pull request #5176 from chipitsine/ninja_gitignore + +2019-01-02 21:22:51 +0500 Ilya Shipitsin (43a16a3e5) + + * add ninja to gitignore + +2019-01-02 20:35:24 +0500 Ilya Shipitsin (bdc039e71) + + * resolve several issues found by cppcheck + +2019-01-02 12:51:40 +0100 akallabeth (442ba916b) + + * Merge pull request #5166 from informatimago/detect-kerberos-version + +2019-01-02 11:34:27 +0100 David Fort (4d086c0e4) + + * Merge pull request #5175 from simon04/patch-1 + +2019-01-02 08:18:07 +0100 Simon Legner (ff375d238) + + * fix(crypto/tls): typo + +2018-12-29 09:16:05 +0100 Hendrik Woltersdorf (f561ef957) + + * enable fonts smoothing per default + +2018-12-24 11:17:16 +0100 David Fort (15fd55ded) + + * Merge pull request #5168 from ckelsel/master + +2018-12-24 14:52:59 +0800 kunming.xie (3ef6dd2f7) + + * fix button_set_locked no return statement + +2018-12-21 11:59:04 +0100 Pascal J. Bourguignon (7d07bce64) + + * cmake: made FindGSSAPI.cmake able to detect kerberos versions such + as: "Kerberos 5 release 1.18-prerelease". + +2018-12-18 15:38:41 +0100 David Fort (5b24dc1ac) + + * Merge pull request #5158 from akallabeth/wayland_mouse + +2018-12-17 10:36:55 +0100 Armin Novak (8bf601902) + + * Feature #4841: Added flatpak manifest. + +2018-12-18 13:30:13 +0100 Armin Novak (1984f73db) + + * Implemented horizontal mouse wheel for wayland. + +2018-12-18 13:43:17 +0100 Armin Novak (f647e5cc3) + + * Implemented mouse buttons 4 and 5 for wayland. + +2018-12-17 09:09:02 +0100 Armin Novak (5dea64a46) + + * Added backtrace function working on allocated logger. + +2018-12-14 14:13:38 +0100 David Fort (faff639ad) + + * Merge pull request #5148 from akallabeth/cert_accepted_fail + +2018-12-14 10:17:52 +0100 Armin Novak (b60045af2) + + * New option to disable user certificate dialog + +2018-12-14 09:52:25 +0100 Armin Novak (6906efa35) + + * Fixed return value for already accepted certificate. + +2018-12-14 08:13:42 +0000 Bernhard Miklautz (da819bf77) + + * Merge pull request #5146 from oshogbo/master + +2018-12-13 14:02:38 -0800 Jeffrey Hein (d316e7fa1) + + * Clarified defaults of /floatbar flag + +2018-12-13 14:16:50 +0100 Mariusz Zaborski (4974af1f7) + + * There is only one primary monitor do not look for more. + +2018-12-13 13:48:44 +0100 akallabeth (6c6f08482) + + * Merge pull request #5145 from bmiklautz/sshagent_server + +2018-12-13 10:21:11 +0100 David Fort (b619ba542) + + * Merge pull request #5144 from ondrejholy/coverity2 + +2018-12-13 10:17:46 +0100 Bernhard Miklautz (9f6abd270) + + * fix [channels]: remove sshagent server side + +2018-12-13 09:47:26 +0100 Ondrej Holy (24cdcbccc) + + * uwac: Do not return destroyed UwacSeat + +2018-12-12 21:25:14 +0100 David Fort (3d4b195c4) + + * Merge pull request #5143 from jphein/master + +2018-12-12 11:29:58 -0800 Jeffrey Hein (1e84f00ef) + + * Added help description for /drive:hotplug,* + +2018-12-12 15:40:50 +0100 Armin Novak (34c9404c9) + + * Added OpenSSL include path globally. + +2018-12-12 15:36:39 +0100 akallabeth (b8cfa0f02) + + * Merge pull request #5142 from astrand/master + +2018-12-12 14:42:50 +0100 Armin Novak (31d5a3b0c) + + * Don't reset configuration and driver name when supplied via command + line. + +2018-12-12 14:10:46 +0100 Armin Novak (d13bd66f5) + + * Implemented printer name based backend to remember settings. + +2018-12-12 12:08:34 +0000 Bernhard Miklautz (7be596a5f) + + * Merge pull request #5133 from akallabeth/enable_fonts_by_default + +2018-12-12 11:43:03 +0100 Peter Åstrand (astrand) (9aced5945) + + * Define scancodes for virtual keys, used by VNC servers + +2018-12-12 10:06:41 +0100 Armin Novak (192680a00) + + * Added callback to handle printer custom components in printer + backend. + +2018-12-11 15:24:24 +0100 Armin Novak (8ddabd265) + + * Fix #1195: Implement callback for Gateway Messages + +2018-12-11 14:40:58 +0100 Martin Fleisz (4dac07667) + + * Merge pull request #5134 from oshogbo/master + +2018-12-11 13:34:31 +0100 Mariusz Zaborski (269002f0a) + + * Respect settings while sending the input capabilities. + +2018-12-11 13:02:26 +0100 Armin Novak (717b0eac9) + + * Enable smooth fonts by default. + +2018-12-11 10:30:39 +0100 Martin Fleisz (5bff8bf69) + + * Merge pull request #5125 from + akallabeth/clipboard_string_length_fix + +2018-12-11 09:12:24 +0000 Bernhard Miklautz (2fe1c786c) + + * Merge pull request #5075 from akallabeth/clipboard_channel_cleanup + +2018-12-11 08:53:39 +0000 Bernhard Miklautz (6f6c8473a) + + * Merge pull request #5126 from akallabeth/x11_button_mapping + +2018-12-11 09:32:11 +0100 Armin Novak (0fa9f0656) + + * Modified flag checks to avoid invalid flag sets. + +2018-12-11 09:19:46 +0100 Martin Fleisz (29e2e2221) + + * Merge pull request #5083 from akallabeth/mac_client_fixes + +2018-12-10 18:03:53 +0100 Bernhard Miklautz (b3ff75b59) + + * fix [client/Mac]: UI API needs to be called in main thread + +2018-12-10 17:07:16 +0000 Bernhard Miklautz (531b1b63e) + + * Merge pull request #5128 from akallabeth/rail_crashes + +2018-12-10 15:41:20 +0100 Armin Novak (2ce04069c) + + * Fixed crashes in rail mode after merge of floatbar fixes. + +2018-12-10 14:25:07 +0100 Armin Novak (710292754) + + * X11 extended button remapping support. + +2018-12-10 14:45:10 +0100 Martin Fleisz (b82c4f779) + + * Merge pull request #5020 from akallabeth/floatbar_fixes + +2018-12-10 14:31:38 +0100 Armin Novak (15011b478) + + * Fixed variable hiding by not redeclaring it in subscope. + +2018-12-10 14:02:57 +0100 Armin Novak (66e71ef96) + + * Added missing define for _wcsnlen for windows. + +2018-12-10 13:41:06 +0100 David Fort (9940c0002) + + * Merge pull request #5123 from akallabeth/rail_hash_function + +2018-12-10 12:23:13 +0000 Bernhard Miklautz (27ca916cf) + + * Merge pull request #5124 from akallabeth/cert_accept_fix + +2018-12-10 12:41:04 +0100 Armin Novak (d198f7308) + + * Fix #5121: Determine actual string length for input data + +2018-12-10 12:39:32 +0100 Armin Novak (1e644fc37) + + * Added _wcsnlen function for WCHAR string length. + +2018-12-10 12:03:55 +0100 Armin Novak (d2ac7acdd) + + * Fixed certificate accept + +2018-12-10 11:58:43 +0100 Martin Fleisz (97c5210db) + + * Merge pull request #5096 from akallabeth/dsp_channel_mix + +2018-12-10 11:16:43 +0100 Armin Novak (0d3192b9f) + + * Fixed rail window key hash function to work with UINT32 + +2018-12-10 10:26:52 +0100 akallabeth (2927114e7) + + * Merge pull request #5117 from hardening/rail_hash + +2018-12-07 10:33:07 +0100 David Fort (88e361fa0) + + * rails: allow a window with id == 0 + +2018-12-07 15:45:05 +0100 Armin Novak (9166df355) + + * Fixed windows floatbar title. + +2018-12-07 15:45:59 +0100 Martin Fleisz (fc12b9336) + + * Merge pull request #5109 from akallabeth/gw_logging + +2018-11-21 09:54:09 +0100 Armin Novak (4fd8987f5) + + * Unified windows client window title settings. + +2018-11-21 09:49:50 +0100 Armin Novak (594d10620) + + * Fixed #5040: Unified xfreerdp window title setting. + +2018-11-16 10:33:29 +0100 Armin Novak (6a9fa3dcb) + + * Refactored floatbar, extended command line settings. + +2016-06-22 14:58:39 -0400 Don Caton (68c34d5ab) + + * Windows client: Suppress minimize and restore buttons in float bar + when toggle-fullscreen is false, added window title to + float bar, improved overall appearance with gradients, + shadow and transparent icons. + +2016-06-14 14:15:08 -0400 Don Caton (352a65b49) + + * Updated .gitignore to exclude Visual Studio 2015 db files + +2018-11-15 17:58:00 +0100 Armin Novak (ac702e073) + + * Updated settings.h + +2018-11-15 17:53:28 +0100 Armin Novak (e7724cb8c) + + * Fixed a compiler warning for iterator type + +2018-11-15 17:35:52 +0100 Armin Novak (5343f6931) + + * Fixed monitor width and height checks. + +2018-11-15 14:42:31 +0100 Armin Novak (56156d217) + + * Floatbar self contained. + +2018-12-06 10:07:15 +0100 Armin Novak (aa12026ef) + + * Added additional gateway error logging. + +2018-12-07 13:03:46 +0000 Bernhard Miklautz (6c88c2173) + + * Merge pull request #5099 from akallabeth/floatbar_close_window + +2018-12-07 12:30:55 +0000 Bernhard Miklautz (62515cfd4) + + * Merge pull request #5118 from akallabeth/pem_warn_fix + +2018-12-07 12:36:18 +0100 Armin Novak (d05217454) + + * Fix #5115: Cast PEM data from BYTE* to char* to silence warnings. + +2018-12-07 11:30:58 +0100 David Fort (696fa22fb) + + * Merge pull request #5116 from akallabeth/drive_ts_fix + +2018-12-07 11:28:22 +0100 Martin Fleisz (d0688f058) + + * Merge pull request #5102 from akallabeth/rail_cleanups + +2018-12-07 10:59:52 +0100 Armin Novak (fdf9ca327) + + * Fixed #5113: The timestamps for FileFullDirectoryInformation were + inverted. + +2018-11-30 11:35:40 +0100 Armin Novak (ace9bfffd) + + * Moved to extended certificate verification API + +2018-11-29 18:35:20 +0100 Armin Novak (ec8cc65a1) + + * Fixed compile issue + +2018-11-29 18:13:31 +0100 Armin Novak (730b6f02c) + + * Fixed glitches with certificate dialog. + +2018-11-29 17:23:09 +0100 Armin Novak (ec34657ff) + + * Added certificate dialog. + +2018-11-29 16:29:07 +0100 Armin Novak (4dd6e7577) + + * Added client callbacks. + +2018-11-29 15:50:43 +0100 Armin Novak (e3c85eb3d) + + * removed strcpy + +2018-11-29 15:46:37 +0100 Armin Novak (c8938c357) + + * Updated mac build. + +2018-12-06 10:08:17 +0100 Martin Fleisz (8c7f8eb39) + + * Merge pull request #5085 from akallabeth/cert_callbacks_update + +2018-12-06 09:39:50 +0100 Armin Novak (0aaf14bed) + + * Fixe accidental removal of certificate_data_replace + +2018-12-05 16:27:05 +0100 Martin Fleisz (f678a91d6) + + * Merge pull request #5106 from hardening/wayland_seat7 + +2018-12-05 15:21:00 +0100 David Fort (b9ceb1305) + + * uwac: handle wl_seat with version >= 7 + +2018-12-05 15:20:11 +0100 David Fort (42c083eae) + + * script: add a usefull script to create code snippets from + specification blobs + +2018-12-05 11:24:51 +0100 akallabeth (5e0fef582) + + * Merge pull request #5104 from hardening/license_2k3 + +2018-12-05 11:20:34 +0100 Martin Fleisz (7db6ac063) + + * Merge pull request #5036 from akallabeth/auth_fixes + +2018-12-05 11:19:53 +0100 Martin Fleisz (bb187d8ea) + + * Merge pull request #5103 from akallabeth/android_timezone + +2018-12-05 10:57:43 +0100 Martin Fleisz (30b31b7fb) + + * Merge pull request #5062 from + akallabeth/init_freerdp_image_copy_from_pointer_data + +2018-11-20 18:01:13 +0100 Armin Novak (e49adfc51) + + * Updated error info from spec. + +2018-11-20 17:27:47 +0100 Armin Novak (8110c391b) + + * Fixed requested protocol define names according to spec. + +2018-11-20 17:03:50 +0100 Armin Novak (b1d2a4767) + + * Fixed warnings in nego. + +2018-11-20 16:48:59 +0100 Armin Novak (82863a851) + + * Refactored NLA to be self contained. + +2018-11-20 16:40:42 +0100 Armin Novak (80d246283) + + * Hide redirection implementation details. + +2018-11-20 16:38:06 +0100 Armin Novak (5ca8eca18) + + * Made nego self contained. + +2018-12-05 10:50:47 +0100 David Fort (635b17d0a) + + * license: fix licencing against windows 2003 server + +2018-12-05 10:20:21 +0100 Armin Novak (3d487d071) + + * Fixed #5093: Try to read timezone from java TimeZone first + +2018-12-05 09:13:04 +0100 Armin Novak (f5e449a4f) + + * Cleaned up xf_rail_server_handshake + +2018-12-05 08:58:08 +0100 akallabeth (1b4ee6594) + + * Merge pull request #5100 from wintersandroid/master + +2018-12-04 22:42:25 +0100 David Fort (46ffa611c) + + * Merge pull request #5097 from hualet/master + +2018-12-05 07:56:05 +1300 Mathew Winters (bd7ff9b10) + + * Add jni interface for get_last_error_string + +2018-12-04 16:56:22 +0100 Armin Novak (0c13c3199) + + * Follow up to #4959: Lock gdi_UpdateSurfaces like xf_UpdateSurfaces + +2018-12-04 16:42:28 +0100 Armin Novak (d260d4e29) + + * Fixed #5098: Abort connection and let the application clean up + resources before exit. + +2018-12-04 16:40:44 +0100 Martin Fleisz (df6d045f4) + + * Merge pull request #5087 from hardening/remotefx_chunks + +2018-12-04 14:38:11 +0100 David Fort (a1c203322) + + * Merge pull request #5094 from akallabeth/suppress_output_setting + +2018-12-04 14:29:59 +0100 Martin Fleisz (5510f9304) + + * Merge pull request #4959 from akallabeth/gfx_lock_fix + +2018-12-04 20:28:32 +0800 Hualet Wang (e33efccf4) + + * Fixed RAIL window can't show again once hidden + +2018-12-04 11:38:02 +0100 Armin Novak (e46575671) + + * Fix #5019: Added channel up/downmixing code for mono/stereo. + +2018-11-30 11:37:23 +0100 David Fort (579a13b05) + + * remotefx: don't require data messages to come all in one chunk + +2018-12-04 10:31:01 +0100 Martin Fleisz (4108fc51a) + + * Merge pull request #5077 from akallabeth/win_client_fixes + +2018-11-30 11:41:51 +0100 Armin Novak (b27470405) + + * Duplicate PEM when accepted. + +2018-11-30 11:04:20 +0100 Armin Novak (e04c319d2) + + * Added new default certificate callbacks with extended information. + +2018-11-30 10:36:15 +0100 Armin Novak (a8823fdf9) + + * Cleaned up certificate verification code. + +2018-11-30 10:25:06 +0100 Armin Novak (7ab07ab98) + + * Added certificate callbacks with source indications. + +2018-11-30 09:55:10 +0100 Armin Novak (dd3276d66) + + * Prefer VerifyX509Certificate and fixed const arguments + +2018-12-03 16:15:51 +0100 Armin Novak (1398fa5b2) + + * Fixed missing NULL check for thread handle. + +2018-11-28 16:09:38 +0100 Armin Novak (0831c34fc) + + * Fix #4730: Add git revision, architecture and minimum os support to + file properties. + +2018-11-28 14:44:26 +0100 Armin Novak (c5512de26) + + * Fix #4999: Increase reference count + +2018-11-28 13:12:28 +0100 Armin Novak (53b018bfe) + + * Fix callback function return types. + +2018-11-28 13:12:04 +0100 Armin Novak (22be8f21a) + + * Fix length type, use size_t + +2018-11-29 18:42:32 +0000 Alessandro Muggianu (9b1c9da6a) + + * Make "suppress output" setting available on command line + +2018-12-04 08:23:14 +0000 Bernhard Miklautz (1e27c3d19) + + * Merge pull request #5091 from akallabeth/ios_compiles_again + +2018-12-03 17:23:55 +0100 Armin Novak (d27cd1b19) + + * Fixed unit tests, use uniqe file names + +2018-12-03 17:06:43 +0100 Armin Novak (6a75bc806) + + * Updated OpenSSL version for iOS + +2018-12-03 16:54:56 +0100 Armin Novak (4c3626340) + + * Set minimum deployment target to 10.0 + +2018-12-03 14:45:16 +0100 Martin Fleisz (47066c25e) + + * Merge pull request #5082 from akallabeth/win_env_fix + +2018-11-29 16:24:28 +0100 David Fort (7ad24b606) + + * Merge pull request #5080 from akallabeth/scanbuild-ex-warn + +2018-11-29 13:44:21 +0100 Armin Novak (edd6d49f2) + + * Fix #4909: Do not initialize HOME environment variable as it is no + longer used. + +2018-11-29 13:22:23 +0100 David Fort (06e2651b4) + + * Merge pull request #5081 from akallabeth/kerberos_config_option + +2018-11-29 13:00:22 +0100 Armin Novak (b8b308af7) + + * Add WITH_GSSAPI config option, defaults to OFF + +2018-11-29 12:14:20 +0100 Armin Novak (aeeaba5bc) + + * Fixed a memory leak. + +2018-11-29 11:07:46 +0100 Armin Novak (d975fd045) + + * Fixed zero sized allocation. + +2018-11-29 11:06:41 +0100 Armin Novak (7ec9e942f) + + * Fixed zero sized allocation. + +2018-11-29 11:05:13 +0100 Armin Novak (16a761319) + + * Fixed zero sized allocation. + +2018-11-29 11:10:14 +0000 Bernhard Miklautz (1a33b3383) + + * Merge pull request #5070 from akallabeth/gw_fixes_redirection + +2018-10-23 11:52:06 +0200 Armin Novak (2e019b2fd) + + * Implemented GFX locking and enforce return value checks. + +2018-11-29 10:57:46 +0100 Armin Novak (c97d4eec6) + + * Fixed uninitialized value. + +2018-11-29 09:50:12 +0000 Bernhard Miklautz (62d982b62) + + * Merge pull request #5073 from akallabeth/trust_settings + +2018-11-29 10:02:28 +0100 David Fort (7478a938a) + + * Merge pull request #5074 from akallabeth/ycbcr_padding_fix + +2018-11-28 17:46:18 +0100 David Fort (e7a44bc43) + + * Merge pull request #5057 from + akallabeth/order_settings_init_generic + +2018-11-28 09:32:28 +0100 Armin Novak (f3e1ffb12) + + * Fix #4764: Second try, use X509_STORE_CTX_set_purpose + +2018-11-28 11:40:15 +0100 Armin Novak (81a0cd701) + + * Fixed clipboard channel cleanup. + +2018-11-28 11:05:45 +0100 Armin Novak (98bc4358e) + + * Fixed padding of general_yCbCrToRGB_16s8u_P3AC4R* functions. + +2018-11-26 14:11:29 +0100 Armin Novak (263cc7458) + + * Fixed buffer reset in fields_present_to_string + +2018-11-26 13:01:00 +0000 Bernhard Miklautz (657087e3a) + + * Merge pull request #5066 from akallabeth/ssl_verify_fix + +2018-11-26 11:10:59 +0000 Bernhard Miklautz (52d1b35a6) + + * Merge pull request #5046 from akallabeth/silence_wlog + +2018-11-26 11:03:42 +0000 Bernhard Miklautz (e06ed191a) + + * Merge pull request #5067 from akallabeth/gfx_log_fix + +2018-11-26 08:12:51 +0100 Armin Novak (77744200a) + + * Fix #4768: Set SSL verify purpose to ANY + +2018-11-26 10:57:20 +0000 Bernhard Miklautz (0b8010f8d) + + * Merge pull request #5065 from akallabeth/tcp_connect_multi_fix + +2018-11-26 11:33:23 +0100 Armin Novak (d06c3980a) + + * Fixed error log for avc420_decompress failures. + +2018-11-23 09:16:23 +0100 Armin Novak (0d8a1e108) + + * Fix #5061: Initialize output buffer transparent. + +2018-11-23 10:49:00 +0100 MartinHaimberger (8ae6b463e) + + * Merge pull request #5064 from akallabeth/rdg_length_check_fix + +2018-11-23 10:32:52 +0100 Armin Novak (5623a4761) + + * Fixed a possible NULL dereference. + +2018-11-22 16:54:42 +0100 Armin Novak (7d89ea22d) + + * Unified initialization of OrderSupport + +2018-11-23 10:03:56 +0100 Martin Fleisz (394bc6286) + + * Merge pull request #5035 from akallabeth/better_cmdline_format + +2018-11-23 09:48:08 +0100 Martin Fleisz (9684a06f8) + + * Merge pull request #5053 from akallabeth/sample_client_update + +2018-11-23 09:45:09 +0100 Armin Novak (391528f40) + + * Fixed a broken length check in rdg_process_packet + +2018-11-22 22:22:57 +0000 Bernhard Miklautz (4c4e5b887) + + * Merge pull request #5060 from akallabeth/small_fixes + +2018-11-22 19:10:05 +0100 akallabeth (effa8b856) + + * Fix #5049: Libressl declares OPENSSL_VERSION_NUMBER too high + +2018-11-22 19:08:25 +0100 akallabeth (d0d414dfa) + + * Fix #5059: Changed return type of peer_free to void. + +2018-11-22 17:53:00 +0100 David Fort (edcff62ff) + + * Merge pull request #5058 from akallabeth/wtsapi_warning_fix + +2018-11-22 17:28:31 +0100 Armin Novak (96fe23193) + + * Initialize WtsApi32_WtsApiFunctionTable NULL + +2018-11-22 16:28:30 +0100 Armin Novak (e6e87eb3b) + + * Unified strto[u]l in cmdline.c + +2018-11-20 14:11:10 +0100 Armin Novak (2f8737d97) + + * Improved formatting of terminal help messages. + +2018-11-22 15:50:52 +0100 David Fort (8d62ced6a) + + * Merge pull request #5056 from akallabeth/direct_fb_remove + +2018-11-22 15:10:58 +0100 Martin Fleisz (6c97d318e) + + * Merge pull request #5022 from akallabeth/gw_rdg_error_mapping + +2018-11-22 14:37:10 +0100 Armin Novak (fff22f027) + + * Removed DirectFB client as it is unmaintained + +2018-11-22 14:29:22 +0100 Armin Novak (3110b5f5c) + + * Simplified string empty check. + +2018-11-22 14:03:01 +0100 Martin Fleisz (3610ab0ac) + + * Merge pull request #5054 from akallabeth/spelling_fix + +2018-11-22 12:06:30 +0100 Armin Novak (a471fc593) + + * Spelling fix in log message. + +2018-11-22 11:47:58 +0100 Martin Fleisz (1331d0b77) + + * Merge pull request #4998 from akallabeth/assistance_v2 + +2018-11-22 11:21:57 +0100 Armin Novak (7ba34962e) + + * Removed duplcate NULL checks. + +2018-11-22 11:19:12 +0100 Armin Novak (f79eeb744) + + * Fixed NULL access checks. + +2018-11-22 11:17:13 +0100 Armin Novak (f904d8463) + + * Fixed freerdp_assistance_parse_address_list + +2018-11-22 11:16:43 +0100 Armin Novak (3f655db3c) + + * Fixed test_msrsc_incident_file_type1 return checks. + +2018-11-21 15:03:30 +0100 Armin Novak (59e9abc73) + + * Fixed memory leak in reallocate. + +2018-11-12 13:40:40 +0100 Armin Novak (c8908c8be) + + * Updated windows shadow server assistance usage. + +2018-11-12 12:37:33 +0100 Armin Novak (8df39fdad) + + * Use blocking sockets in freerdp_tcp_connect_multi + +2018-11-12 11:16:24 +0100 Armin Novak (1ed436c8f) + + * Fixed socket cleanup in connect multi. + +2018-11-12 10:34:21 +0100 Armin Novak (a531930f3) + + * Disable NLA for remote assistance. + +2018-11-12 10:33:46 +0100 Armin Novak (6c02a1c7d) + + * Fixed version check for remote assistance channel. + +2018-11-12 09:19:38 +0100 Armin Novak (484ceaed3) + + * Fixed assistance unit test. + +2018-11-09 15:21:13 +0100 Armin Novak (4b3f4cc2f) + + * Fixed event check in freerdp_tcp_connect_multi + +2018-11-09 15:20:37 +0100 Armin Novak (e1555662d) + + * Set username from assistance file. + +2018-11-09 14:42:10 +0100 Armin Novak (35c1eac6e) + + * Unified address parsing for assistance files. + +2018-11-08 09:27:57 +0100 Armin Novak (6de2129a9) + + * assistance v2 support + +2018-11-22 10:45:12 +0100 Martin Fleisz (a1712a6c9) + + * Merge pull request #5051 from akallabeth/libressl_fix + +2018-11-22 10:22:40 +0100 Armin Novak (6ab3d3e8f) + + * Fix #5052: Updated client sample + +2018-11-22 09:23:46 +0100 Armin Novak (649f49fa6) + + * Fix #5049: LibreSSL does not have SSL_CTX_set_security_level + +2018-11-21 16:03:18 +0100 David Fort (5e7ac925f) + + * Merge pull request #5045 from akallabeth/license_double_free_fix + +2018-11-21 16:02:47 +0100 Martin Fleisz (947aa8003) + + * Merge pull request #5016 from akallabeth/windows_server_build_fix + +2018-11-21 15:36:31 +0100 Armin Novak (17bbe7a23) + + * Do not compile extended authentication debugging by default. + +2018-11-21 15:03:42 +0100 Armin Novak (feb993b94) + + * Fixed double free in license_free_binary_blob + +2018-11-21 15:06:58 +0100 MartinHaimberger (66733e9c3) + + * Merge pull request #5041 from akallabeth/compile_fix + +2018-11-21 14:32:07 +0100 Armin Novak (cdf1ee61f) + + * Proper field to string debug functions for each response in RDG + +2018-11-21 11:49:45 +0100 akallabeth (1cc739f10) + + * Merge pull request #5039 from mcsong/master + +2018-11-21 09:55:38 +0100 Armin Novak (a97bf2110) + + * Fixed broken DEBUG_RDP log message. + +2018-11-21 09:18:38 +0100 Armin Novak (d8d30a055) + + * Fix #5037: Fix calls to ntlm_print_av_pair_list + +2018-11-20 13:11:14 -0800 mcsong (34e8b9271) + + * Fixed recreate activity issue when a bluetooth device connected or + disconnected + +2018-11-20 12:57:07 -0800 mcsong (1d7fd201b) + + * Fixed recreate activity issue when a bluetooth device connected or + disconnected. + +2018-11-20 12:14:28 +0100 akallabeth (3cea4bfb5) + + * Merge pull request #5008 from wintersandroid/master + +2018-11-20 12:05:47 +0100 akallabeth (bfbe0cb3d) + + * Merge pull request #5033 from bmiklautz/dev5 + +2018-11-20 11:49:34 +0100 Bernhard Miklautz (58091dc13) + + * new: development cycle dev5 + 2018-11-20 11:43:51 +0100 akallabeth (e21b72c95) * Merge pull request #5032 from bmiklautz/rc4 @@ -98,6 +1471,10 @@ * Merge pull request #5025 from DustPuppyNet/openssl_1_1_1 +2018-11-19 08:27:36 +1300 Mathew Winters (eceb107dd) + + * Revert store password variable + 2018-11-18 14:09:37 +0000 Christian Gall (fffe4f077) * * remove obsolete SSLv23_client_method in tls_connect() * set min @@ -112,6 +1489,14 @@ * call xf_SetWindowTitle before XMapWindow, so window manager can act on window name +2018-11-16 15:48:10 +0100 Armin Novak (7839091f8) + + * Skip redirection resolve test if we're connecting via gateway. + +2018-11-16 15:41:19 +0100 Armin Novak (870b7025b) + + * Improved error mapping and tightened checks in rdg_process_packet + 2018-11-15 17:52:43 +0100 Armin Novak (d2e1248b0) * Fixed profiler API @@ -153,6 +1538,14 @@ * Merge pull request #5012 from akallabeth/rail_app_icons +2018-11-14 15:13:11 +0100 Armin Novak (26b83ea74) + + * Reenabled and fixed windows server compile. + +2018-11-14 14:59:58 +0100 Armin Novak (a2cd93418) + + * Fixed windows build warnings. + 2018-11-15 08:43:54 +0100 akallabeth (cf2c8ef6a) * Merge pull request #5015 from chipitsine/cleanup @@ -165,6 +1558,10 @@ * remove not needed check +2018-11-15 08:29:51 +1300 Mathew Winters (0e88eb5a9) + + * Fixes as per merge request + 2018-11-14 13:45:31 +0100 akallabeth (268a2c0cf) * Merge pull request #4979 from hardening/CAL @@ -276,6 +1673,10 @@ * Updated RDP_VERSION definitions. +2018-11-14 15:25:38 +1300 Mathew Winters (f91a4d0b6) + + * Resolve thread not exiting when remote lost or disconnected. + 2018-11-13 14:39:39 +0100 akallabeth (ca6d1d591) * Merge pull request #5005 from bmiklautz/nightly_build @@ -365,6 +1766,14 @@ * Fixed #2039: Check for overflow in calculations. +2018-11-09 15:20:52 +1300 Mathew (2ff19597d) + + * fix scripts to build with ndk r15c, cache dependancies so we are + not hitting github often update android dependancies to + latest and compile. ./android-build-freerdp.sh --ndk + ~/Programming/android-ndk-r15c --relWithDebug --jpeg Still + an error compiling openh264 + 2018-11-08 17:41:56 +0100 Armin Novak (cf8bc72dc) * Fixed profiler naming in tests. diff --git a/channels/audin/client/opensles/audin_opensl_es.c b/channels/audin/client/opensles/audin_opensl_es.c index 549edd0..7ad5601 100644 --- a/channels/audin/client/opensles/audin_opensl_es.c +++ b/channels/audin/client/opensles/audin_opensl_es.c @@ -93,11 +93,6 @@ static UINT audin_opensles_free(IAudinDevice* device) WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*) device); - /* The function may have been called out of order, - * ignore duplicate requests. */ - if (!opensles) - return CHANNEL_RC_OK; - free(opensles->device_name); free(opensles); return CHANNEL_RC_OK; @@ -154,11 +149,6 @@ static UINT audin_opensles_set_format(IAudinDevice* device, (void*) device, (void*) format, FramesPerPacket); assert(format); - /* The function may have been called out of order, ignore - * requests before the device is available. */ - if (!opensles) - return CHANNEL_RC_OK; - opensles->format = *format; switch (format->wFormatTag) diff --git a/channels/audin/client/oss/audin_oss.c b/channels/audin/client/oss/audin_oss.c index e1d73b2..9919ee5 100644 --- a/channels/audin/client/oss/audin_oss.c +++ b/channels/audin/client/oss/audin_oss.c @@ -279,7 +279,7 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg) err_out: - if (error && oss->rdpcontext) + if (error && oss && oss->rdpcontext) setChannelError(oss->rdpcontext, error, "audin_oss_thread_func reported an error"); diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c index 5e21005..00f098d 100644 --- a/channels/audin/client/winmm/audin_winmm.c +++ b/channels/audin/client/winmm/audin_winmm.c @@ -27,8 +27,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index 8ab0903..2b7622f 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -216,7 +216,7 @@ static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, - UINT16 length, UINT16 flags) + UINT32 length, UINT16 flags) { UINT16 index; UINT16 lengthCapability; @@ -257,7 +257,6 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, default: WLog_ERR(TAG, "unknown cliprdr capability set: %"PRIu16"", capabilitySetType); return CHANNEL_RC_BAD_PROC; - break; } } @@ -270,7 +269,7 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, - UINT16 length, UINT16 flags) + UINT32 length, UINT16 flags) { CLIPRDR_MONITOR_READY monitorReady; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); @@ -587,10 +586,10 @@ static UINT cliprdr_order_recv(cliprdrPlugin* cliprdr, wStream* s) * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_client_capabilities(CliprdrClientContext* context, - CLIPRDR_CAPABILITIES* capabilities) + const CLIPRDR_CAPABILITIES* capabilities) { wStream* s; - CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet; + const CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN); @@ -602,7 +601,7 @@ static UINT cliprdr_client_capabilities(CliprdrClientContext* context, Stream_Write_UINT16(s, 1); /* cCapabilitiesSets */ Stream_Write_UINT16(s, 0); /* pad1 */ - generalCapabilitySet = (CLIPRDR_GENERAL_CAPABILITY_SET*)capabilities->capabilitySets; + generalCapabilitySet = (const CLIPRDR_GENERAL_CAPABILITY_SET*)capabilities->capabilitySets; Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetType); /* capabilitySetType */ Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetLength); /* lengthCapability */ Stream_Write_UINT32(s, generalCapabilitySet->version); /* version */ @@ -617,7 +616,7 @@ static UINT cliprdr_client_capabilities(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_temp_directory(CliprdrClientContext* context, - CLIPRDR_TEMP_DIRECTORY* tempDirectory) + const CLIPRDR_TEMP_DIRECTORY* tempDirectory) { int length; wStream* s; @@ -639,8 +638,8 @@ static UINT cliprdr_temp_directory(CliprdrClientContext* context, if (length > 520) length = 520; - Stream_Write(s, wszTempDir, length * 2); - Stream_Zero(s, (520 - length) * 2); + Stream_Write(s, wszTempDir, (size_t)length * 2); + Stream_Zero(s, (520 - (size_t)length) * 2); free(wszTempDir); WLog_Print(cliprdr->log, WLOG_DEBUG, "TempDirectory: %s", tempDirectory->szTempDir); @@ -653,15 +652,15 @@ static UINT cliprdr_temp_directory(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_client_format_list(CliprdrClientContext* context, - CLIPRDR_FORMAT_LIST* formatList) + const CLIPRDR_FORMAT_LIST* formatList) { wStream* s; UINT32 index; - int length = 0; + UINT32 length = 0; int cchWideChar; LPWSTR lpWideCharStr; - int formatNameSize; - int formatNameLength; + size_t formatNameSize; + size_t formatNameLength; char* szFormatName; WCHAR* wszFormatName; BOOL asciiNames = FALSE; @@ -703,8 +702,14 @@ static UINT cliprdr_client_format_list(CliprdrClientContext* context, wszFormatName = NULL; if (szFormatName) - formatNameSize = ConvertToUnicode(CP_UTF8, 0, szFormatName, -1, &wszFormatName, - 0); + { + int rc = ConvertToUnicode(CP_UTF8, 0, szFormatName, -1, &wszFormatName, 0); + + if (rc < 0) + return ERROR_INTERNAL_ERROR; + + formatNameSize = (size_t)rc; + } if (formatNameSize > 15) formatNameSize = 15; @@ -726,8 +731,14 @@ static UINT cliprdr_client_format_list(CliprdrClientContext* context, formatNameSize = 2; if (format->formatName) - formatNameSize = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL, - 0) * 2; + { + int rc = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL, 0); + + if (rc < 0) + return ERROR_INTERNAL_ERROR; + + formatNameSize = (size_t)rc * 2; + } length += formatNameSize; } @@ -771,14 +782,12 @@ static UINT cliprdr_client_format_list(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_client_format_list_response(CliprdrClientContext* context, - CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) + const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) { wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - formatListResponse->msgType = CB_FORMAT_LIST_RESPONSE; - formatListResponse->dataLen = 0; - s = cliprdr_packet_new(formatListResponse->msgType, - formatListResponse->msgFlags, formatListResponse->dataLen); + s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, + formatListResponse->msgFlags, 0); if (!s) { @@ -796,7 +805,7 @@ static UINT cliprdr_client_format_list_response(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_client_lock_clipboard_data(CliprdrClientContext* context, - CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) + const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) { wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; @@ -821,7 +830,7 @@ static UINT cliprdr_client_lock_clipboard_data(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context, - CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) + const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) { wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; @@ -846,15 +855,12 @@ static UINT cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_client_format_data_request(CliprdrClientContext* context, - CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) + const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - formatDataRequest->msgType = CB_FORMAT_DATA_REQUEST; - formatDataRequest->msgFlags = 0; - formatDataRequest->dataLen = 4; - s = cliprdr_packet_new(formatDataRequest->msgType, formatDataRequest->msgFlags, - formatDataRequest->dataLen); + + s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4); if (!s) { @@ -873,12 +879,12 @@ static UINT cliprdr_client_format_data_request(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_client_format_data_response(CliprdrClientContext* context, - CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) + const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) { wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - formatDataResponse->msgType = CB_FORMAT_DATA_RESPONSE; - s = cliprdr_packet_new(formatDataResponse->msgType, + + s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, formatDataResponse->msgFlags, formatDataResponse->dataLen); if (!s) @@ -899,7 +905,7 @@ static UINT cliprdr_client_format_data_response(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_client_file_contents_request(CliprdrClientContext* context, - CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) + const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; @@ -933,7 +939,7 @@ static UINT cliprdr_client_file_contents_request(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_client_file_contents_response(CliprdrClientContext* context, - CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) + const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) { wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; @@ -989,7 +995,7 @@ static UINT cliprdr_virtual_channel_event_data_received(cliprdrPlugin* cliprdr, return CHANNEL_RC_NO_MEMORY; } - if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength)) + if (!Stream_EnsureRemainingCapacity(data_in, dataLength)) { Stream_Free(cliprdr->data_in, TRUE); cliprdr->data_in = NULL; @@ -1100,6 +1106,17 @@ static DWORD WINAPI cliprdr_virtual_channel_client_thread(LPVOID arg) return error; } +static void cliprdr_free_msg(void* obj) +{ + wMessage* msg = (wMessage*)obj; + + if (msg) + { + wStream* s = (wStream*)msg->wParam; + Stream_Free(s, TRUE); + } +} + /** * Function description * @@ -1109,6 +1126,7 @@ static UINT cliprdr_virtual_channel_event_connected(cliprdrPlugin* cliprdr, LPVOID pData, UINT32 dataLength) { UINT32 status; + wObject obj = { 0 }; status = cliprdr->channelEntryPoints.pVirtualChannelOpenEx(cliprdr->InitHandle, &cliprdr->OpenHandle, cliprdr->channelDef.name, cliprdr_virtual_channel_open_event_ex); @@ -1120,7 +1138,8 @@ static UINT cliprdr_virtual_channel_event_connected(cliprdrPlugin* cliprdr, return status; } - cliprdr->queue = MessageQueue_New(NULL); + obj.fnObjectFree = cliprdr_free_msg; + cliprdr->queue = MessageQueue_New(&obj); if (!cliprdr->queue) { diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index f27381b..bfc24c8 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -1447,12 +1447,12 @@ static UINT drdynvc_virtual_channel_event_disconnected(drdynvcPlugin* drdynvc) { UINT status; - if (drdynvc->OpenHandle == 0) - return CHANNEL_RC_OK; - if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; + if (drdynvc->OpenHandle == 0) + return CHANNEL_RC_OK; + if (!MessageQueue_PostQuit(drdynvc->queue, 0)) { status = GetLastError(); diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index f816695..0b5a707 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -54,8 +54,7 @@ static void drive_file_fix_path(WCHAR* path) { size_t i; - size_t length; - length = (int) _wcslen(path); + size_t length = _wcslen(path); for (i = 0; i < length; i++) { @@ -80,10 +79,10 @@ static void drive_file_fix_path(WCHAR* path) } static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path, - UINT32 PathLength) + size_t PathLength) { WCHAR* fullpath; - UINT32 base_path_length; + size_t base_path_length; if (!base_path || !path) return NULL; @@ -107,11 +106,10 @@ static BOOL drive_file_remove_dir(const WCHAR* path) { WIN32_FIND_DATAW findFileData; BOOL ret = TRUE; - INT len; HANDLE dir; WCHAR* fullpath; WCHAR* path_slash; - UINT32 base_path_length; + size_t base_path_length; if (!path) return FALSE; @@ -140,7 +138,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path) do { - len = _wcslen(findFileData.cFileName); + size_t len = _wcslen(findFileData.cFileName); if ((len == 1 && findFileData.cFileName[0] == L'.') || (len == 2 && findFileData.cFileName[0] == L'.' && findFileData.cFileName[1] == L'.')) @@ -335,7 +333,7 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat file->file_handle = INVALID_HANDLE_VALUE; file->find_handle = INVALID_HANDLE_VALUE; file->id = id; - file->basepath = (WCHAR*) base_path; + file->basepath = base_path; file->FileAttributes = FileAttributes; file->DesiredAccess = DesiredAccess; file->CreateDisposition = CreateDisposition; @@ -397,7 +395,10 @@ BOOL drive_file_seek(DRIVE_FILE* file, UINT64 Offset) if (!file) return FALSE; - loffset.QuadPart = Offset; + if (Offset > INT64_MAX) + return FALSE; + + loffset.QuadPart = (LONGLONG)Offset; return SetFilePointerEx(file->file_handle, loffset, NULL, FILE_BEGIN); } @@ -615,6 +616,8 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN return FALSE; } + liSize.QuadPart = size; + if (!SetFilePointerEx(file->file_handle, liSize, NULL, FILE_BEGIN)) { WLog_ERR(TAG, "Unable to truncate %s to %d (%"PRId32")", file->fullpath, size, GetLastError()); @@ -755,7 +758,10 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT if (!Stream_EnsureRemainingCapacity(output, 4 + 64 + length)) goto out_fail; - Stream_Write_UINT32(output, 64 + length); /* Length */ + if (length > UINT32_MAX - 64) + goto out_fail; + + Stream_Write_UINT32(output, (UINT32)(64 + length)); /* Length */ Stream_Write_UINT32(output, 0); /* NextEntryOffset */ Stream_Write_UINT32(output, 0); /* FileIndex */ Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */ @@ -771,7 +777,7 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */ Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */ Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */ - Stream_Write_UINT32(output, length); /* FileNameLength */ + Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */ Stream_Write(output, file->find_data.cFileName, length); break; @@ -781,23 +787,26 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT if (!Stream_EnsureRemainingCapacity(output, 4 + 68 + length)) goto out_fail; - Stream_Write_UINT32(output, 68 + length); /* Length */ + if (length > UINT32_MAX - 68) + goto out_fail; + + Stream_Write_UINT32(output, (UINT32)(68 + length)); /* Length */ Stream_Write_UINT32(output, 0); /* NextEntryOffset */ Stream_Write_UINT32(output, 0); /* FileIndex */ - Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */ Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */ - Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */ Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */ - Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ - Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */ Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */ Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */ Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */ Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */ Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */ Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */ - Stream_Write_UINT32(output, length); /* FileNameLength */ + Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */ Stream_Write_UINT32(output, 0); /* EaSize */ Stream_Write(output, file->find_data.cFileName, length); break; @@ -808,7 +817,10 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT if (!Stream_EnsureRemainingCapacity(output, 4 + 93 + length)) goto out_fail; - Stream_Write_UINT32(output, 93 + length); /* Length */ + if (length > UINT32_MAX - 93) + goto out_fail; + + Stream_Write_UINT32(output, (UINT32)(93 + length)); /* Length */ Stream_Write_UINT32(output, 0); /* NextEntryOffset */ Stream_Write_UINT32(output, 0); /* FileIndex */ Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */ @@ -824,7 +836,7 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */ Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */ Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */ - Stream_Write_UINT32(output, length); /* FileNameLength */ + Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */ Stream_Write_UINT32(output, 0); /* EaSize */ Stream_Write_UINT8(output, 0); /* ShortNameLength */ /* Reserved(1), MUST NOT be added! */ @@ -838,14 +850,18 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT if (!Stream_EnsureRemainingCapacity(output, 4 + 12 + length)) goto out_fail; - Stream_Write_UINT32(output, 12 + length); /* Length */ + if (length > UINT32_MAX - 12) + goto out_fail; + + Stream_Write_UINT32(output, (UINT32)(12 + length)); /* Length */ Stream_Write_UINT32(output, 0); /* NextEntryOffset */ Stream_Write_UINT32(output, 0); /* FileIndex */ - Stream_Write_UINT32(output, length); /* FileNameLength */ + Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */ Stream_Write(output, file->find_data.cFileName, length); break; default: + WLog_ERR(TAG, "unhandled FsInformationClass %"PRIu32, FsInformationClass); /* Unhandled FsInformationClass */ goto out_fail; } diff --git a/channels/drive/client/drive_file.h b/channels/drive/client/drive_file.h index b928187..45e7612 100644 --- a/channels/drive/client/drive_file.h +++ b/channels/drive/client/drive_file.h @@ -40,7 +40,7 @@ struct _DRIVE_FILE HANDLE file_handle; HANDLE find_handle; WIN32_FIND_DATAW find_data; - WCHAR* basepath; + const WCHAR* basepath; WCHAR* fullpath; WCHAR* filename; BOOL delete_pending; diff --git a/channels/printer/client/printer_cups.c b/channels/printer/client/printer_cups.c index d6f0705..8af8752 100644 --- a/channels/printer/client/printer_cups.c +++ b/channels/printer/client/printer_cups.c @@ -84,7 +84,7 @@ static void printer_cups_get_printjob_name(char* buf, int size) * * @return 0 on success, otherwise a Win32 error code */ -static UINT printer_cups_write_printjob(rdpPrintJob* printjob, BYTE* data, int size) +static UINT printer_cups_write_printjob(rdpPrintJob* printjob, const BYTE* data, size_t size) { rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*) printjob; diff --git a/channels/printer/client/printer_main.c b/channels/printer/client/printer_main.c index 630c0c0..c7b0407 100644 --- a/channels/printer/client/printer_main.c +++ b/channels/printer/client/printer_main.c @@ -35,8 +35,10 @@ #include #include #include +#include #include +#include #include "../printer.h" @@ -71,6 +73,364 @@ struct _PRINTER_DEVICE char port[64]; }; +typedef enum +{ + PRN_CONF_PORT = 0, + PRN_CONF_PNP = 1, + PRN_CONF_DRIVER = 2, + PRN_CONF_DATA = 3 +} +prn_conf_t; + +static const char* filemap[] = +{ + "PortDosName", + "PnPName", + "DriverName", + "CachedPrinterConfigData" +}; + +static char* get_printer_config_path(const rdpSettings* settings, const WCHAR* name, size_t length) +{ + char* dir = GetCombinedPath(settings->ConfigPath, "printers"); + char* bname = crypto_base64_encode((const BYTE*) name, (int)length); + char* config = GetCombinedPath(dir, bname); + + if (config && !PathFileExistsA(config)) + { + if (!PathMakePathA(config, NULL)) + { + free(config); + config = NULL; + } + } + + free(dir); + free(bname); + return config; +} + +static BOOL printer_write_setting(const char* path, prn_conf_t type, const void* data, + size_t length) +{ + DWORD written = 0; + BOOL rc = FALSE; + HANDLE file; + size_t b64len; + char* base64 = NULL; + const char* name = filemap[type]; + char* abs = GetCombinedPath(path, name); + + if (!abs) + return FALSE; + + file = CreateFileA(abs, GENERIC_WRITE, 0, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + free(abs); + + if (file == INVALID_HANDLE_VALUE) + return FALSE; + + if (length > 0) + { + base64 = crypto_base64_encode(data, length); + + if (!base64) + goto fail; + + b64len = strlen(base64); + rc = WriteFile(file, base64, b64len, &written, NULL); + + if (b64len != written) + rc = FALSE; + } + else + rc = TRUE; + +fail: + CloseHandle(file); + free(base64); + return rc; +} + +static BOOL printer_config_valid(const char* path) +{ + if (!path) + return FALSE; + + if (!PathFileExistsA(path)) + return FALSE; + + return TRUE; +} + +static BOOL printer_read_setting(const char* path, prn_conf_t type, void** data, size_t* length) +{ + DWORD lowSize, highSize; + DWORD read = 0; + BOOL rc = FALSE; + HANDLE file; + BYTE* fdata = NULL; + const char* name = filemap[type]; + char* abs = GetCombinedPath(path, name); + + if (!abs) + return FALSE; + + file = CreateFileA(abs, GENERIC_READ, 0, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + free(abs); + + if (file == INVALID_HANDLE_VALUE) + return FALSE; + + lowSize = GetFileSize(file, &highSize); + + if ((lowSize == INVALID_FILE_SIZE) || (highSize != 0)) + goto fail; + + if (lowSize != 0) + { + fdata = malloc(lowSize); + + if (!fdata) + goto fail; + + rc = ReadFile(file, fdata, lowSize, &read, NULL); + + if (lowSize != read) + rc = FALSE; + } + +fail: + CloseHandle(file); + + if (rc) + { + int blen = 0; + crypto_base64_decode(fdata, lowSize, data, &blen); + + if (*data) + *length = blen; + else + { + rc = FALSE; + *length = 0; + } + } + else + { + *length = 0; + *data = NULL; + } + + free(fdata); + return rc; +} + +static BOOL printer_save_to_config(const rdpSettings* settings, + const char* PortDosName, size_t PortDosNameLen, + const WCHAR* PnPName, size_t PnPNameLen, + const WCHAR* DriverName, size_t DriverNameLen, + const WCHAR* PrinterName, size_t PrintNameLen, + const BYTE* CachedPrinterConfigData, size_t CacheFieldsLen) +{ + BOOL rc = FALSE; + char* path = get_printer_config_path(settings, PrinterName, PrintNameLen); + + if (!path) + goto fail; + + if (!printer_write_setting(path, PRN_CONF_PORT, PortDosName, PortDosNameLen)) + goto fail; + + if (!printer_write_setting(path, PRN_CONF_PNP, PnPName, PnPNameLen)) + goto fail; + + if (!printer_write_setting(path, PRN_CONF_DRIVER, DriverName, DriverNameLen)) + goto fail; + + if (!printer_write_setting(path, PRN_CONF_DATA, CachedPrinterConfigData, CacheFieldsLen)) + goto fail; + +fail: + free(path); + return rc; +} + +static BOOL printer_update_to_config(const rdpSettings* settings, const WCHAR* name, size_t length, + const BYTE* data, size_t datalen) +{ + BOOL rc = FALSE; + char* path = get_printer_config_path(settings, name, length); + rc = printer_write_setting(path, PRN_CONF_DATA, data, datalen); + free(path); + return rc; +} + +static BOOL printer_remove_config(const rdpSettings* settings, const WCHAR* name, size_t length) +{ + BOOL rc = FALSE; + char* path = get_printer_config_path(settings, name, length); + + if (!printer_config_valid(path)) + goto fail; + + rc = RemoveDirectoryA(path); +fail: + free(path); + return rc; +} + +static BOOL printer_move_config(const rdpSettings* settings, const WCHAR* oldName, size_t oldLength, + const WCHAR* newName, size_t newLength) +{ + BOOL rc = FALSE; + char* oldPath = get_printer_config_path(settings, oldName, oldLength); + char* newPath = get_printer_config_path(settings, newName, newLength); + + if (printer_config_valid(oldPath)) + rc = MoveFileA(oldPath, newPath); + + free(oldPath); + free(newPath); + return rc; +} + +static BOOL printer_load_from_config(const rdpSettings* settings, rdpPrinter* printer, + PRINTER_DEVICE* printer_dev) +{ + BOOL res = FALSE; + WCHAR* wname = NULL; + size_t wlen; + char* path = NULL; + int rc; + UINT32 flags = 0; + WCHAR* DriverName = NULL; + size_t DriverNameLen = 0; + WCHAR* PnPName = NULL; + size_t PnPNameLen = 0; + BYTE* CachedPrinterConfigData = NULL; + size_t CachedFieldsLen = 0; + size_t PrinterNameLen = 0; + + if (!settings || !printer) + return FALSE; + + rc = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &wname, 0); + + if (rc <= 0) + goto fail; + + wlen = _wcslen(wname) + 1; + path = get_printer_config_path(settings, wname, wlen * sizeof(WCHAR)); + PrinterNameLen = (wlen + 1) * sizeof(WCHAR); + + if (!path) + goto fail; + + if (printer->is_default) + flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER; + + if (!printer_read_setting(path, PRN_CONF_PNP, &PnPName, &PnPNameLen)) + { + } + + if (!printer_read_setting(path, PRN_CONF_DRIVER, &DriverName, &DriverNameLen)) + { + DriverNameLen = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &DriverName, + 0) * 2 + 1; + } + + if (!printer_read_setting(path, PRN_CONF_DATA, &CachedPrinterConfigData, &CachedFieldsLen)) + { + } + + Stream_SetPosition(printer_dev->device.data, 0); + + if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, 24)) + goto fail; + + Stream_Write_UINT32(printer_dev->device.data, flags); + Stream_Write_UINT32(printer_dev->device.data, 0); /* CodePage, reserved */ + Stream_Write_UINT32(printer_dev->device.data, PnPNameLen); /* PnPNameLen */ + Stream_Write_UINT32(printer_dev->device.data, DriverNameLen); + Stream_Write_UINT32(printer_dev->device.data, PrinterNameLen); + Stream_Write_UINT32(printer_dev->device.data, CachedFieldsLen); + + if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, PnPNameLen)) + goto fail; + + if (PnPNameLen > 0) + Stream_Write(printer_dev->device.data, PnPName, PnPNameLen); + + if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, DriverNameLen)) + goto fail; + + Stream_Write(printer_dev->device.data, DriverName, DriverNameLen); + + if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, PrinterNameLen)) + goto fail; + + Stream_Write(printer_dev->device.data, wname, PrinterNameLen); + + if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, CachedFieldsLen)) + goto fail; + + Stream_Write(printer_dev->device.data, CachedPrinterConfigData, CachedFieldsLen); + res = TRUE; +fail: + free(path); + free(wname); + free(PnPName); + free(DriverName); + free(CachedPrinterConfigData); + return res; +} + +static BOOL printer_save_default_config(const rdpSettings* settings, rdpPrinter* printer) +{ + BOOL res = FALSE; + WCHAR* wname = NULL; + WCHAR* driver = NULL; + size_t wlen, dlen; + char* path = NULL; + int rc; + + if (!settings || !printer) + return FALSE; + + rc = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &wname, 0); + + if (rc <= 0) + goto fail; + + rc = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &driver, 0); + + if (rc <= 0) + goto fail; + + wlen = _wcslen(wname) + 1; + dlen = _wcslen(driver) + 1; + path = get_printer_config_path(settings, wname, wlen * sizeof(WCHAR)); + + if (!path) + goto fail; + + if (dlen > 1) + { + if (!printer_write_setting(path, PRN_CONF_DRIVER, driver, dlen * sizeof(WCHAR))) + goto fail; + } + + res = TRUE; +fail: + free(path); + free(wname); + free(driver); + return res; +} + /** * Function description * @@ -293,6 +653,182 @@ static UINT printer_irp_request(DEVICE* device, IRP* irp) return CHANNEL_RC_OK; } +static UINT printer_custom_component(DEVICE* device, UINT16 component, UINT16 packetId, wStream* s) +{ + UINT32 eventID; + PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) device; + const rdpSettings* settings = printer_dev->rdpcontext->settings; + + if (component != RDPDR_CTYP_PRN) + return ERROR_INVALID_DATA; + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, eventID); + + switch (packetId) + { + case PAKID_PRN_CACHE_DATA: + switch (eventID) + { + case RDPDR_ADD_PRINTER_EVENT: + { + char PortDosName[8]; + UINT32 PnPNameLen, DriverNameLen, PrintNameLen, CacheFieldsLen; + const WCHAR* PnPName, *DriverName, *PrinterName; + const BYTE* CachedPrinterConfigData; + + if (Stream_GetRemainingLength(s) < 24) + return ERROR_INVALID_DATA; + + Stream_Read(s, PortDosName, sizeof(PortDosName)); + Stream_Read_UINT32(s, PnPNameLen); + Stream_Read_UINT32(s, DriverNameLen); + Stream_Read_UINT32(s, PrintNameLen); + Stream_Read_UINT32(s, CacheFieldsLen); + + if (Stream_GetRemainingLength(s) < PnPNameLen) + return ERROR_INVALID_DATA; + + PnPName = (const WCHAR*)Stream_Pointer(s); + Stream_Seek(s, PnPNameLen); + + if (Stream_GetRemainingLength(s) < DriverNameLen) + return ERROR_INVALID_DATA; + + DriverName = (const WCHAR*)Stream_Pointer(s); + Stream_Seek(s, DriverNameLen); + + if (Stream_GetRemainingLength(s) < PrintNameLen) + return ERROR_INVALID_DATA; + + PrinterName = (const WCHAR*)Stream_Pointer(s); + Stream_Seek(s, PrintNameLen); + + if (Stream_GetRemainingLength(s) < CacheFieldsLen) + return ERROR_INVALID_DATA; + + CachedPrinterConfigData = Stream_Pointer(s); + Stream_Seek(s, CacheFieldsLen); + + if (!printer_save_to_config(settings, + PortDosName, sizeof(PortDosName), + PnPName, PnPNameLen, + DriverName, DriverNameLen, + PrinterName, PrintNameLen, + CachedPrinterConfigData, CacheFieldsLen)) + return ERROR_INTERNAL_ERROR; + } + break; + + case RDPDR_UPDATE_PRINTER_EVENT: + { + UINT32 PrinterNameLen, ConfigDataLen; + const WCHAR* PrinterName; + const BYTE* ConfigData; + + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, PrinterNameLen); + Stream_Read_UINT32(s, ConfigDataLen); + + if (Stream_GetRemainingLength(s) < PrinterNameLen) + return ERROR_INVALID_DATA; + + PrinterName = (const WCHAR*)Stream_Pointer(s); + Stream_Seek(s, PrinterNameLen); + + if (Stream_GetRemainingLength(s) < ConfigDataLen) + return ERROR_INVALID_DATA; + + ConfigData = Stream_Pointer(s); + Stream_Seek(s, ConfigDataLen); + + if (!printer_update_to_config(settings, PrinterName, PrinterNameLen, ConfigData, ConfigDataLen)) + return ERROR_INTERNAL_ERROR; + } + break; + + case RDPDR_DELETE_PRINTER_EVENT: + { + UINT32 PrinterNameLen; + const WCHAR* PrinterName; + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, PrinterNameLen); + + if (Stream_GetRemainingLength(s) < PrinterNameLen) + return ERROR_INVALID_DATA; + + PrinterName = (const WCHAR*)Stream_Pointer(s); + Stream_Seek(s, PrinterNameLen); + printer_remove_config(settings, PrinterName, PrinterNameLen); + } + break; + + case RDPDR_RENAME_PRINTER_EVENT: + { + UINT32 OldPrinterNameLen, NewPrinterNameLen; + const WCHAR* OldPrinterName; + const WCHAR* NewPrinterName; + + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, OldPrinterNameLen); + Stream_Read_UINT32(s, NewPrinterNameLen); + + if (Stream_GetRemainingLength(s) < OldPrinterNameLen) + return ERROR_INVALID_DATA; + + OldPrinterName = (const WCHAR*)Stream_Pointer(s); + Stream_Seek(s, OldPrinterNameLen); + + if (Stream_GetRemainingLength(s) < NewPrinterNameLen) + return ERROR_INVALID_DATA; + + NewPrinterName = (const WCHAR*)Stream_Pointer(s); + Stream_Seek(s, NewPrinterNameLen); + + if (!printer_move_config(settings, OldPrinterName, OldPrinterNameLen, NewPrinterName, + NewPrinterNameLen)) + return ERROR_INTERNAL_ERROR; + } + break; + + default: + WLog_ERR(TAG, "Unknown cache data eventID: 0x%08"PRIX32"", eventID); + return ERROR_INVALID_DATA; + } + + break; + + case PAKID_PRN_USING_XPS: + { + UINT32 flags; + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, flags); + WLog_ERR(TAG, + "Ignoring unhandled message PAKID_PRN_USING_XPS [printerID=%08"PRIx32", flags=%08"PRIx32"]", + eventID, flags); + } + break; + + default: + WLog_ERR(TAG, "Unknown printing component packetID: 0x%04"PRIX16"", packetId); + return ERROR_INVALID_DATA; + } + + return CHANNEL_RC_OK; +} + /** * Function description * @@ -309,7 +845,13 @@ static UINT printer_free(DEVICE* device) { error = GetLastError(); WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + + /* The analyzer is confused by this premature return value. + * Since this case can not be handled gracefully silence the + * analyzer here. */ +#ifndef __clang_analyzer__ return error; +#endif } while ((irp = (IRP*) InterlockedPopEntrySList(printer_dev->pIrpList)) != NULL) @@ -336,15 +878,8 @@ static UINT printer_free(DEVICE* device) UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* printer) { - UINT32 Flags; - int DriverNameLen; - WCHAR* DriverName = NULL; - int PrintNameLen; - WCHAR* PrintName = NULL; - UINT32 CachedFieldsLen; - BYTE* CachedPrinterConfigData; PRINTER_DEVICE* printer_dev; - UINT error; + UINT error = ERROR_INTERNAL_ERROR; printer_dev = (PRINTER_DEVICE*) calloc(1, sizeof(PRINTER_DEVICE)); if (!printer_dev) @@ -353,55 +888,19 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, return CHANNEL_RC_NO_MEMORY; } + printer_dev->device.data = Stream_New(NULL, 1024); + + if (!printer_dev->device.data) + goto error_out; + sprintf_s(printer_dev->port, sizeof(printer_dev->port), "PRN%d", printer->id); printer_dev->device.type = RDPDR_DTYP_PRINT; printer_dev->device.name = printer_dev->port; printer_dev->device.IRPRequest = printer_irp_request; + printer_dev->device.CustomComponentRequest = printer_custom_component; printer_dev->device.Free = printer_free; printer_dev->rdpcontext = pEntryPoints->rdpcontext; printer_dev->printer = printer; - CachedFieldsLen = 0; - CachedPrinterConfigData = NULL; - Flags = 0; - - if (printer->is_default) - Flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER; - - DriverNameLen = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &DriverName, - 0) * 2; - PrintNameLen = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &PrintName, - 0) * 2; - printer_dev->device.data = Stream_New(NULL, - 28 + DriverNameLen + PrintNameLen + CachedFieldsLen); - - if (!printer_dev->device.data) - { - WLog_ERR(TAG, "calloc failed!"); - error = CHANNEL_RC_NO_MEMORY; - free(DriverName); - free(PrintName); - goto error_out; - } - - Stream_Write_UINT32(printer_dev->device.data, Flags); - Stream_Write_UINT32(printer_dev->device.data, 0); /* CodePage, reserved */ - Stream_Write_UINT32(printer_dev->device.data, 0); /* PnPNameLen */ - Stream_Write_UINT32(printer_dev->device.data, DriverNameLen + 2); - Stream_Write_UINT32(printer_dev->device.data, PrintNameLen + 2); - Stream_Write_UINT32(printer_dev->device.data, CachedFieldsLen); - Stream_Write(printer_dev->device.data, DriverName, DriverNameLen); - Stream_Write_UINT16(printer_dev->device.data, 0); - Stream_Write(printer_dev->device.data, PrintName, PrintNameLen); - Stream_Write_UINT16(printer_dev->device.data, 0); - - if (CachedFieldsLen > 0) - { - Stream_Write(printer_dev->device.data, CachedPrinterConfigData, - CachedFieldsLen); - } - - free(DriverName); - free(PrintName); printer_dev->pIrpList = (WINPR_PSLIST_HEADER) _aligned_malloc(sizeof( WINPR_SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT); @@ -412,6 +911,9 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, goto error_out; } + if (!printer_load_from_config(pEntryPoints->rdpcontext->settings, printer, printer_dev)) + goto error_out; + InitializeSListHead(printer_dev->pIrpList); if (!(printer_dev->event = CreateEvent(NULL, TRUE, FALSE, NULL))) @@ -497,6 +999,9 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) return CHANNEL_RC_INITIALIZATION_ERROR; } + if (!printer_save_default_config(pEntryPoints->rdpcontext->settings, printer)) + return CHANNEL_RC_INITIALIZATION_ERROR; + if ((error = printer_register(pEntryPoints, printer))) { WLog_ERR(TAG, "printer_register failed with error %"PRIu32"!", error); diff --git a/channels/printer/client/printer_main.h b/channels/printer/client/printer_main.h index dfb56d8..07bd608 100644 --- a/channels/printer/client/printer_main.h +++ b/channels/printer/client/printer_main.h @@ -54,7 +54,7 @@ struct rdp_printer pcFreePrinter Free; }; -typedef UINT (*pcWritePrintJob) (rdpPrintJob* printjob, BYTE* data, int size); +typedef UINT (*pcWritePrintJob) (rdpPrintJob* printjob, const BYTE* data, size_t size); typedef void (*pcClosePrintJob) (rdpPrintJob* printjob); struct rdp_print_job diff --git a/channels/rdpdr/client/devman.c b/channels/rdpdr/client/devman.c index 93db1b7..6c72df7 100644 --- a/channels/rdpdr/client/devman.c +++ b/channels/rdpdr/client/devman.c @@ -68,8 +68,8 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr) devman->plugin = (void*) rdpdr; devman->id_sequence = 1; - devman->devices = ListDictionary_New(TRUE); + if (!devman->devices) { WLog_INFO(TAG, "ListDictionary_New failed!"); @@ -78,7 +78,6 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr) } ListDictionary_ValueObject(devman->devices)->fnObjectFree = devman_device_free; - return devman; } @@ -114,26 +113,57 @@ static UINT devman_register_device(DEVMAN* devman, DEVICE* device) return ERROR_INVALID_PARAMETER; device->id = devman->id_sequence++; - key = (void*) (size_t) device->id; + key = (void*)(size_t) device->id; if (!ListDictionary_Add(devman->devices, key, device)) { WLog_INFO(TAG, "ListDictionary_Add failed!"); return ERROR_INTERNAL_ERROR; } + return CHANNEL_RC_OK; } DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id) { DEVICE* device = NULL; - void* key = (void*) (size_t) id; + void* key = (void*)(size_t) id; if (!devman) return NULL; device = (DEVICE*) ListDictionary_GetItemValue(devman->devices, key); + return device; +} +DEVICE* devman_get_device_by_type(DEVMAN* devman, UINT32 type) +{ + DEVICE* device = NULL; + ULONG_PTR* keys; + int count, x; + + if (!devman) + return NULL; + + ListDictionary_Lock(devman->devices); + count = ListDictionary_GetKeys(devman->devices, &keys); + + for (x = 0; x < count; x++) + { + DEVICE* cur = (DEVICE*) ListDictionary_GetItemValue(devman->devices, (void*)keys[x]); + + if (!cur) + continue; + + if (cur->type != type) + continue; + + device = cur; + break; + } + + free(keys); + ListDictionary_Unlock(devman->devices); return device; } @@ -178,7 +208,9 @@ UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext WLog_INFO(TAG, "Loading device service %s [%s] (static)", ServiceName, device->Name); else WLog_INFO(TAG, "Loading device service %s (static)", ServiceName); - entry = (PDEVICE_SERVICE_ENTRY) freerdp_load_channel_addin_entry(ServiceName, NULL, "DeviceServiceEntry", 0); + + entry = (PDEVICE_SERVICE_ENTRY) freerdp_load_channel_addin_entry(ServiceName, NULL, + "DeviceServiceEntry", 0); if (!entry) { @@ -190,6 +222,5 @@ UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext ep.RegisterDevice = devman_register_device; ep.device = device; ep.rdpcontext = rdpcontext; - return entry(&ep); } diff --git a/channels/rdpdr/client/devman.h b/channels/rdpdr/client/devman.h index c99a179..060038c 100644 --- a/channels/rdpdr/client/devman.h +++ b/channels/rdpdr/client/devman.h @@ -28,6 +28,7 @@ void devman_unregister_device(DEVMAN* devman, void* key); UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext* rdpcontext); DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id); +DEVICE* devman_get_device_by_type(DEVMAN* devman, UINT32 type); DEVMAN* devman_new(rdpdrPlugin* rdpdr); void devman_free(DEVMAN* devman); diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 602268f..4f1a4ac 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -135,7 +135,8 @@ BOOL check_path(char* path) { UINT type = GetDriveTypeA(path); - if (!(type == DRIVE_FIXED ||type == DRIVE_REMOVABLE || type == DRIVE_CDROM || type == DRIVE_REMOTE)) + if (!(type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM || + type == DRIVE_REMOTE)) return FALSE; return GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, NULL, 0); @@ -1324,6 +1325,31 @@ static UINT rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s) return error; } +static UINT rdpdr_process_component(rdpdrPlugin* rdpdr, UINT16 component, UINT16 packetId, + wStream* s) +{ + UINT32 type; + DEVICE* device; + + switch (component) + { + case RDPDR_CTYP_PRN: + type = RDPDR_DTYP_PRINT; + break; + + default: + return ERROR_INVALID_DATA; + } + + device = devman_get_device_by_type(rdpdr->devman, type); + + if (!device) + return ERROR_INVALID_PARAMETER; + + return IFCALLRESULT(ERROR_INVALID_PARAMETER, device->CustomComponentRequest, device, component, + packetId, s); +} + /** * Function description * @@ -1368,141 +1394,114 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) UINT16 packetId; UINT32 deviceId; UINT32 status; - UINT error; + UINT error = ERROR_INVALID_DATA; if (!rdpdr || !s) return CHANNEL_RC_NULL_DATA; - if (Stream_GetRemainingLength(s) < 4) - return ERROR_INVALID_DATA; - - Stream_Read_UINT16(s, component); /* Component (2 bytes) */ - Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */ - - if (component == RDPDR_CTYP_CORE) + if (Stream_GetRemainingLength(s) >= 4) { - switch (packetId) + Stream_Read_UINT16(s, component); /* Component (2 bytes) */ + Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */ + + if (component == RDPDR_CTYP_CORE) { - case PAKID_CORE_SERVER_ANNOUNCE: - if ((error = rdpdr_process_server_announce_request(rdpdr, s))) - return error; + switch (packetId) + { + case PAKID_CORE_SERVER_ANNOUNCE: + if ((error = rdpdr_process_server_announce_request(rdpdr, s))) + { + } + else if ((error = rdpdr_send_client_announce_reply(rdpdr))) + { + WLog_ERR(TAG, "rdpdr_send_client_announce_reply failed with error %"PRIu32"", error); + } + else if ((error = rdpdr_send_client_name_request(rdpdr))) + { + WLog_ERR(TAG, "rdpdr_send_client_name_request failed with error %"PRIu32"", error); + } + else if ((error = rdpdr_process_init(rdpdr))) + { + WLog_ERR(TAG, "rdpdr_process_init failed with error %"PRIu32"", error); + } - if ((error = rdpdr_send_client_announce_reply(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_send_client_announce_reply failed with error %"PRIu32"", error); - return error; - } + break; - if ((error = rdpdr_send_client_name_request(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_send_client_name_request failed with error %"PRIu32"", error); - return error; - } + case PAKID_CORE_SERVER_CAPABILITY: + if ((error = rdpdr_process_capability_request(rdpdr, s))) + { + } + else if ((error = rdpdr_send_capability_response(rdpdr))) + { + WLog_ERR(TAG, "rdpdr_send_capability_response failed with error %"PRIu32"", error); + } - if ((error = rdpdr_process_init(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_process_init failed with error %"PRIu32"", error); - return error; - } + break; - break; + case PAKID_CORE_CLIENTID_CONFIRM: + if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s))) + { + } + else if ((error = rdpdr_send_device_list_announce_request(rdpdr, FALSE))) + { + WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"", + error); + } - case PAKID_CORE_SERVER_CAPABILITY: - if ((error = rdpdr_process_capability_request(rdpdr, s))) - return error; + break; - if ((error = rdpdr_send_capability_response(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_send_capability_response failed with error %"PRIu32"", error); - return error; - } + case PAKID_CORE_USER_LOGGEDON: + if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE))) + { + WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"", + error); + } - break; + break; - case PAKID_CORE_CLIENTID_CONFIRM: - if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s))) - return error; + case PAKID_CORE_DEVICE_REPLY: - if ((error = rdpdr_send_device_list_announce_request(rdpdr, FALSE))) - { - WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"", - error); - return error; - } + /* connect to a specific resource */ + if (Stream_GetRemainingLength(s) >= 8) + { + Stream_Read_UINT32(s, deviceId); + Stream_Read_UINT32(s, status); + error = CHANNEL_RC_OK; + } - break; + break; - case PAKID_CORE_USER_LOGGEDON: - if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE))) - { - WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"", - error); - return error; - } + case PAKID_CORE_DEVICE_IOREQUEST: + if ((error = rdpdr_process_irp(rdpdr, s))) + { + WLog_ERR(TAG, "rdpdr_process_irp failed with error %"PRIu32"", error); + return error; + } + else + s = NULL; - break; + break; - case PAKID_CORE_DEVICE_REPLY: - - /* connect to a specific resource */ - if (Stream_GetRemainingLength(s) < 8) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, deviceId); - Stream_Read_UINT32(s, status); - break; - - case PAKID_CORE_DEVICE_IOREQUEST: - if ((error = rdpdr_process_irp(rdpdr, s))) - { - WLog_ERR(TAG, "rdpdr_process_irp failed with error %"PRIu32"", error); - return error; - } - - s = NULL; - break; - - default: - WLog_ERR(TAG, "RDPDR_CTYP_CORE unknown PacketId: 0x%04"PRIX16"", packetId); - return ERROR_INVALID_DATA; - break; + default: + WLog_ERR(TAG, "RDPDR_CTYP_CORE unknown PacketId: 0x%04"PRIX16"", packetId); + error = ERROR_INVALID_DATA; + break; + } } - } - else if (component == RDPDR_CTYP_PRN) - { - switch (packetId) + else { - case PAKID_PRN_CACHE_DATA: - { - UINT32 eventID; + error = rdpdr_process_component(rdpdr, component, packetId, s); - if (Stream_GetRemainingLength(s) < 4) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, eventID); - WLog_ERR(TAG, - "Ignoring unhandled message PAKID_PRN_CACHE_DATA (EventID: 0x%08"PRIX32")", eventID); - } - break; - - case PAKID_PRN_USING_XPS: - WLog_ERR(TAG, "Ignoring unhandled message PAKID_PRN_USING_XPS"); - break; - - default: - WLog_ERR(TAG, "Unknown printing component packetID: 0x%04"PRIX16"", packetId); - return ERROR_INVALID_DATA; + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "Unknown message: Component: 0x%04"PRIX16" PacketId: 0x%04"PRIX16"", component, + packetId); + } } } - else - { - WLog_ERR(TAG, "Unknown message: Component: 0x%04"PRIX16" PacketId: 0x%04"PRIX16"", component, - packetId); - return ERROR_INVALID_DATA; - } Stream_Free(s, TRUE); - return CHANNEL_RC_OK; + return error; } /** diff --git a/channels/rdpgfx/client/rdpgfx_codec.c b/channels/rdpgfx/client/rdpgfx_codec.c index d2dfbb3..cf96f44 100644 --- a/channels/rdpgfx/client/rdpgfx_codec.c +++ b/channels/rdpgfx/client/rdpgfx_codec.c @@ -243,10 +243,7 @@ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd h264.bitstream[1].length = Stream_GetRemainingLength(s); } else - { h264.bitstream[0].length = Stream_GetRemainingLength(s); - memset(&h264.bitstream[1], 0, sizeof(h264.bitstream[1])); - } cmd->extra = (void*) &h264; diff --git a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c index c61e02c..706876a 100644 --- a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c +++ b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c @@ -29,8 +29,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -102,14 +102,12 @@ static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWO case MM_WOM_CLOSE: WLog_DBG(TAG, "MM_WOM_CLOSE"); - SetEvent(winmm->next); break; case MM_WOM_DONE: WLog_DBG(TAG, "MM_WOM_DONE"); lpWaveHdr = (LPWAVEHDR) dwParam1; free(lpWaveHdr); - SetEvent(winmm->next); break; default: @@ -176,7 +174,6 @@ static void rdpsnd_winmm_free(rdpsndDevicePlugin* device) if (winmm) { rdpsnd_winmm_close(device); - CloseHandle(winmm->next); free(winmm); } } @@ -269,7 +266,6 @@ static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size return 0; } - WaitForSingleObject(winmm->next, INFINITE); return 10; /* TODO: Get real latencry in [ms] */ } @@ -305,13 +301,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p winmm->device.Play = rdpsnd_winmm_play; winmm->device.Close = rdpsnd_winmm_close; winmm->device.Free = rdpsnd_winmm_free; - winmm->next = CreateEventA(NULL, FALSE, FALSE, "winmm-play-event"); - - if (!winmm->next) - { - free(winmm); - return CHANNEL_RC_NO_MEMORY; - } args = pEntryPoints->args; rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*) winmm, args); diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index 9252929..9bcfc35 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -255,7 +255,13 @@ static UINT remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, Stream_Read_UINT32(s, versionMajor); /* versionMajor (4 bytes) */ Stream_Read_UINT32(s, versionMinor); /* versionMinor (4 bytes) */ - remdesk->Version = versionMajor; + + if ((versionMajor != 1) || (versionMinor > 2) || (versionMinor == 0)) + { + WLog_ERR(TAG, "Unsupported protocol version %"PRId32".%"PRId32, versionMajor, versionMinor); + } + + remdesk->Version = versionMinor; return CHANNEL_RC_OK; } diff --git a/channels/remdesk/client/remdesk_main.h b/channels/remdesk/client/remdesk_main.h index 13ae5c7..852e18e 100644 --- a/channels/remdesk/client/remdesk_main.h +++ b/channels/remdesk/client/remdesk_main.h @@ -55,7 +55,7 @@ struct remdesk_plugin UINT32 Version; char* ExpertBlob; BYTE* EncryptedPassStub; - int EncryptedPassStubSize; + size_t EncryptedPassStubSize; rdpContext* rdpcontext; }; typedef struct remdesk_plugin remdeskPlugin; diff --git a/channels/smartcard/client/smartcard_pack.c b/channels/smartcard/client/smartcard_pack.c index b2f3563..5cdc99f 100644 --- a/channels/smartcard/client/smartcard_pack.c +++ b/channels/smartcard/client/smartcard_pack.c @@ -161,7 +161,7 @@ LONG smartcard_pack_write_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, UI SCARDCONTEXT smartcard_scard_context_native_from_redir(SMARTCARD_DEVICE* smartcard, REDIR_SCARDCONTEXT* context) { - SCARDCONTEXT hContext = 0; + SCARDCONTEXT hContext = { 0 }; if ((context->cbContext != sizeof(ULONG_PTR)) && (context->cbContext != 0)) { @@ -173,8 +173,6 @@ SCARDCONTEXT smartcard_scard_context_native_from_redir(SMARTCARD_DEVICE* smartca if (context->cbContext) CopyMemory(&hContext, &(context->pbContext), context->cbContext); - else - ZeroMemory(&hContext, sizeof(ULONG_PTR)); return hContext; } diff --git a/channels/sshagent/CMakeLists.txt b/channels/sshagent/CMakeLists.txt index f3fa34e..71aab99 100644 --- a/channels/sshagent/CMakeLists.txt +++ b/channels/sshagent/CMakeLists.txt @@ -21,7 +21,3 @@ define_channel("sshagent") if(WITH_CLIENT_CHANNELS) add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) endif() - -if(WITH_SERVER_CHANNELS) - add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) -endif() diff --git a/channels/sshagent/ChannelOptions.cmake b/channels/sshagent/ChannelOptions.cmake index 083d8d5..99c96d0 100644 --- a/channels/sshagent/ChannelOptions.cmake +++ b/channels/sshagent/ChannelOptions.cmake @@ -1,13 +1,11 @@ set(OPTION_DEFAULT OFF) set(OPTION_CLIENT_DEFAULT OFF) -set(OPTION_SERVER_DEFAULT OFF) define_channel_options(NAME "sshagent" TYPE "dynamic" - DESCRIPTION "SSH Agent Forwarding Extension" + DESCRIPTION "SSH Agent Forwarding (experimental)" SPECIFICATIONS "" DEFAULT ${OPTION_DEFAULT}) define_channel_client_options(${OPTION_CLIENT_DEFAULT}) -define_channel_server_options(${OPTION_SERVER_DEFAULT}) diff --git a/channels/sshagent/server/CMakeLists.txt b/channels/sshagent/server/CMakeLists.txt deleted file mode 100644 index 9d62995..0000000 --- a/channels/sshagent/server/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# FreeRDP: A Remote Desktop Protocol Implementation -# FreeRDP cmake build script -# -# Copyright 2012 Marc-Andre Moreau -# Copyright 2017 Ben Cohen -# -# 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. - -define_channel_server("sshagent") - -set(${MODULE_PREFIX}_SRCS - sshagent_main.c) - -add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry") - - - -target_link_libraries(${MODULE_NAME} freerdp) - - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/sshagent/server/sshagent_main.c b/channels/sshagent/server/sshagent_main.c deleted file mode 100644 index dce713c..0000000 --- a/channels/sshagent/server/sshagent_main.c +++ /dev/null @@ -1,422 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * SSH Agent Virtual Channel Extension - * - * Copyright 2012-2013 Jay Sorg - * Copyright 2012-2013 Laxmikant Rashinkar - * Copyright 2017 Ben Cohen - * - * 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. - */ - -/* - * Portions are from OpenSSH, under the following license: - * - * Author: Tatu Ylonen - * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - * All rights reserved - * The authentication agent program. - * - * As far as I am concerned, the code I have written for this software - * can be used freely for any purpose. Any derived versions of this - * software must be clearly marked as such, and if the derived work is - * incompatible with the protocol description in the RFC file, it must be - * called by a name other than "ssh" or "Secure Shell". - * - * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * xrdp-ssh-agent.c: program to forward ssh-agent protocol from xrdp session - * - * This performs the equivalent function of ssh-agent on a server you connect - * to via ssh, but the ssh-agent protocol is over an RDP dynamic virtual - * channel and not an SSH channel. - * - * This will print out variables to set in your environment (specifically, - * $SSH_AUTH_SOCK) for ssh clients to find the agent's socket, then it will - * run in the background. This is suitable to run just as you would run the - * normal ssh-agent, e.g. in your Xsession or /etc/xrdp/startwm.sh. - * - * Your RDP client needs to be running a compatible client-side plugin - * that can see a local ssh-agent. - * - * usage (from within an xrdp session): - * xrdp-ssh-agent - * - * build instructions: - * gcc xrdp-ssh-agent.c -o xrdp-ssh-agent -L./.libs -lxrdpapi -Wall - * - * protocol specification: - * Forward data verbatim over RDP dynamic virtual channel named "sshagent" - * between a ssh client on the xrdp server and the real ssh-agent where - * the RDP client is running. Each connection by a separate client to - * xrdp-ssh-agent gets a separate DVC invocation. - */ - -#if defined(HAVE_CONFIG_H) -#include -#endif - -#ifdef __WIN32__ -#include -#endif - -#include - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define _PATH_DEVNULL "/dev/null" - -static char socket_name[PATH_MAX]; -static char socket_dir[PATH_MAX]; -static int sa_uds_fd = -1; -static int is_going = 1; - - -/* Make a template filename for mk[sd]temp() */ -/* This is from mktemp_proto() in misc.c from openssh */ -void -mktemp_proto(char* s, size_t len) -{ - const char* tmpdir; - int r; - - if ((tmpdir = getenv("TMPDIR")) != NULL) - { - r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir); - - if (r > 0 && (size_t)r < len) - return; - } - - r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX"); - - if (r < 0 || (size_t)r >= len) - { - fprintf(stderr, "%s: template string too short", __func__); - exit(1); - } -} - - -/* This uses parts of main() in ssh-agent.c from openssh */ -static void -setup_ssh_agent(struct sockaddr_un* addr) -{ - int rc; - /* Create private directory for agent socket */ - mktemp_proto(socket_dir, sizeof(socket_dir)); - - if (mkdtemp(socket_dir) == NULL) - { - perror("mkdtemp: private socket dir"); - exit(1); - } - - snprintf(socket_name, sizeof(socket_name), "%s/agent.%ld", socket_dir, - (long)getpid()); - /* Create unix domain socket */ - unlink(socket_name); - sa_uds_fd = socket(AF_UNIX, SOCK_STREAM, 0); - - if (sa_uds_fd == -1) - { - fprintf(stderr, "sshagent: socket creation failed"); - exit(2); - } - - memset(addr, 0, sizeof(struct sockaddr_un)); - addr->sun_family = AF_UNIX; - strncpy(addr->sun_path, socket_name, sizeof(addr->sun_path)); - addr->sun_path[sizeof(addr->sun_path) - 1] = 0; - /* Create with privileges rw------- so other users can't access the UDS */ - mode_t umask_sav = umask(0177); - rc = bind(sa_uds_fd, (struct sockaddr*)addr, sizeof(struct sockaddr_un)); - - if (rc != 0) - { - fprintf(stderr, "sshagent: bind failed"); - close(sa_uds_fd); - unlink(socket_name); - exit(3); - } - - umask(umask_sav); - rc = listen(sa_uds_fd, /* backlog = */ 5); - - if (rc != 0) - { - fprintf(stderr, "listen failed\n"); - close(sa_uds_fd); - unlink(socket_name); - exit(1); - } - - /* Now fork: the child becomes the ssh-agent daemon and the parent prints - * out the pid and socket name. */ - pid_t pid = fork(); - - if (pid == -1) - { - perror("fork"); - exit(1); - } - else if (pid != 0) - { - /* Parent */ - close(sa_uds_fd); - printf("SSH_AUTH_SOCK=%s; export SSH_AUTH_SOCK;\n", socket_name); - printf("SSH_AGENT_PID=%d; export SSH_AGENT_PID;\n", pid); - printf("echo Agent pid %d;\n", pid); - exit(0); - } - - /* Child */ - - if (setsid() == -1) - { - fprintf(stderr, "setsid failed"); - exit(1); - } - - (void)chdir("/"); - int devnullfd; - - if ((devnullfd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) - { - /* XXX might close listen socket */ - (void)dup2(devnullfd, STDIN_FILENO); - (void)dup2(devnullfd, STDOUT_FILENO); - (void)dup2(devnullfd, STDERR_FILENO); - - if (devnullfd > 2) - close(devnullfd); - } - - /* deny core dumps, since memory contains unencrypted private keys */ - struct rlimit rlim; - rlim.rlim_cur = rlim.rlim_max = 0; - - if (setrlimit(RLIMIT_CORE, &rlim) < 0) - { - fprintf(stderr, "setrlimit RLIMIT_CORE: %s", strerror(errno)); - exit(1); - } -} - - -static void -handle_connection(int client_fd) -{ - int rdp_fd = -1; - int rc; - void* channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, - "SSHAGENT", - WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED); - - if (channel == NULL) - { - fprintf(stderr, "WTSVirtualChannelOpenEx() failed\n"); - } - - unsigned int retlen; - int* retdata; - rc = WTSVirtualChannelQuery(channel, - WTSVirtualFileHandle, - (void**)&retdata, - &retlen); - - if (!rc) - { - fprintf(stderr, "WTSVirtualChannelQuery() failed\n"); - } - - if (retlen != sizeof(rdp_fd)) - { - fprintf(stderr, "WTSVirtualChannelQuery() returned wrong length %d\n", - retlen); - } - - rdp_fd = *retdata; - int client_going = 1; - - while (client_going) - { - /* Wait for data from RDP or the client */ - fd_set readfds; - FD_ZERO(&readfds); - FD_SET(client_fd, &readfds); - FD_SET(rdp_fd, &readfds); - select(FD_SETSIZE, &readfds, NULL, NULL, NULL); - - if (FD_ISSET(rdp_fd, &readfds)) - { - /* Read from RDP and write to the client */ - char buffer[4096]; - unsigned int bytes_to_write; - rc = WTSVirtualChannelRead(channel, - /* TimeOut = */ 5000, - buffer, - sizeof(buffer), - &bytes_to_write); - - if (rc == 1) - { - char* pos = buffer; - errno = 0; - - while (bytes_to_write > 0) - { - int bytes_written = send(client_fd, pos, bytes_to_write, 0); - - if (bytes_written > 0) - { - bytes_to_write -= bytes_written; - pos += bytes_written; - } - else if (bytes_written == 0) - { - fprintf(stderr, "send() returned 0!\n"); - } - else if (errno != EINTR) - { - /* Error */ - fprintf(stderr, "Error %d on recv\n", errno); - client_going = 0; - } - } - } - else - { - /* Error */ - fprintf(stderr, "WTSVirtualChannelRead() failed: %d\n", errno); - client_going = 0; - } - } - - if (FD_ISSET(client_fd, &readfds)) - { - /* Read from the client and write to RDP */ - char buffer[4096]; - ssize_t bytes_to_write = recv(client_fd, buffer, sizeof(buffer), 0); - - if (bytes_to_write > 0) - { - char* pos = buffer; - - while (bytes_to_write > 0) - { - unsigned int bytes_written; - int rc = WTSVirtualChannelWrite(channel, - pos, - bytes_to_write, - &bytes_written); - - if (rc == 0) - { - fprintf(stderr, "WTSVirtualChannelWrite() failed: %d\n", - errno); - client_going = 0; - } - else - { - bytes_to_write -= bytes_written; - pos += bytes_written; - } - } - } - else if (bytes_to_write == 0) - { - /* Client has closed connection */ - client_going = 0; - } - else - { - /* Error */ - fprintf(stderr, "Error %d on recv\n", errno); - client_going = 0; - } - } - } - - WTSVirtualChannelClose(channel); -} - - -int -main(int argc, char** argv) -{ - /* Setup the Unix domain socket and daemon process */ - struct sockaddr_un addr; - setup_ssh_agent(&addr); - - /* Wait for a client to connect to the socket */ - while (is_going) - { - fd_set readfds; - FD_ZERO(&readfds); - FD_SET(sa_uds_fd, &readfds); - select(FD_SETSIZE, &readfds, NULL, NULL, NULL); - - /* If something connected then get it... - * (You can test this using "socat - UNIX-CONNECT:".) */ - if (FD_ISSET(sa_uds_fd, &readfds)) - { - socklen_t addrsize = sizeof(addr); - int client_fd = accept(sa_uds_fd, - (struct sockaddr*)&addr, - &addrsize); - handle_connection(client_fd); - close(client_fd); - } - } - - close(sa_uds_fd); - unlink(socket_name); - return 0; -} - -/* vim: set sw=4:ts=4:et: */ diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index 0addbe7..22f6698 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -151,11 +151,7 @@ static BOOL tsmf_gstreamer_change_volume(ITSMFDecoder* decoder, UINT32 newVolume return TRUE; } -#ifdef __OpenBSD__ static inline GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_timestamp) -#else -static inline const GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_timestamp) -#endif { /* * Convert Microsoft 100ns timestamps to Gstreamer 1ns units. @@ -633,7 +629,8 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) { tsmf_gstreamer_need_data, tsmf_gstreamer_enough_data, - tsmf_gstreamer_seek_data + tsmf_gstreamer_seek_data, + { NULL } }; g_object_set(mdecoder->src, "format", GST_FORMAT_TIME, NULL); g_object_set(mdecoder->src, "is-live", FALSE, NULL); diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index 05ca6c4..ccc8ee3 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -702,16 +702,8 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) buffer_filled = FALSE; } - if (buffer_filled) - { - ack_anticipation_time += (sample->duration / 2 < MAX_ACK_TIME) ? - sample->duration / 2 : MAX_ACK_TIME; - } - else - { - ack_anticipation_time += (sample->duration / 2 < MAX_ACK_TIME) ? - sample->duration / 2 : MAX_ACK_TIME; - } + ack_anticipation_time += (sample->duration / 2 < MAX_ACK_TIME) ? + sample->duration / 2 : MAX_ACK_TIME; switch (sample->stream->major_type) { diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index 6be973d..7a25e13 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -1387,7 +1387,7 @@ static int libusb_udev_isoch_transfer(IUDEVICE* idev, UINT32 RequestId, UINT32 E if (iso_transfer == NULL) { WLog_ERR(TAG, "Error: libusb_alloc_transfer."); - status = -1; + return -1; } /** process URB_FUNCTION_IOSCH_TRANSFER */ diff --git a/client/.gitignore b/client/.gitignore index 574a1de..7c1ea95 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -1,7 +1,6 @@ /* !/Android !/common -!/DirectFB !/iOS !/Mac !/Sample diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 4c2e4df..7cba44e 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -26,10 +26,6 @@ if(FREERDP_VENDOR AND WITH_CLIENT) if(WITH_SAMPLE) add_subdirectory(Sample) endif() - - if(WITH_DIRECTFB) - add_subdirectory(DirectFB) - endif() endif() if(WITH_X11) diff --git a/client/DirectFB/CMakeLists.txt b/client/DirectFB/CMakeLists.txt deleted file mode 100644 index 6cf7cea..0000000 --- a/client/DirectFB/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -# FreeRDP: A Remote Desktop Protocol Implementation -# FreeRDP DirectFB Client -# -# Copyright 2012 Marc-Andre Moreau -# -# 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. - -set(MODULE_NAME "dfreerdp") -set(MODULE_PREFIX "FREERDP_CLIENT_DIRECTFB") - -include_directories(${DIRECTFB_INCLUDE_DIRS}) - -set(${MODULE_PREFIX}_SRCS - df_event.c - df_event.h - df_graphics.c - df_graphics.c - dfreerdp.c - dfreerdp.h) - -add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) - -set(${MODULE_PREFIX}_LIBS ${DIRECTFB_LIBRARIES}) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/DirectFB") diff --git a/client/DirectFB/ModuleOptions.cmake b/client/DirectFB/ModuleOptions.cmake deleted file mode 100644 index 2ef9266..0000000 --- a/client/DirectFB/ModuleOptions.cmake +++ /dev/null @@ -1,4 +0,0 @@ - -set(FREERDP_CLIENT_NAME "dfreerdp") -set(FREERDP_CLIENT_PLATFORM "DirectFB") -set(FREERDP_CLIENT_VENDOR "FreeRDP") diff --git a/client/DirectFB/df_event.c b/client/DirectFB/df_event.c deleted file mode 100644 index 5ec8b96..0000000 --- a/client/DirectFB/df_event.c +++ /dev/null @@ -1,271 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * DirectFB Event Handling - * - * Copyright 2011 Marc-Andre Moreau - * - * 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 -#include - -#include - -#include "df_event.h" - -static BYTE keymap[256]; -static BYTE functionmap[128]; - -void df_keyboard_init() -{ - ZeroMemory(keymap, sizeof(keymap)); - - /* Map DirectFB keycodes to Virtual Key Codes */ - - keymap[DIKI_A - DIKI_UNKNOWN] = VK_KEY_A; - keymap[DIKI_B - DIKI_UNKNOWN] = VK_KEY_B; - keymap[DIKI_C - DIKI_UNKNOWN] = VK_KEY_C; - keymap[DIKI_D - DIKI_UNKNOWN] = VK_KEY_D; - keymap[DIKI_E - DIKI_UNKNOWN] = VK_KEY_E; - keymap[DIKI_F - DIKI_UNKNOWN] = VK_KEY_F; - keymap[DIKI_G - DIKI_UNKNOWN] = VK_KEY_G; - keymap[DIKI_H - DIKI_UNKNOWN] = VK_KEY_H; - keymap[DIKI_I - DIKI_UNKNOWN] = VK_KEY_I; - keymap[DIKI_J - DIKI_UNKNOWN] = VK_KEY_J; - keymap[DIKI_K - DIKI_UNKNOWN] = VK_KEY_K; - keymap[DIKI_L - DIKI_UNKNOWN] = VK_KEY_L; - keymap[DIKI_M - DIKI_UNKNOWN] = VK_KEY_M; - keymap[DIKI_N - DIKI_UNKNOWN] = VK_KEY_N; - keymap[DIKI_O - DIKI_UNKNOWN] = VK_KEY_O; - keymap[DIKI_P - DIKI_UNKNOWN] = VK_KEY_P; - keymap[DIKI_Q - DIKI_UNKNOWN] = VK_KEY_Q; - keymap[DIKI_R - DIKI_UNKNOWN] = VK_KEY_R; - keymap[DIKI_S - DIKI_UNKNOWN] = VK_KEY_S; - keymap[DIKI_T - DIKI_UNKNOWN] = VK_KEY_T; - keymap[DIKI_U - DIKI_UNKNOWN] = VK_KEY_U; - keymap[DIKI_V - DIKI_UNKNOWN] = VK_KEY_V; - keymap[DIKI_W - DIKI_UNKNOWN] = VK_KEY_W; - keymap[DIKI_X - DIKI_UNKNOWN] = VK_KEY_X; - keymap[DIKI_Y - DIKI_UNKNOWN] = VK_KEY_Y; - keymap[DIKI_Z - DIKI_UNKNOWN] = VK_KEY_Z; - - keymap[DIKI_0 - DIKI_UNKNOWN] = VK_KEY_0; - keymap[DIKI_1 - DIKI_UNKNOWN] = VK_KEY_1; - keymap[DIKI_2 - DIKI_UNKNOWN] = VK_KEY_2; - keymap[DIKI_3 - DIKI_UNKNOWN] = VK_KEY_3; - keymap[DIKI_4 - DIKI_UNKNOWN] = VK_KEY_4; - keymap[DIKI_5 - DIKI_UNKNOWN] = VK_KEY_5; - keymap[DIKI_6 - DIKI_UNKNOWN] = VK_KEY_6; - keymap[DIKI_7 - DIKI_UNKNOWN] = VK_KEY_7; - keymap[DIKI_8 - DIKI_UNKNOWN] = VK_KEY_8; - keymap[DIKI_9 - DIKI_UNKNOWN] = VK_KEY_9; - - keymap[DIKI_F1 - DIKI_UNKNOWN] = VK_F1; - keymap[DIKI_F2 - DIKI_UNKNOWN] = VK_F2; - keymap[DIKI_F3 - DIKI_UNKNOWN] = VK_F3; - keymap[DIKI_F4 - DIKI_UNKNOWN] = VK_F4; - keymap[DIKI_F5 - DIKI_UNKNOWN] = VK_F5; - keymap[DIKI_F6 - DIKI_UNKNOWN] = VK_F6; - keymap[DIKI_F7 - DIKI_UNKNOWN] = VK_F7; - keymap[DIKI_F8 - DIKI_UNKNOWN] = VK_F8; - keymap[DIKI_F9 - DIKI_UNKNOWN] = VK_F9; - keymap[DIKI_F10 - DIKI_UNKNOWN] = VK_F10; - keymap[DIKI_F11 - DIKI_UNKNOWN] = VK_F11; - keymap[DIKI_F12 - DIKI_UNKNOWN] = VK_F12; - - keymap[DIKI_COMMA - DIKI_UNKNOWN] = VK_OEM_COMMA; - keymap[DIKI_PERIOD - DIKI_UNKNOWN] = VK_OEM_PERIOD; - keymap[DIKI_MINUS_SIGN - DIKI_UNKNOWN] = VK_OEM_MINUS; - keymap[DIKI_EQUALS_SIGN - DIKI_UNKNOWN] = VK_OEM_PLUS; - - keymap[DIKI_ESCAPE - DIKI_UNKNOWN] = VK_ESCAPE; - keymap[DIKI_LEFT - DIKI_UNKNOWN] = VK_LEFT; - keymap[DIKI_RIGHT - DIKI_UNKNOWN] = VK_RIGHT; - keymap[DIKI_UP - DIKI_UNKNOWN] = VK_UP; - keymap[DIKI_DOWN - DIKI_UNKNOWN] = VK_DOWN; - keymap[DIKI_CONTROL_L - DIKI_UNKNOWN] = VK_LCONTROL; - keymap[DIKI_CONTROL_R - DIKI_UNKNOWN] = VK_RCONTROL; - keymap[DIKI_SHIFT_L - DIKI_UNKNOWN] = VK_LSHIFT; - keymap[DIKI_SHIFT_R - DIKI_UNKNOWN] = VK_RSHIFT; - keymap[DIKI_ALT_L - DIKI_UNKNOWN] = VK_LMENU; - keymap[DIKI_ALT_R - DIKI_UNKNOWN] = VK_RMENU; - keymap[DIKI_TAB - DIKI_UNKNOWN] = VK_TAB; - keymap[DIKI_ENTER - DIKI_UNKNOWN] = VK_RETURN; - keymap[DIKI_SPACE - DIKI_UNKNOWN] = VK_SPACE; - keymap[DIKI_BACKSPACE - DIKI_UNKNOWN] = VK_BACK; - keymap[DIKI_INSERT - DIKI_UNKNOWN] = VK_INSERT; - keymap[DIKI_DELETE - DIKI_UNKNOWN] = VK_DELETE; - keymap[DIKI_HOME - DIKI_UNKNOWN] = VK_HOME; - keymap[DIKI_END - DIKI_UNKNOWN] = VK_END; - keymap[DIKI_PAGE_UP - DIKI_UNKNOWN] = VK_PRIOR; - keymap[DIKI_PAGE_DOWN - DIKI_UNKNOWN] = VK_NEXT; - keymap[DIKI_CAPS_LOCK - DIKI_UNKNOWN] = VK_CAPITAL; - keymap[DIKI_NUM_LOCK - DIKI_UNKNOWN] = VK_NUMLOCK; - keymap[DIKI_SCROLL_LOCK - DIKI_UNKNOWN] = VK_SCROLL; - keymap[DIKI_PRINT - DIKI_UNKNOWN] = VK_PRINT; - keymap[DIKI_PAUSE - DIKI_UNKNOWN] = VK_PAUSE; - keymap[DIKI_KP_DIV - DIKI_UNKNOWN] = VK_DIVIDE; - keymap[DIKI_KP_MULT - DIKI_UNKNOWN] = VK_MULTIPLY; - keymap[DIKI_KP_MINUS - DIKI_UNKNOWN] = VK_SUBTRACT; - keymap[DIKI_KP_PLUS - DIKI_UNKNOWN] = VK_ADD; - keymap[DIKI_KP_ENTER - DIKI_UNKNOWN] = VK_RETURN; - keymap[DIKI_KP_DECIMAL - DIKI_UNKNOWN] = VK_DECIMAL; - - keymap[DIKI_QUOTE_LEFT - DIKI_UNKNOWN] = VK_OEM_3; - keymap[DIKI_BRACKET_LEFT - DIKI_UNKNOWN] = VK_OEM_4; - keymap[DIKI_BRACKET_RIGHT - DIKI_UNKNOWN] = VK_OEM_6; - keymap[DIKI_BACKSLASH - DIKI_UNKNOWN] = VK_OEM_5; - keymap[DIKI_SEMICOLON - DIKI_UNKNOWN] = VK_OEM_1; - keymap[DIKI_QUOTE_RIGHT - DIKI_UNKNOWN] = VK_OEM_7; - keymap[DIKI_COMMA - DIKI_UNKNOWN] = VK_OEM_COMMA; - keymap[DIKI_PERIOD - DIKI_UNKNOWN] = VK_OEM_PERIOD; - keymap[DIKI_SLASH - DIKI_UNKNOWN] = VK_OEM_2; - - keymap[DIKI_LESS_SIGN - DIKI_UNKNOWN] = 0; - - keymap[DIKI_KP_0 - DIKI_UNKNOWN] = VK_NUMPAD0; - keymap[DIKI_KP_1 - DIKI_UNKNOWN] = VK_NUMPAD1; - keymap[DIKI_KP_2 - DIKI_UNKNOWN] = VK_NUMPAD2; - keymap[DIKI_KP_3 - DIKI_UNKNOWN] = VK_NUMPAD3; - keymap[DIKI_KP_4 - DIKI_UNKNOWN] = VK_NUMPAD4; - keymap[DIKI_KP_5 - DIKI_UNKNOWN] = VK_NUMPAD5; - keymap[DIKI_KP_6 - DIKI_UNKNOWN] = VK_NUMPAD6; - keymap[DIKI_KP_7 - DIKI_UNKNOWN] = VK_NUMPAD7; - keymap[DIKI_KP_8 - DIKI_UNKNOWN] = VK_NUMPAD8; - keymap[DIKI_KP_9 - DIKI_UNKNOWN] = VK_NUMPAD9; - - keymap[DIKI_META_L - DIKI_UNKNOWN] = VK_LWIN; - keymap[DIKI_META_R - DIKI_UNKNOWN] = VK_RWIN; - keymap[DIKI_SUPER_L - DIKI_UNKNOWN] = VK_APPS; - - ZeroMemory(functionmap, sizeof(functionmap)); - - functionmap[DFB_FUNCTION_KEY(23) - DFB_FUNCTION_KEY(0)] = VK_HANGUL; - functionmap[DFB_FUNCTION_KEY(24) - DFB_FUNCTION_KEY(0)] = VK_HANJA; - -} - -void df_send_mouse_button_event(rdpInput* input, BOOL down, UINT32 button, UINT16 x, UINT16 y) -{ - UINT16 flags; - - flags = (down) ? PTR_FLAGS_DOWN : 0; - - if (button == DIBI_LEFT) - flags |= PTR_FLAGS_BUTTON1; - else if (button == DIBI_RIGHT) - flags |= PTR_FLAGS_BUTTON2; - else if (button == DIBI_MIDDLE) - flags |= PTR_FLAGS_BUTTON3; - - if (flags != 0) - input->MouseEvent(input, flags, x, y); -} - -void df_send_mouse_motion_event(rdpInput* input, UINT16 x, UINT16 y) -{ - input->MouseEvent(input, PTR_FLAGS_MOVE, x, y); -} - -void df_send_mouse_wheel_event(rdpInput* input, INT16 axisrel, UINT16 x, UINT16 y) -{ - UINT16 flags = PTR_FLAGS_WHEEL; - - if (axisrel < 0) - flags |= 0x0078; - else - flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; - - input->MouseEvent(input, flags, x, y); -} - -void df_send_keyboard_event(rdpInput* input, BOOL down, BYTE keycode, BYTE function) -{ - DWORD scancode = 0; - BYTE vkcode = VK_NONE; - - if (keycode) - vkcode = keymap[keycode]; - else if (function) - vkcode = functionmap[function]; - - if (vkcode != VK_NONE) - scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, input->context->settings->KeyboardType); - - if (scancode) - freerdp_input_send_keyboard_event_ex(input, down, scancode); -} - -BOOL df_event_process(freerdp* instance, DFBEvent* event) -{ - int flags; - rdpGdi* gdi; - dfInfo* dfi; - int pointer_x; - int pointer_y; - DFBInputEvent* input_event; - - gdi = instance->context->gdi; - dfi = ((dfContext*) instance->context)->dfi; - - dfi->layer->GetCursorPosition(dfi->layer, &pointer_x, &pointer_y); - - if (event->clazz == DFEC_INPUT) - { - flags = 0; - input_event = (DFBInputEvent*) event; - - switch (input_event->type) - { - case DIET_AXISMOTION: - - if (pointer_x > (gdi->width - 1)) - pointer_x = gdi->width - 1; - - if (pointer_y > (gdi->height - 1)) - pointer_y = gdi->height - 1; - - if (input_event->axis == DIAI_Z) - { - df_send_mouse_wheel_event(instance->input, input_event->axisrel, pointer_x, pointer_y); - } - else - { - df_send_mouse_motion_event(instance->input, pointer_x, pointer_y); - } - break; - - case DIET_BUTTONPRESS: - df_send_mouse_button_event(instance->input, TRUE, input_event->button, pointer_x, pointer_y); - break; - - case DIET_BUTTONRELEASE: - df_send_mouse_button_event(instance->input, FALSE, input_event->button, pointer_x, pointer_y); - break; - - case DIET_KEYPRESS: - df_send_keyboard_event(instance->input, TRUE, input_event->key_id - DIKI_UNKNOWN, input_event->key_symbol - DFB_FUNCTION_KEY(0)); - break; - - case DIET_KEYRELEASE: - df_send_keyboard_event(instance->input, FALSE, input_event->key_id - DIKI_UNKNOWN, input_event->key_symbol - DFB_FUNCTION_KEY(0)); - break; - - case DIET_UNKNOWN: - break; - } - } - - return TRUE; -} diff --git a/client/DirectFB/df_graphics.c b/client/DirectFB/df_graphics.c deleted file mode 100644 index 3a20ab8..0000000 --- a/client/DirectFB/df_graphics.c +++ /dev/null @@ -1,139 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * DirectFB Graphical Objects - * - * Copyright 2011 Marc-Andre Moreau - * - * 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 - -#include "df_graphics.h" - -/* Pointer Class */ - -void df_Pointer_New(rdpContext* context, rdpPointer* pointer) -{ - dfInfo* dfi; - DFBResult result; - dfPointer* df_pointer; - DFBSurfaceDescription dsc; - - dfi = ((dfContext*) context)->dfi; - df_pointer = (dfPointer*) pointer; - - dsc.flags = DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT; - dsc.caps = DSCAPS_SYSTEMONLY; - dsc.width = pointer->width; - dsc.height = pointer->height; - dsc.pixelformat = DSPF_ARGB; - - result = dfi->dfb->CreateSurface(dfi->dfb, &dsc, &(df_pointer->surface)); - - if (result == DFB_OK) - { - int pitch; - BYTE* point = NULL; - - df_pointer->xhot = pointer->xPos; - df_pointer->yhot = pointer->yPos; - - result = df_pointer->surface->Lock(df_pointer->surface, - DSLF_WRITE, (void**) &point, &pitch); - - if (result != DFB_OK) - { - DirectFBErrorFatal("Error while creating pointer surface", result); - return; - } - - if ((pointer->andMaskData != 0) && (pointer->xorMaskData != 0)) - { - freerdp_alpha_cursor_convert(point, pointer->xorMaskData, pointer->andMaskData, - pointer->width, pointer->height, pointer->xorBpp, dfi->clrconv); - } - - if (pointer->xorBpp > 24) - { - freerdp_image_swap_color_order(point, pointer->width, pointer->height); - } - - df_pointer->surface->Unlock(df_pointer->surface); - } -} - -void df_Pointer_Free(rdpContext* context, rdpPointer* pointer) -{ - dfPointer* df_pointer = (dfPointer*) pointer; - df_pointer->surface->Release(df_pointer->surface); -} - -void df_Pointer_Set(rdpContext* context, rdpPointer* pointer) -{ - dfInfo* dfi; - DFBResult result; - dfPointer* df_pointer; - - dfi = ((dfContext*) context)->dfi; - df_pointer = (dfPointer*) pointer; - - dfi->layer->SetCooperativeLevel(dfi->layer, DLSCL_ADMINISTRATIVE); - - dfi->layer->SetCursorOpacity(dfi->layer, df_pointer ? 255: 0); - - if(df_pointer != NULL) - { - result = dfi->layer->SetCursorShape(dfi->layer, - df_pointer->surface, df_pointer->xhot, df_pointer->yhot); - - if (result != DFB_OK) - { - DirectFBErrorFatal("SetCursorShape Error", result); - return; - } - } - - dfi->layer->SetCooperativeLevel(dfi->layer, DLSCL_SHARED); -} - -void df_Pointer_SetNull(rdpContext* context) -{ - df_Pointer_Set(context, NULL); -} - -void df_Pointer_SetDefault(rdpContext* context) -{ - -} - -/* Graphics Module */ - -void df_register_graphics(rdpGraphics* graphics) -{ - rdpPointer* pointer; - - pointer = (rdpPointer*) malloc(sizeof(rdpPointer)); - ZeroMemory(pointer, sizeof(rdpPointer)); - pointer->size = sizeof(dfPointer); - - pointer->New = df_Pointer_New; - pointer->Free = df_Pointer_Free; - pointer->Set = df_Pointer_Set; - pointer->SetNull = df_Pointer_SetNull; - pointer->SetDefault = df_Pointer_SetDefault; - - graphics_register_pointer(graphics, pointer); - free(pointer); -} - diff --git a/client/DirectFB/dfreerdp.c b/client/DirectFB/dfreerdp.c deleted file mode 100644 index 8e11b01..0000000 --- a/client/DirectFB/dfreerdp.c +++ /dev/null @@ -1,469 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * DirectFB Client - * - * Copyright 2011 Marc-Andre Moreau - * - * 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 -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "df_event.h" -#include "df_graphics.h" - -#include "dfreerdp.h" - -#include -#define TAG CLIENT_TAG("directFB") - -static HANDLE g_sem; -static int g_thread_count = 0; - -struct thread_data -{ - freerdp* instance; -}; - -BOOL df_context_new(freerdp* instance, rdpContext* context) -{ - return TRUE; -} - -void df_context_free(freerdp* instance, rdpContext* context) -{ -} - -void df_begin_paint(rdpContext* context) -{ - rdpGdi* gdi = context->gdi; - gdi->primary->hdc->hwnd->invalid->null = TRUE; -} - -void df_end_paint(rdpContext* context) -{ - rdpGdi* gdi; - dfInfo* dfi; - gdi = context->gdi; - dfi = ((dfContext*) context)->dfi; - - if (gdi->primary->hdc->hwnd->invalid->null) - return; - -#if 1 - dfi->update_rect.x = gdi->primary->hdc->hwnd->invalid->x; - dfi->update_rect.y = gdi->primary->hdc->hwnd->invalid->y; - dfi->update_rect.w = gdi->primary->hdc->hwnd->invalid->w; - dfi->update_rect.h = gdi->primary->hdc->hwnd->invalid->h; -#else - dfi->update_rect.x = 0; - dfi->update_rect.y = 0; - dfi->update_rect.w = gdi->width; - dfi->update_rect.h = gdi->height; -#endif - dfi->primary->Blit(dfi->primary, dfi->surface, &(dfi->update_rect), - dfi->update_rect.x, dfi->update_rect.y); -} - -BOOL df_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, - int* wcount) -{ - dfInfo* dfi; - dfi = ((dfContext*) instance->context)->dfi; - rfds[*rcount] = (void*)(long)(dfi->read_fds); - (*rcount)++; - return TRUE; -} - -BOOL df_check_fds(freerdp* instance, fd_set* set) -{ - dfInfo* dfi; - dfi = ((dfContext*) instance->context)->dfi; - - if (!FD_ISSET(dfi->read_fds, set)) - return TRUE; - - if (read(dfi->read_fds, &(dfi->event), sizeof(dfi->event)) > 0) - df_event_process(instance, &(dfi->event)); - - return TRUE; -} - -BOOL df_pre_connect(freerdp* instance) -{ - dfInfo* dfi; - BOOL bitmap_cache; - dfContext* context; - rdpSettings* settings; - dfi = (dfInfo*) malloc(sizeof(dfInfo)); - ZeroMemory(dfi, sizeof(dfInfo)); - context = ((dfContext*) instance->context); - context->dfi = dfi; - settings = instance->settings; - bitmap_cache = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE; - settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE; - settings->OrderSupport[NEG_LINETO_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE; - settings->OrderSupport[NEG_MEMBLT_INDEX] = bitmap_cache; - settings->OrderSupport[NEG_MEM3BLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = bitmap_cache; - settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE; - settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE; - settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = FALSE; - settings->OrderSupport[NEG_FAST_INDEX_INDEX] = FALSE; - settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = FALSE; - settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE; - settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE; - settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; - settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; - dfi->clrconv = (CLRCONV*) malloc(sizeof(CLRCONV)); - ZeroMemory(dfi->clrconv, sizeof(CLRCONV)); - dfi->clrconv->alpha = 1; - dfi->clrconv->invert = 0; - dfi->clrconv->rgb555 = 0; - dfi->clrconv->palette = (rdpPalette*) malloc(sizeof(rdpPalette)); - ZeroMemory(dfi->clrconv->palette, sizeof(rdpPalette)); - return (instance->context->cache = cache_new(instance->settings)) != NULL; -} - -BOOL df_post_connect(freerdp* instance) -{ - rdpGdi* gdi; - dfInfo* dfi; - dfContext* context; - context = ((dfContext*) instance->context); - dfi = context->dfi; - - if (!gdi_init(instance, CLRCONV_ALPHA | CLRCONV_INVERT | CLRBUF_16BPP | - CLRBUF_32BPP, NULL)) - return FALSE; - - gdi = instance->context->gdi; - dfi->err = DirectFBCreate(&(dfi->dfb)); - dfi->dsc.flags = DSDESC_CAPS; - dfi->dsc.caps = DSCAPS_PRIMARY; - dfi->err = dfi->dfb->CreateSurface(dfi->dfb, &(dfi->dsc), &(dfi->primary)); - dfi->err = dfi->primary->GetSize(dfi->primary, &(gdi->width), &(gdi->height)); - dfi->dfb->SetVideoMode(dfi->dfb, gdi->width, gdi->height, gdi->dstBpp); - dfi->dfb->CreateInputEventBuffer(dfi->dfb, DICAPS_ALL, DFB_TRUE, - &(dfi->event_buffer)); - dfi->event_buffer->CreateFileDescriptor(dfi->event_buffer, &(dfi->read_fds)); - dfi->dfb->GetDisplayLayer(dfi->dfb, 0, &(dfi->layer)); - dfi->layer->EnableCursor(dfi->layer, 1); - dfi->dsc.flags = DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT | - DSDESC_PREALLOCATED | DSDESC_PIXELFORMAT; - dfi->dsc.caps = DSCAPS_SYSTEMONLY; - dfi->dsc.width = gdi->width; - dfi->dsc.height = gdi->height; - - if (gdi->dstBpp == 32 || gdi->dstBpp == 24) - dfi->dsc.pixelformat = DSPF_AiRGB; - else if (gdi->dstBpp == 16 || gdi->dstBpp == 15) - dfi->dsc.pixelformat = DSPF_RGB16; - else if (gdi->dstBpp == 8) - dfi->dsc.pixelformat = DSPF_RGB332; - else - dfi->dsc.pixelformat = DSPF_AiRGB; - - dfi->dsc.preallocated[0].data = gdi->primary_buffer; - dfi->dsc.preallocated[0].pitch = gdi->width * gdi->bytesPerPixel; - dfi->dfb->CreateSurface(dfi->dfb, &(dfi->dsc), &(dfi->surface)); - instance->update->BeginPaint = df_begin_paint; - instance->update->EndPaint = df_end_paint; - df_keyboard_init(); - df_register_graphics(instance->context->graphics); - return TRUE; -} - -BOOL df_verify_certificate(freerdp* instance, char* subject, char* issuer, - char* fingerprint) -{ - char answer; - WLog_INFO(TAG, "Certificate details:"); - WLog_INFO(TAG, "\tSubject: %s", subject); - WLog_INFO(TAG, "\tIssuer: %s", issuer); - WLog_INFO(TAG, "\tThumbprint: %s", fingerprint); - WLog_INFO(TAG, - "The above X.509 certificate could not be verified, possibly because you do not have " - "the CA certificate in your certificate store, or the certificate has expired. " - "Please look at the OpenSSL documentation on how to add a private CA to the store."); - - while (1) - { - WLog_INFO(TAG, "Do you trust the above certificate? (Y/N) "); - answer = fgetc(stdin); - - if (answer == 'y' || answer == 'Y') - { - return TRUE; - } - else if (answer == 'n' || answer == 'N') - { - break; - } - } - - return FALSE; -} - -static int df_receive_channel_data(freerdp* instance, UINT16 channelId, - BYTE* data, int size, int flags, int total_size) -{ - return freerdp_channels_data(instance, channelId, data, size, flags, - total_size); -} - -static void df_process_cb_monitor_ready_event(rdpChannels* channels, - freerdp* instance) -{ - wMessage* event; - RDP_CB_FORMAT_LIST_EVENT* format_list_event; - event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, - NULL); - format_list_event = (RDP_CB_FORMAT_LIST_EVENT*) event; - format_list_event->num_formats = 0; - freerdp_channels_send_event(channels, event); -} - -static void df_process_channel_event(rdpChannels* channels, freerdp* instance) -{ - wMessage* event; - event = freerdp_channels_pop_event(channels); - - if (event) - { - switch (GetMessageType(event->id)) - { - case CliprdrChannel_MonitorReady: - df_process_cb_monitor_ready_event(channels, instance); - break; - - default: - WLog_ERR(TAG, "df_process_channel_event: unknown event type %"PRIu32"", - GetMessageType(event->id)); - break; - } - - freerdp_event_free(event); - } -} - -static void df_free(dfInfo* dfi) -{ - dfi->dfb->Release(dfi->dfb); - free(dfi); -} - -int dfreerdp_run(freerdp* instance) -{ - int i; - int fds; - int max_fds; - int rcount; - int wcount; - void* rfds[32]; - void* wfds[32]; - fd_set rfds_set; - fd_set wfds_set; - dfInfo* dfi; - dfContext* context; - rdpChannels* channels; - ZeroMemory(rfds, sizeof(rfds)); - ZeroMemory(wfds, sizeof(wfds)); - - if (!freerdp_connect(instance)) - return 0; - - context = (dfContext*) instance->context; - dfi = context->dfi; - channels = instance->context->channels; - - while (1) - { - rcount = 0; - wcount = 0; - - if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) - { - WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); - break; - } - - if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, - &wcount) != TRUE) - { - WLog_ERR(TAG, "Failed to get channel manager file descriptor"); - break; - } - - if (df_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) - { - WLog_ERR(TAG, "Failed to get dfreerdp file descriptor"); - break; - } - - max_fds = 0; - FD_ZERO(&rfds_set); - FD_ZERO(&wfds_set); - - for (i = 0; i < rcount; i++) - { - fds = (int)(long)(rfds[i]); - - if (fds > max_fds) - max_fds = fds; - - FD_SET(fds, &rfds_set); - } - - if (max_fds == 0) - break; - - if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1) - { - /* these are not really errors */ - if (!((errno == EAGAIN) || - (errno == EWOULDBLOCK) || - (errno == EINPROGRESS) || - (errno == EINTR))) /* signal occurred */ - { - WLog_ERR(TAG, "dfreerdp_run: select failed"); - break; - } - } - - if (freerdp_check_fds(instance) != TRUE) - { - WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); - break; - } - - if (df_check_fds(instance, &rfds_set) != TRUE) - { - WLog_ERR(TAG, "Failed to check dfreerdp file descriptor"); - break; - } - - if (freerdp_channels_check_fds(channels, instance) != TRUE) - { - WLog_ERR(TAG, "Failed to check channel manager file descriptor"); - break; - } - - df_process_channel_event(channels, instance); - } - - freerdp_disconnect(instance); - df_free(dfi); - gdi_free(instance); - freerdp_free(instance); - return 0; -} - -void* thread_func(void* param) -{ - struct thread_data* data; - data = (struct thread_data*) param; - dfreerdp_run(data->instance); - free(data); - pthread_detach(pthread_self()); - g_thread_count--; - - if (g_thread_count < 1) - ReleaseSemaphore(g_sem, 1, NULL); - - return NULL; -} - -int main(int argc, char* argv[]) -{ - int status; - pthread_t thread; - freerdp* instance; - dfContext* context; - rdpChannels* channels; - struct thread_data* data; - setlocale(LC_ALL, ""); - - if (!(g_sem = CreateSemaphore(NULL, 0, 1, NULL))) - { - WLog_ERR(TAG, "Failed to create semaphore"); - return 1; - } - - instance = freerdp_new(); - instance->PreConnect = df_pre_connect; - instance->PostConnect = df_post_connect; - instance->VerifyCertificate = df_verify_certificate; - instance->ReceiveChannelData = df_receive_channel_data; - instance->ContextSize = sizeof(dfContext); - instance->ContextNew = df_context_new; - instance->ContextFree = df_context_free; - - if (!freerdp_context_new(instance)) - { - WLog_ERR(TAG, "Failed to create FreeRDP context"); - return 1; - } - - context = (dfContext*) instance->context; - channels = instance->context->channels; - DirectFBInit(&argc, &argv); - instance->context->argc = argc; - instance->context->argv = argv; - status = freerdp_client_settings_parse_command_line(instance->settings, argc, - argv, FALSE); - - if (status < 0) - return 0; - - if (!freerdp_client_load_addins(instance->context->channels, - instance->settings)) - return -1; - - data = (struct thread_data*) malloc(sizeof(struct thread_data)); - ZeroMemory(data, sizeof(sizeof(struct thread_data))); - data->instance = instance; - g_thread_count++; - pthread_create(&thread, 0, thread_func, data); - - while (g_thread_count > 0) - { - WaitForSingleObject(g_sem, INFINITE); - } - - return 0; -} diff --git a/client/DirectFB/dfreerdp.h b/client/DirectFB/dfreerdp.h deleted file mode 100644 index 544619b..0000000 --- a/client/DirectFB/dfreerdp.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * DirectFB Client - * - * Copyright 2011 Marc-Andre Moreau - * - * 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 FREERDP_CLIENT_DF_FREERDP_H -#define FREERDP_CLIENT_DF_FREERDP_H - -#include "config.h" -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -typedef struct df_info dfInfo; - -struct df_context -{ - rdpContext _p; - - dfInfo* dfi; - rdpSettings* settings; -}; -typedef struct df_context dfContext; - -struct df_pointer -{ - rdpPointer pointer; - IDirectFBSurface* surface; - UINT32 xhot; - UINT32 yhot; -}; -typedef struct df_pointer dfPointer; - -struct df_info -{ - int read_fds; - DFBResult err; - IDirectFB* dfb; - DFBEvent event; - HCLRCONV clrconv; - DFBRectangle update_rect; - DFBSurfaceDescription dsc; - IDirectFBSurface* primary; - IDirectFBSurface* surface; - IDirectFBDisplayLayer* layer; - IDirectFBEventBuffer* event_buffer; -}; - -#endif /* FREERDP_CLIENT_DF_FREERDP_H */ diff --git a/client/Sample/CMakeLists.txt b/client/Sample/CMakeLists.txt index 1e64733..a3392c9 100644 --- a/client/Sample/CMakeLists.txt +++ b/client/Sample/CMakeLists.txt @@ -19,7 +19,10 @@ set(MODULE_NAME "sfreerdp") set(MODULE_PREFIX "FREERDP_CLIENT_SAMPLE") set(${MODULE_PREFIX}_SRCS - freerdp.c) + tf_channels.c + tf_channels.h + tf_freerdp.h + tf_freerdp.c) # On windows create dll version information. # Vendor, product and year are already set in top level CMakeLists.txt diff --git a/client/Sample/freerdp.c b/client/Sample/freerdp.c deleted file mode 100644 index cfbc30e..0000000 --- a/client/Sample/freerdp.c +++ /dev/null @@ -1,212 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * FreeRDP Test UI - * - * Copyright 2011 Marc-Andre Moreau - * Copyright 2016 Armin Novak - * Copyright 2016 Thincast Technologies GmbH - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define TAG CLIENT_TAG("sample") - -struct tf_context -{ - rdpContext _p; -}; -typedef struct tf_context tfContext; - -static BOOL tf_context_new(freerdp* instance, rdpContext* context) -{ - return TRUE; -} - -static void tf_context_free(freerdp* instance, rdpContext* context) -{ -} - -static BOOL tf_begin_paint(rdpContext* context) -{ - rdpGdi* gdi = context->gdi; - gdi->primary->hdc->hwnd->invalid->null = TRUE; - return TRUE; -} - -static BOOL tf_end_paint(rdpContext* context) -{ - rdpGdi* gdi = context->gdi; - - if (gdi->primary->hdc->hwnd->invalid->null) - return TRUE; - - return TRUE; -} - -static BOOL tf_pre_connect(freerdp* instance) -{ - rdpSettings* settings; - settings = instance->settings; - settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE; - settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = TRUE; - settings->OrderSupport[NEG_LINETO_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE; - settings->OrderSupport[NEG_MEMBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_MEM3BLT_INDEX] = TRUE; - settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = TRUE; - settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE; - settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE; - settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYGON_SC_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYGON_CB_INDEX] = TRUE; - settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = TRUE; - settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = TRUE; - return TRUE; -} - -static BOOL tf_post_connect(freerdp* instance) -{ - if (!gdi_init(instance, PIXEL_FORMAT_XRGB32)) - return FALSE; - - instance->update->BeginPaint = tf_begin_paint; - instance->update->EndPaint = tf_end_paint; - return TRUE; -} - -static DWORD WINAPI tf_client_thread_proc(LPVOID arg) -{ - freerdp* instance = (freerdp*)arg; - DWORD nCount; - DWORD status; - HANDLE handles[64]; - - if (!freerdp_connect(instance)) - { - WLog_ERR(TAG, "connection failure"); - return 0; - } - - while (!freerdp_shall_disconnect(instance)) - { - nCount = freerdp_get_event_handles(instance->context, &handles[0], 64); - - if (nCount == 0) - { - WLog_ERR(TAG, "%s: freerdp_get_event_handles failed", __FUNCTION__); - break; - } - - status = WaitForMultipleObjects(nCount, handles, FALSE, 100); - - if (status == WAIT_FAILED) - { - WLog_ERR(TAG, "%s: WaitForMultipleObjects failed with %"PRIu32"", __FUNCTION__, - status); - break; - } - - if (!freerdp_check_event_handles(instance->context)) - { - if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS) - WLog_ERR(TAG, "Failed to check FreeRDP event handles"); - - break; - } - } - - freerdp_disconnect(instance); - ExitThread(0); - return 0; -} - -int main(int argc, char* argv[]) -{ - int status; - HANDLE thread; - freerdp* instance; - instance = freerdp_new(); - - if (!instance) - { - WLog_ERR(TAG, "Couldn't create instance"); - return 1; - } - - instance->PreConnect = tf_pre_connect; - instance->PostConnect = tf_post_connect; - instance->ContextSize = sizeof(tfContext); - instance->ContextNew = tf_context_new; - instance->ContextFree = tf_context_free; - freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0); - - if (!freerdp_context_new(instance)) - { - WLog_ERR(TAG, "Couldn't create context"); - return 1; - } - - status = freerdp_client_settings_parse_command_line(instance->settings, argc, - argv, FALSE); - - if (status < 0) - { - return 0; - } - - if (!freerdp_client_load_addins(instance->context->channels, - instance->settings)) - return -1; - - if (!(thread = CreateThread(NULL, 0, tf_client_thread_proc, instance, 0, NULL))) - { - WLog_ERR(TAG, "Failed to create client thread"); - } - else - { - WaitForSingleObject(thread, INFINITE); - } - - freerdp_context_free(instance); - freerdp_free(instance); - return 0; -} diff --git a/client/Sample/tf_channels.c b/client/Sample/tf_channels.c new file mode 100644 index 0000000..91e13bc --- /dev/null +++ b/client/Sample/tf_channels.c @@ -0,0 +1,127 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Sample Client Channels + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include + +#include "tf_channels.h" +#include "tf_freerdp.h" + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT tf_encomsp_participant_created(EncomspClientContext* context, + ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated) +{ + return CHANNEL_RC_OK; +} + +static void tf_encomsp_init(tfContext* tf, EncomspClientContext* encomsp) +{ + tf->encomsp = encomsp; + encomsp->custom = (void*) tf; + encomsp->ParticipantCreated = tf_encomsp_participant_created; +} + +static void tf_encomsp_uninit(tfContext* tf, EncomspClientContext* encomsp) +{ + if (encomsp) + { + encomsp->custom = NULL; + encomsp->ParticipantCreated = NULL; + } + + if (tf) + tf->encomsp = NULL; +} + + +void tf_OnChannelConnectedEventHandler(void* context, + ChannelConnectedEventArgs* e) +{ + tfContext* tf = (tfContext*) context; + rdpSettings* settings; + settings = tf->context.settings; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + tf->rdpei = (RdpeiClientContext*) e->pInterface; + } + else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) + { + gdi_graphics_pipeline_init(tf->context.gdi, (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + tf_encomsp_init(tf, (EncomspClientContext*) e->pInterface); + } +} + +void tf_OnChannelDisconnectedEventHandler(void* context, + ChannelDisconnectedEventArgs* e) +{ + tfContext* tf = (tfContext*) context; + rdpSettings* settings; + settings = tf->context.settings; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + tf->rdpei = NULL; + } + else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) + { + gdi_graphics_pipeline_uninit(tf->context.gdi, + (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + } + else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) + { + tf_encomsp_uninit(tf, (EncomspClientContext*) e->pInterface); + } +} diff --git a/client/Sample/tf_channels.h b/client/Sample/tf_channels.h new file mode 100644 index 0000000..5cb3202 --- /dev/null +++ b/client/Sample/tf_channels.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Sample Client Channels + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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 FREERDP_CLIENT_SAMPLE_CHANNELS_H +#define FREERDP_CLIENT_SAMPLE_CHANNELS_H + +#include +#include + +int tf_on_channel_connected(freerdp* instance, const char* name, + void* pInterface); +int tf_on_channel_disconnected(freerdp* instance, const char* name, + void* pInterface); + +void tf_OnChannelConnectedEventHandler(void* context, + ChannelConnectedEventArgs* e); +void tf_OnChannelDisconnectedEventHandler(void* context, + ChannelDisconnectedEventArgs* e); + +#endif /* FREERDP_CLIENT_SAMPLE_CHANNELS_H */ diff --git a/client/Sample/tf_freerdp.c b/client/Sample/tf_freerdp.c new file mode 100644 index 0000000..5549cb0 --- /dev/null +++ b/client/Sample/tf_freerdp.c @@ -0,0 +1,339 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Test UI + * + * Copyright 2011 Marc-Andre Moreau + * Copyright 2016,2018 Armin Novak + * Copyright 2016,2018 Thincast Technologies GmbH + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tf_channels.h" +#include "tf_freerdp.h" + +#define TAG CLIENT_TAG("sample") + +/* This function is called whenever a new frame starts. + * It can be used to reset invalidated areas. */ +static BOOL tf_begin_paint(rdpContext* context) +{ + rdpGdi* gdi = context->gdi; + gdi->primary->hdc->hwnd->invalid->null = TRUE; + return TRUE; +} + +/* This function is called when the library completed composing a new + * frame. Read out the changed areas and blit them to your output device. + * The image buffer will have the format specified by gdi_init + */ +static BOOL tf_end_paint(rdpContext* context) +{ + rdpGdi* gdi = context->gdi; + + if (gdi->primary->hdc->hwnd->invalid->null) + return TRUE; + + return TRUE; +} + +/* This function is called to output a System BEEP */ +static BOOL tf_play_sound(rdpContext* context, + const PLAY_SOUND_UPDATE* play_sound) +{ + /* TODO: Implement */ + return TRUE; +} + +/* This function is called to update the keyboard indocator LED */ +static BOOL tf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags) +{ + /* TODO: Set local keyboard indicator LED status */ + return TRUE; +} + +/* This function is called to set the IME state */ +static BOOL tf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState, + UINT32 imeConvMode) +{ + if (!context) + return FALSE; + + WLog_WARN(TAG, + "KeyboardSetImeStatus(unitId=%04"PRIx16", imeState=%08"PRIx32", imeConvMode=%08"PRIx32") ignored", + imeId, imeState, imeConvMode); + return TRUE; +} + +/* Called before a connection is established. + * Set all configuration options to support and load channels here. */ +static BOOL tf_pre_connect(freerdp* instance) +{ + rdpSettings* settings; + settings = instance->settings; + /* Optional OS identifier sent to server */ + settings->OsMajorType = OSMAJORTYPE_UNIX; + settings->OsMinorType = OSMINORTYPE_NATIVE_XSERVER; + /* settings->OrderSupport is initialized at this point. + * Only override it if you plan to implement custom order + * callbacks or deactiveate certain features. */ + /* Register the channel listeners. + * They are required to set up / tear down channels if they are loaded. */ + PubSub_SubscribeChannelConnected(instance->context->pubSub, + tf_OnChannelConnectedEventHandler); + PubSub_SubscribeChannelDisconnected(instance->context->pubSub, + tf_OnChannelDisconnectedEventHandler); + + /* Load all required plugins / channels / libraries specified by current + * settings. */ + if (!freerdp_client_load_addins(instance->context->channels, + instance->settings)) + return FALSE; + + /* TODO: Any code your client requires */ + return TRUE; +} + +/* Called after a RDP connection was successfully established. + * Settings might have changed during negociation of client / server feature + * support. + * + * Set up local framebuffers and paing callbacks. + * If required, register pointer callbacks to change the local mouse cursor + * when hovering over the RDP window + */ +static BOOL tf_post_connect(freerdp* instance) +{ + if (!gdi_init(instance, PIXEL_FORMAT_XRGB32)) + return FALSE; + + instance->update->BeginPaint = tf_begin_paint; + instance->update->EndPaint = tf_end_paint; + instance->update->PlaySound = tf_play_sound; + instance->update->SetKeyboardIndicators = tf_keyboard_set_indicators; + instance->update->SetKeyboardImeStatus = tf_keyboard_set_ime_status; + return TRUE; +} + +/* This function is called whether a session ends by failure or success. + * Clean up everything allocated by pre_connect and post_connect. + */ +static void tf_post_disconnect(freerdp* instance) +{ + tfContext* context; + + if (!instance) + return; + + if (!instance->context) + return; + + context = (tfContext*) instance->context; + PubSub_UnsubscribeChannelConnected(instance->context->pubSub, + tf_OnChannelConnectedEventHandler); + PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub, + tf_OnChannelDisconnectedEventHandler); + gdi_free(instance); + /* TODO : Clean up custom stuff */ +} + +/* RDP main loop. + * Connects RDP, loops while running and handles event and dispatch, cleans up + * after the connection ends. */ +static DWORD WINAPI tf_client_thread_proc(LPVOID arg) +{ + freerdp* instance = (freerdp*)arg; + DWORD nCount; + DWORD status; + HANDLE handles[64]; + + if (!freerdp_connect(instance)) + { + WLog_ERR(TAG, "connection failure"); + return 0; + } + + while (!freerdp_shall_disconnect(instance)) + { + nCount = freerdp_get_event_handles(instance->context, &handles[0], 64); + + if (nCount == 0) + { + WLog_ERR(TAG, "%s: freerdp_get_event_handles failed", __FUNCTION__); + break; + } + + status = WaitForMultipleObjects(nCount, handles, FALSE, 100); + + if (status == WAIT_FAILED) + { + WLog_ERR(TAG, "%s: WaitForMultipleObjects failed with %"PRIu32"", __FUNCTION__, + status); + break; + } + + if (!freerdp_check_event_handles(instance->context)) + { + if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS) + WLog_ERR(TAG, "Failed to check FreeRDP event handles"); + + break; + } + } + + freerdp_disconnect(instance); + return 0; +} + +/* Optional global initializer. + * Here we just register a signal handler to print out stack traces + * if available. */ +static BOOL tf_client_global_init(void) +{ + if (freerdp_handle_signals() != 0) + return FALSE; + + return TRUE; +} + +/* Optional global tear down */ +static void tf_client_global_uninit(void) +{ +} + +static int tf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) +{ + tfContext* tf; + const char* str_data = freerdp_get_logon_error_info_data(data); + const char* str_type = freerdp_get_logon_error_info_type(type); + + if (!instance || !instance->context) + return -1; + + tf = (tfContext*) instance->context; + WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type); + return 1; +} + +static BOOL tf_client_new(freerdp* instance, rdpContext* context) +{ + tfContext* tf = (tfContext*) context; + + if (!instance || !context) + return FALSE; + + instance->PreConnect = tf_pre_connect; + instance->PostConnect = tf_post_connect; + instance->PostDisconnect = tf_post_disconnect; + instance->Authenticate = client_cli_authenticate; + instance->GatewayAuthenticate = client_cli_gw_authenticate; + instance->VerifyCertificateEx = client_cli_verify_certificate_ex; + instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex; + instance->LogonErrorInfo = tf_logon_error_info; + /* TODO: Client display set up */ + return TRUE; +} + + +static void tf_client_free(freerdp* instance, rdpContext* context) +{ + tfContext* tf = (tfContext*) instance->context; + + if (!context) + return; + + /* TODO: Client display tear down */ +} + +static int tf_client_start(rdpContext* context) +{ + /* TODO: Start client related stuff */ + return 0; +} + +static int tf_client_stop(rdpContext* context) +{ + /* TODO: Stop client related stuff */ + return 0; +} + +static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) +{ + ZeroMemory(pEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS)); + pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION; + pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1); + pEntryPoints->GlobalInit = tf_client_global_init; + pEntryPoints->GlobalUninit = tf_client_global_uninit; + pEntryPoints->ContextSize = sizeof(tfContext); + pEntryPoints->ClientNew = tf_client_new; + pEntryPoints->ClientFree = tf_client_free; + pEntryPoints->ClientStart = tf_client_start; + pEntryPoints->ClientStop = tf_client_stop; + return 0; +} + +int main(int argc, char* argv[]) +{ + int rc = -1; + DWORD status; + RDP_CLIENT_ENTRY_POINTS clientEntryPoints; + rdpContext* context; + RdpClientEntry(&clientEntryPoints); + context = freerdp_client_context_new(&clientEntryPoints); + + if (!context) + goto fail; + + status = freerdp_client_settings_parse_command_line(context->settings, argc, + argv, FALSE); + status = freerdp_client_settings_command_line_status_print(context->settings, + status, argc, argv); + + if (status) + return 0; + + if (freerdp_client_start(context) != 0) + goto fail; + + rc = tf_client_thread_proc(context->instance); + + if (freerdp_client_stop(context) != 0) + rc = -1; + +fail: + freerdp_client_context_free(context); + return rc; +} diff --git a/client/Sample/tf_freerdp.h b/client/Sample/tf_freerdp.h new file mode 100644 index 0000000..de0580f --- /dev/null +++ b/client/Sample/tf_freerdp.h @@ -0,0 +1,43 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Sample Client + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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 FREERDP_CLIENT_SAMPLE_H +#define FREERDP_CLIENT_SAMPLE_H + +#include +#include +#include +#include +#include +#include +#include + +struct tf_context +{ + rdpContext context; + + /* Channels */ + RdpeiClientContext* rdpei; + RdpgfxClientContext* gfx; + EncomspClientContext* encomsp; +}; +typedef struct tf_context tfContext; + +#endif /* FREERDP_CLIENT_SAMPLE_H */ diff --git a/client/Wayland/CMakeLists.txt b/client/Wayland/CMakeLists.txt index bc66f28..eb1cce7 100644 --- a/client/Wayland/CMakeLists.txt +++ b/client/Wayland/CMakeLists.txt @@ -25,8 +25,14 @@ include_directories(${CMAKE_SOURCE_DIR}/uwac/include) set(${MODULE_PREFIX}_SRCS wlfreerdp.c wlfreerdp.h + wlf_disp.c + wlf_disp.h + wlf_pointer.c + wlf_pointer.h wlf_input.c wlf_input.h + wlf_cliprdr.c + wlf_cliprdr.h wlf_channels.c wlf_channels.h ) diff --git a/client/Wayland/wlf_channels.c b/client/Wayland/wlf_channels.c index c8a4c9d..7783eb7 100644 --- a/client/Wayland/wlf_channels.c +++ b/client/Wayland/wlf_channels.c @@ -24,6 +24,8 @@ #include #include "wlf_channels.h" +#include "wlf_cliprdr.h" +#include "wlf_disp.h" #include "wlfreerdp.h" /** @@ -62,7 +64,6 @@ void wlf_OnChannelConnectedEventHandler(void* context, { wlfContext* wlf = (wlfContext*) context; rdpSettings* settings; - settings = wlf->context.settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) @@ -74,19 +75,23 @@ void wlf_OnChannelConnectedEventHandler(void* context, } else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { - if (settings->SoftwareGdi) - gdi_graphics_pipeline_init(wlf->context.gdi, (RdpgfxClientContext*) e->pInterface); + gdi_graphics_pipeline_init(wlf->context.gdi, (RdpgfxClientContext*) e->pInterface); } else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0) { } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { + wlf_cliprdr_init(wlf->clipboard, (CliprdrClientContext*)e->pInterface); } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { wlf_encomsp_init(wlf, (EncomspClientContext*) e->pInterface); } + else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0) + { + wlf_disp_init(wlf->disp, (DispClientContext*)e->pInterface); + } } void wlf_OnChannelDisconnectedEventHandler(void* context, @@ -94,7 +99,6 @@ void wlf_OnChannelDisconnectedEventHandler(void* context, { wlfContext* wlf = (wlfContext*) context; rdpSettings* settings; - settings = wlf->context.settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) @@ -106,18 +110,22 @@ void wlf_OnChannelDisconnectedEventHandler(void* context, } else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { - if (settings->SoftwareGdi) - gdi_graphics_pipeline_uninit(wlf->context.gdi, - (RdpgfxClientContext*) e->pInterface); + gdi_graphics_pipeline_uninit(wlf->context.gdi, + (RdpgfxClientContext*) e->pInterface); } else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0) { } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { + wlf_cliprdr_uninit(wlf->clipboard, (CliprdrClientContext*)e->pInterface); } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { wlf_encomsp_uninit(wlf, (EncomspClientContext*) e->pInterface); } + else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0) + { + wlf_disp_uninit(wlf->disp, (DispClientContext*)e->pInterface); + } } diff --git a/client/Wayland/wlf_cliprdr.c b/client/Wayland/wlf_cliprdr.c new file mode 100644 index 0000000..25ba9db --- /dev/null +++ b/client/Wayland/wlf_cliprdr.c @@ -0,0 +1,895 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Wayland Clipboard Redirection + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "wlf_cliprdr.h" + +#define MAX_CLIPBOARD_FORMATS 255 + +static const char* mime_text[] = +{ + "text/plain", + "text/plain;charset=utf-8", + "UTF8_STRING", + "COMPOUND_TEXT", + "TEXT", + "STRING" +}; + +static const char* mime_image[] = +{ + "image/png", + "image/bmp", + "image/x-bmp", + "image/x-MS-bmp", + "image/x-icon", + "image/x-ico", + "image/x-win-bitmap", + "image/vmd.microsoft.icon", + "application/ico", + "image/ico", + "image/icon", + "image/jpeg", + "image/tiff" +}; + +static const char* mime_html[] = +{ + "text/html" +}; + +struct wlf_clipboard +{ + wlfContext* wfc; + rdpChannels* channels; + CliprdrClientContext* context; + wLog* log; + + UwacSeat* seat; + wClipboard* system; + wClipboardDelegate* delegate; + + size_t numClientFormats; + CLIPRDR_FORMAT* clientFormats; + + size_t numServerFormats; + CLIPRDR_FORMAT* serverFormats; + + BOOL sync; + + /* File clipping */ + BOOL streams_supported; + BOOL file_formats_registered; + + /* Server response stuff */ + FILE* responseFile; + UINT32 responseFormat; + const char* responseMime; +}; + +static BOOL wlf_mime_is_text(const char* mime) +{ + size_t x; + + for (x = 0; x < ARRAYSIZE(mime_text); x++) + { + if (strcmp(mime, mime_text[x]) == 0) + return TRUE; + } + + return FALSE; +} + +static BOOL wlf_mime_is_image(const char* mime) +{ + size_t x; + + for (x = 0; x < ARRAYSIZE(mime_image); x++) + { + if (strcmp(mime, mime_image[x]) == 0) + return TRUE; + } + + return FALSE; +} + +static BOOL wlf_mime_is_html(const char* mime) +{ + size_t x; + + for (x = 0; x < ARRAYSIZE(mime_html); x++) + { + if (strcmp(mime, mime_html[x]) == 0) + return TRUE; + } + + return FALSE; +} + +static void wlf_cliprdr_free_server_formats(wfClipboard* clipboard) +{ + if (clipboard && clipboard->serverFormats) + { + size_t j; + + for (j = 0; j < clipboard->numServerFormats; j++) + { + CLIPRDR_FORMAT* format = &clipboard->serverFormats[j]; + free(format->formatName); + } + + free(clipboard->serverFormats); + clipboard->serverFormats = NULL; + clipboard->numServerFormats = 0; + } + + if (clipboard) + UwacClipboardOfferDestroy(clipboard->seat); +} + +static void wlf_cliprdr_free_client_formats(wfClipboard* clipboard) +{ + if (clipboard && clipboard->numClientFormats) + { + size_t j; + + for (j = 0; j < clipboard->numClientFormats; j++) + { + CLIPRDR_FORMAT* format = &clipboard->clientFormats[j]; + free(format->formatName); + } + + free(clipboard->clientFormats); + clipboard->clientFormats = NULL; + clipboard->numClientFormats = 0; + } + + if (clipboard) + UwacClipboardOfferDestroy(clipboard->seat); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT wlf_cliprdr_send_client_format_list(wfClipboard* clipboard) +{ + CLIPRDR_FORMAT_LIST formatList = { 0 }; + formatList.msgFlags = CB_RESPONSE_OK; + formatList.numFormats = (UINT32)clipboard->numClientFormats; + formatList.formats = clipboard->clientFormats; + return clipboard->context->ClientFormatList(clipboard->context, &formatList); +} + +static void wfl_cliprdr_add_client_format_id(wfClipboard* clipboard, UINT32 formatId) +{ + size_t x; + CLIPRDR_FORMAT* format; + const char* name = ClipboardGetFormatName(clipboard->system, formatId); + + for (x = 0; x < clipboard->numClientFormats; x++) + { + format = &clipboard->clientFormats[x]; + + if (format->formatId == formatId) + return; + } + + format = realloc(clipboard->clientFormats, + (clipboard->numClientFormats + 1) * sizeof(CLIPRDR_FORMAT)); + + if (!format) + return; + + clipboard->clientFormats = format; + format = &clipboard->clientFormats[clipboard->numClientFormats++]; + format->formatId = formatId; + format->formatName = NULL; + + if (name && (formatId >= CF_MAX)) + format->formatName = _strdup(name); +} + +static void wlf_cliprdr_add_client_format(wfClipboard* clipboard, const char* mime) +{ + if (wlf_mime_is_html(mime)) + { + UINT32 formatId = ClipboardGetFormatId(clipboard->system, "HTML Format"); + wfl_cliprdr_add_client_format_id(clipboard, formatId); + } + else if (wlf_mime_is_text(mime)) + { + wfl_cliprdr_add_client_format_id(clipboard, CF_TEXT); + wfl_cliprdr_add_client_format_id(clipboard, CF_OEMTEXT); + wfl_cliprdr_add_client_format_id(clipboard, CF_UNICODETEXT); + } + else if (wlf_mime_is_image(mime)) + { + UINT32 formatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); + wfl_cliprdr_add_client_format_id(clipboard, formatId); + wfl_cliprdr_add_client_format_id(clipboard, CF_DIB); + } + + wlf_cliprdr_send_client_format_list(clipboard); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT wlf_cliprdr_send_data_request(wfClipboard* clipboard, + UINT32 formatId) +{ + CLIPRDR_FORMAT_DATA_REQUEST request = { 0 }; + request.requestedFormatId = formatId; + return clipboard->context->ClientFormatDataRequest(clipboard->context, + &request); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT wlf_cliprdr_send_data_response(wfClipboard* clipboard, const BYTE* data, + size_t size) +{ + CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 }; + if (size > UINT32_MAX) + return ERROR_INVALID_PARAMETER; + + response.msgFlags = (data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL; + response.dataLen = (UINT32)size; + response.requestedFormatData = data; + return clipboard->context->ClientFormatDataResponse(clipboard->context, + &response); +} + +BOOL wlf_cliprdr_handle_event(wfClipboard* clipboard, const UwacClipboardEvent* event) +{ + if (!clipboard || !event) + return FALSE; + + if (!clipboard->context) + return TRUE; + + switch (event->type) + { + case UWAC_EVENT_CLIPBOARD_AVAILABLE: + clipboard->seat = event->seat; + return TRUE; + + case UWAC_EVENT_CLIPBOARD_OFFER: + WLog_Print(clipboard->log, WLOG_INFO, "client announces mime %s", event->mime); + wlf_cliprdr_add_client_format(clipboard, event->mime); + return TRUE; + + case UWAC_EVENT_CLIPBOARD_SELECT: + WLog_Print(clipboard->log, WLOG_DEBUG, "client announces new data"); + wlf_cliprdr_free_client_formats(clipboard); + return TRUE; + + default: + return FALSE; + } +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT wlf_cliprdr_send_client_capabilities(wfClipboard* clipboard) +{ + CLIPRDR_CAPABILITIES capabilities; + CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; + capabilities.cCapabilitiesSets = 1; + capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) & + (generalCapabilitySet); + generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; + generalCapabilitySet.capabilitySetLength = 12; + generalCapabilitySet.version = CB_CAPS_VERSION_2; + generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES; + + if (clipboard->streams_supported && clipboard->file_formats_registered) + generalCapabilitySet.generalFlags |= + CB_STREAM_FILECLIP_ENABLED | CB_FILECLIP_NO_FILE_PATHS; + + return clipboard->context->ClientCapabilities(clipboard->context, + &capabilities); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT wlf_cliprdr_send_client_format_list_response(wfClipboard* clipboard, + BOOL status) +{ + CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse; + formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE; + formatListResponse.msgFlags = status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL; + formatListResponse.dataLen = 0; + return clipboard->context->ClientFormatListResponse(clipboard->context, + &formatListResponse); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT wlf_cliprdr_monitor_ready(CliprdrClientContext* context, + const CLIPRDR_MONITOR_READY* monitorReady) +{ + wfClipboard* clipboard = (wfClipboard*) context->custom; + UINT ret; + + WINPR_UNUSED(monitorReady); + if ((ret = wlf_cliprdr_send_client_capabilities(clipboard)) != CHANNEL_RC_OK) + return ret; + + if ((ret = wlf_cliprdr_send_client_format_list(clipboard)) != CHANNEL_RC_OK) + return ret; + + clipboard->sync = TRUE; + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT wlf_cliprdr_server_capabilities(CliprdrClientContext* context, + const CLIPRDR_CAPABILITIES* capabilities) +{ + UINT32 i; + const BYTE* capsPtr = (const BYTE*) capabilities->capabilitySets; + wfClipboard* clipboard = (wfClipboard*) context->custom; + clipboard->streams_supported = FALSE; + + for (i = 0; i < capabilities->cCapabilitiesSets; i++) + { + const CLIPRDR_CAPABILITY_SET* caps = (const CLIPRDR_CAPABILITY_SET*) capsPtr; + + if (caps->capabilitySetType == CB_CAPSTYPE_GENERAL) + { + const CLIPRDR_GENERAL_CAPABILITY_SET* generalCaps = (const CLIPRDR_GENERAL_CAPABILITY_SET*) caps; + + if (generalCaps->generalFlags & CB_STREAM_FILECLIP_ENABLED) + { + clipboard->streams_supported = TRUE; + } + } + + capsPtr += caps->capabilitySetLength; + } + + return CHANNEL_RC_OK; +} + +static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char* mime, int fd) +{ + wfClipboard* clipboard = (wfClipboard*)context; + size_t x; + WINPR_UNUSED(seat); + clipboard->responseMime = NULL; + + for (x = 0; x < ARRAYSIZE(mime_html); x++) + { + const char* mime_cur = mime_html[x]; + + if (strcmp(mime_cur, mime) == 0) + { + clipboard->responseMime = mime_cur; + clipboard->responseFormat = ClipboardGetFormatId(clipboard->system, "HTML Format"); + break; + } + } + + for (x = 0; x < ARRAYSIZE(mime_text); x++) + { + const char* mime_cur = mime_text[x]; + + if (strcmp(mime_cur, mime) == 0) + { + clipboard->responseMime = mime_cur; + clipboard->responseFormat = CF_UNICODETEXT; + break; + } + } + + for (x = 0; x < ARRAYSIZE(mime_image); x++) + { + const char* mime_cur = mime_image[x]; + + if (strcmp(mime_cur, mime) == 0) + { + clipboard->responseMime = mime_cur; + clipboard->responseFormat = CF_DIB; + break; + } + } + + if (clipboard->responseMime != NULL) + { + clipboard->responseFile = fdopen(fd, "w"); + + if (clipboard->responseFile) + wlf_cliprdr_send_data_request(clipboard, clipboard->responseFormat); + else + WLog_Print(clipboard->log, WLOG_ERROR, "failed to open clipboard file descriptor for MIME %s", + clipboard->responseMime); + } +} + +static void wlf_cliprdr_cancel_data(UwacSeat* seat, void* context) +{ + WINPR_UNUSED(seat); + WINPR_UNUSED(context); +} + +/** + * Called when the clipboard changes server side. + * + * Clear the local clipboard offer and replace it with a new one + * that announces the formats we get listed here. + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT wlf_cliprdr_server_format_list(CliprdrClientContext* context, + const CLIPRDR_FORMAT_LIST* formatList) +{ + UINT32 i; + wfClipboard* clipboard; + BOOL html = FALSE; + BOOL text = FALSE; + BOOL image = FALSE; + + if (!context || !context->custom) + return ERROR_INVALID_PARAMETER; + + clipboard = (wfClipboard*) context->custom; + wlf_cliprdr_free_server_formats(clipboard); + + if (!(clipboard->serverFormats = (CLIPRDR_FORMAT*) calloc( + formatList->numFormats, sizeof(CLIPRDR_FORMAT)))) + { + WLog_Print(clipboard->log, WLOG_ERROR, "failed to allocate %"PRIuz" CLIPRDR_FORMAT structs", + clipboard->numServerFormats); + return CHANNEL_RC_NO_MEMORY; + } + + clipboard->numServerFormats = formatList->numFormats; + + if (!clipboard->seat) + { + WLog_Print(clipboard->log, WLOG_ERROR, "clipboard->seat=NULL, check your client implementation"); + return ERROR_INTERNAL_ERROR; + } + + for (i = 0; i < formatList->numFormats; i++) + { + const CLIPRDR_FORMAT* format = &formatList->formats[i]; + CLIPRDR_FORMAT* srvFormat = &clipboard->serverFormats[i]; + srvFormat->formatId = format->formatId; + + if (format->formatName) + { + srvFormat->formatName = _strdup(format->formatName); + + if (!srvFormat->formatName) + { + wlf_cliprdr_free_server_formats(clipboard); + return CHANNEL_RC_NO_MEMORY; + } + } + + if (format->formatName) + { + if (strcmp(format->formatName, "HTML Format") == 0) + { + text = TRUE; + html = TRUE; + } + } + else + { + switch (format->formatId) + { + case CF_TEXT: + case CF_OEMTEXT: + case CF_UNICODETEXT: + text = TRUE; + break; + + case CF_DIB: + image = TRUE; + break; + + default: + break; + } + } + } + + if (html) + { + size_t x; + + for (x = 0; x < ARRAYSIZE(mime_html); x++) + UwacClipboardOfferCreate(clipboard->seat, mime_html[x]); + } + + if (text) + { + size_t x; + + for (x = 0; x < ARRAYSIZE(mime_text); x++) + UwacClipboardOfferCreate(clipboard->seat, mime_text[x]); + } + + if (image) + { + size_t x; + + for (x = 0; x < ARRAYSIZE(mime_image); x++) + UwacClipboardOfferCreate(clipboard->seat, mime_image[x]); + } + + UwacClipboardOfferAnnounce(clipboard->seat, clipboard, wlf_cliprdr_transfer_data, + wlf_cliprdr_cancel_data); + return wlf_cliprdr_send_client_format_list_response(clipboard, TRUE); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT wlf_cliprdr_server_format_list_response(CliprdrClientContext* + context, const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) +{ + //wfClipboard* clipboard = (wfClipboard*) context->custom; + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT wlf_cliprdr_server_format_data_request(CliprdrClientContext* context, + const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) +{ + int cnv; + UINT rc; + BYTE* data; + LPWSTR cdata; + size_t size; + const char* mime; + UINT32 formatId = formatDataRequest->requestedFormatId; + wfClipboard* clipboard = (wfClipboard*) context->custom; + + switch (formatId) + { + case CF_TEXT: + case CF_OEMTEXT: + case CF_UNICODETEXT: + mime = "text/plain;charset=utf-8"; + break; + + case CF_DIB: + case CF_DIBV5: + mime = "image/bmp"; + break; + + default: + if (formatId == ClipboardGetFormatId(clipboard->system, "HTML Format")) + mime = "text/html"; + else if (formatId == ClipboardGetFormatId(clipboard->system, "image/bmp")) + mime = "image/bmp"; + else + mime = ClipboardGetFormatName(clipboard->system, formatId); + + break; + } + + data = UwacClipboardDataGet(clipboard->seat, mime, &size); + + if (!data) + return ERROR_INTERNAL_ERROR; + + switch (formatId) + { + case CF_UNICODETEXT: + if (size > INT_MAX) + rc = ERROR_INTERNAL_ERROR; + else + { + cnv = ConvertToUnicode(CP_UTF8, 0, (LPCSTR)data, (int)size, &cdata, 0); + free(data); + data = NULL; + + if (cnv < 0) + rc = ERROR_INTERNAL_ERROR; + else + { + size = (size_t)cnv; + data = (BYTE*)cdata; + size *= sizeof(WCHAR); + } + } + break; + + default: + // TODO: Image conversions + break; + } + + rc = wlf_cliprdr_send_data_response(clipboard, data, size); + free(data); + return rc; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT wlf_cliprdr_server_format_data_response(CliprdrClientContext* + context, const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) +{ + int cnv; + UINT rc = ERROR_INTERNAL_ERROR; + UINT32 size = formatDataResponse->dataLen; + LPSTR cdata = NULL; + LPCSTR data = (LPCSTR)formatDataResponse->requestedFormatData; + const WCHAR* wdata = (const WCHAR*)formatDataResponse->requestedFormatData; + wfClipboard* clipboard = (wfClipboard*) context->custom; + + if (size > INT_MAX * sizeof(WCHAR)) + return ERROR_INTERNAL_ERROR; + + switch (clipboard->responseFormat) + { + case CF_UNICODETEXT: + cnv = ConvertFromUnicode(CP_UTF8, 0, wdata, (int)(size / sizeof(WCHAR)), &cdata, 0, NULL, NULL); + if (cnv < 0) + return ERROR_INTERNAL_ERROR; + size = (size_t)cnv; + data = cdata; + break; + + default: + // TODO: Image conversions + break; + } + + fwrite(data, 1, size, clipboard->responseFile); + fclose(clipboard->responseFile); + rc = CHANNEL_RC_OK; + free(cdata); + + return rc; +} + +static UINT wlf_cliprdr_server_file_size_request(wfClipboard* clipboard, + const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +{ + wClipboardFileSizeRequest request = { 0 }; + request.streamId = fileContentsRequest->streamId; + request.listIndex = fileContentsRequest->listIndex; + + if (fileContentsRequest->cbRequested != sizeof(UINT64)) + { + WLog_Print(clipboard->log, WLOG_WARN, "unexpected FILECONTENTS_SIZE request: %"PRIu32" bytes", + fileContentsRequest->cbRequested); + } + + return clipboard->delegate->ClientRequestFileSize(clipboard->delegate, &request); +} + +static UINT wlf_cliprdr_server_file_range_request(wfClipboard* clipboard, + const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +{ + wClipboardFileRangeRequest request = { 0 }; + request.streamId = fileContentsRequest->streamId; + request.listIndex = fileContentsRequest->listIndex; + request.nPositionLow = fileContentsRequest->nPositionLow; + request.nPositionHigh = fileContentsRequest->nPositionHigh; + request.cbRequested = fileContentsRequest->cbRequested; + return clipboard->delegate->ClientRequestFileRange(clipboard->delegate, &request); +} + +static UINT wlf_cliprdr_send_file_contents_failure(CliprdrClientContext* context, + const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +{ + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; + response.msgFlags = CB_RESPONSE_FAIL; + response.streamId = fileContentsRequest->streamId; + response.dwFlags = fileContentsRequest->dwFlags; + return context->ClientFileContentsResponse(context, &response); +} + +static UINT wlf_cliprdr_server_file_contents_request(CliprdrClientContext* context, + const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +{ + UINT error = NO_ERROR; + wfClipboard* clipboard = context->custom; + + /* + * MS-RDPECLIP 2.2.5.3 File Contents Request PDU (CLIPRDR_FILECONTENTS_REQUEST): + * The FILECONTENTS_SIZE and FILECONTENTS_RANGE flags MUST NOT be set at the same time. + */ + if ((fileContentsRequest->dwFlags & (FILECONTENTS_SIZE | FILECONTENTS_RANGE)) == + (FILECONTENTS_SIZE | FILECONTENTS_RANGE)) + { + WLog_Print(clipboard->log, WLOG_ERROR, "invalid CLIPRDR_FILECONTENTS_REQUEST.dwFlags"); + return wlf_cliprdr_send_file_contents_failure(context, fileContentsRequest); + } + + if (fileContentsRequest->dwFlags & FILECONTENTS_SIZE) + error = wlf_cliprdr_server_file_size_request(clipboard, fileContentsRequest); + + if (fileContentsRequest->dwFlags & FILECONTENTS_RANGE) + error = wlf_cliprdr_server_file_range_request(clipboard, fileContentsRequest); + + if (error) + { + WLog_Print(clipboard->log, WLOG_ERROR, "failed to handle CLIPRDR_FILECONTENTS_REQUEST: 0x%08X", + error); + return wlf_cliprdr_send_file_contents_failure(context, fileContentsRequest); + } + + return CHANNEL_RC_OK; +} + +static UINT wlf_cliprdr_clipboard_file_size_success(wClipboardDelegate* delegate, + const wClipboardFileSizeRequest* request, UINT64 fileSize) +{ + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; + wfClipboard* clipboard = delegate->custom; + response.msgFlags = CB_RESPONSE_OK; + response.streamId = request->streamId; + response.dwFlags = FILECONTENTS_SIZE; + response.cbRequested = sizeof(UINT64); + response.requestedData = (BYTE*) &fileSize; + return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); +} + +static UINT wlf_cliprdr_clipboard_file_size_failure(wClipboardDelegate* delegate, + const wClipboardFileSizeRequest* request, UINT errorCode) +{ + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; + wfClipboard* clipboard = delegate->custom; + + WINPR_UNUSED(errorCode); + response.msgFlags = CB_RESPONSE_FAIL; + response.streamId = request->streamId; + response.dwFlags = FILECONTENTS_SIZE; + return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); +} + +static UINT wlf_cliprdr_clipboard_file_range_success(wClipboardDelegate* delegate, + const wClipboardFileRangeRequest* request, const BYTE* data, UINT32 size) +{ + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; + wfClipboard* clipboard = delegate->custom; + response.msgFlags = CB_RESPONSE_OK; + response.streamId = request->streamId; + response.dwFlags = FILECONTENTS_RANGE; + response.cbRequested = size; + response.requestedData = (const BYTE*) data; + return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); +} + +static UINT wlf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegate, + const wClipboardFileRangeRequest* request, UINT errorCode) +{ + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; + wfClipboard* clipboard = delegate->custom; + + WINPR_UNUSED(errorCode); + response.msgFlags = CB_RESPONSE_FAIL; + response.streamId = request->streamId; + response.dwFlags = FILECONTENTS_RANGE; + return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); +} + +wfClipboard* wlf_clipboard_new(wlfContext* wfc) +{ + rdpChannels* channels; + wfClipboard* clipboard; + + if (!(clipboard = (wfClipboard*) calloc(1, sizeof(wfClipboard)))) + return NULL; + + clipboard->wfc = wfc; + channels = wfc->context.channels; + clipboard->log = WLog_Get(TAG); + clipboard->channels = channels; + clipboard->system = ClipboardCreate(); + clipboard->delegate = ClipboardGetDelegate(clipboard->system); + clipboard->delegate->custom = clipboard; + clipboard->delegate->ClipboardFileSizeSuccess = wlf_cliprdr_clipboard_file_size_success; + clipboard->delegate->ClipboardFileSizeFailure = wlf_cliprdr_clipboard_file_size_failure; + clipboard->delegate->ClipboardFileRangeSuccess = wlf_cliprdr_clipboard_file_range_success; + clipboard->delegate->ClipboardFileRangeFailure = wlf_cliprdr_clipboard_file_range_failure; + return clipboard; +} + +void wlf_clipboard_free(wfClipboard* clipboard) +{ + if (!clipboard) + return; + + wlf_cliprdr_free_server_formats(clipboard); + wlf_cliprdr_free_client_formats(clipboard); + ClipboardDestroy(clipboard->system); + free(clipboard); +} + +BOOL wlf_cliprdr_init(wfClipboard* clipboard, CliprdrClientContext* cliprdr) +{ + if (!cliprdr || !clipboard) + return FALSE; + + clipboard->context = cliprdr; + cliprdr->custom = (void*) clipboard; + cliprdr->MonitorReady = wlf_cliprdr_monitor_ready; + cliprdr->ServerCapabilities = wlf_cliprdr_server_capabilities; + cliprdr->ServerFormatList = wlf_cliprdr_server_format_list; + cliprdr->ServerFormatListResponse = wlf_cliprdr_server_format_list_response; + cliprdr->ServerFormatDataRequest = wlf_cliprdr_server_format_data_request; + cliprdr->ServerFormatDataResponse = wlf_cliprdr_server_format_data_response; + cliprdr->ServerFileContentsRequest = wlf_cliprdr_server_file_contents_request; + return TRUE; +} + +BOOL wlf_cliprdr_uninit(wfClipboard* clipboard, CliprdrClientContext* cliprdr) +{ + if (cliprdr) + cliprdr->custom = NULL; + + if (clipboard) + clipboard->context = NULL; + + return TRUE; +} diff --git a/client/Wayland/wlf_cliprdr.h b/client/Wayland/wlf_cliprdr.h new file mode 100644 index 0000000..a113140 --- /dev/null +++ b/client/Wayland/wlf_cliprdr.h @@ -0,0 +1,36 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Wayland Clipboard Redirection + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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 FREERDP_CLIENT_WAYLAND_CLIPRDR_H +#define FREERDP_CLIENT_WAYLAND_CLIPRDR_H + +#include "wlfreerdp.h" + +#include + +wfClipboard* wlf_clipboard_new(wlfContext* wlc); +void wlf_clipboard_free(wfClipboard* clipboard); + +BOOL wlf_cliprdr_init(wfClipboard* clipboard, CliprdrClientContext* cliprdr); +BOOL wlf_cliprdr_uninit(wfClipboard* clipboard, CliprdrClientContext* cliprdr); + +BOOL wlf_cliprdr_handle_event(wfClipboard* clipboard, const UwacClipboardEvent* event); + +#endif /* FREERDP_CLIENT_WAYLAND_CLIPRDR_H */ diff --git a/client/Wayland/wlf_disp.c b/client/Wayland/wlf_disp.c new file mode 100644 index 0000000..39a5309 --- /dev/null +++ b/client/Wayland/wlf_disp.c @@ -0,0 +1,374 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Wayland Display Control Channel + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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 + +#include "wlf_disp.h" + +#define RESIZE_MIN_DELAY 200 /* minimum delay in ms between two resizes */ + +struct _wlfDispContext +{ + wlfContext* wlc; + DispClientContext* disp; + BOOL haveXRandr; + int eventBase, errorBase; + int lastSentWidth, lastSentHeight; + UINT64 lastSentDate; + int targetWidth, targetHeight; + BOOL activated; + BOOL waitingResize; + BOOL fullscreen; + UINT16 lastSentDesktopOrientation; + UINT32 lastSentDesktopScaleFactor; + UINT32 lastSentDeviceScaleFactor; +}; + +static UINT wlf_disp_sendLayout(DispClientContext* disp, rdpMonitor* monitors, size_t nmonitors); + +static BOOL wlf_disp_settings_changed(wlfDispContext* wlfDisp) +{ + rdpSettings* settings = wlfDisp->wlc->context.settings; + + if (wlfDisp->lastSentWidth != wlfDisp->targetWidth) + return TRUE; + + if (wlfDisp->lastSentHeight != wlfDisp->targetHeight) + return TRUE; + + if (wlfDisp->lastSentDesktopOrientation != settings->DesktopOrientation) + return TRUE; + + if (wlfDisp->lastSentDesktopScaleFactor != settings->DesktopScaleFactor) + return TRUE; + + if (wlfDisp->lastSentDeviceScaleFactor != settings->DeviceScaleFactor) + return TRUE; + + if (wlfDisp->fullscreen != wlfDisp->wlc->fullscreen) + return TRUE; + + return FALSE; +} + +static BOOL wlf_update_last_sent(wlfDispContext* wlfDisp) +{ + rdpSettings* settings = wlfDisp->wlc->context.settings; + wlfDisp->lastSentWidth = wlfDisp->targetWidth; + wlfDisp->lastSentHeight = wlfDisp->targetHeight; + wlfDisp->lastSentDesktopOrientation = settings->DesktopOrientation; + wlfDisp->lastSentDesktopScaleFactor = settings->DesktopScaleFactor; + wlfDisp->lastSentDeviceScaleFactor = settings->DeviceScaleFactor; + wlfDisp->fullscreen = wlfDisp->wlc->fullscreen; + return TRUE; +} + +static BOOL wlf_disp_sendResize(wlfDispContext* wlfDisp) +{ + DISPLAY_CONTROL_MONITOR_LAYOUT layout; + wlfContext* wlc; + rdpSettings* settings; + + if (!wlfDisp || !wlfDisp->wlc) + return FALSE; + + wlc = wlfDisp->wlc; + settings = wlc->context.settings; + + if (!settings) + return FALSE; + + if (!wlfDisp->activated || !wlfDisp->disp) + return TRUE; + + if (GetTickCount64() - wlfDisp->lastSentDate < RESIZE_MIN_DELAY) + return TRUE; + + wlfDisp->lastSentDate = GetTickCount64(); + + if (!wlf_disp_settings_changed(wlfDisp)) + return TRUE; + + /* TODO: Multimonitor support for wayland + if (wlc->fullscreen && (settings->MonitorCount > 0)) + { + if (wlf_disp_sendLayout(wlfDisp->disp, settings->MonitorDefArray, + settings->MonitorCount) != CHANNEL_RC_OK) + return FALSE; + } + else + */ + { + wlfDisp->waitingResize = TRUE; + layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY; + layout.Top = layout.Left = 0; + layout.Width = wlfDisp->targetWidth; + layout.Height = wlfDisp->targetHeight; + layout.Orientation = settings->DesktopOrientation; + layout.DesktopScaleFactor = settings->DesktopScaleFactor; + layout.DeviceScaleFactor = settings->DeviceScaleFactor; + layout.PhysicalWidth = wlfDisp->targetWidth; + layout.PhysicalHeight = wlfDisp->targetHeight; + + if (IFCALLRESULT(CHANNEL_RC_OK, wlfDisp->disp->SendMonitorLayout, wlfDisp->disp, 1, + &layout) != CHANNEL_RC_OK) + return FALSE; + } + return wlf_update_last_sent(wlfDisp); +} + +static BOOL wlf_disp_set_window_resizable(wlfDispContext* wlfDisp) +{ +#if 0 // TODO +#endif + return TRUE; +} + +static BOOL wlf_disp_check_context(void* context, wlfContext** ppwlc, wlfDispContext** ppwlfDisp, + rdpSettings** ppSettings) +{ + wlfContext* wlc; + + if (!context) + return FALSE; + + wlc = (wlfContext*)context; + + if (!(wlc->disp)) + return FALSE; + + if (!wlc->context.settings) + return FALSE; + + *ppwlc = wlc; + *ppwlfDisp = wlc->disp; + *ppSettings = wlc->context.settings; + return TRUE; +} + +static void wlf_disp_OnActivated(void* context, ActivatedEventArgs* e) +{ + wlfContext* wlc; + wlfDispContext* wlfDisp; + rdpSettings* settings; + + if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings)) + return; + + wlfDisp->waitingResize = FALSE; + + if (wlfDisp->activated && !settings->Fullscreen) + { + wlf_disp_set_window_resizable(wlfDisp); + + if (e->firstActivation) + return; + + wlf_disp_sendResize(wlfDisp); + } +} + +static void wlf_disp_OnGraphicsReset(void* context, GraphicsResetEventArgs* e) +{ + wlfContext* wlc; + wlfDispContext* wlfDisp; + rdpSettings* settings; + + if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings)) + return; + + wlfDisp->waitingResize = FALSE; + + if (wlfDisp->activated && !settings->Fullscreen) + { + wlf_disp_set_window_resizable(wlfDisp); + wlf_disp_sendResize(wlfDisp); + } +} + +static void wlf_disp_OnTimer(void* context, TimerEventArgs* e) +{ + wlfContext* wlc; + wlfDispContext* wlfDisp; + rdpSettings* settings; + + if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings)) + return; + + if (!wlfDisp->activated || settings->Fullscreen) + return; + + wlf_disp_sendResize(wlfDisp); +} + +wlfDispContext* wlf_disp_new(wlfContext* wlc) +{ + wlfDispContext* ret; + + if (!wlc || !wlc->context.settings || !wlc->context.pubSub) + return NULL; + + ret = calloc(1, sizeof(wlfDispContext)); + + if (!ret) + return NULL; + + ret->wlc = wlc; + ret->lastSentWidth = ret->targetWidth = wlc->context.settings->DesktopWidth; + ret->lastSentHeight = ret->targetHeight = wlc->context.settings->DesktopHeight; + PubSub_SubscribeActivated(wlc->context.pubSub, wlf_disp_OnActivated); + PubSub_SubscribeGraphicsReset(wlc->context.pubSub, wlf_disp_OnGraphicsReset); + PubSub_SubscribeTimer(wlc->context.pubSub, wlf_disp_OnTimer); + return ret; +} + +void wlf_disp_free(wlfDispContext* disp) +{ + if (!disp) + return; + + if (disp->wlc) + { + PubSub_UnsubscribeActivated(disp->wlc->context.pubSub, wlf_disp_OnActivated); + PubSub_UnsubscribeGraphicsReset(disp->wlc->context.pubSub, wlf_disp_OnGraphicsReset); + PubSub_UnsubscribeTimer(disp->wlc->context.pubSub, wlf_disp_OnTimer); + } + + free(disp); +} + +UINT wlf_disp_sendLayout(DispClientContext* disp, rdpMonitor* monitors, size_t nmonitors) +{ + UINT ret = CHANNEL_RC_OK; + DISPLAY_CONTROL_MONITOR_LAYOUT* layouts; + size_t i; + wlfDispContext* wlfDisp = (wlfDispContext*)disp->custom; + rdpSettings* settings = wlfDisp->wlc->context.settings; + layouts = calloc(nmonitors, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT)); + + if (!layouts) + return CHANNEL_RC_NO_MEMORY; + + for (i = 0; i < nmonitors; i++) + { + layouts[i].Flags = (monitors[i].is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0); + layouts[i].Left = monitors[i].x; + layouts[i].Top = monitors[i].y; + layouts[i].Width = monitors[i].width; + layouts[i].Height = monitors[i].height; + layouts[i].Orientation = ORIENTATION_LANDSCAPE; + layouts[i].PhysicalWidth = monitors[i].attributes.physicalWidth; + layouts[i].PhysicalHeight = monitors[i].attributes.physicalHeight; + + switch (monitors[i].attributes.orientation) + { + case 90: + layouts[i].Orientation = ORIENTATION_PORTRAIT; + break; + + case 180: + layouts[i].Orientation = ORIENTATION_LANDSCAPE_FLIPPED; + break; + + case 270: + layouts[i].Orientation = ORIENTATION_PORTRAIT_FLIPPED; + break; + + case 0: + default: + /* MS-RDPEDISP - 2.2.2.2.1: + * Orientation (4 bytes): A 32-bit unsigned integer that specifies the + * orientation of the monitor in degrees. Valid values are 0, 90, 180 + * or 270 + * + * So we default to ORIENTATION_LANDSCAPE + */ + layouts[i].Orientation = ORIENTATION_LANDSCAPE; + break; + } + + layouts[i].DesktopScaleFactor = settings->DesktopScaleFactor; + layouts[i].DeviceScaleFactor = settings->DeviceScaleFactor; + } + + ret = IFCALLRESULT(CHANNEL_RC_OK, disp->SendMonitorLayout, disp, nmonitors, layouts); + free(layouts); + return ret; +} + +BOOL wlf_disp_handle_configure(wlfDispContext* disp, int32_t width, int32_t height) +{ + if (!disp) + return FALSE; + + disp->targetWidth = width; + disp->targetHeight = height; + return wlf_disp_sendResize(disp); +} + +static UINT wlf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors, + UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB) +{ + /* we're called only if dynamic resolution update is activated */ + wlfDispContext* wlfDisp = (wlfDispContext*)disp->custom; + rdpSettings* settings = wlfDisp->wlc->context.settings; + WLog_DBG(TAG, + "DisplayControlCapsPdu: MaxNumMonitors: %"PRIu32" MaxMonitorAreaFactorA: %"PRIu32" MaxMonitorAreaFactorB: %"PRIu32"", + maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB); + wlfDisp->activated = TRUE; + + if (settings->Fullscreen) + return CHANNEL_RC_OK; + + WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizable"); + return wlf_disp_set_window_resizable(wlfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY; +} + +BOOL wlf_disp_init(wlfDispContext* wlfDisp, DispClientContext* disp) +{ + rdpSettings* settings; + + if (!wlfDisp || !wlfDisp->wlc || !disp) + return FALSE; + + settings = wlfDisp->wlc->context.settings; + + if (!settings) + return FALSE; + + wlfDisp->disp = disp; + disp->custom = (void*) wlfDisp; + + if (settings->DynamicResolutionUpdate) + { + disp->DisplayControlCaps = wlf_DisplayControlCaps; + } + + return TRUE; +} + +BOOL wlf_disp_uninit(wlfDispContext* wlfDisp, DispClientContext* disp) +{ + if (!wlfDisp || !disp) + return FALSE; + + wlfDisp->disp = NULL; + return TRUE; +} diff --git a/client/Wayland/wlf_disp.h b/client/Wayland/wlf_disp.h new file mode 100644 index 0000000..58f5424 --- /dev/null +++ b/client/Wayland/wlf_disp.h @@ -0,0 +1,36 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Wayland Display Control Channel + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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 FREERDP_CLIENT_WAYLAND_DISP_H +#define FREERDP_CLIENT_WAYLAND_DISP_H + +#include +#include + +#include "wlfreerdp.h" + +FREERDP_API BOOL wlf_disp_init(wlfDispContext* xfDisp, DispClientContext* disp); +FREERDP_API BOOL wlf_disp_uninit(wlfDispContext* xfDisp, DispClientContext* disp); + +wlfDispContext* wlf_disp_new(wlfContext* wlc); +void wlf_disp_free(wlfDispContext* disp); +BOOL wlf_disp_handle_configure(wlfDispContext* disp, int32_t width, int32_t height); +void wlf_disp_resized(wlfDispContext* disp); + +#endif /* FREERDP_CLIENT_WAYLAND_DISP_H */ diff --git a/client/Wayland/wlf_input.c b/client/Wayland/wlf_input.c index 2516cb4..2687955 100644 --- a/client/Wayland/wlf_input.c +++ b/client/Wayland/wlf_input.c @@ -44,7 +44,8 @@ BOOL wlf_handle_pointer_motion(freerdp* instance, UwacPointerMotionEvent* ev) BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev) { rdpInput* input; - UINT16 flags; + UINT16 flags = 0; + UINT16 xflags = 0; if (!instance || !ev || !instance->input) return FALSE; @@ -52,9 +53,10 @@ BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev) input = instance->input; if (ev->state == WL_POINTER_BUTTON_STATE_PRESSED) - flags = PTR_FLAGS_DOWN; - else - flags = 0; + { + flags |= PTR_FLAGS_DOWN; + xflags |= PTR_XFLAGS_DOWN; + } switch (ev->button) { @@ -70,36 +72,59 @@ BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev) flags |= PTR_FLAGS_BUTTON3; break; + case BTN_SIDE: + xflags |= PTR_XFLAGS_BUTTON1; + break; + + case BTN_EXTRA: + xflags |= PTR_XFLAGS_BUTTON2; + break; + default: return TRUE; } - return freerdp_input_send_mouse_event(input, flags, ev->x, ev->y); + if ((flags & ~PTR_FLAGS_DOWN) != 0) + return freerdp_input_send_mouse_event(input, flags, ev->x, ev->y); + + if ((xflags & ~PTR_XFLAGS_DOWN) != 0) + return freerdp_input_send_extended_mouse_event(input, xflags, ev->x, ev->y); + + return FALSE; } BOOL wlf_handle_pointer_axis(freerdp* instance, UwacPointerAxisEvent* ev) { rdpInput* input; - UINT16 flags; + UINT16 flags = 0; int direction; if (!instance || !ev || !instance->input) return FALSE; input = instance->input; - flags = PTR_FLAGS_WHEEL; - if (ev->axis == WL_POINTER_AXIS_VERTICAL_SCROLL) + switch (ev->axis) { - direction = wl_fixed_to_int(ev->value); + case WL_POINTER_AXIS_VERTICAL_SCROLL: + flags |= PTR_FLAGS_WHEEL; + break; - if (direction < 0) - flags |= 0x0078; - else - flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + flags |= PTR_FLAGS_HWHEEL; + break; + + default: + return FALSE; } + direction = wl_fixed_to_int(ev->value); + flags |= 0x0078; /* TODO: Calculate the distance with the provided value size */ + + if (direction < 0) + flags |= PTR_FLAGS_WHEEL_NEGATIVE; + return freerdp_input_send_mouse_event(input, flags, ev->x, ev->y); } @@ -129,5 +154,5 @@ BOOL wlf_keyboard_enter(freerdp* instance, UwacKeyboardEnterLeaveEvent* ev) input = instance->input; return freerdp_input_send_focus_in_event(input, 0) && - freerdp_input_send_mouse_event(input, PTR_FLAGS_MOVE, 0, 0); + freerdp_input_send_mouse_event(input, PTR_FLAGS_MOVE, 0, 0); } diff --git a/client/Wayland/wlf_pointer.c b/client/Wayland/wlf_pointer.c new file mode 100644 index 0000000..38190ed --- /dev/null +++ b/client/Wayland/wlf_pointer.c @@ -0,0 +1,133 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Wayland Mouse Pointer + * + * Copyright 2019 Armin Novak + * Copyright 2019 Thincast Technologies GmbH + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "wlf_pointer.h" +#include "wlfreerdp.h" + +struct wlf_pointer +{ + rdpPointer pointer; + size_t size; + void* data; +}; +typedef struct wlf_pointer wlfPointer; + +static BOOL wlf_Pointer_New(rdpContext* context, rdpPointer* pointer) +{ + wlfPointer* ptr = (wlfPointer*)pointer; + if (!ptr) + return FALSE; + + ptr->size = pointer->width * pointer->height * 4; + ptr->data = _aligned_malloc(ptr->size, 16); + if (!ptr->data) + return FALSE; + + if (!freerdp_image_copy_from_pointer_data( + ptr->data, PIXEL_FORMAT_RGBA32, + 0, 0, 0, pointer->width, pointer->height, + pointer->xorMaskData, pointer->lengthXorMask, + pointer->andMaskData, pointer->lengthAndMask, + pointer->xorBpp, &context->gdi->palette)) + { + _aligned_free(ptr->data); + return FALSE; + } + + return TRUE; +} + +static void wlf_Pointer_Free(rdpContext* context, rdpPointer* pointer) +{ + wlfPointer* ptr = (wlfPointer*)pointer; + WINPR_UNUSED(context); + if (ptr) + _aligned_free(ptr->data); +} + +static BOOL wlf_Pointer_Set(rdpContext* context, + const rdpPointer* pointer) +{ + wlfContext* wlf = (wlfContext*)context; + wlfPointer* ptr = (wlfPointer*)pointer; + + if (!wlf || !wlf->seat) + return FALSE; + + // TODO: Scale according to SmartSizing + if (UwacSeatSetMouseCursor(wlf->seat, ptr->data, ptr->size, pointer->width, pointer->height, pointer->xPos, pointer->yPos) != UWAC_SUCCESS) + return FALSE; + + return TRUE; +} + +static BOOL wlf_Pointer_SetNull(rdpContext* context) +{ + wlfContext* wlf = (wlfContext*)context; + if (!wlf || !wlf->seat) + return FALSE; + + if (UwacSeatSetMouseCursor(wlf->seat, NULL, 0, 0, 0, 0, 0) != UWAC_SUCCESS) + return FALSE; + + return TRUE; +} + +static BOOL wlf_Pointer_SetDefault(rdpContext* context) +{ + wlfContext* wlf = (wlfContext*)context; + if (!wlf || !wlf->seat) + return FALSE; + + if (UwacSeatSetMouseCursor(wlf->seat, NULL, 1, 0, 0, 0, 0) != UWAC_SUCCESS) + return FALSE; + + return TRUE; +} + +static BOOL wlf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) +{ + // TODO + WLog_WARN(TAG, "%s not implemented", __FUNCTION__); + return TRUE; +} + +BOOL wlf_register_pointer(rdpGraphics* graphics) +{ + rdpPointer* pointer = NULL; + + if (!(pointer = (rdpPointer*) calloc(1, sizeof(rdpPointer)))) + return FALSE; + + pointer->size = sizeof(wlfPointer); + pointer->New = wlf_Pointer_New; + pointer->Free = wlf_Pointer_Free; + pointer->Set = wlf_Pointer_Set; + pointer->SetNull = wlf_Pointer_SetNull; + pointer->SetDefault = wlf_Pointer_SetDefault; + pointer->SetPosition = wlf_Pointer_SetPosition; + graphics_register_pointer(graphics, pointer); + free(pointer); + return TRUE; +} diff --git a/client/DirectFB/df_event.h b/client/Wayland/wlf_pointer.h similarity index 65% rename from client/DirectFB/df_event.h rename to client/Wayland/wlf_pointer.h index fc00674..8ae82e1 100644 --- a/client/DirectFB/df_event.h +++ b/client/Wayland/wlf_pointer.h @@ -1,8 +1,9 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * DirectFB Event Handling + * Wayland Mouse Pointer * - * Copyright 2011 Marc-Andre Moreau + * Copyright 2019 Armin Novak + * Copyright 2019 Thincast Technologies GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +18,11 @@ * limitations under the License. */ -#ifndef FREERDP_CLIENT_DF_EVENT_H -#define FREERDP_CLIENT_DF_EVENT_H +#ifndef FREERDP_CLIENT_WAYLAND_POINTER_H +#define FREERDP_CLIENT_WAYLAND_POINTER_H -#include "dfreerdp.h" +#include -void df_keyboard_init(void); -BOOL df_event_process(freerdp* instance, DFBEvent* event); +BOOL wlf_register_pointer(rdpGraphics* graphics); -#endif /* FREERDP_CLIENT_DF_EVENT_H */ +#endif /* FREERDP_CLIENT_WAYLAND_POINTER_H */ diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index eed827f..ed73d91 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -36,22 +36,10 @@ #include "wlfreerdp.h" #include "wlf_input.h" +#include "wlf_cliprdr.h" +#include "wlf_disp.h" #include "wlf_channels.h" - -static BOOL wl_update_content(wlfContext* context_w) -{ - if (!context_w) - return FALSE; - - if (!context_w->waitingFrameDone && context_w->haveDamage) - { - UwacWindowSubmitBuffer(context_w->window, true); - context_w->waitingFrameDone = TRUE; - context_w->haveDamage = FALSE; - } - - return TRUE; -} +#include "wlf_pointer.h" static BOOL wl_begin_paint(rdpContext* context) { @@ -69,15 +57,68 @@ static BOOL wl_begin_paint(rdpContext* context) return TRUE; } +static BOOL wl_update_buffer(wlfContext* context_w, INT32 ix, INT32 iy, INT32 iw, INT32 ih) +{ + rdpGdi* gdi; + char* data; + size_t baseSrcOffset; + size_t baseDstOffset; + UINT32 i, x, y, w, h; + UwacSize geometry; + size_t stride; + UwacReturnCode rc; + + if (!context_w) + return FALSE; + + if ((ix < 0) || (iy < 0) || (iw < 0) || (ih < 0)) + return FALSE; + + x = (UINT32)ix; + y = (UINT32)iy; + w = (UINT32)iw; + h = (UINT32)ih; + rc = UwacWindowGetDrawingBufferGeometry(context_w->window, &geometry, &stride); + data = UwacWindowGetDrawingBuffer(context_w->window); + + if (!data || (rc != UWAC_SUCCESS)) + return FALSE; + + gdi = context_w->context.gdi; + + if (!gdi) + return FALSE; + + /* Ignore output if the surface size does not match. */ + if ((x > geometry.width) || (y > geometry.height)) + return TRUE; + + baseSrcOffset = y * gdi->stride + x * GetBytesPerPixel(gdi->dstFormat); + baseDstOffset = y * stride + x * 4; + for (i = 0; i < MIN(h, geometry.height - y); i++) + { + const size_t srcOffset = i * gdi->stride + baseSrcOffset; + const size_t dstOffset = i * stride + baseDstOffset; + + memcpy(data + dstOffset, gdi->primary_buffer + srcOffset, + MIN(w, geometry.width - x) * GetBytesPerPixel(gdi->dstFormat)); + } + + if (UwacWindowAddDamage(context_w->window, x, y, w, h) != UWAC_SUCCESS) + return FALSE; + + if (UwacWindowSubmitBuffer(context_w->window, true) != UWAC_SUCCESS) + return FALSE; + + return TRUE; +} static BOOL wl_end_paint(rdpContext* context) { rdpGdi* gdi; - char* data; wlfContext* context_w; INT32 x, y; - UINT32 w, h; - UINT32 i; + INT32 w, h; if (!context || !context->gdi || !context->gdi->primary) return FALSE; @@ -92,27 +133,31 @@ static BOOL wl_end_paint(rdpContext* context) w = gdi->primary->hdc->hwnd->invalid->w; h = gdi->primary->hdc->hwnd->invalid->h; context_w = (wlfContext*) context; - data = UwacWindowGetDrawingBuffer(context_w->window); - - if (!data) - return FALSE; - - for (i = 0; i < h; i++) - { - memcpy(data + ((i + y) * (gdi->width * GetBytesPerPixel( - gdi->dstFormat))) + x * GetBytesPerPixel(gdi->dstFormat), - gdi->primary_buffer + ((i + y) * (gdi->width * GetBytesPerPixel( - gdi->dstFormat))) + x * GetBytesPerPixel(gdi->dstFormat), - w * GetBytesPerPixel(gdi->dstFormat)); - } - - if (UwacWindowAddDamage(context_w->window, x, y, w, h) != UWAC_SUCCESS) - return FALSE; - - context_w->haveDamage = TRUE; - return wl_update_content(context_w); + return wl_update_buffer(context_w, x, y, w, h); } +static BOOL wl_refresh_display(wlfContext* context) +{ + rdpGdi* gdi; + + if (!context || !context->context.gdi) + return FALSE; + + gdi = context->context.gdi; + return wl_update_buffer(context, 0, 0, gdi->width, gdi->height); +} + +static BOOL wl_resize_display(rdpContext* context) +{ + wlfContext* wlc = (wlfContext*)context; + rdpGdi* gdi = context->gdi; + rdpSettings* settings = context->settings; + + if (!gdi_resize(gdi, settings->DesktopWidth, settings->DesktopHeight)) + return FALSE; + + return wl_refresh_display(wlc); +} static BOOL wl_pre_connect(freerdp* instance) { @@ -132,31 +177,6 @@ static BOOL wl_pre_connect(freerdp* instance) settings->OsMajorType = OSMAJORTYPE_UNIX; settings->OsMinorType = OSMINORTYPE_NATIVE_WAYLAND; - ZeroMemory(settings->OrderSupport, 32); - settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE; - settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE; - settings->OrderSupport[NEG_LINETO_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE; - settings->OrderSupport[NEG_MEMBLT_INDEX] = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_MEM3BLT_INDEX] = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE; - settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE; - settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE; - settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE; - settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE; - settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; - settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; PubSub_SubscribeChannelConnected(instance->context->pubSub, wlf_OnChannelConnectedEventHandler); PubSub_SubscribeChannelDisconnected(instance->context->pubSub, @@ -190,6 +210,7 @@ static BOOL wl_post_connect(freerdp* instance) rdpGdi* gdi; UwacWindow* window; wlfContext* context; + UINT32 w, h; if (!instance || !instance->context) return FALSE; @@ -199,27 +220,37 @@ static BOOL wl_post_connect(freerdp* instance) gdi = instance->context->gdi; - if (!gdi) + if (!gdi || (gdi->width < 0) || (gdi->height < 0)) return FALSE; + if (!wlf_register_pointer(instance->context->graphics)) + return FALSE; + + w = (UINT32)gdi->width; + h = (UINT32)gdi->height; context = (wlfContext*) instance->context; - context->window = window = UwacCreateWindowShm(context->display, gdi->width, - gdi->height, WL_SHM_FORMAT_XRGB8888); + context->window = window = UwacCreateWindowShm(context->display, w, h, WL_SHM_FORMAT_XRGB8888); if (!window) return FALSE; UwacWindowSetFullscreenState(window, NULL, instance->context->settings->Fullscreen); UwacWindowSetTitle(window, "FreeRDP"); - UwacWindowSetOpaqueRegion(context->window, 0, 0, gdi->width, gdi->height); + UwacWindowSetOpaqueRegion(context->window, 0, 0, w, h); instance->update->BeginPaint = wl_begin_paint; instance->update->EndPaint = wl_end_paint; - memcpy(UwacWindowGetDrawingBuffer(context->window), gdi->primary_buffer, - gdi->width * gdi->height * 4); - UwacWindowAddDamage(context->window, 0, 0, gdi->width, gdi->height); - context->haveDamage = TRUE; + instance->update->DesktopResize = wl_resize_display; freerdp_keyboard_init(instance->context->settings->KeyboardLayout); - return wl_update_content(context); + + if (!(context->disp = wlf_disp_new(context))) + return FALSE; + + context->clipboard = wlf_clipboard_new(context); + + if (!context->clipboard) + return FALSE; + + return wl_refresh_display(context); } static void wl_post_disconnect(freerdp* instance) @@ -234,6 +265,8 @@ static void wl_post_disconnect(freerdp* instance) context = (wlfContext*) instance->context; gdi_free(instance); + wlf_clipboard_free(context->clipboard); + wlf_disp_free(context->disp); if (context->window) UwacDestroyWindow(&context->window); @@ -247,6 +280,8 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) if (UwacDisplayDispatch(display, 1) < 0) return FALSE; + context = (wlfContext*)instance->context; + while (UwacHasEvent(display)) { if (UwacNextEvent(display, &event) != UWAC_SUCCESS) @@ -255,16 +290,15 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) /*printf("UWAC event type %d\n", event.type);*/ switch (event.type) { + case UWAC_EVENT_NEW_SEAT: + context->seat = event.seat_new.seat; + break; + + case UWAC_EVENT_REMOVED_SEAT: + context->seat = NULL; + break; + case UWAC_EVENT_FRAME_DONE: - if (!instance) - continue; - - context = (wlfContext*)instance->context; - context->waitingFrameDone = FALSE; - - if (context->haveDamage && !wl_update_content(context)) - return FALSE; - break; case UWAC_EVENT_POINTER_ENTER: @@ -298,11 +332,30 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) break; case UWAC_EVENT_KEYBOARD_ENTER: + if (instance->context->settings->GrabKeyboard) + UwacSeatInhibitShortcuts(event.keyboard_enter_leave.seat, true); if (!wlf_keyboard_enter(instance, &event.keyboard_enter_leave)) return FALSE; break; + case UWAC_EVENT_CONFIGURE: + if (!wlf_disp_handle_configure(context->disp, event.configure.width, event.configure.height)) + return FALSE; + + if (!wl_refresh_display(context)) + return FALSE; + + break; + + case UWAC_EVENT_CLIPBOARD_AVAILABLE: + case UWAC_EVENT_CLIPBOARD_OFFER: + case UWAC_EVENT_CLIPBOARD_SELECT: + if (!wlf_cliprdr_handle_event(context->clipboard, &event.clipboard)) + return FALSE; + + break; + default: break; } @@ -328,7 +381,7 @@ static int wlfreerdp_run(freerdp* instance) if (!freerdp_connect(instance)) { - printf("Failed to connect\n"); + WLog_Print(context->log, WLOG_ERROR, "Failed to connect"); return -1; } @@ -339,7 +392,7 @@ static int wlfreerdp_run(freerdp* instance) if (count <= 1) { - printf("Failed to get FreeRDP file descriptor\n"); + WLog_Print(context->log, WLOG_ERROR, "Failed to get FreeRDP file descriptor"); break; } @@ -347,20 +400,20 @@ static int wlfreerdp_run(freerdp* instance) if (WAIT_FAILED == status) { - printf("%s: WaitForMultipleObjects failed\n", __FUNCTION__); + WLog_Print(context->log, WLOG_ERROR, "%s: WaitForMultipleObjects failed", __FUNCTION__); break; } if (!handle_uwac_events(instance, context->display)) { - printf("error handling UWAC events\n"); + WLog_Print(context->log, WLOG_ERROR, "error handling UWAC events"); break; } if (freerdp_check_event_handles(instance->context) != TRUE) { if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS) - printf("Failed to check FreeRDP file descriptor\n"); + WLog_Print(context->log, WLOG_ERROR, "Failed to check FreeRDP file descriptor"); break; } @@ -394,7 +447,7 @@ static int wlf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) return -1; wlf = (wlfContext*) instance->context; - WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type); + WLog_Print(wlf->log, WLOG_INFO, "Logon Error Info %s [%s]", str_data, str_type); return 1; } @@ -411,12 +464,13 @@ static BOOL wlf_client_new(freerdp* instance, rdpContext* context) instance->PostDisconnect = wl_post_disconnect; instance->Authenticate = client_cli_authenticate; instance->GatewayAuthenticate = client_cli_gw_authenticate; - instance->VerifyCertificate = client_cli_verify_certificate; - instance->VerifyChangedCertificate = client_cli_verify_changed_certificate; + instance->VerifyCertificateEx = client_cli_verify_certificate_ex; + instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex; instance->LogonErrorInfo = wlf_logon_error_info; + wfl->log = WLog_Get(TAG); wfl->display = UwacOpenDisplay(NULL, &status); - if (!wfl->display || (status != UWAC_SUCCESS)) + if (!wfl->display || (status != UWAC_SUCCESS) || !wfl->log) return FALSE; wfl->displayHandle = CreateFileDescriptorEvent(NULL, FALSE, FALSE, @@ -445,11 +499,13 @@ static void wlf_client_free(freerdp* instance, rdpContext* context) static int wfl_client_start(rdpContext* context) { + WINPR_UNUSED(context); return 0; } static int wfl_client_stop(rdpContext* context) { + WINPR_UNUSED(context); return 0; } @@ -471,7 +527,7 @@ static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) int main(int argc, char* argv[]) { int rc = -1; - DWORD status; + int status; RDP_CLIENT_ENTRY_POINTS clientEntryPoints; rdpContext* context; RdpClientEntry(&clientEntryPoints); diff --git a/client/Wayland/wlfreerdp.h b/client/Wayland/wlfreerdp.h index 7605e46..24b117d 100644 --- a/client/Wayland/wlfreerdp.h +++ b/client/Wayland/wlfreerdp.h @@ -31,7 +31,8 @@ #define TAG CLIENT_TAG("wayland") typedef struct wlf_context wlfContext; - +typedef struct wlf_clipboard wfClipboard; +typedef struct _wlfDispContext wlfDispContext; struct wlf_context { @@ -40,14 +41,17 @@ struct wlf_context UwacDisplay* display; HANDLE displayHandle; UwacWindow* window; + UwacSeat* seat; - BOOL waitingFrameDone; - BOOL haveDamage; + BOOL fullscreen; /* Channels */ RdpeiClientContext* rdpei; RdpgfxClientContext* gfx; EncomspClientContext* encomsp; + wfClipboard* clipboard; + wlfDispContext* disp; + wLog* log; }; #endif /* FREERDP_CLIENT_WAYLAND_FREERDP_H */ diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 4a3e0d2..47c854d 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -501,6 +501,37 @@ static BOOL xf_process_x_events(freerdp* instance) return status; } +static char* xf_window_get_title(rdpSettings* settings) +{ + BOOL port; + char* windowTitle; + size_t size; + char* name; + const char* prefix = "FreeRDP:"; + + if (!settings) + return NULL; + + name = settings->ServerHostname; + + if (settings->WindowTitle) + return _strdup(settings->WindowTitle); + + port = (settings->ServerPort != 3389); + size = strlen(name) + 16; + windowTitle = calloc(size, sizeof(char)); + + if (!windowTitle) + return NULL; + + if (!port) + sprintf_s(windowTitle, size, "%s %s", prefix, name); + else + sprintf_s(windowTitle, size, "%s %s:%i", prefix, name, settings->ServerPort); + + return windowTitle; +} + BOOL xf_create_window(xfContext* xfc) { XGCValues gcv; @@ -532,37 +563,10 @@ BOOL xf_create_window(xfContext* xfc) xfc->offset_x = 0; xfc->offset_y = 0; #endif + windowTitle = xf_window_get_title(settings); - if (settings->WindowTitle) - { - windowTitle = _strdup(settings->WindowTitle); - - if (!windowTitle) - return FALSE; - } - else if (settings->ServerPort == 3389) - { - size_t size = 1 + sizeof("FreeRDP: ") + strlen( - settings->ServerHostname); - windowTitle = malloc(size); - - if (!windowTitle) - return FALSE; - - sprintf_s(windowTitle, size, "FreeRDP: %s", settings->ServerHostname); - } - else - { - size_t size = 1 + sizeof("FreeRDP: ") + strlen(settings->ServerHostname) - + sizeof(":00000"); - windowTitle = malloc(size); - - if (!windowTitle) - return FALSE; - - sprintf_s(windowTitle, size, "FreeRDP: %s:%i", settings->ServerHostname, - settings->ServerPort); - } + if (!windowTitle) + return FALSE; #ifdef WITH_XRENDER @@ -1032,26 +1036,55 @@ static void xf_get_x11_button_map(xfContext* xfc, unsigned char* x11_map) /* Assignment of physical (not logical) mouse buttons to wire flags. */ /* Notice that the middle button is 2 in X11, but 3 in RDP. */ -static const int xf_button_flags[NUM_BUTTONS_MAPPED] = +static const button_map xf_button_flags[NUM_BUTTONS_MAPPED] = { - PTR_FLAGS_BUTTON1, - PTR_FLAGS_BUTTON3, - PTR_FLAGS_BUTTON2 + {Button1, PTR_FLAGS_BUTTON1}, + {Button2, PTR_FLAGS_BUTTON3}, + {Button3, PTR_FLAGS_BUTTON2}, + {Button4, PTR_FLAGS_WHEEL | 0x78}, + {Button5, PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x78}, + {6, PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x78}, + {7, PTR_FLAGS_HWHEEL | 0x78}, + {8, PTR_XFLAGS_BUTTON1}, + {9, PTR_XFLAGS_BUTTON2}, + {97, PTR_XFLAGS_BUTTON1}, + {112, PTR_XFLAGS_BUTTON2} }; +static UINT16 get_flags_for_button(int button) +{ + size_t x; + + for (x = 0; x < ARRAYSIZE(xf_button_flags); x++) + { + const button_map* map = &xf_button_flags[x]; + + if (map->button == button) + return map->flags; + } + + return 0; +} + static void xf_button_map_init(xfContext* xfc) { + size_t pos = 0; /* loop counter for array initialization */ - int physical; - int logical; + size_t physical; /* logical mouse button which is used for each physical mouse */ /* button (indexed from zero). This is the default map. */ - unsigned char x11_map[NUM_BUTTONS_MAPPED] = - { - Button1, - Button2, - Button3 - }; + unsigned char x11_map[112] = { 0 }; + x11_map[0] = Button1; + x11_map[1] = Button2; + x11_map[2] = Button3; + x11_map[3] = Button4; + x11_map[4] = Button5; + x11_map[5] = 6; + x11_map[6] = 7; + x11_map[7] = 8; + x11_map[8] = 9; + x11_map[96] = 97; + x11_map[111] = 112; /* query system for actual remapping */ if (!xfc->context.settings->UnmapButtons) @@ -1062,18 +1095,23 @@ static void xf_button_map_init(xfContext* xfc) /* iterate over all (mapped) physical buttons; for each of them */ /* find the logical button in X11, and assign to this the */ /* appropriate value to send over the RDP wire. */ - for (physical = 0; physical < NUM_BUTTONS_MAPPED; ++physical) + for (physical = 0; physical < ARRAYSIZE(x11_map); ++physical) { - logical = x11_map[physical]; + const unsigned char logical = x11_map[physical]; + const UINT16 flags = get_flags_for_button(logical); - if (Button1 <= logical && logical <= Button3) + if ((logical != 0) && (flags != 0)) { - xfc->button_map[logical - BUTTON_BASE] = xf_button_flags[physical]; - } - else - { - WLog_ERR(TAG, "Mouse physical button %d is mapped to logical button %d", - physical, logical); + if (pos >= NUM_BUTTONS_MAPPED) + { + WLog_ERR(TAG, "Failed to map mouse button to RDP button, no space"); + } + else + { + button_map* map = &xfc->button_map[pos++]; + map->button = physical + Button1; + map->flags = get_flags_for_button(logical); + } } } } @@ -1100,31 +1138,6 @@ static BOOL xf_pre_connect(freerdp* instance) channels = context->channels; settings->OsMajorType = OSMAJORTYPE_UNIX; settings->OsMinorType = OSMINORTYPE_NATIVE_XSERVER; - ZeroMemory(settings->OrderSupport, 32); - settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE; - settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE; - settings->OrderSupport[NEG_LINETO_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE; - settings->OrderSupport[NEG_MEMBLT_INDEX] = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_MEM3BLT_INDEX] = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE; - settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE; - settings->OrderSupport[NEG_FAST_INDEX_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE; - settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE; - settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE; - settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE; - settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; - settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; PubSub_SubscribeChannelConnected(instance->context->pubSub, xf_OnChannelConnectedEventHandler); PubSub_SubscribeChannelDisconnected(instance->context->pubSub, @@ -1189,7 +1202,6 @@ static BOOL xf_pre_connect(freerdp* instance) xfc->decorations = settings->Decorations; xfc->grab_keyboard = settings->GrabKeyboard; xfc->fullscreen_toggle = settings->ToggleFullscreen; - xfc->floatbar = settings->Floatbar; xf_button_map_init(xfc); return TRUE; } @@ -1571,8 +1583,8 @@ static DWORD WINAPI xf_client_thread(LPVOID param) nCount += tmp; } - if (xfc->floatbar && xfc->fullscreen && !xfc->remote_app) - xf_floatbar_hide_and_show(xfc); + if (xfc->window) + xf_floatbar_hide_and_show(xfc->window->floatbar); waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); @@ -1788,8 +1800,8 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) instance->PostDisconnect = xf_post_disconnect; instance->Authenticate = client_cli_authenticate; instance->GatewayAuthenticate = client_cli_gw_authenticate; - instance->VerifyCertificate = client_cli_verify_certificate; - instance->VerifyChangedCertificate = client_cli_verify_changed_certificate; + instance->VerifyCertificateEx = client_cli_verify_certificate_ex; + instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex; instance->LogonErrorInfo = xf_logon_error_info; PubSub_SubscribeTerminate(context->pubSub, xf_TerminateEventHandler); @@ -1884,7 +1896,7 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) xfc->_NET_WM_WINDOW_TYPE_POPUP = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_POPUP", False); xfc->_NET_WM_WINDOW_TYPE_POPUP_MENU = XInternAtom(xfc->display, - "_NET_WM_WINDOW_TYPE_POPUP_MENU", False); + "_NET_WM_WINDOW_TYPE_POPUP_MENU", False); xfc->_NET_WM_WINDOW_TYPE_UTILITY = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_UTILITY", False); xfc->_NET_WM_WINDOW_TYPE_DROPDOWN_MENU = XInternAtom(xfc->display, diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index 1c86031..004d131 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -266,8 +266,7 @@ static CLIPRDR_FORMAT* xf_cliprdr_get_server_format_by_atom( static UINT xf_cliprdr_send_data_request(xfClipboard* clipboard, UINT32 formatId) { - CLIPRDR_FORMAT_DATA_REQUEST request; - ZeroMemory(&request, sizeof(CLIPRDR_FORMAT_DATA_REQUEST)); + CLIPRDR_FORMAT_DATA_REQUEST request = { 0 }; request.requestedFormatId = formatId; return clipboard->context->ClientFormatDataRequest(clipboard->context, &request); @@ -281,8 +280,7 @@ static UINT xf_cliprdr_send_data_request(xfClipboard* clipboard, static UINT xf_cliprdr_send_data_response(xfClipboard* clipboard, BYTE* data, int size) { - CLIPRDR_FORMAT_DATA_RESPONSE response; - ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE)); + CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 }; response.msgFlags = (data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL; response.dataLen = size; response.requestedFormatData = data; @@ -545,9 +543,8 @@ static void xf_cliprdr_get_requested_targets(xfClipboard* clipboard) { UINT32 numFormats = 0; CLIPRDR_FORMAT* formats = NULL; - CLIPRDR_FORMAT_LIST formatList; + CLIPRDR_FORMAT_LIST formatList = { 0 }; formats = xf_cliprdr_get_client_formats(clipboard, &numFormats); - ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); formatList.msgFlags = CB_RESPONSE_OK; formatList.numFormats = numFormats; formatList.formats = formats; @@ -1096,10 +1093,9 @@ static UINT xf_cliprdr_send_client_format_list(xfClipboard* clipboard) { UINT32 i, numFormats; CLIPRDR_FORMAT* formats = NULL; - CLIPRDR_FORMAT_LIST formatList; + CLIPRDR_FORMAT_LIST formatList = { 0 }; xfContext* xfc = clipboard->xfc; UINT ret; - ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); numFormats = clipboard->numClientFormats; if (numFormats) @@ -1155,7 +1151,7 @@ static UINT xf_cliprdr_send_client_format_list_response(xfClipboard* clipboard, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_cliprdr_monitor_ready(CliprdrClientContext* context, - CLIPRDR_MONITOR_READY* monitorReady) + const CLIPRDR_MONITOR_READY* monitorReady) { xfClipboard* clipboard = (xfClipboard*) context->custom; UINT ret; @@ -1176,7 +1172,7 @@ static UINT xf_cliprdr_monitor_ready(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_cliprdr_server_capabilities(CliprdrClientContext* context, - CLIPRDR_CAPABILITIES* capabilities) + const CLIPRDR_CAPABILITIES* capabilities) { UINT32 i; const CLIPRDR_CAPABILITY_SET* caps; @@ -1211,7 +1207,7 @@ static UINT xf_cliprdr_server_capabilities(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context, - CLIPRDR_FORMAT_LIST* formatList) + const CLIPRDR_FORMAT_LIST* formatList) { UINT32 i; int j; @@ -1301,7 +1297,7 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_cliprdr_server_format_list_response(CliprdrClientContext* - context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) + context, const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) { //xfClipboard* clipboard = (xfClipboard*) context->custom; return CHANNEL_RC_OK; @@ -1313,7 +1309,7 @@ static UINT xf_cliprdr_server_format_list_response(CliprdrClientContext* * @return 0 on success, otherwise a Win32 error code */ static UINT xf_cliprdr_server_format_data_request(CliprdrClientContext* context, - CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) + const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { BOOL rawTransfer; xfCliprdrFormat* format = NULL; @@ -1348,7 +1344,7 @@ static UINT xf_cliprdr_server_format_data_request(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* - context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) + context, const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) { BOOL bSuccess; BYTE* pDstData; @@ -1477,8 +1473,7 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* static UINT xf_cliprdr_server_file_size_request(xfClipboard* clipboard, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { - wClipboardFileSizeRequest request; - ZeroMemory(&request, sizeof(request)); + wClipboardFileSizeRequest request = { 0 }; request.streamId = fileContentsRequest->streamId; request.listIndex = fileContentsRequest->listIndex; @@ -1494,8 +1489,7 @@ static UINT xf_cliprdr_server_file_size_request(xfClipboard* clipboard, static UINT xf_cliprdr_server_file_range_request(xfClipboard* clipboard, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { - wClipboardFileRangeRequest request; - ZeroMemory(&request, sizeof(request)); + wClipboardFileRangeRequest request = { 0 }; request.streamId = fileContentsRequest->streamId; request.listIndex = fileContentsRequest->listIndex; request.nPositionLow = fileContentsRequest->nPositionLow; @@ -1507,8 +1501,7 @@ static UINT xf_cliprdr_server_file_range_request(xfClipboard* clipboard, static UINT xf_cliprdr_send_file_contents_failure(CliprdrClientContext* context, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { - CLIPRDR_FILE_CONTENTS_RESPONSE response; - ZeroMemory(&response, sizeof(response)); + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; response.msgFlags = CB_RESPONSE_FAIL; response.streamId = fileContentsRequest->streamId; response.dwFlags = fileContentsRequest->dwFlags; @@ -1516,7 +1509,7 @@ static UINT xf_cliprdr_send_file_contents_failure(CliprdrClientContext* context, } static UINT xf_cliprdr_server_file_contents_request(CliprdrClientContext* context, - CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) + const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { UINT error = NO_ERROR; xfClipboard* clipboard = context->custom; @@ -1550,9 +1543,8 @@ static UINT xf_cliprdr_server_file_contents_request(CliprdrClientContext* contex static UINT xf_cliprdr_clipboard_file_size_success(wClipboardDelegate* delegate, const wClipboardFileSizeRequest* request, UINT64 fileSize) { - CLIPRDR_FILE_CONTENTS_RESPONSE response; + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; xfClipboard* clipboard = delegate->custom; - ZeroMemory(&response, sizeof(response)); response.msgFlags = CB_RESPONSE_OK; response.streamId = request->streamId; response.dwFlags = FILECONTENTS_SIZE; @@ -1564,9 +1556,8 @@ static UINT xf_cliprdr_clipboard_file_size_success(wClipboardDelegate* delegate, static UINT xf_cliprdr_clipboard_file_size_failure(wClipboardDelegate* delegate, const wClipboardFileSizeRequest* request, UINT errorCode) { - CLIPRDR_FILE_CONTENTS_RESPONSE response; + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; xfClipboard* clipboard = delegate->custom; - ZeroMemory(&response, sizeof(response)); response.msgFlags = CB_RESPONSE_FAIL; response.streamId = request->streamId; response.dwFlags = FILECONTENTS_SIZE; @@ -1576,9 +1567,8 @@ static UINT xf_cliprdr_clipboard_file_size_failure(wClipboardDelegate* delegate, static UINT xf_cliprdr_clipboard_file_range_success(wClipboardDelegate* delegate, const wClipboardFileRangeRequest* request, const BYTE* data, UINT32 size) { - CLIPRDR_FILE_CONTENTS_RESPONSE response; + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; xfClipboard* clipboard = delegate->custom; - ZeroMemory(&response, sizeof(response)); response.msgFlags = CB_RESPONSE_OK; response.streamId = request->streamId; response.dwFlags = FILECONTENTS_RANGE; @@ -1590,9 +1580,8 @@ static UINT xf_cliprdr_clipboard_file_range_success(wClipboardDelegate* delegate static UINT xf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegate, const wClipboardFileRangeRequest* request, UINT errorCode) { - CLIPRDR_FILE_CONTENTS_RESPONSE response; + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; xfClipboard* clipboard = delegate->custom; - ZeroMemory(&response, sizeof(response)); response.msgFlags = CB_RESPONSE_FAIL; response.streamId = request->streamId; response.dwFlags = FILECONTENTS_RANGE; diff --git a/client/X11/xf_disp.c b/client/X11/xf_disp.c index 1b30976..ecb9997 100644 --- a/client/X11/xf_disp.c +++ b/client/X11/xf_disp.c @@ -409,7 +409,7 @@ static UINT xf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors if (settings->Fullscreen) return CHANNEL_RC_OK; - WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizeable"); + WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizable"); return xf_disp_set_window_resizable(xfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY; } diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index 70c3aee..5b6dfdf 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -213,7 +213,7 @@ static BOOL xf_event_execute_action_script(xfContext* xfc, XEvent* event) char buffer[1024] = { 0 }; char command[1024] = { 0 }; - if (!xfc->actionScriptExists || !xfc->xevents) + if (!xfc->actionScriptExists || !xfc->xevents || !xfc->window) return FALSE; if (event->type > LASTEvent) @@ -367,79 +367,58 @@ static BOOL xf_event_MotionNotify(xfContext* xfc, XEvent* event, BOOL app) if (xfc->use_xinput) return TRUE; - if(xfc->floatbar && !(app)) - xf_floatbar_set_root_y(xfc, event->xmotion.y); + if (xfc->window) + xf_floatbar_set_root_y(xfc->window->floatbar, event->xmotion.y); return xf_generic_MotionNotify(xfc, event->xmotion.x, event->xmotion.y, event->xmotion.state, event->xmotion.window, app); } -BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, - Window window, BOOL app) + +BOOL xf_generic_ButtonEvent(xfContext* xfc, int x, int y, int button, + Window window, BOOL app, BOOL down) { - int flags; - BOOL wheel; - BOOL extended; + UINT16 flags = 0; rdpInput* input; Window childWindow; - wheel = FALSE; - extended = FALSE; - input = xfc->context.input; + size_t i; - switch (button) + for (i = 0; i < ARRAYSIZE(xfc->button_map); i++) { - case Button1: - case Button2: - case Button3: - flags = PTR_FLAGS_DOWN | xfc->button_map[button - BUTTON_BASE]; - break; + const button_map* cur = &xfc->button_map[i]; - case 4: - wheel = TRUE; - flags = PTR_FLAGS_WHEEL | 0x0078; - break; - - case 5: - wheel = TRUE; - flags = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0078; - break; - - case 8: /* back */ - case 97: /* Xming */ - extended = TRUE; - flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON1; - break; - - case 9: /* forward */ - case 112: /* Xming */ - extended = TRUE; - flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON2; - break; - - case 6: /* wheel left */ - wheel = TRUE; - flags = PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0078; - break; - - case 7: /* wheel right */ - wheel = TRUE; - flags = PTR_FLAGS_HWHEEL | 0x0078; - break; - - default: - x = 0; - y = 0; - flags = 0; + if (cur->button == button) + { + flags = cur->flags; break; + } } + input = xfc->context.input; + if (flags != 0) { - if (wheel) + if (flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL)) { - freerdp_input_send_mouse_event(input, flags, 0, 0); + if (down) + freerdp_input_send_mouse_event(input, flags, 0, 0); } else { + BOOL extended = FALSE; + + if (flags & (PTR_XFLAGS_BUTTON1 | PTR_XFLAGS_BUTTON2)) + { + extended = TRUE; + + if (down) + flags |= PTR_XFLAGS_DOWN; + } + else if (flags & (PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3)) + { + if (down) + flags |= PTR_FLAGS_DOWN; + } + if (app) { /* make sure window exists */ @@ -468,80 +447,17 @@ static BOOL xf_event_ButtonPress(xfContext* xfc, XEvent* event, BOOL app) if (xfc->use_xinput) return TRUE; - return xf_generic_ButtonPress(xfc, event->xbutton.x, event->xbutton.y, - event->xbutton.button, event->xbutton.window, app); + return xf_generic_ButtonEvent(xfc, event->xbutton.x, event->xbutton.y, + event->xbutton.button, event->xbutton.window, app, TRUE); } -BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, - Window window, BOOL app) -{ - int flags = 0; - BOOL extended = FALSE; - rdpInput* input; - Window childWindow; - if (!xfc || !xfc->context.input) - return FALSE; - - input = xfc->context.input; - - switch (button) - { - case Button1: - case Button2: - case Button3: - flags = xfc->button_map[button - BUTTON_BASE]; - break; - - case 6: - case 8: - case 97: - extended = TRUE; - flags = PTR_XFLAGS_BUTTON1; - break; - - case 7: - case 9: - case 112: - extended = TRUE; - flags = PTR_XFLAGS_BUTTON2; - break; - - default: - flags = 0; - break; - } - - if (flags != 0) - { - if (app) - { - /* make sure window exists */ - if (!xf_AppWindowFromX11Window(xfc, window)) - return TRUE; - - /* Translate to desktop coordinates */ - XTranslateCoordinates(xfc->display, window, - RootWindowOfScreen(xfc->screen), - x, y, &x, &y, &childWindow); - } - - xf_event_adjust_coordinates(xfc, &x, &y); - - if (extended) - freerdp_input_send_extended_mouse_event(input, flags, x, y); - else - freerdp_input_send_mouse_event(input, flags, x, y); - } - - return TRUE; -} static BOOL xf_event_ButtonRelease(xfContext* xfc, XEvent* event, BOOL app) { if (xfc->use_xinput) return TRUE; - return xf_generic_ButtonRelease(xfc, event->xbutton.x, event->xbutton.y, - event->xbutton.button, event->xbutton.window, app); + return xf_generic_ButtonEvent(xfc, event->xbutton.x, event->xbutton.y, + event->xbutton.button, event->xbutton.window, app, FALSE); } static BOOL xf_event_KeyPress(xfContext* xfc, XEvent* event, BOOL app) { @@ -561,6 +477,9 @@ static BOOL xf_event_KeyRelease(xfContext* xfc, XEvent* event, BOOL app) } static BOOL xf_event_FocusIn(xfContext* xfc, XEvent* event, BOOL app) { + if (!xfc->window) + return FALSE; + if (event->xfocus.mode == NotifyGrab) return TRUE; @@ -644,6 +563,9 @@ static BOOL xf_event_ClientMessage(xfContext* xfc, XEvent* event, BOOL app) } static BOOL xf_event_EnterNotify(xfContext* xfc, XEvent* event, BOOL app) { + if (!xfc->window) + return FALSE; + if (!app) { xfc->mouse_active = TRUE; @@ -685,7 +607,12 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, XEvent* event, BOOL app) { Window childWindow; xfAppWindow* appWindow; - rdpSettings* settings = xfc->context.settings; + rdpSettings* settings; + + if (!xfc->window) + return FALSE; + + settings = xfc->context.settings; if (!app) { @@ -900,7 +827,7 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app) xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MINIMIZE); } else if (!minimized && !maxVert && !maxHorz - && (appWindow->rail_state != WINDOW_SHOW)) + && (appWindow->rail_state != WINDOW_SHOW) && (appWindow->rail_state != WINDOW_HIDE)) { appWindow->rail_state = WINDOW_SHOW; xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); @@ -1018,10 +945,13 @@ BOOL xf_event_process(freerdp* instance, XEvent* event) } } - if (xfc->floatbar && xf_floatbar_check_event(xfc, event)) + if (xfc->window) { - xf_floatbar_event_process(xfc, event); - return TRUE; + if (xf_floatbar_check_event(xfc->window->floatbar, event)) + { + xf_floatbar_event_process(xfc->window->floatbar, event); + return TRUE; + } } xf_event_execute_action_script(xfc, event); diff --git a/client/X11/xf_event.h b/client/X11/xf_event.h index 4e880aa..b61c144 100644 --- a/client/X11/xf_event.h +++ b/client/X11/xf_event.h @@ -29,12 +29,14 @@ BOOL xf_event_action_script_init(xfContext* xfc); void xf_event_action_script_free(xfContext* xfc); BOOL xf_event_process(freerdp* instance, XEvent* event); -void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...); +void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, + ...); -void xf_event_adjust_coordinates(xfContext* xfc, int* x, int *y); +void xf_event_adjust_coordinates(xfContext* xfc, int* x, int* y); BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window window, BOOL app); BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, Window window, BOOL app); -BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, Window window, BOOL app); +BOOL xf_generic_ButtonEvent(xfContext* xfc, int x, int y, int button, Window window, BOOL app, + BOOL down); #endif /* FREERDP_CLIENT_X11_EVENT_H */ diff --git a/client/X11/xf_floatbar.c b/client/X11/xf_floatbar.c index 1d60072..51b2021 100644 --- a/client/X11/xf_floatbar.c +++ b/client/X11/xf_floatbar.c @@ -57,6 +57,8 @@ #define XF_FLOATBAR_BUTTON_MINIMIZE 3 #define XF_FLOATBAR_BUTTON_LOCKED 4 +typedef BOOL(*OnClick)(xfFloatbar*); + typedef struct xf_floatbar_button xfFloatbarButton; struct xf_floatbar @@ -71,6 +73,12 @@ struct xf_floatbar bool locked; xfFloatbarButton* buttons[4]; Window handle; + BOOL hasCursor; + xfContext* xfc; + DWORD flags; + BOOL created; + Window root_window; + char* title; }; struct xf_floatbar_button @@ -84,43 +92,70 @@ struct xf_floatbar_button Window handle; }; -static void xf_floatbar_button_onclick_close(xfContext* xfc) +static xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar, int type); + +static BOOL xf_floatbar_button_onclick_close(xfFloatbar* floatbar) { - ExitProcess(EXIT_SUCCESS); + if (!floatbar) + return FALSE; + + return freerdp_abort_connect(floatbar->xfc->context.instance); } -static void xf_floatbar_button_onclick_minimize(xfContext* xfc) +static BOOL xf_floatbar_button_onclick_minimize(xfFloatbar* floatbar) { + xfContext* xfc; + + if (!floatbar || !floatbar->xfc) + return FALSE; + + xfc = floatbar->xfc; xf_SetWindowMinimized(xfc, xfc->window); + return TRUE; } -static void xf_floatbar_button_onclick_restore(xfContext* xfc) +static BOOL xf_floatbar_button_onclick_restore(xfFloatbar* floatbar) { - xf_toggle_fullscreen(xfc); + if (!floatbar) + return FALSE; + + xf_toggle_fullscreen(floatbar->xfc); + return TRUE; } -static void xf_floatbar_button_onclick_locked(xfContext* xfc) +static BOOL xf_floatbar_button_onclick_locked(xfFloatbar* floatbar) { - xfFloatbar* floatbar; - floatbar = xfc->window->floatbar; + if (!floatbar) + return FALSE; + floatbar->locked = (floatbar->locked) ? FALSE : TRUE; + return xf_floatbar_hide_and_show(floatbar); } -void xf_floatbar_set_root_y(xfContext* xfc, int y) +BOOL xf_floatbar_set_root_y(xfFloatbar* floatbar, int y) { - xfFloatbar* floatbar; - floatbar = xfc->window->floatbar; + if (!floatbar) + return FALSE; + floatbar->last_motion_y_root = y; + return TRUE; } -void xf_floatbar_hide_and_show(xfContext* xfc) +BOOL xf_floatbar_hide_and_show(xfFloatbar* floatbar) { - xfFloatbar* floatbar; - floatbar = xfc->window->floatbar; + xfContext* xfc; + + if (!floatbar || !floatbar->xfc) + return FALSE; + + if (!floatbar->created) + return TRUE; + + xfc = floatbar->xfc; if (!floatbar->locked) { - if ((floatbar->mode == 0) && (floatbar->last_motion_y_root > 10) && + if ((floatbar->mode == XF_FLOATBAR_MODE_NONE) && (floatbar->last_motion_y_root > 10) && (floatbar->y > (FLOATBAR_HEIGHT * -1))) { floatbar->y = floatbar->y - 1; @@ -132,16 +167,70 @@ void xf_floatbar_hide_and_show(xfContext* xfc) XMoveWindow(xfc->display, floatbar->handle, floatbar->x, floatbar->y); } } + + return TRUE; } -void xf_floatbar_toggle_visibility(xfContext* xfc, bool visible) +static BOOL create_floatbar(xfFloatbar* floatbar) +{ + xfContext* xfc; + Status status; + XWindowAttributes attr; + + if (floatbar->created) + return TRUE; + + xfc = floatbar->xfc; + status = XGetWindowAttributes(xfc->display, floatbar->root_window, &attr); + floatbar->x = attr.x + attr.width / 2 - FLOATBAR_DEFAULT_WIDTH / 2; + floatbar->y = 0; + + if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked) + floatbar->y = -FLOATBAR_HEIGHT + 1; + + floatbar->handle = XCreateWindow(xfc->display, floatbar->root_window, + floatbar->x, 0, FLOATBAR_DEFAULT_WIDTH, + FLOATBAR_HEIGHT, 0, + CopyFromParent, InputOutput, CopyFromParent, 0, NULL); + floatbar->width = FLOATBAR_DEFAULT_WIDTH; + floatbar->height = FLOATBAR_HEIGHT; + floatbar->mode = XF_FLOATBAR_MODE_NONE; + floatbar->buttons[0] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_CLOSE); + floatbar->buttons[1] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_RESTORE); + floatbar->buttons[2] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_MINIMIZE); + floatbar->buttons[3] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_LOCKED); + XSelectInput(xfc->display, floatbar->handle, ExposureMask | ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask | + PropertyChangeMask); + floatbar->created = TRUE; + return TRUE; +} + +BOOL xf_floatbar_toggle_fullscreen(xfFloatbar* floatbar, bool fullscreen) { - xfFloatbar* floatbar; int i, size; - floatbar = xfc->window->floatbar; + bool visible = False; + xfContext* xfc; + + if (!floatbar || !floatbar->xfc) + return FALSE; + + xfc = floatbar->xfc; + + /* Only visible if enabled */ + if (floatbar->flags & 0x0001) + { + /* Visible if fullscreen and flag visible in fullscreen mode */ + visible |= ((floatbar->flags & 0x0010) != 0) && fullscreen; + /* Visible if window and flag visible in window mode */ + visible |= ((floatbar->flags & 0x0020) != 0) && !fullscreen; + } if (visible) { + if (!create_floatbar(floatbar)) + return FALSE; + XMapWindow(xfc->display, floatbar->handle); size = ARRAYSIZE(floatbar->buttons); @@ -149,15 +238,23 @@ void xf_floatbar_toggle_visibility(xfContext* xfc, bool visible) { XMapWindow(xfc->display, floatbar->buttons[i]->handle); } + + /* If default is hidden (and not sticky) don't show on fullscreen state changes */ + if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked) + floatbar->y = -FLOATBAR_HEIGHT + 1; + + xf_floatbar_hide_and_show(floatbar); } - else + else if (floatbar->created) { XUnmapSubwindows(xfc->display, floatbar->handle); XUnmapWindow(xfc->display, floatbar->handle); } + + return TRUE; } -static xfFloatbarButton* xf_floatbar_new_button(xfContext* xfc, xfFloatbar* floatbar, int type) +xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar, int type) { xfFloatbarButton* button; button = (xfFloatbarButton*) calloc(1, sizeof(xfFloatbarButton)); @@ -191,74 +288,74 @@ static xfFloatbarButton* xf_floatbar_new_button(xfContext* xfc, xfFloatbar* floa button->y = 0; button->focus = FALSE; - button->handle = XCreateWindow(xfc->display, floatbar->handle, button->x, 0, FLOATBAR_BUTTON_WIDTH, + button->handle = XCreateWindow(floatbar->xfc->display, floatbar->handle, button->x, 0, + FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL); - XSelectInput(xfc->display, button->handle, ExposureMask | ButtonPressMask | ButtonReleaseMask | + XSelectInput(floatbar->xfc->display, button->handle, + ExposureMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask); return button; } -xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window) +xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window, const char* name, DWORD flags) { xfFloatbar* floatbar; - XWindowAttributes attr; - int i, width; + + /* Floatbar not enabled */ + if ((flags & 0x0001) == 0) + return NULL; + if (!xfc) return NULL; + /* Force disable with remote app */ + if (xfc->remote_app) + return NULL; + floatbar = (xfFloatbar*) calloc(1, sizeof(xfFloatbar)); - floatbar->locked = TRUE; - XGetWindowAttributes(xfc->display, window, &attr); - for (i = 0; i < xfc->vscreen.nmonitors; i++) - { - if (attr.x >= xfc->vscreen.monitors[i].area.left && attr.x <= xfc->vscreen.monitors[i].area.right) - { - width = xfc->vscreen.monitors[i].area.right - xfc->vscreen.monitors[i].area.left; - floatbar->x = width / 2 + xfc->vscreen.monitors[i].area.left - FLOATBAR_DEFAULT_WIDTH / 2; - } - } + if (!floatbar) + return NULL; - floatbar->y = 0; - floatbar->handle = XCreateWindow(xfc->display, window, floatbar->x, 0, FLOATBAR_DEFAULT_WIDTH, - FLOATBAR_HEIGHT, 0, - CopyFromParent, InputOutput, CopyFromParent, 0, NULL); - floatbar->width = FLOATBAR_DEFAULT_WIDTH; - floatbar->height = FLOATBAR_HEIGHT; - floatbar->mode = XF_FLOATBAR_MODE_NONE; - floatbar->buttons[0] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_CLOSE); - floatbar->buttons[1] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_RESTORE); - floatbar->buttons[2] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_MINIMIZE); - floatbar->buttons[3] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_LOCKED); - XSelectInput(xfc->display, floatbar->handle, ExposureMask | ButtonPressMask | ButtonReleaseMask | - PointerMotionMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask | - PropertyChangeMask); + floatbar->title = _strdup(name); + + if (!floatbar->title) + goto fail; + + floatbar->root_window = window; + floatbar->flags = flags; + floatbar->xfc = xfc; + floatbar->locked = flags & 0x0002; + xf_floatbar_toggle_fullscreen(floatbar, FALSE); return floatbar; +fail: + xf_floatbar_free(floatbar); + return NULL; } -static unsigned long xf_floatbar_get_color(xfContext* xfc, char* rgb_value) +static unsigned long xf_floatbar_get_color(xfFloatbar* floatbar, char* rgb_value) { Colormap cmap; XColor color; - cmap = DefaultColormap(xfc->display, XDefaultScreen(xfc->display)); - XParseColor(xfc->display, cmap, rgb_value, &color); - XAllocColor(xfc->display, cmap, &color); - XFreeColormap(xfc->display, cmap); + Display* display = floatbar->xfc->display; + cmap = DefaultColormap(display, XDefaultScreen(display)); + XParseColor(display, cmap, rgb_value, &color); + XAllocColor(display, cmap, &color); + XFreeColormap(display, cmap); return color.pixel; } -static void xf_floatbar_event_expose(xfContext* xfc, XEvent* event) +static void xf_floatbar_event_expose(xfFloatbar* floatbar, XEvent* event) { GC gc, shape_gc; Pixmap pmap; XPoint shape[5], border[5]; - xfFloatbar* floatbar; int len; - floatbar = xfc->window->floatbar; + Display* display = floatbar->xfc->display; /* create the pixmap that we'll use for shaping the window */ - pmap = XCreatePixmap(xfc->display, floatbar->handle, floatbar->width, floatbar->height, 1); - gc = XCreateGC(xfc->display, floatbar->handle, 0, 0); - shape_gc = XCreateGC(xfc->display, pmap, 0, 0); + pmap = XCreatePixmap(display, floatbar->handle, floatbar->width, floatbar->height, 1); + gc = XCreateGC(display, floatbar->handle, 0, 0); + shape_gc = XCreateGC(display, pmap, 0, 0); /* points for drawing the floatbar */ shape[0].x = 0; shape[0].y = 0; @@ -282,34 +379,32 @@ static void xf_floatbar_event_expose(xfContext* xfc, XEvent* event) border[4].x = border[0].x; border[4].y = border[0].y; /* Fill all pixels with 0 */ - XSetForeground(xfc->display, shape_gc, 0); - XFillRectangle(xfc->display, pmap, shape_gc, 0, 0, floatbar->width, + XSetForeground(display, shape_gc, 0); + XFillRectangle(display, pmap, shape_gc, 0, 0, floatbar->width, floatbar->height); /* Fill all pixels which should be shown with 1 */ - XSetForeground(xfc->display, shape_gc, 1); - XFillPolygon(xfc->display, pmap, shape_gc, shape, 5, 0, CoordModeOrigin); - XShapeCombineMask(xfc->display, floatbar->handle, ShapeBounding, 0, 0, pmap, ShapeSet); + XSetForeground(display, shape_gc, 1); + XFillPolygon(display, pmap, shape_gc, shape, 5, 0, CoordModeOrigin); + XShapeCombineMask(display, floatbar->handle, ShapeBounding, 0, 0, pmap, ShapeSet); /* draw the float bar */ - XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BACKGROUND)); - XFillPolygon(xfc->display, floatbar->handle, gc, shape, 4, 0, CoordModeOrigin); + XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND)); + XFillPolygon(display, floatbar->handle, gc, shape, 4, 0, CoordModeOrigin); /* draw an border for the floatbar */ - XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BORDER)); - XDrawLines(xfc->display, floatbar->handle, gc, border, 5, CoordModeOrigin); + XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER)); + XDrawLines(display, floatbar->handle, gc, border, 5, CoordModeOrigin); /* draw the host name connected to */ - len = strlen(xfc->context.settings->ServerHostname); - XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_FOREGROUND)); - XDrawString(xfc->display, floatbar->handle, gc, floatbar->width / 2 - len * 2, 15, - xfc->context.settings->ServerHostname, len); - XFreeGC(xfc->display, gc); - XFreeGC(xfc->display, shape_gc); + len = strlen(floatbar->title); + XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_FOREGROUND)); + XDrawString(display, floatbar->handle, gc, floatbar->width / 2 - len * 2, 15, + floatbar->title, len); + XFreeGC(display, gc); + XFreeGC(display, shape_gc); } -static xfFloatbarButton* xf_floatbar_get_button(xfContext* xfc, XEvent* event) +static xfFloatbarButton* xf_floatbar_get_button(xfFloatbar* floatbar, XEvent* event) { - xfFloatbar* floatbar; int i, size; size = ARRAYSIZE(floatbar->buttons); - floatbar = xfc->window->floatbar; for (i = 0; i < size; i++) { @@ -322,12 +417,11 @@ static xfFloatbarButton* xf_floatbar_get_button(xfContext* xfc, XEvent* event) return NULL; } -static void xf_floatbar_button_update_positon(xfContext* xfc, XEvent* event) +static void xf_floatbar_button_update_positon(xfFloatbar* floatbar, XEvent* event) { - xfFloatbar* floatbar; xfFloatbarButton* button; int i, size; - floatbar = xfc->window->floatbar; + xfContext* xfc = floatbar->xfc; size = ARRAYSIZE(floatbar->buttons); for (i = 0; i < size; i++) @@ -353,18 +447,17 @@ static void xf_floatbar_button_update_positon(xfContext* xfc, XEvent* event) } XMoveWindow(xfc->display, button->handle, button->x, button->y); - xf_floatbar_event_expose(xfc, event); + xf_floatbar_event_expose(floatbar, event); } } -static void xf_floatbar_button_event_expose(xfContext* xfc, XEvent* event) +static void xf_floatbar_button_event_expose(xfFloatbar* floatbar, XEvent* event) { - xfFloatbar* floatbar; - xfFloatbarButton* button; + xfFloatbarButton* button = xf_floatbar_get_button(floatbar, event); static unsigned char* bits; GC gc; Pixmap pattern; - button = xf_floatbar_get_button(xfc, event); + xfContext* xfc = floatbar->xfc; if (!button) return; @@ -402,43 +495,39 @@ static void xf_floatbar_button_event_expose(xfContext* xfc, XEvent* event) FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH); if (!(button->focus)) - XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BACKGROUND)); + XSetForeground(xfc->display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND)); else - XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BORDER)); + XSetForeground(xfc->display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER)); - XSetBackground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_FOREGROUND)); + XSetBackground(xfc->display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_FOREGROUND)); XCopyPlane(xfc->display, pattern, button->handle, gc, 0, 0, FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH, 0, 0, 1); XFreePixmap(xfc->display, pattern); XFreeGC(xfc->display, gc); } -static void xf_floatbar_button_event_buttonpress(xfContext* xfc, XEvent* event) +static void xf_floatbar_button_event_buttonpress(xfFloatbar* floatbar, XEvent* event) { - xfFloatbarButton* button; - button = xf_floatbar_get_button(xfc, event); + xfFloatbarButton* button = xf_floatbar_get_button(floatbar, event); if (button) button->clicked = TRUE; } -static void xf_floatbar_button_event_buttonrelease(xfContext* xfc, XEvent* event) +static void xf_floatbar_button_event_buttonrelease(xfFloatbar* floatbar, XEvent* event) { xfFloatbarButton* button; - button = xf_floatbar_get_button(xfc, event); + button = xf_floatbar_get_button(floatbar, event); if (button) { if (button->clicked) - button->onclick(xfc); + button->onclick(floatbar); } } -static void xf_floatbar_event_buttonpress(xfContext* xfc, XEvent* event) +static void xf_floatbar_event_buttonpress(xfFloatbar* floatbar, XEvent* event) { - xfFloatbar* floatbar; - floatbar = xfc->window->floatbar; - switch (event->xbutton.button) { case Button1: @@ -456,12 +545,12 @@ static void xf_floatbar_event_buttonpress(xfContext* xfc, XEvent* event) } } -static void xf_floatbar_event_buttonrelease(xfContext* xfc, XEvent* event) +static void xf_floatbar_event_buttonrelease(xfFloatbar* floatbar, XEvent* event) { switch (event->xbutton.button) { case Button1: - xfc->window->floatbar->mode = XF_FLOATBAR_MODE_NONE; + floatbar->mode = XF_FLOATBAR_MODE_NONE; break; default: @@ -469,11 +558,10 @@ static void xf_floatbar_event_buttonrelease(xfContext* xfc, XEvent* event) } } -static void xf_floatbar_resize(xfContext* xfc, XEvent* event) +static void xf_floatbar_resize(xfFloatbar* floatbar, XEvent* event) { - xfFloatbar* floatbar; - floatbar = xfc->window->floatbar; int x, width, movement; + xfContext* xfc = floatbar->xfc; /* calculate movement which happened on the root window */ movement = event->xmotion.x_root - floatbar->last_motion_x_root; @@ -498,11 +586,10 @@ static void xf_floatbar_resize(xfContext* xfc, XEvent* event) } } -static void xf_floatbar_dragging(xfContext* xfc, XEvent* event) +static void xf_floatbar_dragging(xfFloatbar* floatbar, XEvent* event) { - xfFloatbar* floatbar; - floatbar = xfc->window->floatbar; int x, movement; + xfContext* xfc = floatbar->xfc; /* calculate movement and new x position */ movement = event->xmotion.x_root - floatbar->last_motion_x_root; x = floatbar->x + movement; @@ -518,78 +605,82 @@ static void xf_floatbar_dragging(xfContext* xfc, XEvent* event) floatbar->x = x; } -static void xf_floatbar_event_motionnotify(xfContext* xfc, XEvent* event) +static void xf_floatbar_event_motionnotify(xfFloatbar* floatbar, XEvent* event) { int mode; - xfFloatbar* floatbar; Cursor cursor; - mode = xfc->window->floatbar->mode; - floatbar = xfc->window->floatbar; + xfContext* xfc = floatbar->xfc; + mode = floatbar->mode; cursor = XCreateFontCursor(xfc->display, XC_arrow); if ((event->xmotion.state & Button1Mask) && (mode > XF_FLOATBAR_MODE_DRAGGING)) { - xf_floatbar_resize(xfc, event); + xf_floatbar_resize(floatbar, event); } else if ((event->xmotion.state & Button1Mask) && (mode == XF_FLOATBAR_MODE_DRAGGING)) { - xf_floatbar_dragging(xfc, event); + xf_floatbar_dragging(floatbar, event); } else { if (event->xmotion.x <= FLOATBAR_BORDER || - event->xmotion.x >= xfc->window->floatbar->width - FLOATBAR_BORDER) + event->xmotion.x >= floatbar->width - FLOATBAR_BORDER) cursor = XCreateFontCursor(xfc->display, XC_sb_h_double_arrow); } XDefineCursor(xfc->display, xfc->window->handle, cursor); XFreeCursor(xfc->display, cursor); - xfc->window->floatbar->last_motion_x_root = event->xmotion.x_root; + floatbar->last_motion_x_root = event->xmotion.x_root; } -static void xf_floatbar_button_event_focusin(xfContext* xfc, XEvent* event) +static void xf_floatbar_button_event_focusin(xfFloatbar* floatbar, XEvent* event) { xfFloatbarButton* button; - button = xf_floatbar_get_button(xfc, event); + button = xf_floatbar_get_button(floatbar, event); if (button) { button->focus = TRUE; - xf_floatbar_button_event_expose(xfc, event); + xf_floatbar_button_event_expose(floatbar, event); } } -static void xf_floatbar_button_event_focusout(xfContext* xfc, XEvent* event) +static void xf_floatbar_button_event_focusout(xfFloatbar* floatbar, XEvent* event) { xfFloatbarButton* button; - button = xf_floatbar_get_button(xfc, event); + button = xf_floatbar_get_button(floatbar, event); if (button) { button->focus = FALSE; button->clicked = FALSE; - xf_floatbar_button_event_expose(xfc, event); + xf_floatbar_button_event_expose(floatbar, event); } } -static void xf_floatbar_event_focusout(xfContext* xfc, XEvent* event) +static void xf_floatbar_event_focusout(xfFloatbar* floatbar, XEvent* event) { - Cursor cursor; - cursor = XCreateFontCursor(xfc->display, XC_arrow); - XDefineCursor(xfc->display, xfc->window->handle, cursor); - XFreeCursor(xfc->display, cursor); + xfContext* xfc = floatbar->xfc; + + if (xfc->pointer) + { + XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor); + } } -BOOL xf_floatbar_check_event(xfContext* xfc, XEvent* event) +BOOL xf_floatbar_check_event(xfFloatbar* floatbar, XEvent* event) { - xfFloatbar* floatbar; xfFloatbarButton* button; size_t i, size; + xfContext* xfc; - if (!xfc || !event || !xfc->window) + if (!floatbar || !floatbar->xfc || !event) return FALSE; - floatbar = xfc->window->floatbar; + if (!floatbar->created) + return FALSE; + + xfc = floatbar->xfc; if (event->xany.window == floatbar->handle) return TRUE; @@ -607,70 +698,69 @@ BOOL xf_floatbar_check_event(xfContext* xfc, XEvent* event) return FALSE; } -BOOL xf_floatbar_event_process(xfContext* xfc, XEvent* event) +BOOL xf_floatbar_event_process(xfFloatbar* floatbar, XEvent* event) { - xfFloatbar* floatbar; - - if (!xfc || !xfc->window || !event) + if (!floatbar || !floatbar->xfc || !event) return FALSE; - floatbar = xfc->window->floatbar; + if (!floatbar->created) + return FALSE; switch (event->type) { case Expose: if (event->xany.window == floatbar->handle) - xf_floatbar_event_expose(xfc, event); + xf_floatbar_event_expose(floatbar, event); else - xf_floatbar_button_event_expose(xfc, event); + xf_floatbar_button_event_expose(floatbar, event); break; case MotionNotify: - xf_floatbar_event_motionnotify(xfc, event); + xf_floatbar_event_motionnotify(floatbar, event); break; case ButtonPress: if (event->xany.window == floatbar->handle) - xf_floatbar_event_buttonpress(xfc, event); + xf_floatbar_event_buttonpress(floatbar, event); else - xf_floatbar_button_event_buttonpress(xfc, event); + xf_floatbar_button_event_buttonpress(floatbar, event); break; case ButtonRelease: if (event->xany.window == floatbar->handle) - xf_floatbar_event_buttonrelease(xfc, event); + xf_floatbar_event_buttonrelease(floatbar, event); else - xf_floatbar_button_event_buttonrelease(xfc, event); + xf_floatbar_button_event_buttonrelease(floatbar, event); break; case EnterNotify: case FocusIn: if (event->xany.window != floatbar->handle) - xf_floatbar_button_event_focusin(xfc, event); + xf_floatbar_button_event_focusin(floatbar, event); break; case LeaveNotify: case FocusOut: if (event->xany.window == floatbar->handle) - xf_floatbar_event_focusout(xfc, event); + xf_floatbar_event_focusout(floatbar, event); else - xf_floatbar_button_event_focusout(xfc, event); + xf_floatbar_button_event_focusout(floatbar, event); break; case ConfigureNotify: if (event->xany.window == floatbar->handle) - xf_floatbar_button_update_positon(xfc, event); + xf_floatbar_button_update_positon(floatbar, event); break; case PropertyNotify: if (event->xany.window == floatbar->handle) - xf_floatbar_button_update_positon(xfc, event); + xf_floatbar_button_update_positon(floatbar, event); break; @@ -695,16 +785,17 @@ static void xf_floatbar_button_free(xfContext* xfc, xfFloatbarButton* button) free(button); } -void xf_floatbar_free(xfContext* xfc, xfWindow* window, xfFloatbar* floatbar) +void xf_floatbar_free(xfFloatbar* floatbar) { size_t i, size; - size = ARRAYSIZE(floatbar->buttons); + xfContext* xfc; if (!floatbar) return; - if (window->floatbar == floatbar) - window->floatbar = NULL; + free(floatbar->title); + xfc = floatbar->xfc; + size = ARRAYSIZE(floatbar->buttons); for (i = 0; i < size; i++) { diff --git a/client/X11/xf_floatbar.h b/client/X11/xf_floatbar.h index fecb5cb..42ab5f3 100644 --- a/client/X11/xf_floatbar.h +++ b/client/X11/xf_floatbar.h @@ -22,13 +22,13 @@ typedef struct xf_floatbar xfFloatbar; #include "xfreerdp.h" -typedef void(*OnClick)(xfContext*); -xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window); -BOOL xf_floatbar_event_process(xfContext* xfc, XEvent* event); -BOOL xf_floatbar_check_event(xfContext* xfc, XEvent* event); -void xf_floatbar_toggle_visibility(xfContext* xfc, bool visible); -void xf_floatbar_free(xfContext* xfc, xfWindow* window, xfFloatbar* floatbar); -void xf_floatbar_hide_and_show(xfContext* xfc); -void xf_floatbar_set_root_y(xfContext* xfc, int y); +xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window, const char* title, DWORD flags); +void xf_floatbar_free(xfFloatbar* floatbar); + +BOOL xf_floatbar_event_process(xfFloatbar* floatbar, XEvent* event); +BOOL xf_floatbar_check_event(xfFloatbar* floatbar, XEvent* event); +BOOL xf_floatbar_toggle_fullscreen(xfFloatbar* floatbar, bool visible); +BOOL xf_floatbar_hide_and_show(xfFloatbar* floatbar); +BOOL xf_floatbar_set_root_y(xfFloatbar* floatbar, int y); #endif /* FREERDP_CLIENT_X11_FLOATBAR_H */ diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index b68a297..8740e80 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -129,6 +129,7 @@ static UINT xf_UpdateSurfaces(RdpgfxClientContext* context) if (gdi->suppressOutput) return CHANNEL_RC_OK; + EnterCriticalSection(&context->mux); context->GetSurfaceIds(context, &pSurfaceIds, &count); for (index = 0; index < count; index++) @@ -145,6 +146,7 @@ static UINT xf_UpdateSurfaces(RdpgfxClientContext* context) } free(pSurfaceIds); + LeaveCriticalSection(&context->mux); return status; } @@ -153,7 +155,7 @@ UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, { UINT16 count; UINT32 index; - UINT status = CHANNEL_RC_OK; + UINT status = ERROR_INTERNAL_ERROR; xfGfxSurface* surface; RECTANGLE_16 invalidRect; RECTANGLE_16 surfaceRect; @@ -164,7 +166,12 @@ UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, invalidRect.top = y; invalidRect.right = x + width; invalidRect.bottom = y + height; - context->GetSurfaceIds(context, &pSurfaceIds, &count); + status = context->GetSurfaceIds(context, &pSurfaceIds, &count); + + if (status != CHANNEL_RC_OK) + goto fail; + + EnterCriticalSection(&context->mux); for (index = 0; index < count; index++) { @@ -192,7 +199,13 @@ UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, } free(pSurfaceIds); + LeaveCriticalSection(&context->mux); IFCALLRET(context->UpdateSurfaces, status, context); + + if (status != CHANNEL_RC_OK) + goto fail; + +fail: return status; } @@ -343,6 +356,8 @@ static UINT xf_DeleteSurface(RdpgfxClientContext* context, { rdpCodecs* codecs = NULL; xfGfxSurface* surface = NULL; + UINT status; + EnterCriticalSection(&context->mux); surface = (xfGfxSurface*) context->GetSurfaceData(context, deleteSurface->surfaceId); @@ -360,13 +375,14 @@ static UINT xf_DeleteSurface(RdpgfxClientContext* context, free(surface); } - context->SetSurfaceData(context, deleteSurface->surfaceId, NULL); + status = context->SetSurfaceData(context, deleteSurface->surfaceId, NULL); if (codecs && codecs->progressive) progressive_delete_surface_context(codecs->progressive, deleteSurface->surfaceId); - return CHANNEL_RC_OK; + LeaveCriticalSection(&context->mux); + return status; } void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx) diff --git a/client/X11/xf_input.c b/client/X11/xf_input.c index 0bed66c..4279b59 100644 --- a/client/X11/xf_input.c +++ b/client/X11/xf_input.c @@ -581,13 +581,13 @@ static int xf_input_event(xfContext* xfc, XIDeviceEvent* event, int evtype) switch (evtype) { case XI_ButtonPress: - xf_generic_ButtonPress(xfc, (int) event->event_x, (int) event->event_y, - event->detail, event->event, xfc->remote_app); + xf_generic_ButtonEvent(xfc, (int) event->event_x, (int) event->event_y, + event->detail, event->event, xfc->remote_app, TRUE); break; case XI_ButtonRelease: - xf_generic_ButtonRelease(xfc, (int) event->event_x, (int) event->event_y, - event->detail, event->event, xfc->remote_app); + xf_generic_ButtonEvent(xfc, (int) event->event_x, (int) event->event_y, + event->detail, event->event, xfc->remote_app, FALSE); break; case XI_Motion: diff --git a/client/X11/xf_monitor.c b/client/X11/xf_monitor.c index 9eb854e..7b86ae6 100644 --- a/client/X11/xf_monitor.c +++ b/client/X11/xf_monitor.c @@ -141,7 +141,7 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) int monitor_index = 0; BOOL primaryMonitorFound = FALSE; VIRTUAL_SCREEN* vscreen; - rdpSettings* settings = xfc->context.settings; + rdpSettings* settings; int mouse_x, mouse_y, _dummy_i; Window _dummy_w; int current_monitor = 0; @@ -154,6 +154,11 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) XRRMonitorInfo* rrmonitors = NULL; BOOL useXRandr = FALSE; #endif + + if (!xfc || !pMaxWidth || !pMaxHeight || !xfc->context.settings) + return FALSE; + + settings = xfc->context.settings; vscreen = &xfc->vscreen; *pMaxWidth = settings->DesktopWidth; *pMaxHeight = settings->DesktopHeight; @@ -274,6 +279,9 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) if (settings->NumMonitorIds == 1) { monitor = vscreen->monitors + current_monitor; + if (!monitor) + return FALSE; + xfc->workArea.x = monitor->area.left; xfc->workArea.y = monitor->area.top; xfc->workArea.width = monitor->area.right - monitor->area.left + 1; @@ -305,6 +313,9 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) */ if (vscreen->nmonitors > 0) { + if (!vscreen->monitors) + return FALSE; + *pMaxWidth = vscreen->monitors[current_monitor].area.right - vscreen->monitors[current_monitor].area.left + 1; *pMaxHeight = vscreen->monitors[current_monitor].area.bottom - @@ -346,12 +357,15 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) if (!xf_is_monitor_id_active(xfc, i)) continue; + if (!vscreen->monitors) + return FALSE; + settings->MonitorDefArray[nmonitors].x = vscreen->monitors[i].area.left; settings->MonitorDefArray[nmonitors].y = vscreen->monitors[i].area.top; settings->MonitorDefArray[nmonitors].width = - MIN(vscreen->monitors[i].area.right - vscreen->monitors[i].area.left + 1, *pMaxWidth); + vscreen->monitors[i].area.right - vscreen->monitors[i].area.left + 1; settings->MonitorDefArray[nmonitors].height = - MIN(vscreen->monitors[i].area.bottom - vscreen->monitors[i].area.top + 1, *pMaxHeight); + vscreen->monitors[i].area.bottom - vscreen->monitors[i].area.top + 1; settings->MonitorDefArray[nmonitors].orig_screen = i; #ifdef USABLE_XRANDR @@ -380,7 +394,10 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) /* If no monitor is active(bogus command-line monitor specification) - then lets try to fallback to go fullscreen on the current monitor only */ if (nmonitors == 0 && vscreen->nmonitors > 0) - { + { + if (!vscreen->monitors) + return FALSE; + settings->MonitorDefArray[0].x = vscreen->monitors[current_monitor].area.left; settings->MonitorDefArray[0].y = vscreen->monitors[current_monitor].area.top; settings->MonitorDefArray[0].width = MIN( @@ -509,8 +526,8 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) } /* Set the desktop width and height according to the bounding rectangle around the active monitors */ - *pMaxWidth = vscreen->area.right - vscreen->area.left + 1; - *pMaxHeight = vscreen->area.bottom - vscreen->area.top + 1; + *pMaxWidth = MIN(*pMaxWidth, vscreen->area.right - vscreen->area.left + 1); + *pMaxHeight = MIN(*pMaxHeight, vscreen->area.bottom - vscreen->area.top + 1); } /* some 2008 server freeze at logon if we announce support for monitor layout PDU with diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index 0b4e992..df45e05 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -222,8 +222,7 @@ static void xf_rail_invalidate_region(xfContext* xfc, REGION16* invalidRegion) for (index = 0; index < count; index++) { - appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*) pKeys[index]); + appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, (void*)pKeys[index]); if (appWindow) { @@ -327,14 +326,12 @@ static BOOL xf_rail_window_common(rdpContext* context, return FALSE; } - HashTable_Add(xfc->railWindows, (void*)(UINT_PTR) orderInfo->windowId, - (void*) appWindow); + HashTable_Add(xfc->railWindows, &appWindow->windowId, (void*) appWindow); xf_AppWindowInit(xfc, appWindow); } else { - appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*)(UINT_PTR) orderInfo->windowId); + appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, &orderInfo->windowId); } if (!appWindow) @@ -544,7 +541,7 @@ static BOOL xf_rail_window_delete(rdpContext* context, if (!xfc) return FALSE; - HashTable_Remove(xfc->railWindows, (void*)(UINT_PTR) orderInfo->windowId); + HashTable_Remove(xfc->railWindows, &orderInfo->windowId); return TRUE; } @@ -809,8 +806,7 @@ static void xf_rail_set_window_icon(xfContext* xfc, static xfAppWindow* xf_rail_get_window_by_id(xfContext* xfc, UINT32 windowId) { - return (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*)(UINT_PTR) windowId); + return (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, &windowId); } static BOOL xf_rail_window_icon(rdpContext* context, @@ -999,17 +995,24 @@ static UINT xf_rail_server_system_param(RailClientContext* context, static UINT xf_rail_server_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake) { - RAIL_EXEC_ORDER exec; - RAIL_SYSPARAM_ORDER sysparam; + UINT status; + RAIL_EXEC_ORDER exec = { 0 }; + RAIL_SYSPARAM_ORDER sysparam = { 0 }; RAIL_HANDSHAKE_ORDER clientHandshake; - RAIL_CLIENT_STATUS_ORDER clientStatus; + RAIL_CLIENT_STATUS_ORDER clientStatus = { 0 }; xfContext* xfc = (xfContext*) context->custom; rdpSettings* settings = xfc->context.settings; clientHandshake.buildNumber = 0x00001DB0; - context->ClientHandshake(context, &clientHandshake); - ZeroMemory(&clientStatus, sizeof(RAIL_CLIENT_STATUS_ORDER)); + status = context->ClientHandshake(context, &clientHandshake); + + if (status != CHANNEL_RC_OK) + return status; + clientStatus.flags = RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE; - context->ClientInformation(context, &clientStatus); + status = context->ClientInformation(context, &clientStatus); + + if (status != CHANNEL_RC_OK) + return status; if (settings->RemoteAppLanguageBarSupported) { @@ -1018,7 +1021,6 @@ static UINT xf_rail_server_handshake(RailClientContext* context, context->ClientLanguageBarInfo(context, &langBarInfo); } - ZeroMemory(&sysparam, sizeof(RAIL_SYSPARAM_ORDER)); sysparam.params = 0; sysparam.params |= SPI_MASK_SET_HIGH_CONTRAST; sysparam.highContrast.colorScheme.string = NULL; @@ -1038,13 +1040,15 @@ static UINT xf_rail_server_handshake(RailClientContext* context, sysparam.workArea.right = settings->DesktopWidth; sysparam.workArea.bottom = settings->DesktopHeight; sysparam.dragFullWindows = FALSE; - context->ClientSystemParam(context, &sysparam); - ZeroMemory(&exec, sizeof(RAIL_EXEC_ORDER)); + status = context->ClientSystemParam(context, &sysparam); + + if (status != CHANNEL_RC_OK) + return status; + exec.RemoteApplicationProgram = settings->RemoteApplicationProgram; exec.RemoteApplicationWorkingDir = settings->ShellWorkingDirectory; exec.RemoteApplicationArguments = settings->RemoteApplicationCmdLine; - context->ClientExecute(context, &exec); - return CHANNEL_RC_OK; + return context->ClientExecute(context, &exec); } /** @@ -1072,7 +1076,7 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context, xfAppWindow* appWindow = NULL; xfContext* xfc = (xfContext*) context->custom; appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*)(UINT_PTR) localMoveSize->windowId); + (void*)&localMoveSize->windowId); if (!appWindow) return ERROR_INTERNAL_ERROR; @@ -1167,8 +1171,7 @@ static UINT xf_rail_server_min_max_info(RailClientContext* context, { xfAppWindow* appWindow = NULL; xfContext* xfc = (xfContext*) context->custom; - appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*)(UINT_PTR) minMaxInfo->windowId); + appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, (void*)&minMaxInfo->windowId); if (appWindow) { @@ -1204,6 +1207,16 @@ static UINT xf_rail_server_get_appid_response(RailClientContext* context, return CHANNEL_RC_OK; } +static BOOL rail_window_key_equals(void* key1, void* key2) +{ + return *(UINT32*)key1 == *(UINT32*)key2; +} + +static UINT32 rail_window_key_hash(void* key) +{ + return *(UINT32*)key; +} + static void rail_window_free(void* value) { xfAppWindow* appWindow = (xfAppWindow*) value; @@ -1237,6 +1250,8 @@ int xf_rail_init(xfContext* xfc, RailClientContext* rail) if (!xfc->railWindows) return 0; + xfc->railWindows->keyCompare = rail_window_key_equals; + xfc->railWindows->hash = rail_window_key_hash; xfc->railWindows->valueFree = rail_window_free; xfc->railIconCache = RailIconCache_New(xfc->context.settings); diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index a86ad4c..a119c3c 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -163,9 +163,7 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) /* show/hide decorations (e.g. title bar) as guided by xfc->decorations */ xf_SetWindowDecorations(xfc, window->handle, window->decorations); DEBUG_X11(TAG, "X window decoration set to %d", (int)window->decorations); - - if (xfc->floatbar) - xf_floatbar_toggle_visibility(xfc, fullscreen); + xf_floatbar_toggle_fullscreen(xfc->window->floatbar, fullscreen); if (fullscreen) { @@ -587,7 +585,7 @@ xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, settings->DesktopPosY); } - window->floatbar = xf_floatbar_new(xfc, window->handle); + window->floatbar = xf_floatbar_new(xfc, window->handle, name, settings->Floatbar); return window; } @@ -636,8 +634,7 @@ void xf_DestroyDesktopWindow(xfContext* xfc, xfWindow* window) if (xfc->window == window) xfc->window = NULL; - if (window->floatbar) - xf_floatbar_free(xfc, window, window->floatbar); + xf_floatbar_free(window->floatbar); if (window->gc) XFreeGC(xfc->display, window->gc); @@ -988,6 +985,8 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state) if (appWindow->is_transient) xf_SetWindowUnlisted(xfc, appWindow->handle); + XMapWindow(xfc->display, appWindow->handle); + break; } @@ -1118,8 +1117,7 @@ xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd) for (index = 0; index < count; index++) { - appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*) pKeys[index]); + appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, (void*) pKeys[index]); if (appWindow->handle == wnd) { diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 746ea33..5d6dfb9 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -85,13 +85,14 @@ typedef struct _xfDispContext xfDispContext; typedef struct _xfVideoContext xfVideoContext; typedef struct xf_rail_icon_cache xfRailIconCache; -/* Value of the first logical button number in X11 which must be */ -/* subtracted to go from a button number in X11 to an index into */ -/* a per-button array. */ -#define BUTTON_BASE Button1 - /* Number of buttons that are mapped from X11 to RDP button events. */ -#define NUM_BUTTONS_MAPPED 3 +#define NUM_BUTTONS_MAPPED 11 + +typedef struct +{ + int button; + UINT16 flags; +} button_map; struct xf_context { @@ -161,7 +162,6 @@ struct xf_context BOOL use_xinput; BOOL mouse_active; BOOL fullscreen_toggle; - BOOL floatbar; BOOL controlToggle; UINT32 KeyboardLayout; BOOL KeyboardState[256]; @@ -232,7 +232,7 @@ struct xf_context BOOL xrenderAvailable; /* value to be sent over wire for each logical client mouse button */ - int button_map[NUM_BUTTONS_MAPPED]; + button_map button_map[NUM_BUTTONS_MAPPED]; BYTE savedMaximizedState; }; diff --git a/client/common/client.c b/client/common/client.c index 06146a4..7b2c54d 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -303,24 +303,38 @@ out: } int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, - const char* filename) + int argc, char* argv[]) { - int status; + int status, x; int ret = -1; + char* filename; + char* password = NULL; rdpAssistanceFile* file; + + if (!settings || !argv || (argc < 2)) + return -1; + + filename = argv[1]; + + for (x = 2; x < argc; x++) + { + const char* key = strstr(argv[x], "assistance:"); + + if (key) + password = strchr(key, ':') + 1; + } + file = freerdp_assistance_file_new(); if (!file) return -1; - status = freerdp_assistance_parse_file(file, filename); + status = freerdp_assistance_parse_file(file, filename, password); if (status < 0) goto out; - status = freerdp_client_populate_settings_from_assistance_file(file, settings); - - if (status < 0) + if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings)) goto out; ret = 0; @@ -492,6 +506,7 @@ static DWORD client_cli_accept_certificate(rdpSettings* settings) * when the connection requires it. * This function will actually be called by tls_verify_certificate(). * @see rdp_client_connect() and tls_connect() + * @deprecated Use client_cli_verify_certificate_ex * @param instance - pointer to the rdp_freerdp structure that contains the connection settings * @param common_name * @param subject @@ -504,6 +519,7 @@ DWORD client_cli_verify_certificate(freerdp* instance, const char* common_name, const char* subject, const char* issuer, const char* fingerprint, BOOL host_mismatch) { + printf("WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n"); printf("Certificate details:\n"); printf("\tSubject: %s\n", subject); printf("\tIssuer: %s\n", issuer); @@ -514,10 +530,50 @@ DWORD client_cli_verify_certificate(freerdp* instance, const char* common_name, return client_cli_accept_certificate(instance->settings); } +/** Callback set in the rdp_freerdp structure, and used to make a certificate validation + * when the connection requires it. + * This function will actually be called by tls_verify_certificate(). + * @see rdp_client_connect() and tls_connect() + * @param instance pointer to the rdp_freerdp structure that contains the connection settings + * @param host The host currently connecting to + * @param port The port currently connecting to + * @param common_name The common name of the certificate, should match host or an alias of it + * @param subject The subject of the certificate + * @param issuer The certificate issuer name + * @param fingerprint The fingerprint of the certificate + * @param flags See VERIFY_CERT_FLAG_* for possible values. + * + * @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise. + */ +DWORD client_cli_verify_certificate_ex(freerdp* instance, const char* host, UINT16 port, + const char* common_name, + const char* subject, const char* issuer, + const char* fingerprint, DWORD flags) +{ + const char* type = "RDP-Server"; + + if (flags & VERIFY_CERT_FLAG_GATEWAY) + type = "RDP-Gateway"; + + if (flags & VERIFY_CERT_FLAG_REDIRECT) + type = "RDP-Redirect"; + + printf("Certificate details for %s:%"PRIu16" (%s):\n", host, port, type); + printf("\tCommon Name: %s\n", common_name); + printf("\tSubject: %s\n", subject); + printf("\tIssuer: %s\n", issuer); + printf("\tThumbprint: %s\n", fingerprint); + printf("The above X.509 certificate could not be verified, possibly because you do not have\n" + "the CA certificate in your certificate store, or the certificate has expired.\n" + "Please look at the OpenSSL documentation on how to add a private CA to the store.\n"); + return client_cli_accept_certificate(instance->settings); +} + /** Callback set in the rdp_freerdp structure, and used to make a certificate validation * when a stored certificate does not match the remote counterpart. * This function will actually be called by tls_verify_certificate(). * @see rdp_client_connect() and tls_connect() + * @deprecated Use client_cli_verify_changed_certificate_ex * @param instance - pointer to the rdp_freerdp structure that contains the connection settings * @param common_name * @param subject @@ -535,6 +591,7 @@ DWORD client_cli_verify_changed_certificate(freerdp* instance, const char* old_subject, const char* old_issuer, const char* old_fingerprint) { + printf("WARNING: This callback is deprecated, migrate to client_cli_verify_changed_certificate_ex\n"); printf("!!! Certificate has changed !!!\n"); printf("\n"); printf("New Certificate details:\n"); @@ -553,6 +610,59 @@ DWORD client_cli_verify_changed_certificate(freerdp* instance, return client_cli_accept_certificate(instance->settings); } +/** Callback set in the rdp_freerdp structure, and used to make a certificate validation + * when a stored certificate does not match the remote counterpart. + * This function will actually be called by tls_verify_certificate(). + * @see rdp_client_connect() and tls_connect() + * @param instance pointer to the rdp_freerdp structure that contains the connection settings + * @param host The host currently connecting to + * @param port The port currently connecting to + * @param common_name The common name of the certificate, should match host or an alias of it + * @param subject The subject of the certificate + * @param issuer The certificate issuer name + * @param fingerprint The fingerprint of the certificate + * @param old_subject The subject of the previous certificate + * @param old_issuer The previous certificate issuer name + * @param old_fingerprint The fingerprint of the previous certificate + * @param flags See VERIFY_CERT_FLAG_* for possible values. + * + * @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise. + */ +DWORD client_cli_verify_changed_certificate_ex(freerdp* instance, + const char* host, UINT16 port, + const char* common_name, + const char* subject, const char* issuer, + const char* fingerprint, + const char* old_subject, const char* old_issuer, + const char* old_fingerprint, DWORD flags) +{ + const char* type = "RDP-Server"; + + if (flags & VERIFY_CERT_FLAG_GATEWAY) + type = "RDP-Gateway"; + + if (flags & VERIFY_CERT_FLAG_REDIRECT) + type = "RDP-Redirect"; + + printf("!!!Certificate for %s:%"PRIu16" (%s) has changed!!!\n", host, port, type); + printf("\n"); + printf("New Certificate details:\n"); + printf("\tCommon Name: %s\n", common_name); + printf("\tSubject: %s\n", subject); + printf("\tIssuer: %s\n", issuer); + printf("\tThumbprint: %s\n", fingerprint); + printf("\n"); + printf("Old Certificate details:\n"); + printf("\tSubject: %s\n", old_subject); + printf("\tIssuer: %s\n", old_issuer); + printf("\tThumbprint: %s\n", old_fingerprint); + printf("\n"); + printf("The above X.509 certificate does not match the certificate used for previous connections.\n" + "This may indicate that the certificate has been tampered with.\n" + "Please contact the administrator of the RDP server and clarify.\n"); + return client_cli_accept_certificate(instance->settings); +} + BOOL client_auto_reconnect(freerdp* instance) { return client_auto_reconnect_ex(instance, NULL); diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 103b4d2..a10947c 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -58,6 +58,46 @@ static BOOL copy_value(const char* value, char** dst) return (*dst) != NULL; } +static BOOL value_to_int(const char* value, LONGLONG* result, LONGLONG min, LONGLONG max) +{ + long long rc; + + if (!value || !result) + return FALSE; + + errno = 0; + rc = _strtoi64(value, NULL, 0); + + if (errno != 0) + return FALSE; + + if ((rc < min) || (rc > max)) + return FALSE; + + *result = rc; + return TRUE; +} + +static BOOL value_to_uint(const char* value, ULONGLONG* result, ULONGLONG min, ULONGLONG max) +{ + unsigned long long rc; + + if (!value || !result) + return FALSE; + + errno = 0; + rc = _strtoui64(value, NULL, 0); + + if (errno != 0) + return FALSE; + + if ((rc < min) || (rc > max)) + return FALSE; + + *result = rc; + return TRUE; +} + BOOL freerdp_client_print_version(void) { printf("This is FreeRDP version %s (%s)\n", FREERDP_VERSION_FULL, @@ -71,6 +111,65 @@ BOOL freerdp_client_print_buildconfig(void) return TRUE; } +static char* print_token(char* text, int start_offset, int* current, int limit, + const char delimiter) +{ + int len = (int)strlen(text); + + if (*current < start_offset) + *current += printf("%*c", (start_offset - *current), ' '); + + if (*current + len > limit) + { + int x; + + for (x = MIN(len, limit - start_offset); x > 1; x--) + { + if (text[x] == delimiter) + { + printf("%.*s\n", x, text); + *current = 0; + return &text[x]; + } + } + + return NULL; + } + + *current += printf("%s", text); + return NULL; +} + +static int print_optionals(const char* text, int start_offset, int current) +{ + const size_t limit = 80; + char* str = _strdup(text); + char* cur = print_token(str, start_offset, ¤t, limit, '['); + + while (cur) + cur = print_token(cur, start_offset, ¤t, limit, '['); + + free(str); + return current; +} + +static int print_description(const char* text, int start_offset, int current) +{ + const size_t limit = 80; + char* str = _strdup(text); + char* cur = print_token(str, start_offset, ¤t, limit, ' '); + + while (cur) + { + cur++; + cur = print_token(cur, start_offset, ¤t, limit, ' '); + } + + free(str); + current += (size_t) printf("\n"); + return current; +} + static void freerdp_client_print_command_line_args(COMMAND_LINE_ARGUMENT_A* arg) { if (!arg) @@ -78,46 +177,45 @@ static void freerdp_client_print_command_line_args(COMMAND_LINE_ARGUMENT_A* arg) do { - if (arg->Flags & COMMAND_LINE_VALUE_FLAG) - { - printf(" %s", "/"); - printf("%-20s", arg->Name); - printf("\t%s\n", arg->Text); - } - else if ((arg->Flags & COMMAND_LINE_VALUE_REQUIRED) - || (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL)) - { - BOOL overlong = FALSE; - printf(" %s", "/"); + int pos = 0; + const int description_offset = 30 + 8; + if (arg->Flags & COMMAND_LINE_VALUE_BOOL) + pos += printf(" %s%s", arg->Default ? "-" : "+", arg->Name); + else + pos += printf(" /%s", arg->Name); + + if ((arg->Flags & COMMAND_LINE_VALUE_REQUIRED) + || (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL)) + { if (arg->Format) { - size_t length = (strlen(arg->Name) + strlen(arg->Format) + 2); - if (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL) - length += 2; - - if (length >= 20 + 8 + 8) - overlong = TRUE; - - if (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL) - printf("%s[:%s]", arg->Name, overlong ? "..." : arg->Format); + { + pos += printf("[:"); + pos = print_optionals(arg->Format, pos, pos); + pos += printf("]"); + } else - printf("%s:%s", arg->Name, overlong ? "..." : arg->Format); - } - else - { - printf("%-20s", arg->Name); - } + { + pos += printf(":"); + pos = print_optionals(arg->Format, pos, pos); + } - printf("\t%s\n", arg->Text); - } - else if (arg->Flags & COMMAND_LINE_VALUE_BOOL) - { - printf(" %s", arg->Default ? "-" : "+"); - printf("%-20s", arg->Name); - printf("\t%s %s\n", arg->Default ? "Disable" : "Enable", arg->Text); + if (pos > description_offset) + { + printf("\n"); + pos = 0; + } + } } + + pos += printf("%*c", (description_offset - pos), ' '); + + if (arg->Flags & COMMAND_LINE_VALUE_BOOL) + pos += printf("%s ", arg->Default ? "Disable" : "Enable"); + + print_description(arg->Text, description_offset, pos); } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); } @@ -130,6 +228,9 @@ BOOL freerdp_client_print_command_line_help(int argc, char** argv) BOOL freerdp_client_print_command_line_help_ex(int argc, char** argv, COMMAND_LINE_ARGUMENT_A* custom) { + WINPR_UNUSED(argc); + WINPR_UNUSED(argv); + printf("\n"); printf("FreeRDP - A Free Remote Desktop Protocol Implementation\n"); printf("See www.freerdp.com for more information\n"); @@ -188,6 +289,10 @@ static int freerdp_client_command_line_pre_filter(void* context, int index, { size_t length; rdpSettings* settings; + + if (argc <= index) + return -1; + length = strlen(argv[index]); if (length > 4) @@ -480,7 +585,7 @@ BOOL freerdp_client_add_static_channel(rdpSettings* settings, int count, int index; ADDIN_ARGV* args; - if (!settings || !params || !params[0]) + if (!settings || !params || !params[0] || (count < 0)) return FALSE; if (freerdp_static_channel_collection_find(settings, params[0])) @@ -492,7 +597,7 @@ BOOL freerdp_client_add_static_channel(rdpSettings* settings, int count, return FALSE; args->argc = count; - args->argv = (char**) calloc(args->argc, sizeof(char*)); + args->argv = (char**) calloc((size_t)args->argc, sizeof(char*)); if (!args->argv) goto error_argv; @@ -532,7 +637,7 @@ BOOL freerdp_client_add_dynamic_channel(rdpSettings* settings, int count, int index; ADDIN_ARGV* args; - if (!settings || !params || !params[0]) + if (!settings || !params || !params[0] || (count < 0)) return FALSE; if (freerdp_dynamic_channel_collection_find(settings, params[0])) @@ -544,7 +649,7 @@ BOOL freerdp_client_add_dynamic_channel(rdpSettings* settings, int count, return FALSE; args->argc = count; - args->argv = (char**) calloc(args->argc, sizeof(char*)); + args->argv = (char**) calloc((size_t)args->argc, sizeof(char*)); if (!args->argv) goto error_argv; @@ -839,14 +944,14 @@ static int freerdp_client_command_line_post_filter(void* context, BOOL freerdp_parse_username(const char* username, char** user, char** domain) { char* p; - int length = 0; + size_t length = 0; p = strchr(username, '\\'); *user = NULL; *domain = NULL; if (p) { - length = (int)(p - username); + length = (size_t)(p - username); *user = _strdup(&p[1]); if (!*user) @@ -897,12 +1002,10 @@ BOOL freerdp_parse_hostname(const char* hostname, char** host, int* port) if (p) { - unsigned long val; - SSIZE_T length = (p - hostname); - errno = 0; - val = strtoul(p + 1, NULL, 0); + size_t length = (size_t)(p - hostname); + LONGLONG val; - if ((errno != 0) || (val <= 0) || (val > UINT16_MAX)) + if (!value_to_int(p + 1, &val, 1, UINT16_MAX)) return FALSE; *host = (char*) calloc(length + 1UL, sizeof(char)); @@ -912,7 +1015,7 @@ BOOL freerdp_parse_hostname(const char* hostname, char** host, int* port) CopyMemory(*host, hostname, length); (*host)[length] = '\0'; - *port = val; + *port = (UINT16)val; } else { @@ -927,7 +1030,7 @@ BOOL freerdp_parse_hostname(const char* hostname, char** host, int* port) return TRUE; } -BOOL freerdp_set_connection_type(rdpSettings* settings, int type) +BOOL freerdp_set_connection_type(rdpSettings* settings, UINT32 type) { settings->ConnectionType = type; @@ -1062,11 +1165,16 @@ int freerdp_map_keyboard_layout_name_to_id(char* name) static int freerdp_detect_command_line_pre_filter(void* context, int index, int argc, LPSTR* argv) { - int length; + size_t length; + + WINPR_UNUSED(context); if (index == 1) { - length = (int) strlen(argv[index]); + if (argc < index) + return -1; + + length = strlen(argv[index]); if (length > 4) { @@ -1323,21 +1431,22 @@ static void activate_smartcard_logon_rdp(rdpSettings* settings) * @param v2: pointer to output v2 * @return if the parsing was successful */ -static BOOL parseSizeValue(const char *input, unsigned long *v1, unsigned long *v2) +static BOOL parseSizeValue(const char* input, unsigned long* v1, unsigned long* v2) { - const char *xcharpos; - char *endPtr; + const char* xcharpos; + char* endPtr; unsigned long v; - errno = 0; v = strtoul(input, &endPtr, 10); if ((v == 0 || v == ULONG_MAX) && (errno != 0)) return FALSE; + if (v1) *v1 = v; xcharpos = strchr(input, 'x'); + if (!xcharpos || xcharpos != endPtr) return FALSE; @@ -1349,6 +1458,7 @@ static BOOL parseSizeValue(const char *input, unsigned long *v1, unsigned long * if (*endPtr != '\0') return FALSE; + if (v2) *v2 = v; @@ -1410,7 +1520,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (assist) { if (freerdp_client_settings_parse_assistance_file(settings, - argv[1]) < 0) + argc, argv) < 0) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } @@ -1438,6 +1548,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "v") { + assert(arg->Value); + free(settings->ServerHostname); settings->ServerHostname = NULL; p = strchr(arg->Value, '['); @@ -1449,13 +1561,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (p) { - unsigned long val = strtoul(&p[1], NULL, 0); + LONGLONG val; - if ((errno != 0) || (val == 0) || (val > UINT16_MAX)) + if (!value_to_int(&p[1], &val, 1, UINT16_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - length = (int)(p - arg->Value); - settings->ServerPort = val; + length = (size_t)(p - arg->Value); + settings->ServerPort = (UINT16)val; if (!(settings->ServerHostname = (char*) calloc(length + 1UL, sizeof(char)))) return COMMAND_LINE_ERROR_MEMORY; @@ -1477,7 +1589,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (!p2) continue; - length = p2 - p; + length = (size_t)(p2 - p); if (!(settings->ServerHostname = (char*) calloc(length, sizeof(char)))) return COMMAND_LINE_ERROR_MEMORY; @@ -1486,12 +1598,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (*(p2 + 1) == ':') { - unsigned long val = strtoul(&p2[2], NULL, 0); + LONGLONG val; - if ((errno != 0) || (val == 0) || (val > UINT16_MAX)) + if (!value_to_int(&p[2], &val, 0, UINT16_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->ServerPort = val; + settings->ServerPort = (UINT16)val; } printf("hostname %s port %"PRIu32"\n", settings->ServerHostname, settings->ServerPort); @@ -1506,6 +1618,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { size_t count = 0; char* cur = arg->Value; + assert(arg->Value); + settings->RedirectionPreferType = 0; do @@ -1558,35 +1672,37 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "w") { - long val = strtol(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val <= 0) || (val > UINT16_MAX)) + if (!value_to_int(arg->Value, &val, -1, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->DesktopWidth = val; + settings->DesktopWidth = (UINT32)val; } CommandLineSwitchCase(arg, "h") { - long val = strtol(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val <= 0) || (val > UINT16_MAX)) + if (!value_to_int(arg->Value, &val, -1, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->DesktopHeight = val; + settings->DesktopHeight = (UINT32)val; } CommandLineSwitchCase(arg, "size") { + assert(arg->Value); p = strchr(arg->Value, 'x'); if (p) { unsigned long w, h; + if (!parseSizeValue(arg->Value, &w, &h) || (w > UINT16_MAX) || (h > UINT16_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->DesktopWidth = w; - settings->DesktopHeight = h; + settings->DesktopWidth = (UINT32)w; + settings->DesktopHeight = (UINT32)h; } else { @@ -1619,15 +1735,15 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, *p = '\0'; { - long val = strtol(str, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val < 0) || (val > 100)) + if (!value_to_int(str, &val, 0, 100)) { free(str); return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } - settings->PercentScreen = val; + settings->PercentScreen = (UINT32)val; } } @@ -1638,6 +1754,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { settings->Fullscreen = enable; } + CommandLineSwitchCase(arg, "suppress-output") + { + settings->SuppressOutput = enable; + } CommandLineSwitchCase(arg, "multimon") { settings->UseMultimon = TRUE; @@ -1677,12 +1797,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, for (i = 0; i < settings->NumMonitorIds; i++) { - unsigned long val = strtoul(p[i], NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT16_MAX)) + if (!value_to_int(p[i], &val, 0, UINT16_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->MonitorIds[i] = val; + settings->MonitorIds[i] = (UINT32)val; } free(p); @@ -1729,19 +1849,17 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (!parseSizeValue(arg->Value, &w, &h) || (w > UINT16_MAX) || (h > UINT16_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->SmartSizingWidth = w; - settings->SmartSizingHeight = h; + settings->SmartSizingWidth = (UINT32)w; + settings->SmartSizingHeight = (UINT32)h; } } CommandLineSwitchCase(arg, "bpp") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if (errno != 0) + if (!value_to_int(arg->Value, &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->ColorDepth = val; - switch (settings->ColorDepth) { case 32: @@ -1749,6 +1867,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, case 16: case 15: case 8: + settings->ColorDepth = (UINT32)val; break; default: @@ -1783,9 +1902,9 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "kbd") { - unsigned long id = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (id > UINT32_MAX) || (id == 0)) + if (!value_to_int(arg->Value, &val, 1, UINT32_MAX)) { const int rc = freerdp_map_keyboard_layout_name_to_id(arg->Value); @@ -1797,38 +1916,38 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } /* Found a valid mapping, reset errno */ - id = (unsigned long)rc; + val = rc; errno = 0; } - settings->KeyboardLayout = (UINT32) id; + settings->KeyboardLayout = (UINT32) val; } CommandLineSwitchCase(arg, "kbd-type") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT32_MAX)) + if (!value_to_int(arg->Value, &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->KeyboardType = val; + settings->KeyboardType = (UINT32)val; } CommandLineSwitchCase(arg, "kbd-subtype") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT32_MAX)) + if (!value_to_int(arg->Value, &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->KeyboardSubType = val; + settings->KeyboardSubType = (UINT32)val; } CommandLineSwitchCase(arg, "kbd-fn-key") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT32_MAX)) + if (!value_to_int(arg->Value, &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->KeyboardFunctionKey = val; + settings->KeyboardFunctionKey = (UINT32)val; } CommandLineSwitchCase(arg, "u") { @@ -1850,23 +1969,26 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { + assert(arg->Value); + p = strchr(arg->Value, ':'); if (p) { - unsigned long val = strtoul(&p[1], NULL, 0); + size_t s; + LONGLONG val; - if ((errno != 0) || (val == 0) || (val > UINT16_MAX)) + if (!value_to_int(&p[1], &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - length = (int)(p - arg->Value); - settings->GatewayPort = val; + s = (size_t)(p - arg->Value); + settings->GatewayPort = (UINT32)val; - if (!(settings->GatewayHostname = (char*) calloc(length + 1UL, sizeof(char)))) + if (!(settings->GatewayHostname = (char*) calloc(s + 1UL, sizeof(char)))) return COMMAND_LINE_ERROR_MEMORY; - strncpy(settings->GatewayHostname, arg->Value, length); - settings->GatewayHostname[length] = '\0'; + strncpy(settings->GatewayHostname, arg->Value, s); + settings->GatewayHostname[s] = '\0'; } else { @@ -1892,6 +2014,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { char* atPtr; + assert(arg->Value); + /* value is [scheme://][user:password@]hostname:port */ p = strstr(arg->Value, "://"); @@ -1960,13 +2084,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (p) { - unsigned long val = strtoul(&p[1], NULL, 0); + LONGLONG val; - if ((errno != 0) || (val == 0) || (val > UINT16_MAX)) + if (!value_to_int(&p[1], &val, 0, UINT16_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - length = (p - arg->Value); - settings->ProxyPort = val; + length = (size_t)(p - arg->Value); + settings->ProxyPort = (UINT16)val; settings->ProxyHostname = (char*) malloc(length + 1); strncpy(settings->ProxyHostname, arg->Value, length); settings->ProxyHostname[length] = '\0'; @@ -2024,8 +2148,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "gateway-usage-method") { - long type = 0; - char* pEnd; + UINT32 type = 0; if (_stricmp(arg->Value, "none") == 0) type = TSC_PROXY_MODE_NONE_DIRECT; @@ -2037,13 +2160,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, type = TSC_PROXY_MODE_DEFAULT; else { - type = strtol(arg->Value, &pEnd, 10); + LONGLONG val; - if (errno != 0) + if (!value_to_int(arg->Value, &val, TSC_PROXY_MODE_NONE_DIRECT, TSC_PROXY_MODE_NONE_DETECT)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } - freerdp_set_gateway_usage_method(settings, (UINT32) type); + freerdp_set_gateway_usage_method(settings, type); } CommandLineSwitchCase(arg, "app") { @@ -2095,12 +2218,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "compression-level") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT32_MAX)) + if (!value_to_int(arg->Value, &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->CompressionLevel = val; + settings->CompressionLevel = (UINT32)val; } CommandLineSwitchCase(arg, "drives") { @@ -2130,29 +2253,33 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "audio-mode") { - long mode = strtol(arg->Value, NULL, 0); + LONGLONG val; - if (errno != 0) + if (!value_to_int(arg->Value, &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - if (mode == AUDIO_MODE_REDIRECT) + switch (val) { - settings->AudioPlayback = TRUE; - } - else if (mode == AUDIO_MODE_PLAY_ON_SERVER) - { - settings->RemoteConsoleAudio = TRUE; - } - else if (mode == AUDIO_MODE_NONE) - { - settings->AudioPlayback = FALSE; - settings->RemoteConsoleAudio = FALSE; + case AUDIO_MODE_REDIRECT: + settings->AudioPlayback = TRUE; + break; + + case AUDIO_MODE_PLAY_ON_SERVER: + settings->RemoteConsoleAudio = TRUE; + break; + + case AUDIO_MODE_NONE: + settings->AudioPlayback = FALSE; + settings->RemoteConsoleAudio = FALSE; + break; + + default: + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } } CommandLineSwitchCase(arg, "network") { - long type = 0; - char* pEnd; + UINT32 type = 0; if (_stricmp(arg->Value, "modem") == 0) type = CONNECTION_TYPE_MODEM; @@ -2174,10 +2301,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } else { - type = strtol(arg->Value, &pEnd, 10); + LONGLONG val; - if (errno != 0) + if (!value_to_int(arg->Value, &val, 1, 7)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + + type = (UINT32)val; } if (!freerdp_set_connection_type(settings, type)) @@ -2208,8 +2337,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, return COMMAND_LINE_ERROR_MISSING_ARGUMENT; } - settings->DesktopPosX = x; - settings->DesktopPosY = y; + settings->DesktopPosX = (UINT32)x; + settings->DesktopPosY = (UINT32)y; } CommandLineSwitchCase(arg, "menu-anims") { @@ -2300,6 +2429,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "rfx-mode") { + assert(arg->Value); + if (strcmp(arg->Value, "video") == 0) settings->RemoteFxCodecMode = 0x00; else if (strcmp(arg->Value, "image") == 0) @@ -2307,12 +2438,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "frame-ack") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT32_MAX)) + if (!value_to_int(arg->Value, &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->FrameAcknowledge = val; + settings->FrameAcknowledge = (UINT32)val; } CommandLineSwitchCase(arg, "nsc") { @@ -2326,12 +2457,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "jpeg-quality") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > 100)) + if (!value_to_int(arg->Value, &val, 0, 100)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->JpegQuality = val; + settings->JpegQuality = (UINT32)val; } #endif CommandLineSwitchCase(arg, "nego") @@ -2347,16 +2478,18 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "pcid") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT32_MAX)) + if (!value_to_int(arg->Value, &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; settings->SendPreconnectionPdu = TRUE; - settings->PreconnectionId = val; + settings->PreconnectionId = (UINT32)val; } CommandLineSwitchCase(arg, "sec") { + assert(arg->Value); + if (strcmp("rdp", arg->Value) == 0) /* Standard RDP */ { settings->RdpSecurity = TRUE; @@ -2423,6 +2556,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { + assert(arg->Value); + promptForPassword = (strncmp(arg->Value, "force", 6) == 0); if (!promptForPassword) @@ -2459,6 +2594,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "tls-ciphers") { + assert(arg->Value); + free(settings->AllowedTlsCiphers); if (strcmp(arg->Value, "netmon") == 0) @@ -2479,12 +2616,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "tls-seclevel") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > 5)) + if (!value_to_int(arg->Value, &val, 0, 5)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->TlsSecLevel = val; + settings->TlsSecLevel = (UINT32)val; } CommandLineSwitchCase(arg, "cert-name") { @@ -2499,6 +2636,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { settings->AutoAcceptCertificate = enable; } + CommandLineSwitchCase(arg, "cert-deny") + { + settings->AutoDenyCertificate = enable; + } CommandLineSwitchCase(arg, "authentication") { settings->Authentication = enable; @@ -2521,7 +2662,70 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "floatbar") { - settings->Floatbar = enable; + /* Defaults are enabled, visible, sticky, fullscreen */ + settings->Floatbar = 0x0017; + + if (arg->Value) + { + char* start = arg->Value; + + do + { + char* cur = start; + start = strchr(start, ','); + + if (start) + { + *start = '\0'; + start = start + 1; + } + + /* sticky:[on|off] */ + if (_strnicmp(cur, "sticky:", 7) == 0) + { + const char* val = cur + 7; + settings->Floatbar &= ~0x02u; + + if (_strnicmp(val, "on", 3) == 0) + settings->Floatbar |= 0x02u; + else if (_strnicmp(val, "off", 4) == 0) + settings->Floatbar &= ~0x02u; + else + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + } + /* default:[visible|hidden] */ + else if (_strnicmp(cur, "default:", 8) == 0) + { + const char* val = cur + 8; + settings->Floatbar &= ~0x04u; + + if (_strnicmp(val, "visible", 8) == 0) + settings->Floatbar |= 0x04u; + else if (_strnicmp(val, "hidden", 7) == 0) + settings->Floatbar &= ~0x04u; + else + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + } + /* show:[always|fullscreen|window] */ + else if (_strnicmp(cur, "show:", 5) == 0) + { + const char* val = cur + 5; + settings->Floatbar &= ~0x30u; + + if (_strnicmp(val, "always", 7) == 0) + settings->Floatbar |= 0x30u; + else if (_strnicmp(val, "fullscreen", 11) == 0) + settings->Floatbar |= 0x10u; + else if (_strnicmp(val, "window", 7) == 0) + settings->Floatbar |= 0x20u; + else + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + } + else + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + } + while (start); + } } CommandLineSwitchCase(arg, "mouse-motion") { @@ -2529,12 +2733,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "parent-window") { - UINT64 val = _strtoui64(arg->Value, NULL, 0); + ULONGLONG val; - if (errno != 0) + if (!value_to_uint(arg->Value, &val, 0, UINT64_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->ParentWindowId = val; + settings->ParentWindowId = (UINT64)val; } CommandLineSwitchCase(arg, "bitmap-cache") { @@ -2542,7 +2746,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "offscreen-cache") { - settings->OffscreenSupportLevel = enable; + settings->OffscreenSupportLevel = (UINT32)enable; } CommandLineSwitchCase(arg, "glyph-cache") { @@ -2553,6 +2757,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { settings->BitmapCacheV3Enabled = TRUE; + assert(arg->Value); + if (strcmp(arg->Value, "rfx") == 0) { settings->RemoteFxCodec = TRUE; @@ -2580,32 +2786,24 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "max-fast-path-size") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT32_MAX)) + if (!value_to_int(arg->Value, &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->MultifragMaxRequestSize = val; + settings->MultifragMaxRequestSize = (UINT32)val; } CommandLineSwitchCase(arg, "max-loop-time") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT32_MAX)) + if (!value_to_int(arg->Value, &val, -1, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->MaxTimeInCheckLoop = val; - - if ((long) settings->MaxTimeInCheckLoop < 0) - { - WLog_ERR(TAG, "invalid max loop time: %s", arg->Value); - return COMMAND_LINE_ERROR; - } - - if ((long) settings->MaxTimeInCheckLoop <= 0) - { + if (val < 0) settings->MaxTimeInCheckLoop = 10 * 60 * 60 * 1000; /* 10 hours can be considered as infinite */ - } + else + settings->MaxTimeInCheckLoop = (UINT32)val; } CommandLineSwitchCase(arg, "async-input") { @@ -2641,26 +2839,26 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "auto-reconnect-max-retries") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT32_MAX)) + if (!value_to_int(arg->Value, &val, 0, 1000)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->AutoReconnectMaxRetries = val; - - if (settings->AutoReconnectMaxRetries > 1000) - return COMMAND_LINE_ERROR; + settings->AutoReconnectMaxRetries = (UINT32)val; } CommandLineSwitchCase(arg, "reconnect-cookie") { BYTE* base64 = NULL; int length; + + assert(arg->Value); + crypto_base64_decode((const char*)(arg->Value), (int) strlen(arg->Value), &base64, &length); if ((base64 != NULL) && (length == sizeof(ARC_SC_PRIVATE_PACKET))) { - memcpy(settings->ServerAutoReconnectCookie, base64, length); + memcpy(settings->ServerAutoReconnectCookie, base64, (size_t)length); } else { @@ -2673,39 +2871,32 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { settings->PrintReconnectCookie = enable; } - CommandLineSwitchCase(arg, "assistance") - { - settings->RemoteAssistanceMode = TRUE; - - if (!copy_value(arg->Value, &settings->RemoteAssistancePassword)) - return COMMAND_LINE_ERROR_MEMORY; - } CommandLineSwitchCase(arg, "pwidth") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT32_MAX)) + if (!value_to_int(arg->Value, &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->DesktopPhysicalWidth = val; + settings->DesktopPhysicalWidth = (UINT32)val; } CommandLineSwitchCase(arg, "pheight") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > UINT32_MAX)) + if (!value_to_int(arg->Value, &val, 0, UINT32_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->DesktopPhysicalHeight = val; + settings->DesktopPhysicalHeight = (UINT32)val; } CommandLineSwitchCase(arg, "orientation") { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val > INT16_MAX)) + if (!value_to_int(arg->Value, &val, 0, UINT16_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->DesktopOrientation = val; + settings->DesktopOrientation = (UINT16)val; } CommandLineSwitchCase(arg, "old-license") { @@ -2713,55 +2904,49 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "scale") { - unsigned long scaleFactor = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if (errno != 0) + if (!value_to_int(arg->Value, &val, 100, 180)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - if (scaleFactor == 100 || scaleFactor == 140 || scaleFactor == 180) + switch (val) { - settings->DesktopScaleFactor = scaleFactor; - settings->DeviceScaleFactor = scaleFactor; - } - else - { - WLog_ERR(TAG, "scale: invalid scale factor (%d)", scaleFactor); - return COMMAND_LINE_ERROR; + case 100: + case 140: + case 180: + settings->DeviceScaleFactor = (UINT32)val; + break; + + default: + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } } CommandLineSwitchCase(arg, "scale-desktop") { - unsigned long desktopScaleFactor = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if (errno != 0) - return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + if (!value_to_int(arg->Value, &val, 100, 500)) + return FALSE; - if (desktopScaleFactor >= 100 && desktopScaleFactor <= 500) - { - settings->DesktopScaleFactor = desktopScaleFactor; - } - else - { - WLog_ERR(TAG, "scale: invalid desktop scale factor (%d)", desktopScaleFactor); - return COMMAND_LINE_ERROR; - } + settings->DesktopScaleFactor = (UINT32)val; } CommandLineSwitchCase(arg, "scale-device") { - unsigned long deviceScaleFactor = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if (errno != 0) + if (!value_to_int(arg->Value, &val, 100, 180)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - if (deviceScaleFactor == 100 || deviceScaleFactor == 140 - || deviceScaleFactor == 180) + switch (val) { - settings->DeviceScaleFactor = deviceScaleFactor; - } - else - { - WLog_ERR(TAG, "scale: invalid device scale factor (%d)", deviceScaleFactor); - return COMMAND_LINE_ERROR; + case 100: + case 140: + case 180: + settings->DeviceScaleFactor = (UINT32)val; + break; + + default: + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } } CommandLineSwitchCase(arg, "action-script") @@ -2867,12 +3052,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT) { - unsigned long val = strtoul(arg->Value, NULL, 0); + LONGLONG val; - if ((errno != 0) || (val == 0) || (val > UINT16_MAX)) + if (!value_to_int(arg->Value, &val, 1, UINT16_MAX)) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - settings->ServerPort = val; + settings->ServerPort = (UINT32)val; } arg = CommandLineFindArgumentA(args, "p"); @@ -3057,6 +3242,7 @@ BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) { settings->EncomspVirtualChannel = TRUE; settings->RemdeskVirtualChannel = TRUE; + settings->NlaSecurity = FALSE; } if (settings->EncomspVirtualChannel) diff --git a/client/common/cmdline.h b/client/common/cmdline.h index 7f1d9e0..030ff7b 100644 --- a/client/common/cmdline.h +++ b/client/common/cmdline.h @@ -46,19 +46,20 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "bitmap-cache", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "bitmap cache" }, { "bpp", COMMAND_LINE_VALUE_REQUIRED, "", "16", NULL, -1, NULL, "Session bpp (color depth)" }, { "buildconfig", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_BUILDCONFIG, NULL, NULL, NULL, -1, NULL, "Print the build configuration" }, + { "cert-deny", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Automatically abort connection for any certificate that can not be validated." }, { "cert-ignore", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Ignore certificate" }, { "cert-name", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Certificate name" }, { "cert-tofu", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Automatically accept certificate on first connect" }, { "client-hostname", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Client Hostname to send to server" }, { "clipboard", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Redirect clipboard" }, - { "codec-cache", COMMAND_LINE_VALUE_REQUIRED, "rfx|nsc|jpeg", NULL, NULL, -1, NULL, "Bitmap codec cache" }, + { "codec-cache", COMMAND_LINE_VALUE_REQUIRED, "[rfx|nsc|jpeg]", NULL, NULL, -1, NULL, "Bitmap codec cache" }, { "compression", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, "z", "compression" }, { "compression-level", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Compression level (0,1,2)" }, { "credentials-delegation", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "credentials delegation" }, { "d", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Domain" }, { "decorations", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Window decorations" }, { "disp", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Display control" }, - { "drive", COMMAND_LINE_VALUE_REQUIRED, ",", NULL, NULL, -1, NULL, "Redirect directory as named share " }, + { "drive", COMMAND_LINE_VALUE_REQUIRED, ",", NULL, NULL, -1, NULL, "Redirect directory as named share . Hotplug support is enabled with /drive:hotplug,*. This argument provides the same function as \"Drives that I plug in later\" option in MSTSC." }, { "drives", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect all mount points as shares" }, { "dvc", COMMAND_LINE_VALUE_REQUIRED, "[,]", NULL, NULL, -1, NULL, "Dynamic virtual channel" }, { "dynamic-resolution", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Send resolution updates when the window is resized" }, @@ -68,19 +69,19 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "f", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Fullscreen mode (++ toggles fullscreen)" }, { "fast-path", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "fast-path input/output" }, { "fipsmode", COMMAND_LINE_VALUE_BOOL, NULL, NULL, NULL, -1, NULL, "FIPS mode" }, - { "floatbar", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "floatbar in fullscreen mode" }, - { "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "smooth fonts (ClearType)" }, + { "floatbar", COMMAND_LINE_VALUE_OPTIONAL, "sticky:[on|off],default:[visible|hidden],show:[always|fullscreen||window]", NULL, NULL, -1, NULL, "floatbar is disabled by default (when enabled defaults to sticky in fullscreen mode)" }, + { "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "smooth fonts (ClearType)" }, { "frame-ack", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Number of frame acknowledgement" }, { "from-stdin", COMMAND_LINE_VALUE_OPTIONAL, "force", NULL, NULL, -1, NULL, "Read credentials from stdin. With the prompt is done before connection, otherwise on server request." }, { "g", COMMAND_LINE_VALUE_REQUIRED, "[:]", NULL, NULL, -1, NULL, "Gateway Hostname" }, - { "gateway-usage-method", COMMAND_LINE_VALUE_REQUIRED, "direct|detect", NULL, NULL, -1, "gum", "Gateway usage method" }, + { "gateway-usage-method", COMMAND_LINE_VALUE_REQUIRED, "[direct|detect]", NULL, NULL, -1, "gum", "Gateway usage method" }, { "gd", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Gateway domain" }, { "gdi", COMMAND_LINE_VALUE_REQUIRED, "sw|hw", NULL, NULL, -1, NULL, "GDI rendering" }, { "geometry", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Geometry tracking channel" }, { "gestures", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Consume multitouch input locally" }, #ifdef WITH_GFX_H264 - { "gfx", COMMAND_LINE_VALUE_OPTIONAL, "RFX|AVC420|AVC444", NULL, NULL, -1, NULL, "RDP8 graphics pipeline (experimental)" }, - { "gfx-h264", COMMAND_LINE_VALUE_OPTIONAL, "AVC420|AVC444", NULL, NULL, -1, NULL, "RDP8.1 graphics pipeline using H264 codec" }, + { "gfx", COMMAND_LINE_VALUE_OPTIONAL, "[RFX|AVC420|AVC444]", NULL, NULL, -1, NULL, "RDP8 graphics pipeline (experimental)" }, + { "gfx-h264", COMMAND_LINE_VALUE_OPTIONAL, "[AVC420|AVC444]", NULL, NULL, -1, NULL, "RDP8.1 graphics pipeline using H264 codec" }, #else { "gfx", COMMAND_LINE_VALUE_OPTIONAL, "RFX", NULL, NULL, -1, NULL, "RDP8 graphics pipeline (experimental)" }, #endif @@ -90,8 +91,8 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "glyph-cache", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Glyph cache (experimental)" }, { "gp", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Gateway password" }, { "grab-keyboard", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Grab keyboard" }, - { "gt", COMMAND_LINE_VALUE_REQUIRED, "rpc|http|auto", NULL, NULL, -1, NULL, "Gateway transport type" }, - { "gu", COMMAND_LINE_VALUE_REQUIRED, "[\\] or [@]", NULL, NULL, -1, NULL, "Gateway username" }, + { "gt", COMMAND_LINE_VALUE_REQUIRED, "[rpc|http|auto]", NULL, NULL, -1, NULL, "Gateway transport type" }, + { "gu", COMMAND_LINE_VALUE_REQUIRED, "[[\\]|[@]]", NULL, NULL, -1, NULL, "Gateway username" }, { "gat", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Gateway Access Token" }, { "h", COMMAND_LINE_VALUE_REQUIRED, "", "768", NULL, -1, NULL, "Height" }, { "heartbeat", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support heartbeat PDUs" }, @@ -109,7 +110,7 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "kbd-type", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Keyboard type" }, { "load-balance-info", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Load balance info" }, { "log-filters", COMMAND_LINE_VALUE_REQUIRED, ":[,:[,...]]", NULL, NULL, -1, NULL, "Set logger filters, see wLog(7) for details" }, - { "log-level", COMMAND_LINE_VALUE_REQUIRED, "OFF|FATAL|ERROR|WARN|INFO|DEBUG|TRACE", NULL, NULL, -1, NULL, "Set the default log level, see wLog(7) for details" }, + { "log-level", COMMAND_LINE_VALUE_REQUIRED, "[OFF|FATAL|ERROR|WARN|INFO|DEBUG|TRACE]", NULL, NULL, -1, NULL, "Set the default log level, see wLog(7) for details" }, { "max-fast-path-size", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Specify maximum fast-path update size" }, { "max-loop-time", COMMAND_LINE_VALUE_REQUIRED, "